Fix(vinaya-web): site chrome polish — nav, switch label, badges, spacing, ring labels, hero - #704
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
VERDICT: PASS FINDINGS (ordered by severity): CONFIG SCAN: not applicable — no agent/skill/hook/MCP config touched Scope confirmed via merge-base diff (main...pr704): 9 files, matches Tokens: misc-hardening-v1/18: security — Security — claude-sonnet-5 — —/—/— |
|
VERDICT: APPROVE BRIEF CONFORMANCE: Yes, all six parts of Issue #702 delivered exactly as specified. Verified each against the brief's own tables: (1) nav order SPEC CONFORMANCE: Clean. FINDINGS (ordered by severity): SCOPE: Clean — 9 files changed, matches the brief's §3 surface map and TESTS: Honest — route/nav/badge checks run curl against a booted app and assert real rendered markup, not mocks. Build/typecheck/lint/unscoped-test evidence all present and match the brief's §7 gates. DOCS: Tier-appropriate and correct, verified at the sentence level. Tokens: misc-hardening-v1/18: review — Reviewer — claude-sonnet-5 — —/—/— |
06ecb26 to
15c31f4
Compare
AEG provenance — task 18 (tranche misc-hardening-v1)
|
Closes #702
For: Sonnet (a coding-agent CLI on a dev machine, interactive session)
Project: vinaya
Summary
Six presentational fixes on the public Vinaya site, all inside
apps/vinaya/web: reordered the top nav so Start/CLI sit before Studio; gave the Portal↔Studio switch a visible STUDIO label (kept itsaria-labeland the retro-onlysize='sm'prop unchanged); wrapped state-machine-vocabulary cells inBadgeon/state-machine, matching the sibling diagram's own treatment; gave/cliits ownlayout.tsxduplicating the/docs//startcontent-pane shape (measure, top spacing, background, independent scroll) rather than extracting a shared layout, since tasks #692/#696 are mid-edit on those two routes; raised harness ring/wedge label sizes on/the-harnessfor legibility; re-enabled the hero build animation on every page load by commenting out (not deleting) the once-only gate. Decisions beyond the brief's explicit table: after the Principal reviewed the first pass live and found the ring/wedge labels and the hero's VINAYA/HARNESS labels still too large, I stepped them down further (wedge/band labelstext-3xl→text-2xl, hero labelstext-2xl→text-xl) — verified against the same computed-geometry check described below, which showed the size reduction also shrank (but did not eliminate) the one wedge-label overflow finding on the Contracts ring.Test plan
bun run build(turbo build --filter=@atta/vinaya-web) completes with exit 0, no error mentioningSwitchPropsorsize. Verified twice (before and after the post-review label-size follow-up).curl -s -o /dev/null -w '%{http_code}' localhost:3006/{,cli,state-machine,the-harness}→200for all four.curl -s localhost:3006/ | grep -o 'href="/[a-z-]*"'(deduped) →/,/the-harness,/state-machine,/start,/cli,/docs,/the-studio,/roadmap, in that document order.curl -s localhost:3006/state-machinecontains<span data-slot="badge" ...>vinaya/tier:1</span>-shaped markup (76 badge spans total on the page), and the response contains no'use client'literal./the-harness: drill into every ring; labels are comfortably readable and no label —tranche-archivistespecially, on a left/right wedge — overflows or overlaps its wedge (see the one known exception below)./clibeside/docsand/startat the same window size: same top spacing, same measure, same background, content pane scrolling the same way./state-machine: label cells read as badges, prose cells unchanged, no table spilling sideways at ~800px width.Premise
Premise:
Verification evidence
Scoped,
@atta/vinaya-web:bun run typecheck --filter=@atta/vinaya-web→Tasks: 14 successful, 14 totalbunx biome lint .→Checked 1204 files ... Found 1 warning(the one accepted warning below, no errors)bunx turbo test --filter=@atta/vinaya-web→Test Files 15 passed (15) / Tests 90 passed (90)bunx turbo build --filter=@atta/vinaya-web→Tasks: 15 successful, 15 total, all 27 routes including/cli,/state-machine,/the-harnesscompiledUnscoped, full monorepo:
bunx turbo test(all packages) →Tasks: 53 successful, 53 totalAccepted lint warning (Part 6 / §10 fallback):
VinayaHeroEmblem.tsx:89—seenis assigned (via thelocalStorageread) but, with the once-only branch commented out, never read.noUnusedVariablesiswarn-level in this repo'sbiome.json(does not failbiome lint ., exit 0). No existing pattern in this codebase silences an intentionally-unused variable (checked forvoid x/biome-ignore/ underscore-prefix precedent — none exists). Per the brief's own fallback: kept the read live (the mechanism that must survive), accepted the warning rather than inventing a new suppression convention.Route/nav/badge/layout checks — see the Test Plan
[agent]rows above; each ran againstbunx next dev --turbopack --port 3006from the worktree.Diff vs merge-base:
Nine files — matches the brief's §3 surface map exactly. Zero files under
packages/— theblast-radius-ack:holds.Scope
All six edits are presentational and confined to
apps/vinaya/web; no shared package (packages/uior otherwise) is touched, so no consumer beyond this app is affected./docsand/startthemselves are untouched (C1) —/cli's content-pane shape is a deliberate duplicate, not a shared extraction, because tasks #692 and #696 are open on those two routes right now. The switch label lives in the app-localProductSwitchControl.tsx, notpackages/ui/topbar(C2), keeping this a one-project change. Non-goals, all explicitly out of scope per the brief:/docsand/startinternals,/cli's below-lgsidebar behavior,the-harness/_lib/geometry.ts(ring radii/wedge angles), the hero's storage mechanism itself (key/read/write all still live), and any nav copy/route/new page.Known, documented, non-blocking finding: the Contracts ring's
archivist-tranche-archivistwedge label overflows its wedge — verified by computing the real geometry (the actuald3-piecentroid position and the drilled ring's 330-viewBox-unit radial thickness, replicatingwrapLabel/shortLabel/humanLabelanddrillArcsfrom the real source), not assumed. It lands on the ring's left wedge, where only the wedge's radial thickness — not the wider arc width a top/bottom wedge gets — is available to a horizontal label. Fixing it needs the wedge's own geometry, which is out of scope by construction (§9 stop condition, not a blocker for this PR); recorded invinaya-spec.md's Known limits.Tier: 1
Token report
No
/cost-equivalent tool is exposed to this session, so exact token/cost figures are not available to report here — noting the gap explicitly rather than fabricating a number, per this repo's own anti-pattern list.Reference — the dispatched brief
Full brief (reference copy — the gates read the anchored fields above, never this block)
Task brief — misc-hardening-v1 18 — The site's own chrome is the least finished surface it ships
For: Sonnet (a coding-agent CLI on a dev machine, interactive session)
Reason: mid — six small, disjoint presentational edits in one app. No architecture to decide, no shared package, no data layer. What the task actually demands is discipline: holding three "read this file, do not edit it" boundaries while working directly next to those files, and one SVG-in-viewBox change where the naive fix is subtly wrong. A fast model reliably takes the refactor bait in Constraint C1; a high model buys nothing the reasoning needs — the Planner and Brief Author already did it.
Owner: Principal (Daniel Estevez)
Goal: Fix six presentational defects on the public Vinaya site — nav order, a labelled Portal↔Studio switch, state-machine labels as Badges,
/cli's content pane brought to the/docs+/startshape, legible harness ring labels, and a hero animation that plays on every visit.Tier: 1
Project: vinaya
Closes #702
You are the AEG Developer. Read
aeg-root/roles/developer.mdfirst, then.claude/skills/executor-protocol/SKILL.md. Those two govern how you execute this brief; this brief governs what you build.1. Context — read before doing anything
What this is
apps/vinaya/webis the public site for Vinaya, an agentic engineering harness (vinaya.attalabs.dev). The(site)route group is the marketing/reference surface: Home, The Harness, State Machine, Studio, Start, CLI, Docs, Roadmap. A separate/studiosubtree is the local-only dashboard and is not in scope.The Principal walked the live site and collected eight polish defects in one sitting. The Planner's dig resolved those eight reports into six edit sites, because two pairs collapse: the two nav-order requests are one array, and the desktop and mobile "label the switch" requests are one component rendered through one slot. You are implementing six changes, not eight.
The Planner's rationale, carried forward
Boundary. Six presentational edits, all inside
apps/vinaya/web. Explicitly out:packages/uiin its entirety;/docsand/startthemselves; a shared layout factored out of the three sidebar routes;/cli's below-lgsidebar behaviour; the ring diagram's radii and wedge geometry; the hero's once-only storage mechanism itself; any nav copy, route target, or new page.Blast radius.
vinayaonly — and that is a decision, not an observation. The switch label could be implemented in the shared TopBar instead of the app-local control. Routing it that way would put five consumers in the blast radius (Vinaya's site shell, Vinaya Studio's shell, Vāda's main layout, and two Herald surfaces), make this a three-product regression surface, and fire a C5 doc binding requiring.claude/skills/ui-components/SKILL.mdin the same diff. The Issue carries an explicitblast-radius-ack:that is only valid while no file underpackages/uiis edited. Keep it valid.Traps are reproduced as hard constraints in §11. Read them before you write code, not after.
What is locked and must not be relitigated
/cliadopts the/docs+/startshape./docsand/startare the reference; they do not move toward/cli.Doc knowledge you need (surfaced here, not by reference)
Read during the Dig; the load-bearing facts, so you do not have to re-derive them:
apps/vinaya/specs/vinaya-spec.mdcarries a## Pagesroute table with a per-route UI polish column — the standing record of each page's finish state — and a## /the-harness pagesection describing the ring renderer's label treatment. Both go stale from this task.Status:is already present on the spec; you are not adding one.CLAUDE.mdfiles hold architecture, never low-level UI detail. No pixel values, no Tailwind class names, no nav arrays, no switch-label copy in a spec. Record that/clishares the content-pane shape of/docsand/start, and that harness ring labels are sized for legibility at rendered scale. Do not transcribe your diff.apps/vinaya/web/CLAUDE.mdis the de-facto detailed web-surface doc. It currently states, among much else, that/cli"is hidden belowlgwith no drawer because that sidebar is a same-page scroll-spy TOC rather than cross-route nav" — still true after this task — and describes the ProductSwitch split across a server gate and a client control. Update only what this task makes false..claude/rules/ui-patterns.mdloads automatically on.tsxedits. Its rules bind here:@atta/uicomponents over raw HTML, semantic theme tokens only (notext-green-500, no hex, nobg-[#…]), no inlinestyle={{}}unless provably impossible in Tailwind,lucide-reactfor icons, semantic font classes.apps/vinaya/web/**..claude/skills/*/paths.txtbindspackages/ui/**,packages/cms/**,apps/herald-ai/**,apps/vada-ai/**and similar — none match this surface. Nothing will force you to loadui-componentsorui-theme-tokens. The conventions still apply; this brief is what carries them.2. Technical dependencies — what must already exist
All satisfied at authoring time; verify in pre-flight.
Badgefrom@atta/ui/components— required by Part 3. Already used on this same page's sibling component (StateMachineDiagram.tsxrenders status names in<Badge variant='outline' className='font-mono text-xs font-normal'>) and imported by(site)/cli/page.tsx. You are matching an existing in-page treatment, not introducing one.Flexfrom@atta/ui/shared— required by Part 4's new layout file. Already imported bydocs/layout.tsx,start/layout.tsx, andcli/page.tsx.COMMANDSfrom@atta/vinaya-sources— required by Part 4; the newcli/layout.tsxmust pass it toCliSidebar. Currently imported bycli/page.tsx.Switchfrom@atta/ui/componentswith its retro-onlysize='sm'prop — Part 2 keeps this working.apps/vinaya/webresolves the retro library at build time;sizeis retro-only and fails at compile time on basic/animate/brutal. Do not remove or change it.depends-on. Noconflicts-with. Nothing must merge before this runs.3. Technical surface map
Files you will modify or create
apps/vinaya/web/src/app/(site)/layout.tsxlinksarray (Part 1)apps/vinaya/web/src/app/_components/ProductSwitchControl.tsxapps/vinaya/web/src/app/(site)/state-machine/_components/StateMachineTables.tsxBadge(Part 3)apps/vinaya/web/src/app/(site)/cli/layout.tsx/docs+/startshell shape (Part 4)apps/vinaya/web/src/app/(site)/cli/page.tsxapps/vinaya/web/src/app/(site)/the-harness/_components/DiagramCanvas.tsxapps/vinaya/web/src/app/(site)/_components/hero-canvas/VinayaHeroEmblem.tsxif (seen)early-return (Part 6)apps/vinaya/specs/vinaya-spec.mdapps/vinaya/web/CLAUDE.mdExplicitly out of surface — do NOT touch
packages/ui/. Includingpackages/ui/topbar/index.tsx,packages/ui/lib/color-scheme-toggle.tsx, and every library variant.apps/vinaya/web/src/app/(site)/docs/**— task 13 ([misc-hardening-v1] 13 — Two docs pages print their own title twice #692) is live on this subtree.apps/vinaya/web/src/app/(site)/start/**— task 16 ([misc-hardening-v1] 16 — Every stage of the loop says what it takes in and what it hands on, and draws it #696) is live on this subtree.apps/vinaya/web/src/app/(site)/cli/_components/CliSidebar.tsx— its rail behaviour is unchanged.apps/vinaya/web/src/app/(site)/the-harness/_lib/geometry.ts— radii, band thicknesses, wedge angles all stay.apps/vinaya/web/src/app/_components/ProductSwitch.tsx— the server-side authorization gate. Only the client control changes.apps/vinaya/web/src/app/studio/**and every other route.Shared-symbol check
No symbol is deleted or renamed.
SEEN_KEYstays defined and referenced (the write site keeps using it).ProductSwitchControl's export signature is unchanged. No importer anywhere is affected.Premise:
4. Pre-flight checks
Step 0 (mandatory, first) — create the worktree
Remaining pre-flight
git status— clean.git log --oneline -3— parent isorigin/main.bun packages/aeg-core/bin/verify-dispatch.ts misc-hardening-v1 18 --premise <this-brief-file>— READY, and every premise assertion holds. A failed premise means a file moved since authoring: STOP.apps/vinaya/web/src/app/(site)/cli/layout.tsxdoes not exist (you are creating it).bun run dev:vinaya(or the app's dev script) boots and/,/cli,/state-machine,/the-harnessall render before you change anything. You need the before-state to compare against.5. Parts
Part 1 — Nav order
File:
apps/vinaya/web/src/app/(site)/layout.tsxReorder the
linksarray to exactly:Only the order changes. Every
label,hrefandexactvalue stays byte-identical.Studioremains/the-studio.The array carries a comment above
State Machineexplaining why it sits besideThe Harness("both are code-derived reference pages"). That reasoning survives the reorder — they stay adjacent — so keep the comment with the entry it describes.Part 2 — A visible name for the Portal↔Studio switch
File:
apps/vinaya/web/src/app/_components/ProductSwitchControl.tsxWrap the existing
Switchso the word STUDIO renders directly above it in very small type, with no gap — the two must read as one control, not a label and a separate widget.Requirements:
@atta/uiprimitives and semantic tokens.Textfrom@atta/ui/sharedis the house primitive for this; a bare<span>is a raw-HTML violation ofui-patterns.mdRULE 1.text-muted-foregroundwith the smallest step on the type scale. Match the eyebrow treatment already used elsewhere in this app (font-mono … uppercase tracking-…), do not invent a new one.size='sm'on theSwitchand its entire explanatory comment block verbatim — it documents a real compile-time coupling to the retro library.aria-labelexactly as-is. It states the current surface and the destination; the new visible text does not replace it and must not be duplicated into it.This one change covers both the desktop right cluster and the mobile sheet row:
(site)/layout.tsxpasses<ProductSwitch current='portal' />into TopBar'sextraActions, and TopBar renders that same slot in both places. You do not edit TopBar.The mobile sheet renders
extraActionsinside a fixed-height row (flex h-14 items-center). A stacked label-over-switch is taller than a bare switch. Verify it still sits correctly at a phone width — see the Test Plan.Part 3 — State-machine labels become Badges
File:
apps/vinaya/web/src/app/(site)/state-machine/_components/StateMachineTables.tsxAdd
Badgeto the existing@atta/ui/componentsimport. Wrap the cell contents that are labels — an identifier drawn from the model's vocabulary — in aBadge. Leave prose cells as prose.Wrap these (they are labels):
input.factlabel.idrow.statusrow.concludedByrule.idrule.statusLeave these alone (they are prose or data, not labels):
input.readsFrom,input.meaning,label.category,label.carries,row.derivable's Yes/No,rule.chainStep,rule.when,rule.why.Rules:
StateMachineDiagram.tsxuses<Badge variant='outline' className='font-mono text-xs font-normal'>. Use the same variant and class shape so the two components agree.row.concludedBycurrently renders as.join(', '). Replace the join with oneBadgeper rule id in a wrapping flex container. Keep theEMPTY_CELL(—) fallback for the empty case rendered as plain text, not a Badge — an em-dash is an absence marker, not a label.'use client'. This is a server component holding@atta/aeg-core-sourced data; a client directive dragsnode:child_processinto the browser bundle.Badgeis a presentational component and works server-side.min-w-[720px]/min-w-[760px]values with a long comment explaining the 780pxstickyHeaderthreshold. Do not change them. If badge padding makes a table overflow, that is a finding to report, not a licence to retune the width.Part 4 —
/cli's content pane matches/docsand/startCreate
apps/vinaya/web/src/app/(site)/cli/layout.tsxin the shapedocs/layout.tsxandstart/layout.tsxshare:COMMANDScomes from@atta/vinaya-sources;CliSidebarfrom./_components/CliSidebar. This is a synchronous server component — unlike/docsit needs no async data fetch, exactly asstart/layout.tsxdoes not.Then reduce
cli/page.tsxto its content only: it returns the two<section>elements it already renders, wrapped in a container supplying their vertical rhythm (flex flex-col gap-10). Delete theFlexshell, the<main>, the innermx-auto max-w-3xl … lg:max-w-4xldiv, theCliSidebarrender and its now-unused imports (Flex,CliSidebar,COMMANDSonly ifCOMMANDSis genuinely no longer read in the page — it still is, by the.map, so keep it).What this deliberately changes: measure becomes
max-w-4xlat every breakpoint (wasmax-w-3xlbelowlg); top spacing becomespt-10at every breakpoint (waspy-12/lg:pt-4);bg-backgroundis now set; the content pane scrolls at all widths rather than only atlg. All four are the point of the task.Keep the existing
scroll-mt-6on each command block — the scroll-spy anchor offset still applies.Do not add a mobile drawer or a
lg:hiddenbar./cli's sidebar is a same-page scroll-spy TOC, not cross-route nav, and its below-lgbehaviour is deliberately different from/docsand/start. Out of scope.Part 5 — Legible harness ring labels
File:
apps/vinaya/web/src/app/(site)/the-harness/_components/DiagramCanvas.tsxThe ring labels are SVG
<text>sized in viewBox units, not CSS pixels. The canvas hasviewBox='36 36 1468 1468'and scales to its container, so a Tailwind size class here is a viewBox-unit size that then scales. The evidence the current sizes are wrong is in the file itself: the drilled hub title was already scaled totext-6xlwith a comment sayingtext-xl"read tiny inside a 380-radius circle" — the wedge labels sitting beside it attext-xlnever got the same treatment.Raise these, keeping the Tailwind scale (the file's own rule: no arbitrary px values):
text-xltext-3xlprincipal,planner,brief-author, …)text-xltext-3xl2639text-xltext-2xltext-xstext-lgLeave
text-6xl(hub title),text-2xl(hub legend) andtext-5xl("main") as they are — those were already scaled.The binding constraint, derived — verify it, do not assume it. The drilled ring runs
DRILL_R_IN 400→DRILL_R_OUT 730, so a wedge is 330 viewBox units thick radially. A label is horizontal text at the wedge centroid, so for wedges sitting at the left and right of the ring, the available width is that 330 units — not the much larger arc width the top and bottom wedges get. The longest actor label istranche-archivist(17 characters), and it renders on a left wedge.wrapLabelsplits on spaces only, so a hyphenated label never wraps: all 17 characters are one line. Attext-3xla monospace character advances roughly 0.6em ≈ 18 units, so 17 characters ≈ 306 units — inside 330, with little to spare.text-4xloverflows it. If your visual check shows overflow attext-3xl, that ceiling — not the font scale — is the real finding: report it and stop, per §10.Apply the same "does the longest label still fit" check at every ring level, not just actors. Drill into each ring from the overview and look.
Do not touch
geometry.ts. Radii, band thicknesses and wedge angles are out of surface.Part 6 — The hero animation plays on every visit
File:
apps/vinaya/web/src/app/(site)/_components/hero-canvas/VinayaHeroEmblem.tsxComment out the
if (seen) { … return }early-return block (currently ~lines 96–104) so the build timeline always runs.Keep, working and uncommented:
const SEEN_KEY = 'vinaya-hero-seen'try { seen = window.localStorage.getItem(SEEN_KEY) === '1' } catch {}readat(6300, …)localStorage.setItemwriteAdd a short comment above the commented block saying the gate is deliberately disabled so the animation plays on every load, and that restoring it means uncommenting this block — nothing else. The intent is a one-line flip back, not a removal.
Update the component's existing comment at ~line 85 ("Plays the build ONCE, ever…"), which will otherwise assert the opposite of what the code does.
Expect a lint warning that
seenis assigned but never read once the branch is commented. Resolve it the way this codebase already does elsewhere rather than deleting the read — the read is part of what must stay live. If the only clean resolution is deleting the read, that contradicts the keep-the-mechanism instruction: take the safe half (keep the read), record the choice in the PR body, and continue.6. Documentation-update list
apps/vinaya/specs/vinaya-spec.md— the## Pagesroute table's UI polish column for/cli,/state-machineand/the-harness; and the## /the-harness pagesection where it describes ring label treatment. Record the architectural facts only:/clishares the content-pane shape of/docsand/start; harness ring labels are sized for legibility at rendered scale, bounded by the drilled wedge's radial thickness; state-machine label cells render as badges. No class names, no pixel values, no nav array, no label copy. The spec already carries aStatus:field — do not add one.apps/vinaya/web/CLAUDE.md— update where this task makes it false: the(site)nav order it enumerates; the ProductSwitch description ("no visible text label" is no longer true);/cli's layout description. Its statement that/clihides its sidebar belowlgwith no drawer remains true — do not change it.Write both so a reader with no access to this tracker can resolve them: state the durable fact, do not cite this Issue number or the tranche slug as the explanation, and do not use coined vocabulary (tranche, brief, forge, provenance) without a definition or a glossary link at first use on a page.
No new file is created for any finding, report or summary. Findings go in the PR body.
7. Verification before claiming done
bun run typecheck --filter=@atta/vinaya-webpasses.bun run lint --filter=@atta/vinaya-webpasses.bunx turbo testpasses unscoped. (bun run checkfilters tests to cms + aeg-core and will not run everything.)bun run buildfor the vinaya web app. This catches stricter resolution the dev server tolerates, and it is the gate that would catch aSwitchprop regression.bun packages/aeg-core/bin/verify-docs.ts --prpasses withPR_BODYset to the intended body.git diff $(git merge-base HEAD origin/main) --statshows zero files underpackages/. If any appear, the Issue'sblast-radius-ack:is void — stop and escalate.git diff $(git merge-base HEAD origin/main) --statmatches the §3 surface map exactly — nine files, no more. Use the merge-base, not a baregit diff main: sibling tasks merging while you work make a bare diff drift.8. Test Plan
Test Plan:
bun run buildfor@atta/vinaya-webcompletes with exit 0 and no type error mentioningSwitchPropsorsize.curl -s -o /dev/null -w '%{http_code}' localhost:3000/cli→200, and the same for/state-machine,/the-harness,/— all200.curl -s localhost:3000/ | grep -o 'href="/[a-z-]*"'on the topbar region shows/the-harness,/state-machine,/start,/cli,/docs,/the-studio,/roadmapin that document order.curl -s localhost:3000/state-machinecontains the rendered badge markup around a known label id (e.g.vinaya/tier:1) and the page still contains no'use client'-only failure in the console./the-harness: drill into every ring; labels are comfortably readable and no label —tranche-archivistespecially, on a left/right wedge — overflows or overlaps its wedge./clibeside/docsand/startat the same window size: same top spacing, same measure, same background, content pane scrolling the same way./state-machine: label cells read as badges, prose cells unchanged, no table spilling sideways at ~800px width.9. Stop conditions
STOP and report rather than improvising if:
--premiseassertion fails (a file moved since authoring).packages/ui. This converts a one-project task into a three-product one and must be re-planned, not absorbed. Escalateseverity:strategy. Do not "just add a small prop" to the shared TopBar./docsor/start. That collides with tasks 13 ([misc-hardening-v1] 13 — Two docs pages print their own title twice #692) and 16 ([misc-hardening-v1] 16 — Every stage of the loop says what it takes in and what it hands on, and draws it #696); the Principal decides the ordering, not you.severity:strategy.10. Constraints
C1. Do NOT factor a shared layout out of
/docs,/startand/cli. This is the obvious engineering instinct on reading Part 4 and it is wrong here: tasks 13 (#692) and 16 (#696) are open right now on/docsand/start, and a shared extraction rewrites exactly the files they are editing — turning a clean no-conflict into a three-way merge. Duplicate the shape into a newcli/layout.tsx. The de-duplication is a legitimate later task once those merge; it is not this one.C2. Do NOT put the switch label in
packages/ui/topbar. The label goes in the app-localProductSwitchControl, already rendered intoextraActionson both desktop and mobile — one edit, both breakpoints, zero shared-package diff. This single decision determines whether the task is one project or three.C3. Do NOT leave the stale "no visible text label" comment in
ProductSwitchControl.tsx. A rationale comment asserting the opposite of what the file does is worse than none — the next agent reads it as a constraint and reverts your work.C4. Do NOT change the wedge font size without scaling the line offset with it, and do NOT assume a hyphenated label wraps —
wrapLabelsplits on spaces only. Verify against the longest label at each ring level, on a left or right wedge where only the 330-unit radial thickness is available.C5. Do NOT delete the hero's once-only logic. Key, read and write all stay live; only the acting branch is commented, with a restore note.
C6. Semantic theme tokens only. No
text-green-500, no hex, nooklch/hsl, nobg-[#…]. No inlinestyle={{}}unless provably impossible in Tailwind.@atta/uicomponents over raw HTML — no bare<span>/<div>where a primitive exists.lucide-reactfor any icon.C7. Do NOT add a hand-authored row, cell or literal to
StateMachineTables.tsx, and do NOT add'use client'to it or tostate-machine/page.tsx.C8. Never write status anywhere — status is derived from the forge. Never add execution metadata to a tranche file. Never commit a new file for a finding, report or audit summary; that content goes in the PR body.
C9. Never
git stashin a worktree — the stash stack is per-repo, and a barepopcan apply another task's work.Autonomy: Do not stop to ask clarifying questions. For any ambiguity not covered by a Section 10 stop condition, choose the most reasonable option consistent with this brief, record the choice in the PR body, and continue. Halt only for the explicit Section 10 stop conditions — and when you halt, record the blocker in the PR body or an Issue comment rather than waiting interactively for input.
11. Deliverable
Open a PR with:
Fix(vinaya-web): site chrome polish — nav, switch label, badges, spacing, ring labels, heroaeg-root/templates/pr-report-template.mdfor the report half, carryingTier: 1,Project: vinaya,Closes #702, and the §8 Test Plan checkboxes in their anchored homes. Paste this brief below it inside a collapsed<details><summary>Brief</summary>…</details>block.--statoutput; confirmation that zero files underpackages/changed; every choice you made under the autonomy clause; and any finding you hit a stop condition on.bun packages/aeg-core/bin/verify-docs.ts --prwithPR_BODYset before opening, and fix any failure. Never open a PR that would be red on arrival.bun packages/aeg-core/bin/open-pr.ts— rawgh pr createis blocked by the forge gate.Then stop. The PR is not done when it opens. Code review, security review, and the Verification phase (executing the §8 Test Plan and posting evidence) are separate invocations. Address REQUEST CHANGES / FAIL findings in follow-up commits on the same branch.