← Qnative (provisional) · c4
review-1.md
Review stop 1: the messaging slice
Contents
2026-11-11. qnative c4, design c137 Phase 3: the V1 slice of the message channel, built in the brief's five steps on the pipes c2 made. What to look at, the figures, the calls for Mark. The record of each step is in CYCLE.md.
How to try it
- The inbox on the pilot world.
cargo run -p app -- --data synthetic --world pilot, then Messages › Inbox in the sidebar (the count beside it). The open required censure sits first though it is the oldest of the day; a row opens its card; Acknowledge ends the censure and the toast says HQ sees it; the fold at the bottom holds the ended ones. Settings opens the Messages page: the four positions per kind, the tray switch, quiet hours, mutes, the required count, what this build can post, what this app records. - The tray. The menu's Inbox item reads "Inbox (4): From HQ: stop using a personal ChatGPT account for work" and the icon carries the count as its title; Off on the tray switch empties both; the inbox still fills.
- The two flows, without a pointer.
QPOINT_SPIKE_DRILL=2delivers the local enforcement notice two seconds in (synthetic worlds only);QPOINT_SPIKE_CONNECT=2runs the identity confirmation as if Connect had just finished against hq.example (it asks the OS for alert permission once, which a bundle shows as the system prompt). - Through a plane.
cargo run -p fixture-plane -- --world pilot --port 47612, thencargo run -p app -- --data plane --plane-url http://127.0.0.1:47612: the ten arrive over HTTP from/api/messagesinto~/Library/Application Support/io.qpoint.desktop/inbox.sqlite(QPOINT_INBOXmoves it), the new ones delivered, the seen ones adopted as they are. Over--world meridian-day90the plane holds none, so the app composes the confirmation itself, once; a second launch finds it in the file. - The real notification. macOS posts only for a bundle, so
scripts/bundle-dev-app.shwraps the release binary intarget/Qpoint-dev.app(ad hoc signed). Run its executable withQPOINT_DATA=synthetic QPOINT_WORLD=pilot: the Messages page then says "allowed" or "not asked yet" with the "Allow notifications" button (asked once; the OS prompt is the OS's), and a drill at Normal posts a banner.prioritystays an ordinary notification until a signed build carries the entitlement (call 4). - The stories.
cargo run -p stories -- --only app-inboxand the other nine (app-inbox-empty,-card,-acknowledged,-expired,-withheld,-drill,-connected,app-messages-settings,-tuned);QPOINT_NOW=2026-11-11T22:30:00Zpins the clock so the captures read the same tomorrow. Thirteen are in design's atlas under threadc4-messaging.
What was built, in one table
| Piece | Where | State |
|---|---|---|
The bones as types, the ten examples as a fixture, the drift test against bones.md | types::messages, fixtures/messages/bones-examples.json | done; 5 + 2 tests |
| The inbox store: SQLite beside the settings, §5's transitions, expiry, the required count, a delivery record per message | messages::store, messages::deliver, messages::clock | done; 11 tests |
| The OS notification behind one trait; the macOS port with the interruption level per post; the entitlement read from the signature | messages::notify, notify::macos | done on macOS; Windows and Linux say "not available here" |
| The inbox page: the lift, the card, the actions, the toast, the honesty line, the fold | app::pages::inbox | done |
| Messages, the settings page | app::pages::messages_settings | done |
| The tray's count and one line; the sidebar count; a notification click opens the card | app::tray, app::shell, app::messaging | done |
| Messages as a resource of the nozzle; the inbox syncs from it | types::routes::MESSAGES, nozzle, fixture-plane, app::messaging::sync | done; synced once at open and on a world switch |
| The identity confirmation on Connect; the enforcement notice by drill | app::messaging::connected, ::drill | done; Connect itself is c131's page, not built |
| Stories, captures, the budget | stories, captures/messaging.json, below | done |
The figures
- Tests: the workspace's suite passes (types 5, fixtures 7 with the strict drift test, messages 11, nozzle 10, app 11 and the rest); run
cargo test --workspace. - Stories: 10 new, 13 captures published (thread
c4-messaging). - Budget: strobe, release builds, c1's recipe (5 s to settle, 60 s recorded,
QPOINT_DATA=synthetic QPOINT_WORLD=pilot), interleaved with the tree as it stood before the slice (273ada7, the last commit before it that builds: c5's groundwork commit carried this cycle'sRepo::world()ahead of the trait method it calls, so the two commits between do not compile on their own). The readings were taken while this session worked on the same Mac, so they are not the quiet readings c3 took on an idle machine; the two builds were read back to back under the same conditions.
| Build | Mode | Private memory (strobe) | Physical footprint (footprint) | RSS | CPU, idle | Wakes/s | Recording |
|---|---|---|---|---|---|---|---|
| 273ada7 (before) | window, overview | 62.2 MB | 62 MB | 76 MB | 0.002% of one core (1.20 ms in 60 s) | 0.83 | rec_1d0efa |
| 2c01ebf (the slice) | window, overview | 83.3 MB | 83 MB | 88 MB | 2.43% of one core (1456 ms in 60 s) | 212 | rec_f10f1b |
| 2c01ebf (the slice) | window, Inbox (ten messages) | 63.5 MB | 64 MB | 79 MB | 0.15% of one core (90.3 ms in 60 s) | 25.9 | rec_aba199 |
| 273ada7 (before) | tray only | 23.3 MB | 23 MB | 47 MB | 0.003% of one core (1.85 ms in 60 s) | 0.88 | rec_25b5b5 |
| 2c01ebf (the slice) | tray only (four waiting) | 23.0 MB | 23 MB | 48 MB | 0.01% of one core (3.04 ms in 60 s) | 0.73 | rec_d700fd |
| 2c01ebf (the slice) | window, Inventory overview (second round) | 68.5 MB | 69 MB | — | 0.06% of one core (34.3 ms in 60 s) | 6.39 | rec_088645 |
| 2c01ebf (the slice) | window, Inbox (second round) | 61.8 MB | 62 MB | — | 0.02% of one core (12.6 ms in 60 s) | 2.96 | rec_fa9be6 |
Binaries: before 23.9 MB, the slice 24.9 MB (+0.99 MB: the messages crate, its SQLite binding and the notification bindings, the two pages, c5's two pages and c3's stream core together).
- The inbox at rest costs nothing measurable. The second round read the Inbox at 61.8 MB, 0.02 % of a core and 3 wakes a second, the baseline's overview at 62.2 MB, 0.002 % and 0.8; the first inbox round (63.5 MB, 0.15 %, 26 wakes) was taken while this session was building on the Mac. The Inventory overview on the slice build read 68.5 MB, 0.06 %, 6.4 wakes.
- The Status landing draws at rest. The slice build opened on its landing, Status (c5's page, on main since 04531db), read 83 MB, 2.43 % of a core and 212 wakes a second for the whole minute, with 1.76 s of CPU by the five-second mark: something on that page asks for frames continuously. It is not this cycle's (the Inbox and the overview on the same binary read quiet) and is handed to c5 by message; it is the one number in this table that is not a rest reading.
- The tray at rest is 23 MB on both builds, with the inbox holding the pilot world's ten messages and four of them waiting (the count in the icon's title, the Inbox item's line); the record is SQLite in memory for a synthetic world, and nothing polls.
- The readings were taken while this session worked on the Mac, not under c3's idle-Mac rule; the two builds were read in one session, back to back. strobe's insights found nothing to flag in any recording.
Findings for the specification (design c137)
required_reasonis not in bones §1. §6 says the card carries HQ's reason line above the soft ceiling; the field is added here as optional and recorded as drift to resolve inbones.md.- Reply is not an action kind. E6 names "Acknowledge · Reply · See the server"; §4's seven kinds have no reply. Here Reply rides
contact-itwith its own label. - The ten speak of Acme and MBP-2291 (Dana Whitfield at HQ, Mark Parson), while the worlds are Meridian's (priya-x1, nina-mbp). The fixture is verbatim, as the voice fixtures should be; a recut of the examples onto the Meridian cast is a design task (c137 or c132).
- The
connectedworld is not bundled. The fixture names it (nine of the ten) and the seed rule is ready;pilotcarries the ten today and the quiet default none. When c131 cutsconnected, the inbox follows with no code. - Dismiss has no sender. §4 says
dismissexists only for info and ends it; nobody lists it. The app adds Dismiss on info cards the way it adds Acknowledge when owed. seenis "opened". A row click opens the card and marks the message seen, so the lift moves it from the new band to the seen band on the next look. Clicking the OS notification does the same.
Calls for Mark
- The delivery words. D9 gives three modes (quiet · normal · priority) and the brief adds "off · inbox"; the inventory had four positions (off · inbox · tray · notify). Built as a ladder of five: Off keeps a kind in the inbox and nowhere else; Inbox counts it in the tray (its badge and one line); Quiet and Normal add one notification at passive or active; Priority is reserved to required messages (time-sensitive with the entitlement, else active) and the person's own controls stop at Normal. The defaults map the inventory's: notify → Normal (censures), tray → Inbox (enforcement notices and the rest), inbox → Off (HQ notices). Accept these five words, or rename the second rung "Tray" so "Inbox" can mean the inventory's quiet inbox?
- The mailto's
it_contactsource. qcontrol's configuration has no such field (qconfigwas searched); the fixture's E2 carriesmailto:it-help@acme.examplein its action's target. Proposal: anit_contactstring in qcontrol's config file, served by the/api/configroute c131 D17 asks for, so a local notice's Contact IT reads it; until then the card says "This machine's configuration names no IT contact. Connect to HQ to reply from here." - The OS crates. macOS:
objc2-user-notifications0.3.2, the bindings GPUI's own platform uses (one copy in the binary), because GPUI'sshow_system_notificationcannot set the interruption level. The store:rusqlite0.32 linking the system SQLite on macOS and bundling one on Linux and Windows. Time:chrono. Not written, behind the same trait: Windows (tauri-winrt-notificationor thewindowscrate's toasts; needs an AppUserModelID and a Start-menu shortcut, so it waits for packaging, c131 Phase 4) and Linux (notify-rustover zbus with theurgencyhint). Choose now, or leave them to packaging? - What the entitlement question needs from a signed build.
priorityposts time-sensitive only when the process's signature carriescom.apple.developer.usernotifications.time-sensitive; the app reads it at start and the Messages page says which. That entitlement is restricted on macOS: the capability must be enabled on the App ID in the Qpoint developer account and the build signed with Developer ID and a provisioning profile that embeds it. An ad hoc bundle (the script) has none, so it proves the port and the prompt, not the break-through. Ask for the capability now, so c131 Phase 4's first signed build answers it. - Sync cadence. The inbox pulls
/api/messagesonce at open and on a world switch; nothing polls. The real plane's stream (or a pull interval) is c134's contract; a periodic pull here is a few lines once the cadence is ruled. - The tray's one line lives in the Inbox menu item ("Inbox (3): subject") and the count is the icon's title; ports §1.2 places the line under the sensor's own state line, which the Status/tray work owns. Keep it in the item until the tray's long form lands?
- Pushing. The brief said qnative has no remote and never to push; CLAUDE.md now names
originand says to push fast-forward after a step lands. Nothing was pushed from this cycle; the commits wait for your word.
Ruled by Mark on 2026-11-11
Walked in this session after the stop; each call took the recommended answer. Built the same evening where a ruling asked for code.
| # | Call | Ruling | What followed |
|---|---|---|---|
| 1 | The delivery words | Inbox · Tray · Quiet · Normal, each word saying where the message goes; no position sounds like hiding. Priority stays reserved to required. | Built: the ladder renamed in types::messages::Delivery (today's Off is Inbox, today's Inbox is Tray), the hold reasons with it, the settings page's note, the honesty line ("Notices from HQ is set to Inbox"), the guide's map. A settings file or an inbox row that still says off reads as Inbox. Four captures retaken and republished. |
| 2 | The IT contact's source | A field in qcontrol's configuration, it_contact (a mailto or URL), served by the /api/config route c131 D17 asks for. | Built: the bridge's EffectiveConfig carries it_contact (hand-written until D17's routes are generated); the pilot world's config names mailto:it-help@meridian.dev, the quiet default none. A local notice's Contact IT opens the configuration's contact, never the message's own target (bones §4), and says so plainly when none is named. The ask for qcontrol's engineer: the field in the config file, and /api/config serving it. |
| 3 | The Windows and Linux ports | With packaging, c131 Phase 4: Windows toasts need the installed app's AppUserModelID and Start-menu shortcut; Linux (notify-rust over D-Bus) comes with it. | Nothing to build now; the trait is ready and both platforms say "not available here". |
| 4 | The time-sensitive entitlement | Ask for the capability now, so the first signed build answers it. | The ask for whoever holds Qpoint's Apple developer account: enable Time Sensitive Notifications on the App ID (provisionally io.qpoint.desktop; it moves with c0's name) so a Developer ID build's provisioning profile carries com.apple.developer.usernotifications.time-sensitive. The app already reads it from its signature and says which. |
| 5 | Sync cadence | Leave it to c134. The inbox pulls at open and on a world switch until the plane's push or pull contract is ruled. | The pull for local and plane now runs on the background executor (it was a blocking read on the main thread at launch); a synthetic world still reads at once from memory. |
| 6 | The tray's one line | In the Inbox item for now; it moves under the sensor's line when the tray's long form lands with the Status work. | Nothing to build. |
| 7 | Pushing | Settled before the walk by the new rule (push your own commits, fast-forward only). | The stop's commits were pushed (6c13512). This evening's (6fceb1c, 4ccf511) went out with c3's Phase 3 when c5 pushed 045eed1..4ccf511 on your word, a fast-forward. |
Not built, and why
- Contact IT as a thread (replies back and forth) and the operator's side: c134's. In local mode the mailto opens the mail app, one way (D13).
- Acknowledge from the notification: off by ruling (D13). The notification's body opens the card.
- The Connect page (c131 Phase 2):
connected()is wired for it; today a plane-mode launch andQPOINT_SPIKE_CONNECTcall it. - The OS notification mocked per platform as captures (c137 D8): the macOS one can be seen through the bundle; Windows and Linux have no port yet to capture.
- The violation tour (c131 D15): the drill is ready for its simulate step; the tour's JSON and its stops come next.
- A reading on an idle Mac: the readings below were taken on a working machine; repeat c3's quiet recipe before quoting them beside its numbers.