CYCLE.md
Cycle 5: Status
Created: 2026-11-11
Focus: The Status page, the app's first page and the tray's long form: is qcontrol on, what is it reading, what has it found. Built from design c132's Phase 4 brief and mock (the worked example of the loop for native screens) as the loop's push: the page on our layer, a story per state, the state read from the source and the data and never from a flag in the page, captured per world into both atlases, the budget read with strobe.
Mode: evolution (the page is ruled and mocked in design; this cycle ports it onto the pipes c2 built and records what the port taught).
Answers: design:c132 Phase 4 (../design/cycles/c132.native-design-prototyping/status-brief.md S1–S6, review-phase4.md, the mock at /pages/native/status, D10 the bridge) and design:c131 (the page table: Status; R4 the sentence; D12 the grant line; D13 the plane connection; D17 the six endpoint-only shapes become qdash routes) and design:c138 (Live and the Sensor page are developer mode's; V1's Status stays here).
Origin: the c130 session, 2026-11-11, after c2 closed: the Status page handed from c132's Phase 4 to this repo as c5 (design 6a8ee09055). The brief is initial-prompt.md, verbatim.
Siblings in the tree: c3 (Developer Mode) and c4 (Messaging) work in this checkout at the same time, and design's c132 session was found editing Status's own paths here when c5 began (see Key Changes). This cycle commits only its own paths, re-reads a shared file (router.rs, shell.rs, main.rs, Cargo.toml) before touching it, and names the other sessions here when it does.
Rulings taken over the brief (from design c131 D21, 2026-11-11)
Mark walked the Status brief's S1–S6 the evening c5 began; three change the brief and this cycle takes them over it (design 6c8ba4b80d, c131 plan.md D21):
| # | Ruled | What it changes here |
|---|---|---|
| S1, changed | Status is the landing. The app opens on Status; the Inventory index's twenty micros move onto it below the state line and the found-here set; Inventory keeps its own index page in its group. The rail: a "This machine" group first (working name until c0) holding Status, Sensor and Activity, then Inventory. | Status takes the start of the navigator and the home path; the Inventory overview keeps its page under Inventory; the rail gains the group. |
| S2, kept | The state from the source and the data; the Dev switch for the states no world carries; the lab's knob is chrome. | As briefed. |
| S3, changed | A Sensor page under "This machine" shows the five sensor facts in full (SensorState, Resources, EffectiveConfig, the LogLine tail, PlaneConnection), each row honest "not served yet" naming its qdash route until D17's route lands, then live. Status shows only the one-line state and the plane line. | The facts block leaves Status for pages/sensor.rs. |
| S4, kept and extended | The found-here set stands (sessions, agents, events, tokens and spend as micros; the harnesses here with monitored or shadow; the oldest event; the database size; the coverage counters). An Activity page after Status: sessions over time, filterable, as qdash's /monitor/activity shows them (the plane app's word for sessions); under "This machine"; the Events page of the app map stays the live stream and the audit log. | Activity is built after Status and Sensor, same loop: stories per world, captures to design under thread p2-activity. |
| S5, changed | The log tail lives on the Sensor page once served; the full viewer stays Developer Mode's (qnative c3, design c138). | The log band leaves Status for Sensor. |
| S6 | Mark's. | The review stops. |
Order: Status as the landing first (review stop 1, as briefed), then Sensor, then Activity (review stop 2). The shared-file rule is unchanged.
Why
Status is the page a person opens to know whether qcontrol is on, what it is reading and what it has found, and the first page the app shows. c131 placed it first in the page table and gave it five states (off · starting · on-local · on-connected · degraded); c132 took it through the whole loop in the lab (brief, mock on the four worlds, review) so that the first native screen built after the Inventory port would be the first one designed in the new loop rather than copied from qdash. Building it as its own cycle keeps the push honest: a page state is a world where a world carries it, a confession where none does, and the sentence the page says is R4's (nothing alarming; the app says which state it is in).
Objective
Done means: crates/app/src/pages/status.rs on the layer with the brief's bands (the sensor's own facts, said honestly where no route serves them; what was found here, from the worlds); the five states with the brief's sentence each, the state from the source and the data; S1 built (Status first in the rail, under "This machine", above Inventory; the route; the landing's link); a story per state, captured per world into the qnative atlas and design's; a strobe reading with Status open at rest beside c2's figures; the record kept; a review stop (review-1.md) with what to look at per state and world, the figures, the wipe against design's mock, and the calls for Mark (S1–S6).
Scope
- Here:
crates/app/src/pages/status.rs(the page) andpages/mod.rs(its module and route);crates/app/src/router.rs,shell.rs(S1: the route and the rail item; shared files);- a dev-chrome switch for the states no world carries (the brief's step 2);
crates/stories(a story per state);cycles/c5.status/(this record,review-1.md).
- Design:
scripts/shot-programs/c131-status-native.jsonand the captures it produces, committed there with a message naming c131 and c5. Nothing else. - Reads, never changed: design's
status-brief.md,review-phase4.md,status.vueandapp/components/native/,synthetic-data.md,process.md. - Out: the routes themselves (
/api/sensor,/api/config,/api/plane: c131 D17, engineering's through c134); the log viewer (c138); the grant line's data (c136; no world carries a grant); the Connect flow (c131 D13).
Key Changes
- headless tests (2026-11-11, evening): a test per page state of This machine, and CI runs the suite (R6: the demo is the test). Sixteen
#[gpui::test]s incrates/stories/src/main.rs(mod tests), each opening the shell the way its story does (app_status,app_shell_full,app_session_on) on a world read frozen, the forced state and the lean switch cleared first, the page's read landed and a frame drawn, then reading what the page says two ways: through the page's own API on a repo built the same way (SensorRead::sentence,State::word,SensorRead::why,found_words,sensor::facts,Repo::sessions,Repo::session) and through the tour layer's regions (layer::tour::find, the region'stext). Per page: Status 6 (on-local onmeridian-day90, degraded onpilotnaming the sensor's two words, off and starting forced, connected over the in-process fixture plane with the footer naming it,freshsaying nothing found yet); Sensor 2 (the Version row served from the bridge; over the plane "not served yet (/api/sensor)"); Activity 2 (16 sessions in the 30-day window with the band, the usage row and 16 ledger rows;freshsaying no sessions captured yet); the session page 2 (the newest run with its grain, the reading column and the rail; a run not on record); the regions 4 (every region the app map names forstatus,sensor,activity,sessionis drawn, keyless or keyed).cargo test -p stories: 28 (12 before);cargo test --workspace --locked: 128 in the eight crates that hold tests, green on Linux in this session's container and on all three CI runners. The page-state tests run one at a time behind a mutex: the forced state and the lean switch are process-wide, as developer mode's.- The regions say their words to the guide (no test-only text; Info View and the guide read the same):
status.stateandsensor.statecarry the word and why ("qcontrol on · degraded: … (part of what runs here is out of its sight: …)"),status.foundits lede,sensor.factsits rows in one line (sensor::facts,facts_words),activity.listits empty words (DataTable::empty_words, the layer),session.readingthe not-found sentence. Repo::sessionanswersNonefor a run the synthetic world carries no detail for (qdash'snull), so the page's not-found state is reachable on every source. The trade-off is Mark's to rule: the worlds are cut to the 30-day window (review stop 2), so an all-time row older than that opens as "Session not found: no run with this id is on record here" rather than as a failed read naming the synthetic gap.- Found on the way: CI had never built on Linux or Windows. Every run on main (4–12) failed both at the debug build while macOS passed:
crates/stories/Cargo.tomllisted every workspace crate under its macOS-only target section (since c2), andtray.rscalledwith_icon_templated, the macOS backend's alone, on every OS. Both fixed (the tray draws the icon as given elsewhere). Linking the kit on Linux needslibxkbcommon-devandlibxkbcommon-x11-dev, which the workflow's package list already installs. - CI, run by run on the branch (workflow dispatch; macOS green in every one):
- run 13: Linux and Windows built for the first time. Linux passed the tests and failed the lean check: its full release binary did not hold "Component demos" whole, so the check's control failed. Windows failed
nozzle'sa_stale_lock_is_not_found: the ladder could not check a pid there, so a stale lock read as Found. - run 14: the ladder checks a pid on Windows with
tasklist(askill -0on Unix); that test passed. Windows then failedtypes'rfc3339_round_trips_to_the_millisecond: aSystemTimethere holds hundreds of nanoseconds, so the fixture's…456789came back…456700. The fixture is now whole hundreds; the function is unchanged. - run 15: the lean check names the Component demos tool by its description; Linux passed every step.
- run 16: every OS passed every step, the Windows lean check included, and then the Linux job failed saving its cache with "No space left on device".
- run 17: the workflow frees the Ubuntu runner's unused toolchains (.NET, Android, Haskell, CodeQL) first. Green on all three OSes, every step: the build, the workspace's tests, both release builds and the lean check, the binary size and the cache. Wall time per OS: macOS 4 min, Linux 26 min, Windows 36 min (the release builds dominate both). The push to main that carries this record runs the same workflow.
- run 13: Linux and Windows built for the first time. Linux passed the tests and failed the lean check: its full release binary did not hold "Component demos" whole, so the check's control failed. Windows failed
- The workflow:
.github/workflows/build.ymlrunscargo test --workspace --lockedas one step per OS (the--exclude appand-p app --libpair is gone). No crate is scoped out on any OS.scripts/check-lean.shstays. - Not attempted: captures and strobe (the Mac's).
- The regions say their words to the guide (no test-only text; Info View and the guide read the same):
- Activity and the session page (2026-11-11, afternoon), at review stop 2 (review-2.md): after Mark walked review-1's calls (every one stood; call 9 built: a lock file whose URL nobody answers reads as off,
48d97df), the third page of D21 in Mark's chosen shape: band, history and ledger, with the session page now.- The worlds recut with every session's detail and Surface (
2e9286d):cut-world.pycrawls/api/sessions?run=and/api/surface?run=; 112 details; the contract test readsSessionDetail; the generator keeps an interface's index signature as a flattenedextramap (nodeny_unknown_fieldsthere) and readsSessionEvent.outputas a string or a token count (OVERRIDES). Worlds 1.1 → 2.5 MB. Design's copies are owed async-worlds.sh. DataHistoryGraphin the layer (2e9286d, fit in53e443c): the web's history graph drawn from flex boxes.- Activity (
53e443c):pages/activity.rs, qdash's Activity on one machine (Users ⇄ Teams → harnesses; no user or host column; a row opens the session); the per-day rollup anchored on the rows; the status, harness and flagged filters client-side. - The session page (
53e443c):pages/session.rs, qdash's detail page less the Device line and the Working section (the header carries the metadata); the transcript, raw events, Surface chips, rail, ledgers and the run's Surface, every string from an event or the row. - Routes
Activity(/activity) andSession(run)(/activity/detail?runId=); the rail's group is Status, Sensor, Activity; the app map 23 pages; storiesapp-activity,app-activity-ledger,app-session,app-session-flagged;Repo::session,SurfaceScope::Run. - Captures (thread
p2-activity): designscripts/shot-programs/c131-activity-native.json, ten captures into both atlases (designde64db8979). - Not ported: the day tip on hover; the Working section. The idle strobe re-read is still owed (Mark: when convenient, with him away from the Mac).
- The worlds recut with every session's detail and Surface (
- Call 9 ruled (2026-11-11, evening): Total Sessions stacks each day by the harness that ran, as c132's lab mock does, not compliant · non-compliant as qdash does; the flag stays in Recent Work's pill and filter. The Activity thread recaptured (design
705f44ee3f). - Review stop 2 walked (2026-11-11, afternoon): all eight calls ruled (review-2.md §Ruled). Built from them:
app-activity-leanfor the band bake-off; the synthetic world's clock shifted to today at load (nozzle::clock, the footer saysclock +Nd; frozen in the stories and byQPOINT_CLOCK=frozen); the session details capped at the 30-day window and the worlds recut (1.7 MB); the lab's world copies re-synced by c5 (design39953031a8);app-activity-todaycaptured with the shift on (designd963d5a8a4; the lean capture retaken in1ce2141fa0once its switch outlived the shell's first render). - Status as the landing, Sensor, the states, the stories (2026-11-11, 12:46–13:20), at review stop 1 (review-1.md): built on design c132's own push of its Phase 4 (
4d38192the D10 bridge behind the synthetic nozzle,21f6869pages/status.rsand the app's asset source,273ada7the route, the rail item, four stories), reshaped by D21.- The state from the source and the data (S2):
nozzle::processholds a forced state (off, starting) for the whole process;Repo::describenames it in the footer (process: forced off (dev));Repo::base_urlgives the plane line its address. The page derives: forced → that; the local source answering NotRunning → off; the sensor's served word (the bridge in synthetic worlds) → on · degraded · off · starting; nothing served → the coverage counters decide degraded; the source being a plane → connected. c132'sStoryStateflag in the page is gone. Developer mode's Tools page gained the Process state switch (as served · starting · off), dev chrome;devmodenow depends onnozzle. - Status is the landing (D21 S1):
pages/status.rsdraws the header with the brief's sentence, the state line (dot, qcontrol, pill; why degraded on the line below), the plane line (reads this machine or HQ at its address, last sync or its honest gap, where the configuration lives; a link to Sensor), "What it has found" (c132's second band as it was), then the Inventory index's twenty micros throughlanding::index_section(the overview keeps its page). RouteStatusis qdash's Home/, the Inventory overview/inventory;Navopens on Status; the extension fallback lands there. The rail's first group is "This machine" (Status, Sensor); the old header went, since the group carries its words. Icons: StatusLayoutDashboard, SensorRadar, OverviewLayoutGrid(the asset source embeds the two the kit's default set lacks). - Sensor (D21 S3, S5):
pages/sensor.rs, the three fact columns (the process; reads; configuration) each row served or "not served yet (route)", wrapped so the route reads whole, the note, and the log tail;SensorReadandstate_lineare shared with Status. - The app map and the tour: Status and Sensor pages first in
guide/app-map.json(regionsstatus.header/state/found/card/index/micro,sensor.header/state/facts/log); the Overview's route/inventory; the tour's first step lands on Status and points at its Inventory cards (status.micro). - The stories:
app-status,app-status-degraded(pinned topilot),app-status-off,app-status-starting(forced throughnozzle::processafter the shell is built),app-status-connected(theplanesource:fixture-planeis now a library,fixture_plane::serve, and the stories serve the world once per process on loopback),app-sensor,app-sensor-connected. The app map test counts 19 pages. - Captures (step 5): design
scripts/shot-programs/c131-status-native.json(threadp2-status, mirrored into design's atlas under c131): 12 captures, design2c93e17eb8. - Commits here:
9b0bc16(the groundwork:nozzle::process,base_url, the fixture plane as a library) and the landing step, which rode into2e95f3a("CLAUDE.md: the remote…", Mark's, pushed) because that commit was made from the shared index while c5's files were staged;9b0bc16also carries one hunk of c4's (Repo::world, uncommitted on its side), so HEAD builds once c4 commits its trait method. The c4 session was told twice (the shared files touched, then the stray hunk); no c3 session was running to tell. - Found on the way: two sessions in one tree share one index: a commit by either carries whatever the other has staged. c5 now stages a shared file as its own hunks on HEAD (
stage_c5.pyin the session's scratchpad), never the working file, and commits in the same minute it stages. - The budget (step 6): release builds of the shared tree read with strobe, Status at rest and after the walk of every Inventory page (review-1.md §Figures): 66.4 MB private at rest on
30021dfand 106 MB after the walk; 108 MB and 91 MB on2c01ebf; first render 328–408 ms; the binary 24.9 MB. The two at-rest readings were taken on a Mac in use and read 1.2 % and 3.2 % of a core at 100–330 wakes/s, while every page read 0.00–0.01 s of CPU over 20 s untouched and nothing on Status asks for frames; a reading on an idle Mac is owed before the figure stands. Against shape.md §6 (D22): at rest under the 80 MB window target, after every page over it (the GPU atlases, as in c2), first render under 400 ms in three of four starts.
- The state from the source and the data (S2):
- D21 taken (2026-11-11, 12:45): the c130 session relayed Mark's rulings on S1–S6 (the table above): Status is the landing with the Inventory micros on it, the sensor facts and the log go to a Sensor page, an Activity page follows. The order is Status, Sensor, Activity.
- kick-off (2026-11-11, 12:40): this record and the brief, verbatim. On reading the tree, design's c132 session was found mid-edit on Status's own paths (uncommitted, 12:33–12:37): the D10 bridge (
crates/types/src/bridge.rs,crates/fixtures/bridge/*.json,fixtures::bridge,Repo::sensor/config/plane, the synthetic nozzle answering the three routes from the bridge and sayingsensor: bridgein the footer),Route::Statuswith its path/status, the rail item under the header,pub mod statusinpages/mod.rsand four story entries namingapp::pages::status::StoryState, withstatus.rsitself not yet written. The brief here predates D10 (it asks for a "not served yet" block; D10 gives the worlds a bridge for the sensor's facts). Nothing of the page touched by c5 until the two sessions agree who builds what; the question is with the c130 session.
Outcome
In progress.