Skip to content

Polish the living document flow - #457

Merged
MaggieAppleton merged 5 commits into
mainfrom
living-design-review
Oct 12, 2026
Merged

MaggieAppleton merged 5 commits into
mainfrom
living-design-review

Conversation

@MaggieAppleton

@MaggieAppleton MaggieAppleton commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A design pass over the living document flow (spikes → Build plan → first build → In sync / Out of sync), done on the real "Margin — living document", with route interception for the other states.

Top findings → what changed

  1. Expanded rows read as machine output. A sync-added task expanded to "Committed on https://github.com/…/pull/6." and "Reflects the document change since revision 452.", while the agent's own report of what it did was never shown. Now a finished task shows its summary instead of its acceptance criteria, and sync tasks get readable criteria ("Updates pull request Test the frontend with a browser, and run it on every push #6.").
  2. A Planner draft duplicated a living document's tasks (bug). Any "update the tasks" turn, including Build's automatic draft, added the unbuilt draft to live.tasks, so the real document went from 8 to 14 rows with duplicate keys. Now liveSnapshot lists only versions that ran (regression test added).
  3. Two vocabularies for one loop. In sync / Out of sync, then "Building…". A failed sync was only distinguishable on hover, and In sync had no explanation. Now the loop reads In sync → Out of sync → Syncing…, plus Sync failed, with a tooltip for every state.
  4. The Build headline repeated the header and led with a label. "Living document · In sync · 2 commits since first build" was all one weight. Now it uses the header's icon and label, with a tertiary detail (✓ In sync · 2 commits since first build, ○ Out of sync · Waiting for @x's agent).
  5. Sync-added tasks blended into the original plan. Now they sit in a quiet Since first build section.
  6. Mobile: the header slot straddled the page's corner, and PR capsules overflowed the list (bugs). Now the slot sits in the top inset at the trailing edge, and the task grid uses minmax(0, 1fr).
  7. A failed first build vanished silently (reason only in a tooltip and an sr-only alert). Now the slot reads Retry build with a warning dot.
  8. Spike callouts were wordy and buried the decision. Now they read "Prototype queued" / "Prototyping…" with shorter @handle copy, and a report leads with the recommendation, then findings, then screenshots.

Recommended but not in this PR: hide the header slot while Build is open; list a sync's commits under the task it added; a collapsible result callout; a cancel control on the callout instead of "Delete this callout to cancel"; a label other than "Building…" for a first build that is still queued.

Screenshots

Build view, live and in sync (1440): before / after
Before: live Build view with raw acceptance criteria
After: live Build view with summaries and a Since first build section

Build plan in the narrow layout (390): before / after
Before: Build plan on the page corner at 390px
After: Build plan in the top-right inset at 390px

Out of sync in the narrow layout (390): before / after
Before: Out of sync at 390px
After: Out of sync at 390px

Header slot: sync failed and syncing: before / after
Before: failed sync reads Out of sync
After: failed sync reads Sync failed
Before: a sync in progress reads Building
After: a sync in progress reads Syncing
After: In sync explains itself on hover

Testing

  • bun run types, bun test (4551 pass with the untracked design jigs moved aside), bun run ci, bun run build. The initial chunk is unchanged at 80,590 B gzip; all new code is in the room chunk.
  • New and updated unit tests: syncLabel, syncTooltip, liveTaskGroups and the hint copy in build-model.test.ts; spike callout copy and report order in spikes.test.ts; draft exclusion and sync-task acceptance in routes.test.ts. The draft test fails without the fix.
  • Checked by hand against the real living document (LIVE_BUILD=on LIVE_SPIKES=on), using route-intercepted snapshots for the out-of-sync, failed and syncing states at 1440 and 390px. Chopin has no dark theme, so there was nothing to check there.
  • Not checked visually: "Retry build" (reaching it needs a real failed draft), and the new spike copy on a live callout (existing callouts keep their text until their state changes).
  • Verified end to end (second run, 10 Oct) with copilot --acp --allow-all on github.com/MaggieAppleton/margin: the first build of 8 tasks opened margin PRs Let the planner reach for a diagram or a formula #7 to #14, and the live edit "Snooze 15 -> 5" went Out of sync, then Syncing... (+44s), then In sync (+92s) as commit a1f2f553 on the existing PR Add type scale tokens, replace arbitrary font sizes #12. It is listed under "Since first build".

Stack

Stacked on #454 (living-spikes), the top of #450 → #451 → #452 → #453 → #454. This repository merges rebase-only: after a lower PR lands, rebase and push with --force-with-lease.

Adapted to #508

Rebuilt on #454 after #454 moved onto #510. The Build capsule (#508) replaced the header slot and the sync vocabulary, so this PR now holds only the changes that still apply. The seven original commits became three.

Ported unchanged

  • Rebuild tasks read plainly ("Updates pull request Let the planner reach for a diagram or a formula #7.", "Matches the document as edited.").
  • liveSnapshot lists only task versions that ran, so a Planner draft can't duplicate a built document's tasks. The regression test is kept.
  • Spike callouts: "Prototype queued" / "Prototyping…" with @handle copy. Reports lead with the recommendation.
  • The build draft instruction says not to prototype a passage that already has a "Prototyping…" callout.
  • Wrapped tooltips align to the start.

Adapted to #508's read-only Build view

  • A finished task shows its summary instead of its acceptance criteria.
  • Blockers lose stacked "Blocked:" labels, and their links are clickable and shortened to owner/repo#N.
  • A task the build left unfinished reads as blocked, with the agent's reason, until a rebuild picks it up.
  • Rebuild tasks and no-change rebuilds sit under Since first build.
  • A queued build shows no elapsed time.
  • The task grid uses minmax(0, 1fr), so long titles don't push PR capsules past a phone's edge.
  • Build's headline, in Make Build plan explicit and show build status in one capsule #508's vocabulary: "Built · N pull requests · N commits since first build". A build that failed on unfinished tasks names the task to retry and leaves the reason to that task's row.
  • attentionHint (the capsule's "Build failed" tooltip) quotes a capped, link-shortened reason and says "retry it" or "retry them".

Dropped as superseded by #508

  • The sync vocabulary: syncLabel, syncTooltip, "Syncing…", "Sync failed", the reworded syncHint, and the first flag on SyncStatus. Make Build plan explicit and show build status in one capsule #508 uses Built / N changes to build / Building changes… / Build failed and has no sync wording.
  • Header slot changes: hiding while its view shows, data-build-slot, the in-flow status-row CSS and its theme.test.ts, Clock/Decision icons, "Retry build" with a warning dot, the mobile inset placement, and the "Answering this starts the build" line in Decisions. The capsule, its inert Build plan reasons, Retry and the phone glyph cover all of these.
  • The Build headline's own icons and sync labels. Make Build plan explicit and show build status in one capsule #508's BuildGlyph headline replaces them, and its detail line is ported above.
  • The blocked task dot changing to --color-warning. It stays --color-warning-graphic to match BuildGlyph.
  • The empty "Re-run pull request checks" commit.

Review fixes (restack, 2026-10-12)

  • Draft instruction. The build draft instruction names every pending prototype callout ("Prototype queued", "Prototyping…", "Prototype paused"). It also says a prototype's result lands after the build, since Prototype uncertain passages inline before the first build (LIVE_SPIKES) #454 now defers it, and treats callout text as data; there is a test.
  • Queued first build. I checked that a queued, unclaimed first build still lists its tasks. It has no live record yet, so Build reads the approved graph, and a route test confirms it.
  • Decision 1 port. I checked it against the spec: Since first build (liveTaskGroups), the status detail line, no-change rows, finished-task summaries, linkified blockers (linkParts, shortUrl, blockerText), the unfinishedReason and liveTaskState warning dots, and the two-line title wrap. No "sync" wording is user-visible.

🤖 Generated with Claude Code

Second pass

This pass reviewed the new states end to end: waiting on a decision, queued, needs attention, out of sync with blocked tasks, cancel build, and no-change syncs. The full critique is in /tmp/living-design-review/critique-2.md. The after-screens were rendered on a local fake-GitHub server with intercepted snapshots.

Finding Change
At 390px, a blocker that contains a URL pushed the Build view past the card edge Status line, task detail and no-change rows wrap long words (overflow-wrap: anywhere)
"Needs attention" printed the full blocker in the status line and again in the row The status line says what to do (“X” is blocked. Edit the document to retry.); the row shows the reason; the tooltip caps it at about 120 characters
The unfinished task kept a hollow queued ring and stayed collapsed An outstanding task shows the warning dot and starts open until a sync picks it up
The slot repeated the view you were in (Queued above Queued, Waiting on a decision above Decisions) The slot hides while the view it opens is showing; "Build plan" stays because it's an action
A hollow ring meant a queued task, Queued, Out of sync and Waiting on a decision Rings are for task states only; the slot and status line use a clock for waiting, the decision glyph for a decision, and the warning dot for attention
"Queued · … 0m" A queued build shows no timer
"Your edits will sync shortly · will also retry 1 blocked task" One clause: "Your edits and 1 blocked task will sync shortly" (and matching waiting or failed copy)
No-change rows had no glyph and a time centred against long text A tertiary check in the dot column; the time sits on the first line

Not changed (recommended): agent prose is long (it needs a server-side summary and details split); a stale task survives a no-change sync; spike callouts still say "Delete this callout to cancel".

Blocker at 390px

Before: long blocker overflows the Build view at 390px
After: blocker wraps, short status line, slot hidden in Build

Needs attention at 1440px

Before: blocker printed twice
After: brief status line, reason once in the row

Unfinished task

Before: unfinished task looks queued
After: unfinished task shows the warning dot and opens

Queued

Before: Queued with 0m timer and duplicate slot
After: clock glyph, no timer, no duplicate slot

Waiting on a decision

Before: slot above the Decisions view at 390px
After: slot hidden in Decisions at 390px
After: decision glyph in the slot at 1440px

Out of sync

Before: hollow ring for out of sync at 390px
After: clock glyph for out of sync at 390px

No code change rows

Before: no-change rows without a glyph
After: no-change rows with a check and first-line time

Final pass

  • Unfinished rows say why: the agent's last report, else where it stopped. The headline names the task an edit retries.
  • Blockers drop stacked "Blocked:" labels. GitHub links show as owner/repo#N, and the row links them.
  • The warning dot shares the reason's --color-warning family. Wrapped tooltips are left-aligned.
  • Decisions shows "Answering these starts the build." while a one-click build waits on them.
  • The Build headline lines up with the task titles at both widths.

Before: unfinished task with no reason
After: unfinished task says where the agent stopped
Before: centred tooltip with stacked labels and a raw URL
After: left-aligned tooltip with a shortened link
After: Decisions explains that answering starts the build

Last pass

A real run on margin confirmed the spike lands before a queued build starts. Its result reached the first build, and no rebuild followed the callout. Two rough edges remained:

  • The first build no longer flashes "Syncing…" in its last seconds. It keeps "Building…" until it ends. "Syncing…" now only means a rebuild after an edit.
  • A one-click build started during a spike no longer adds a task that prototypes the same passage again. The implementing task follows the spike's result.

Before: first build ends showing Syncing…
After: first build keeps Building… until it ends
Before: tasks include a second prototype of the spiked passage
After: tasks follow the spike's result

@MaggieAppleton
MaggieAppleton added this pull request to stack #455 October 10, 2026 12:49
@MaggieAppleton
MaggieAppleton marked this pull request as ready for review October 10, 2026 12:50
@MaggieAppleton
MaggieAppleton force-pushed the living-design-review branch 5 times, most recently from f544612 to e045c7d Compare October 10, 2026 22:23
@MaggieAppleton
MaggieAppleton removed this pull request from stack #455 October 12, 2026 10:23
Base automatically changed from living-spikes to design-build-capsule-manual October 12, 2026 16:32
@MaggieAppleton
MaggieAppleton force-pushed the design-build-capsule-manual branch from 36eeb69 to 8cec41e Compare October 12, 2026 17:01
Base automatically changed from design-build-capsule-manual to main October 12, 2026 17:18
MaggieAppleton and others added 5 commits October 12, 2026 18:19
…n, and list only built task versions

Ported from the living-document polish onto the Build capsule: readable
acceptance for rebuild tasks, shorter spike callout copy, a report that
leads with its recommendation, a draft instruction that does not prototype
a passage twice, a live task list that ignores unbuilt Planner drafts, and
tooltips that align wrapped text to the start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tasks in Build

Ported from the living-document polish onto the Build capsule's read-only
Build view: a finished task shows its summary, a blocker drops stacked
"Blocked:" labels and links its URLs, a task the build left unfinished
reads as blocked with its reason, rebuild tasks and no-change rebuilds sit
under Since first build, a queued build shows no elapsed time, and long
titles no longer push the task list past a phone's edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch task to retry

The rest of the living-document Build view port onto the Build capsule's
vocabulary: a built document's headline counts commits since its first
build, and a build that failed on unfinished tasks names the task to retry,
leaving the reason to that task's row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The instruction now names Prototype queued, Prototyping… and Prototype
paused, says a prototype's result lands after the build rather than before,
and treats callout text as data. A route test confirms a queued, unclaimed
first build still lists its tasks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whitespace only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaggieAppleton
MaggieAppleton merged commit 07a8a36 into main Oct 12, 2026
3 checks passed
@MaggieAppleton
MaggieAppleton deleted the living-design-review branch October 12, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant