Surfaces v2: slotted schema, opinionated action rendering, design contract - #1041
Merged
Conversation
…tract Breaking pre-release schema change (v1 docs render a recreate notice): - Document slots: header (status+progress strip), footer.actions; section actions footer; per-item/row actions[] (1 inline ghost, 2+ kebab menu). - Standalone actions block removed — placement is renderer-owned. - Action policy: split button with overflow, destructive de-emphasized (ghost-destructive, never gains area), compact h-7/h-6 buttons. - Tone rescale (healthy dim, neutral plain text), typographic ramp, 3-primary-column table budget, 2-col tables render as key/value, timestamp + enum-label normalization, form submit full-width primary, muted required markers, attestation checkbox grouping, text tone callouts. - Tool descriptions carry a thin design contract; surfaces skill rewritten; seed gallery + tests + e2e re-authored under v2; migration 0044 adds header/footer columns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…line link arrow - Single item/row actions render as compact bordered chips (they read as buttons again, per feedback) instead of bare ghost text. - A standalone destructive button keeps a visible border. - List item link arrows flow inline after the last word instead of wrapping to their own line. - Checkbox labels use the muted required marker like other fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ance - Block-header counts render as "(4)" on the title line so they read as intentional rather than a stray digit. - Skill's table guidance: keep a relative-time column primary when recency matters (a history with no time cue is worse than one fewer column). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Nested action menus claim Escape (preventDefault + controlled close) and GlassSidebar ignores claimed Escapes, so the first press dismisses only the menu in the mobile drawer (#2479); e2e regression covers it. - Confirm dialogs opened from an overflow menu item return focus to the split trigger via a returnFocusRef instead of falling to <body> (#2480); e2e asserts cancel refocuses the trigger. - Menu items get the coarse-pointer 44px minimum (#2481). - Authored-disabled overflow actions stay focusable via aria-disabled with their reason rendered inside the item and aria-describedby wired (#2482). - humanizeLabel only rewrites separator-bearing tokens; plain all-caps values (API, AWS, NASA) pass through, with unit regression tests (#2483). - Checkbox, radiogroup, select trigger, and multi-select group carry aria-required now that the visual asterisk is aria-hidden (#2484). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The non-claude harvest test walked the developer's actual codex sessions dir (gigabytes of rollout files on a busy machine), blowing the 30s test timeout on the self-hosted runner. Point CODEX_HOME at an empty temp dir for the test's duration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- dispatch_surface_list projection strips header/footer along with blocks so list stays the tab-summary contract; MCP assertion added (#2538). - Section-action interaction snapshots omit the section's descendant tree (up to 100 nested blocks) to stop repeatable clicks amplifying storage; test asserts the snapshot carries no blocks (#2539). - Escape e2e regression test waits for focus inside the menu before dismissing, closing the mount race that flaked under load (#2540). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Also imports AgentPin/AgentStatus in apps/web/src/components/app/types.ts: the file used them locally but only re-exported them (a re-export creates no local binding), so check:web failed on main after #1044 — pushes to main don't run CI, which is how it slipped through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
selfcontained
added a commit
that referenced
this pull request
Sep 4, 2026
* test(server): isolate the vitest suite from the host's ~/.codex The Codex token harvester resolves its rollout directory from CODEX_HOME and falls back to the host's real ~/.codex (src/agents/codex-sessions.ts:11). Any server test that harvests a codex agent then recursively walks that tree and reads the head of every rollout file. On this machine that is 5.7 GB / ~11.7k files, and the self-hosted CI runner is the same machine — so it is not a "works on CI" situation. PR #1041 patched the one test whose 30s budget it blew by swapping CODEX_HOME inside that test, but stopAgent harvests fire-and-forget (manager.ts:1173), so codex agents stopped by other tests still walked the real directory. The file was still spending ~24s on host I/O. Point CODEX_HOME at an empty directory for the whole server suite via vitest.config.ts `test.env`, and drop the now-redundant per-test override. apps/server/test/db/agent-manager.test.ts alone: 55.5s with one 30s timeout before, 7.5s and 129/129 after. Full server suite: 3130 passed in 40.4s. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(server): use mkdtempSync for the suite's isolated CODEX_HOME Review 1107 item 2612: a fixed name under os.tmpdir() is not guaranteed to be empty — mkdirSync(..., { recursive: true }) silently reuses an existing directory or follows an existing symlink, so a stale or planted `sessions` tree would put host-controlled data back in the harvester's path. mkdtempSync creates a fresh 0700 directory with a random suffix on every run, so it can never adopt an existing tree, and concurrent runs no longer share one. Removed on process exit. Verified: zero `dispatch-server-vitest-codex-*` directories in TMPDIR before and after a run; agent-manager.test.ts 129/129 in 8.1s; full server suite 3130 passed in 32.2s; pnpm run check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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
Breaking pre-release redesign of agent surfaces, driven by a 6-surface UX audit (screenshots + critique + design proposal in the agent's media). The core move: placement and visual weight are now renderer-owned — agents supply meaning, the renderer owns the design.
Schema (v2, breaking — feature is unreleased)
header(status + progress strip, always first),blocks, optionalfooter.actions(the surface's verbs).actionsblock removed — actions live only in slots: document footer,section.actionsfooter, and per-item/rowactions[](replacing singularaction). Bad placement is now inexpressible.textgainstone(callout rendering); formsubmitloses itsstyleknob (always primary); tablealign:"center"removed; ≤3 primary table columns enforced; block idsheader/footerreserved.0044addsheader/footerjsonb columns. Stored v1 documents render a "recreate this tab" notice (no crash), refuse interactions, and upgrade in place via a full v2blocksreplacement.Renderer
neutralbadges are plain text — color budget goes to exceptions.md:responsive branch is removed (the rail is a fixed 400px).IN_PROGRESS→ "In progress"); progress bars neutral by default with an inline percentage; form submits full-width primary, muted required markers, trailing checkbox runs grouped as an attestation gate.Guidance
dispatch_surface_create/updatetool descriptions carry a thin design contract; thesurfacesplugin skill is rewritten for v2 (slots, contract, re-authored recipes).Validation
pnpm run check,pnpm run finalize:webclean; full unit suite passes; full e2e: 186 passed / 12 skipped (including the 4 re-authored surfaces specs).🤖 Generated with Claude Code