Repository navigation
Quiet the machine status, and make a lost connection calm - #792
Merged
Merged
Conversation
…when it can't connect, and say a lost connection once at the top of the document A healthy Chopin now says nothing. The "Planner: <login> attached" line under the composer is gone, and so is the connection label inside it, so the composer is the same size in every state. What is left is told where a person already looks. The Planner's state is on the document header's machine button (and in the phone top bar): its dot becomes a thin petrol spinner while the machine is being connected to, a warning where it cannot be, and a muted grey while the Planner is away. The button's name and the top of its menu say it in words about the machine, such as "Connecting to Build box" or "Can’t connect to Build box" with the reason in full, what has been tried and a "How to fix" link, now documented in docs/chopin-cli.md. A machine that cannot be connected to also warns on the composer's existing attached top strip, which gains a warning tone and eases open and shut with the shared collapse motion; the other states, and a Planner that is not attached, are told there only while a message is addressed to Chopin, so a person with no machine button still hears of them when it matters. The status model is one pure module, so the button, its menu and the strip cannot disagree. A lost connection is one InlineNotice in the warning roles at the top of the document's content (the top of Chat where Chat is all that shows, and just under the floating top bar on a phone): "You’re offline. Your changes are kept and will sync when you reconnect." It waits out the existing 1.5 second grace period so a blip shows nothing, and Retry joins it only after four failed reconnect attempts. Wire now reports an outage and counts each failed attempt, automatic or a person's, reusing its existing jittered backoff; the timing and decisions are pure and unit tested. The header status, the Reconnect to Reload fallback and the composer's label and button are removed, and nothing confirms a state that clears. A screen reader hears the notice once as it appears and "Reconnected" once when it is gone. Placement and copy follow Primer's degraded-experience, loading and notification messaging patterns and Apple's progress-indicator guidance, in Chopin's own tokens and components; the research and the vendors' documented offline behaviour are cited in the pull request. The e2e traces the notice and the strip frame by frame, so they are shown to ease and not jump, and to settle at once under reduced motion. The design audit plates, DESIGN.md and the docs describe the new places. Assistant-model: Claude Sonnet 5.5 Assistant-workflow: goal (run 19ea4b06-26bd-4515-94f7-1201b0f8463c) Assistant-verification: bun test (apps/web, packages, scripts) passed: 2617 tests across 322 files, including the new unit tests for outage counting, timing, planner status and the strips Assistant-verification: bun test (full, as run here) failed: connector and routes tests need an unsigned git config (332 pass with GIT_CONFIG_GLOBAL=/dev/null) and the memory adapter flaked under load and passes alone Assistant-verification: bun run types passed: every package and the e2e project type-check Assistant-verification: bun run ci passed: dprint, oxlint, tokens, design contract, design record and Impeccable show no new findings Assistant-verification: bun run design:behavior passed: 22 keyboard, focus, reduced-motion and reflow checks at two widths Assistant-verification: bun run e2e (14 specs) passed: 137 passed on the built client, the offline notice, Retry, reduced motion, the machine button states and the composer strips in Chromium Assistant-verification: bun run e2e machines.e2e.ts passed: 2 tests that failed only on commit signing pass with GIT_CONFIG_GLOBAL=/dev/null Assistant-verification: screenshot review passed: desktop and phone shots of each state were opened and checked against DESIGN.md Assistant-verification: design:browser unavailable: Linux visual baselines were not regenerated User-preference: Status UI stays quiet when things are healthy and calm when they aren't, like Notion Co-authored-by: Alex Lavaee <lavaman131@github.com> Assistant-duration: 72m 28s
…and keep a lost connection one calm notice that never covers the page The status words are now plain. A machine that is starting, cannot be connected to, is offline, has stepped away or is missing is told as "Connecting to Build box", "Can't connect to Build box", "Build box is offline. Your work is kept.", "Build box stepped away. Your work is kept until 10:31 AM." and "No machine is connected.", with ASCII apostrophes and none of Chopin's own terms: no Planner, attach, held or Decisions, and no mention of Chopin. A unit test walks every state, glyph and place that says them and fails on any of those words. The refusals shown in Chat for an @chopin message or a comment are machine-first and plain too ("Connect a machine to get a reply", "Can't connect to @mona's machine: <reason>"), with their error codes unchanged, and docs/agent-connection.md says the same. One pure function now decides where a state is told, so the machine button, its menu and the composer's strip cannot disagree. A person with the button reads every state there and the composer warns only for a machine that cannot be connected to. A person without it (no machine, a title bar that does not show one, a phone whose top bar an open child has taken) reads every state on the composer's top edge, always, and for a machine that cannot be connected to the reason is drawn beneath it. The reason is kept exactly as the machine reported it, with no trimming and no stop added or taken away. One polite live region owned by the room announces each problem state once as it is entered and nothing as it clears; the strips carry no live role of their own, so nothing is said twice. A lost connection is shown even while the request that asks why it was lost never answers: the outage the wire reports, not its status, drives the notice, the status turns to reconnecting as soon as the socket closes, the probe gives up after four seconds, and the network coming back wakes a wire that is waiting on it. The notice's timing and announcement are decided above wherever it is drawn, and Workspace draws it once above Chat and the document, so switching between them during an outage neither restarts its grace period nor announces it again. On a phone it floats under the top bar and its height is added to every pane's top inset, so it never covers the first heading or the first message, and it sits above the panes so Retry can be pressed. The composer's unused slot under the field is removed. The design audit plates, the docs and DESIGN.md show the strip with and without the button. The e2e checks the notice against real Document and Chat content on a phone, in a compact window, through tab switches, with a hung probe, and that the lost-edits alert is the one left after a rebuild. Residuals, honestly: the offline copy says changes are kept while edits made across a server rebuild are dropped and said to be in a small header alert, and transcript lines, run cards and Build tooltips written before this change still say Planner and Decisions. Assistant-model: Claude Sonnet 5.5 Assistant-workflow: goal (run 19ea4b06-26bd-4515-94f7-1201b0f8463c) Assistant-verification: bun test (apps/web, packages, scripts) passed: 2634 tests, including the new tests for placement, once-only announcements, verbatim reasons, plain words, the hung-probe wire and the single page notice Assistant-verification: bun test (full, as run here) failed: 101 connector and routes tests need an unsigned git config (332 pass with GIT_CONFIG_GLOBAL=/dev/null), and no other test failed Assistant-verification: bun run types passed: every package and the e2e project type-check Assistant-verification: bun run ci passed: dprint, oxlint (no new warning), tokens, design contract, design record and Impeccable show no new findings Assistant-verification: bun run design:behavior passed: 22 keyboard, focus, reduced-motion and reflow checks at two widths Assistant-verification: bun run e2e (15 specs) passed: 184 passed on the built client, including the hung probe, the phone notice over real content, tab switching, the strips with and without the button and the live region Assistant-verification: e2e phone overlap check passed: it failed with the notice's inset removed and passes with it Assistant-verification: screenshot review passed: desktop and phone shots of each state, with and without the machine button, and of Document and Chat during an outage were opened and checked against DESIGN.md Assistant-verification: design:browser unavailable: Linux visual baselines were not regenerated User-preference: Status UI stays quiet when things are healthy and calm when they aren't, like Notion Co-authored-by: Alex Lavaee <lavaman131@github.com> Assistant-duration: 1h 0m 11s converged, estimated 3h
…hat Build needs in machine words, and make the plain-words check catch detach Three gaps in the previous commit. When a document's machine said "No machine is connected." its button still drew the machine's own connected dot, so a green dot sat beside those words. The button now draws no dot at all for that state: the bare icon in tertiary ink, as for a person who has no machine. The status-graphics rules decide it: success is for a connected machine and the muted dot already means a machine that is there but unreachable, which a document with nothing connected is not, so absence is drawn as absence. Every state that is not healthy now draws the Planner's own dot or none, and that dot no longer carries the machine's `data-state` at all, so the green cannot come back through the cascade. The design audit plate takes its dots from the same `plannerGlyph` as the button, and its labels speak of the machine. A real app test with a connected machine that cannot reply checks the button on desktop and phone. Build plan's tooltip and the refusal after pressing it still said "Reconnect the Planner to build" and "Connect a Planner to this document to build". They now say "Reconnect the machine to build" and "Connect a machine to this document to build", the same machine-first words as "Connect a machine to get a reply". It is the machine, not "your machine", because the document may run on a machine a teammate shares. The connect copy is one constant shared by the tooltip, the refusal and the key Build plan uses to offer how to connect a machine, so they cannot drift apart. The plain-words test now walks every reason Build plan waits and every refusal Build shows, and Build plan's tooltip with its connect key. The plain-words pattern missed "detached", whose letters are `tach`, not `attach`. It now matches planner, detach, attach, held, decisions and @chopin in any form, and a test shows it flags each banned term, "detached" and "reattach" among them, and none of the plain words. The docs and DESIGN.md say the same. Strings that name the Planner or Decisions and were not edited by this change (transcript lines, run cards, composer hints, busy labels, the setup popover Build plan opens) are listed in the pull request as untouched, and so is the known duplication of an offline notice on a parent and its open child. Assistant-model: Claude Sonnet 5.5 Assistant-workflow: goal (run 19ea4b06-26bd-4515-94f7-1201b0f8463c) Assistant-verification: bun test apps/web packages scripts e2e/focus-color.test.ts passed: 2639 pass, 3 skip, 0 fail, five more than before; bun test scripts passed again after the design-contract hash was renewed (137 pass, 1 skip) Assistant-verification: the new and rewritten cases were each seen red first: the button cases drew data-state="connected" for no machine and for every unhealthy state, the Build cases returned the Planner copy, and the old pattern let "detached" through; taking plannerGlyph's none back to undefined fails the button and audit plate cases, and swapping a Build refusal back to Planner words fails the Build case Assistant-verification: bun run types passed: every package and the e2e project type-check Assistant-verification: bun run fix then bun run ci passed: dprint, oxlint (71 warnings, 0 errors, as before), tokens, design contract (the reviewed hash of machine-button.tsx renewed, its one dynamic class unchanged), design record and Impeccable show no new findings Assistant-verification: bun run design:behavior passed: 22 keyboard, focus, reduced-motion, reflow and build-blocker checks at two widths Assistant-verification: E2E_SKIP_BUILD=1 bun run e2e planner-attachment planner-picker machine-choice machines connection implementation-launcher on a client built from this tree gave 93 passed and 10 failed, all 10 (8 in implementation-launcher, 2 in machines) with "either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured", this machine's global commit signing; the 93 include the new no-dot button test on desktop and phone Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun run e2e implementation-launcher machines passed: 32 passed, 0 failed, so the 10 are environmental Assistant-verification: screenshot review passed: audit-presence desktop and phone (only the healthy cell keeps the machine's green, and No machine connected shows the bare icon with no dot, its computed colours read back from the page), audit-composer-states and audit-build-blockers desktop, and the real-app planner-none-button desktop and phone, planner-starting and planner-failing-menu, were opened and checked against DESIGN.md Assistant-verification: not run: design:browser (Linux visual baselines are not regenerated), the full bun test, bun run test:postgres, the Docker image build, the whole e2e suite (six specs only), and GitHub's checks on a pushed head User-preference: Status UI stays quiet when things are healthy and calm when they aren't, like Notion Co-authored-by: Alex Lavaee <lavaman131@github.com> Assistant-duration: 20m 54s
…he teammate's strip fits On GitHub's runners the phone test for a machine that cannot start measured the teammate's composer strip while the Chat pane they had just tapped was still sliding in, its left edge at -229 px and then -67 px on the retries, so it failed on all three tries. The check now retries until the strip is inside the viewport, as Playwright's own assertions wait, and a strip that never fits still fails it. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: GitHub e2e shard 2/12 failed: planner-picker.e2e.ts:644 at expectInsideViewport with the strip's left at -229 and -67 px on its retries Assistant-verification: E2E_SKIP_BUILD=1 bun run e2e planner-picker -g "keeps failing to start" --repeat-each 4 --workers 1 passed: 4 passed (parallel repeats collide on one Postgres database name, an environment limit) Co-authored-by: Alex Lavaee <lavaman131@github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A healthy Chopin says nothing. How the machine behind a document is doing now lives on the document header's existing machine button, in plain words that name no Chopin concept; a failure someone can act on also warns on the composer's top edge; and a lost connection is one calm notice at the top of the page. Nothing sits under the composer and nothing about the connection sits in it, so the composer is the same size in every state.
The words are the user's, and plain: no "Planner", "attach", "detach", "held", "Decisions" or "@chopin" in any status, button name, strip, notice, Build tooltip or refusal, or screen reader announcement. A unit test walks every state, glyph and place that says them, Build's reasons and refusals included, and fails on any of those words; its pattern is itself tested against each banned term, "detached" among them.
State by state, where it is told, and in what words:
A lost connection is the page, not the machine: a warning InlineNotice at the top of the document's content, after a 1.5 s grace period, You're offline. Your changes are kept and will sync when you reconnect. Retry only after 4 failed reconnect attempts. On compact windows and phones it is one element above Chat and the document.
Where a state is told: one decision
When the person has the machine button, the button and its menu carry every state, and the composer's top edge is used only for a machine that cannot be connected to, the one state a person can act on. When the person does not have the button (no machine paired or shared, a title bar that does not show one, a phone whose top bar an open child has taken), the composer's top edge is the fallback carrier for every state, always and not only while a message is addressed to Chopin, and for a machine that cannot be connected to it also draws the reason inline. One pure function,
plannerPlacement(status, hasButton), makes that decision for the button, its menu and the strip, so they cannot disagree;room-workspace.tsxcomputeshasButtonfrom the same conditions that draw the button. A lost connection hides the button without moving where the state is told; the offline notice speaks for the connection meanwhile.The machine button with no machine connected: no dot
When a document's machine says No machine is connected. the machine button now draws no status dot: the bare icon in tertiary ink, exactly as the button of a person who has no machine at all. It used to keep the machine's own dot, so the connected green sat beside those words. I chose no dot over the muted dot from the status-graphics rules in
apps/web/DESIGN.md: success is reserved for a connected machine, and the muted tertiary dot already means a machine that is there but unreachable (offline, stepped away), which is not true of a document with nothing connected to it. Absence is drawn as absence, the existing treatment for a button with no machine, and it is the quieter of the two. Every state that is not healthy now draws the Planner's own dot or none, and that dot carries nodata-stateat all, so the machine's green cannot come back through the cascade.plannerGlyphmapsnoneto"none"andMachineGlyphdraws nothing for it; the design audit plate takes its dots from the same function.Build says it in machine words too
The Build plan tooltip and the refusal after pressing it used to say Reconnect the Planner to build and Connect a Planner to this document to build. They now say Reconnect the machine to build and Connect a machine to this document to build (with a stop when it is the refusal shown after a press), the same machine-first words as Connect a machine to get a reply. I wrote "the machine", not "your machine", because the document can be running on a machine a teammate shares, which the person pressing Build cannot reconnect. The connect copy is one constant,
CONNECT_MACHINE_TO_BUILD, shared by the tooltip, the refusal and the key Build plan uses to offer how to connect a machine, so copy and key cannot drift apart.status-copy.test.tsxwalks every reason Build plan can be inert while drafting and every refusaldraftRefusalCopycan give.What changed
apps/web/src/wire.ts): reports an outage (onOutage) when a connection is lost, each failed attempt in it, and when it opens again; automatic and manual attempts both count and only an open socket resets the count. New in this round: the status becomesreconnectingthe moment the socket closes, not after the HTTP probe that asks why; the probe has a 4 s timeout so a probe that never answers (a network that drops packets) cannot stall retries; theonlineevent wakes a wire that is waiting on the probe as well as on the backoff timer. The jittered exponential backoff is unchanged.isOffline(packages/editor/src/connection-notice.ts): follows the outage the connection reports, not only its status, so a hung probe still shows the notice after the grace period. A slow first connection, a refusal and a deleted document are still not an outage.apps/web/src/offline-notice.tsx): the decision (grace, Retry, the one polite word) is held inuseOfflineNoticeinRoomWorkspace, above wherever the notice is drawn;OfflineNoticeonly eases open and shut from what it is told, so a notice mounted again somewhere else is simply there.Workspacedraws it once above Chat and the document where they take turns (pageNoticePlace), so switching tabs during an outage neither restarts the grace period, nor remounts the alert, nor announces it again.--phone-notice-heightand added to every pane's top inset (--phone-pane-top), so the first of the Document's or Chat's content starts below it instead of under it. It sits above the panes (z-index 20) so Retry can be pressed.apps/web/src/chat/planner-status.ts, pure): one model for the button's name and tooltip, its menu, the composer's strip and the live region, with the plain words above. The failure reason is kept exactly as the machine reported it: not trimmed and no stop added or removed (a path that ends in a slash stays a path); layout and separate lines carry the separation instead.plannerPlacementis the placement decision;plannerAnnouncementis the once-per-entered-state rule.chat/planner-announcement.tsx): one visually hidden politerole="status"inRoomWorkspace, independent of the button or the strip, that says each problem state's sentence once as it is entered, nothing while healthy, nothing as a state clears, and nothing as the attempt count rises. The strips carry no live role of their own (silent), so nothing is announced twice.composer.tsx): the deadattachmentslot under the composer is gone. A strip may show its detail lines (the reason, then the tries) or hand them to a screen reader only.apps/server/src/harness/remote/attachments.ts,docs/agent-connection.md): the@chopinand comment refusals are machine-first and plain: Connect a machine to get a reply. Choose one with the machine button, or runchopin connecton a machine that can reply., @mona's machine is offline, so it can't reply now. Your work is kept and picks up when it's back., Still connecting to @mona's machine. Try again in a moment., Can't connect to @mona's machine: (3 attempts in a row). It keeps trying; try again once that is fixed. The error codes (planner-not-attached) are unchanged, and Build's matching of these messages (draftRefusalCopy) is unchanged; only the copy it returns is plain now (below).Motion
The offline notice and the composer's strip are the only things that move: the grid track eases from 0 to its height in 250 ms and back in 200 ms while the content fades and settles, so what is below is pushed a frame at a time. The e2e traces the document's and the composer's top edge on every animation frame and asserts they pass through intermediate values; with
prefers-reduced-motionnothing is passed through. Clearing is quiet: no check mark, no "Back online", no toast.Accessibility
Research, and what was copied
Placement, scope and copy follow Primer's patterns; colour and components are Chopin's own (
apps/web/DESIGN.md).Primer
role="status"region always rendered.Apple Human Interface Guidelines, Progress indicators, https://developer.apple.com/design/human-interface-guidelines/progress-indicators: indicators are transient and specific, in a consistent place (the machine button).
Notion, Linear and Figma (research, 2026-11-05; the vendors document very little of this): changes are kept locally and sync on their own when the connection returns (Linear docs, https://linear.app/docs/get-the-app; Notion help, https://www.notion.com/help/guides/working-offline-in-notion-everything-you-need-to-know; Figma, https://help.figma.com/hc/en-us/articles/360040328553-What-can-I-do-offline-in-Figma). We kept Chopin's existing 1.5 s grace period rather than copy any vendor's number, and Retry, which appears only after repeated failures, is ours.
Honest residuals and decisions worth a second look
forbiddenMessage, ... its Planner was released, A document has one Planner at a time); the run cards' notes and Pause labels (It carries on when the Planner reconnects, Pause when the Planner reconnects); the composer's picker hints (Sends to the Planner, which will reply, Room only. Add @chopin to ask the Planner) and the@chopinmention itself; the busy labels Planner is working (document status), Planner working (Chat tab) and Document, Planner writing; the Decisions tab and Showing Decisions: N to answer; The Planner job could not be retried; the Machines page's Planner and runs Planners labels; and the setup popover that Build plan opens when no machine is connected (Connect Chopin, Planner command, Open your Planner and attach this document), a terminal setup guide for a custom backend that this change does not touch. Two design audit captions (the Conversation plate's description and the Workflow runs plate's) still say Planner too; the audit labels this change wrote do not. Whether any of these should follow is a decision for a deliberate change, and several are visible in the same Chat as the new strip.Verification
Run on the final working tree, with the client built from it. This round's checks first, then what the earlier commits ran that was not repeated.
This round:
bun test apps/web packages scripts e2e/focus-color.test.ts: 2639 passed, 3 skipped, 0 failed (five more than before: the rewritten no-machine test, the iterate-every-unhealthy-state test, the leak-check self-test, Build's reasons and refusals, and Build plan's tooltip with its connect key).bun test scriptsagain after renewing the design-contract hash: 137 passed, 1 skipped, 0 failed. The new tests were each seen red first: the button tests drewdata-state="connected"beside No machine is connected., the Build tests still returned the Planner copy, and the leak check was shown to miss "detached" with the old pattern; the audit plate test and the leak check also fail when the fix is taken back out.bun run types: passed (14 packages and the e2e project).bun run fixthenbun run ci: passed. dprint, oxlint (71 warnings and 0 errors, as before), tokens, design contract, design record and Impeccable (no new findings). The contract asked for the reviewed hash ofmachine-button.tsxto be renewed; its one dynamic class (presence.className, finite state classes from the shared presence hook) is untouched, so only the hash changed.bun run design:behavior: 22 passed, including the build blockers plate whose Connect Chopin trigger is still found by the new copy.E2E_SKIP_BUILD=1 bun run e2e planner-attachment planner-picker machine-choice machines connection implementation-launcher): 93 passed and 10 failed. All 10 failures (8 inimplementation-launcher, 2 inmachines) end infatal: either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured, this machine's global commit-signing config.GIT_CONFIG_GLOBAL=/dev/nullwithimplementation-launcherandmachinesonly: 32 passed, 0 failed, so they are environmental. The 93 include the new real-app test: with a machine that cannot reply, the button is named Runs on desk. No machine is connected., has no.machine-glyph-dotand no[data-state]on desktop and on a phone, its menu still says Connected for the machine's own row, and the page's live region says it once.design:browser(Linux visual baselines are not regenerated), the fullbun test(carried below from the earlier commits),test:postgres, the Docker image build, and the whole e2e suite (six specs here); GitHub's checks run on this pull request.Carried from the earlier commits and not repeated: the full
bun testgave 7092 passed, 22 skipped, 101 failed, 1 error, every one inapps/connectororapps/server/src/experiments/routes.test.tswith the same signing error, and 332 passed withGIT_CONFIG_GLOBAL=/dev/null; the whole 15-spec browser run gave 184 passed before this round.Screenshots
The full set was captured with
CHOPIN_SHOTS=/tmp/chopin-shots-quiet-offline(and a script against the design audit) on desktop and on a 390 px touch phone, opened and reviewed. Not committed. The design audit plates were regenerated this round, and the real-app shots were retaken by the browser run above.Offline:
offline-desktop.png,offline-retry-desktop.png,offline-phone.png,offline-retry-phone.png,offline-phone-document.png(real Document content below the notice),offline-phone-chat.png(real Chat content below the notice),lost-edits-after-offline-desktop.png.With the machine button:
planner-starting-desktop.png,planner-starting-phone.png,planner-failing-desktop.png,planner-failing-menu-desktop.png,planner-failing-phone.png,planner-failing-sheet-phone.png,planner-attached-desktop.png,planner-attached-phone.png, and, new,planner-none-button-desktop.pngandplanner-none-button-phone.png(a machine that cannot reply: the button is the bare icon with no dot).With no machine button, the composer's top edge carrying the state:
planner-starting-teammate-desktop.png,planner-starting-teammate-phone.png,planner-failing-teammate-desktop.png,planner-failing-teammate-phone.png,link-drop-disconnected-desktop.png,link-drop-disconnected-phone.png,planner-held-desktop.png,planner-held-phone.png,planner-none-desktop.png,planner-none-phone.png.Design audit:
audit-presence-desktop.pngandaudit-presence-phone.png(only the healthy cell has the machine's green; No machine connected: no dot shows the bare icon beside No machine is connected.),audit-composer-states-desktop.png,audit-composer-states-phone.png,audit-build-blockers-desktop.png,audit-build-blockers-phone.png(the Connect Chopin trigger),audit-loading-status-desktop.png,audit-loading-status-phone.png.Deferred
design:browserbaselines for the Conversation and Loading plates.Assistant-model: Claude Sonnet 5.5
Assistant-workflow: goal (run 19ea4b06-26bd-4515-94f7-1201b0f8463c)
Assistant-verification: bun test apps/web packages scripts e2e/focus-color.test.ts passed: 2639 pass, 3 skip, 0 fail, five more than before; bun test scripts passed again after the design-contract hash was renewed (137 pass, 1 skip)
Assistant-verification: the new and rewritten cases were each seen red first: the button cases drew data-state="connected" for no machine and for every unhealthy state, the Build cases returned the Planner copy, and the old pattern let "detached" through; taking plannerGlyph's none back to undefined fails the button and audit plate cases, and swapping a Build refusal back to Planner words fails the Build case
Assistant-verification: bun run types passed: every package and the e2e project type-check
Assistant-verification: bun run fix then bun run ci passed: dprint, oxlint (71 warnings, 0 errors, as before), tokens, design contract (the reviewed hash of machine-button.tsx renewed, its one dynamic class unchanged), design record and Impeccable show no new findings
Assistant-verification: bun run design:behavior passed: 22 keyboard, focus, reduced-motion, reflow and build-blocker checks at two widths
Assistant-verification: E2E_SKIP_BUILD=1 bun run e2e planner-attachment planner-picker machine-choice machines connection implementation-launcher on a client built from this tree gave 93 passed and 10 failed, all 10 (8 in implementation-launcher, 2 in machines) with "either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured", this machine's global commit signing; the 93 include the new no-dot button test on desktop and phone
Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun run e2e implementation-launcher machines passed: 32 passed, 0 failed, so the 10 are environmental
Assistant-verification: screenshot review passed: audit-presence desktop and phone (only the healthy cell keeps the machine's green, and No machine connected shows the bare icon with no dot, its computed colours read back from the page), audit-composer-states and audit-build-blockers desktop, and the real-app planner-none-button desktop and phone, planner-starting and planner-failing-menu, were opened and checked against DESIGN.md
Assistant-verification: not run: design:browser (Linux visual baselines are not regenerated), the full bun test, bun run test:postgres, the Docker image build, the whole e2e suite (six specs only), and GitHub's checks on a pushed head
User-preference: Status UI stays quiet when things are healthy and calm when they aren't, like Notion
Co-authored-by: Alex Lavaee lavaman131@github.com
Assistant-duration: 20m 54s