ADR-016 — Layout output review path
Date: 2026-07-08 Status: accepted
Context
CLAUDE.md’s on-demand loop guardrails state “no agent code reaches main unreviewed.” For
components this is enforced end-to-end: /add-component runs a deterministic gate, then
/review-component spawns one fresh-context adversarial reviewer, then opens a PR — nothing
lands on main without both a gate pass and an independent review.
/layout-generation has no equivalent. Its final step runs npm run layout:validate +
npm run typecheck and stops; the output (a route page in apps/showcase/src/pages/ or a
story file) is never required to go through a PR, let alone a review. This was flagged in the
2026-07-08 agentic moments audit (.claude/handoff/2026-07-08-agentic-moments-audit.handoff.md,
finding 4) as an inconsistency: the same failure mode the component reviewer exists for — a
generator rationalizing its own structural choices (here, its own Figma-to-grammar mapping) —
is unguarded for layouts.
The options considered:
- Do nothing — leaves the stated invariant false for one of the two agent-code-generating moments.
- Always spawn the adversarial reviewer for layout output, mirroring
/review-componentexactly. - Tiered default: every generated layout goes through a PR with in-session
/code-review(cheap, no subagent, no fresh context); a full route page may optionally also get the adversarial reviewer subagent, reusing/review-component’s subagent shape.
Option 2 conflicts with the Pro-window-scarcity guardrail already governing moment 6 (“Sequential, ≤2 agents” — spawn at most one fresh subagent, spent where independent context is the whole point). Layout generation runs more often and more exploratory than component scaffolding (iterating on a page draft is normal; iterating on a component is not), so making every run pay for a fresh-context subagent would burn the scarce resource on low-stakes drafts.
Decision
Layout-generation output always goes through a PR before landing on main, but the review tier
is tiered by stakes, not uniform:
- Default: every generated layout (route page or
--storyoutput) is committed on a feature branch and opened as a PR againstmain; the developer runs in-session/code-reviewon the diff before merging. No subagent, no handoff file — same cost profile as any other hand-written diff. - Opt-in: for a full route page (not a
--storyfragment), the developer may additionally invoke the adversarial reviewer subagent, reusing the read-onlyadversarial-revieweragent definition and.review.jsonshape from/review-component. This is opt-in, not automatic — the generator’s own Figma-mapping rationalization risk is real but not every layout run justifies spending a fresh context window on it.
This keeps “no agent code reaches main unreviewed” true for both agent-code moments while
respecting the ≤2-agent / sequential / Pro-window-scarcity guardrails already in place: the
default path spends zero subagents, and the opt-in path spends at most one, exactly like
/review-component.
Consequences
/layout-generation’s final step changes from “run the validator and stop” to “run the validator, then commit to a feature branch and open a PR” — the git workflow’s blanket “commit directly to the current branch” rule gets a second named exception (alongside/add-component+/review-componentand/docs-sync).- No new agent role is created — the opt-in path reuses
.claude/agents/adversarial-reviewer.mdand the.review.jsonshape verbatim rather than defining a parallel reviewer for layouts. - Cost stays bounded: routine layout iteration (the common case) costs one in-session
/code-reviewpass, not a subagent spawn; only full route pages the developer flags as higher-stakes pay for the fresh-context review. - CLAUDE.md’s “Git workflow” section needs its exception list updated to name this new PR path,
and
/layout-generation’s final step needs the branch+PR instructions and the opt-in reviewer invocation.