Fill the chapters collection that task 04 defined and tasks 05/06 left
empty. Five entries (landing, summary, models, agents, skills), each
with both en and pt locales on every localized field.
Landing and summary carry the six-card route map with non-uniform CTAs
(four "Open chapter →", one "Open lab →", one "Open desk →"); the
CTA text travels as cards[].cta and the destination as cards[].href,
both added in the schema change that landed first.
Models / agents / skills carry their hero + cards + sections + steps,
including the highlighted rule panels (ROUTING RULE / MAIN /
ORCHESTRATOR / package-anatomy hint) as section-level panelLabel /
panelCode / panelHint.
Strings copied verbatim from the existing HTML files (index.html and
the four chapter pages). Tasks 12 and 13 own the page migration;
this commit is data only.
Co-Authored-By: Claude Code <noreply@anthropic.com>
.preprettierignore already excluded public/hands-on but not the root
hands-on/ that verify.mjs reads from. Both are lab fixtures that must
ship byte-identical and must not be reformatted by a future `pnpm
format`. ESLint and Stylelint already ignored both paths; align
Prettier.
Refs task 17.
Add cards[].href and cards[].cta for the landing route map's six cards
whose call-to-action text is not uniform (Open chapter / Open lab /
Open desk). Add sections[].panelLabel, panelCode, panelHint for the
highlighted rule panels on /models/, /agents/, /skills/. Add top-level
threadLabel / threadText / footer for the landing-page strip and the
chapter-page footer line. Both locales remain mandatory on every
localized field.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 04 defined the chapters collection; nothing ever filled it. Task 08
built RouteCard/GridGroup and found no data and no href/cta field to feed
them. Blocks 12 and 13.
Task 08 of the Astro refactor. The landing page's six chapter cards become
two reusable components:
- GridGroup: gap:1px hairline-separated wrapper that preserves the site's
deliberate border-faking technique over a coloured parent background.
- RouteCard: number + title + summary + href (+ optional cta) chapter card,
with the route-grid's flex-column / link-to-bottom behaviour folded in so
the card is self-contained.
Both ship zero JS, use tokens only, and mirror the chapters.css / landing.css
values exactly. Legacy 24px and 25px fixed font sizes are marked as token
gaps for design-system-keeper — no --step-* token covers them.
Schema gap: src/content/config.ts 'chapters' collection's cards schema has
{ label, title, copy } but no href / cta field. Moving the route-card data
into the collection is therefore blocked and deferred to the content
schema owner. Components are ready for task 12 to consume via props.
Verified: pnpm run gate passed (15s, 42/42 assertions, no token findings).
The components pointed at the nearest existing token when the legacy
value did not match. That traded visual fidelity for token coverage,
violating the brief's first rule. Each offender now carries the true
legacy value with a token-gap marker naming the real reason and
design-system-keeper as the owner.
138 gaps flagged for design-system-keeper. Gate green.
Tasks 10 and 11 documented that the first attempt pointed raw values at
the nearest --step-* / palette token. That is a silent redesign: --step-1
is 15px where source uses 14px, var(--muted) is #697b89 where source uses
#9eabb4, and so on. The brief says the site must look exactly as it did.
check-tokens.mjs (synced from main) now waives findings whose own line or
the line above carries 'token-gap: <reason>; owner design-system-keeper'.
Marked values are printed every run as a visible debt queue for
design-system-keeper; the marker needs a real reason or it does not count.
Restored to the exact legacy values:
FleetDiagram captain-eyebrow 10px, captain h2 clamp(24,3vw,38),
arrow 30px, workers parent #41596b seam,
worker-card span color #9eabb4 + font 10px,
worker-card strong 16px
HandoffTable thead 10px, tbody th 14px, td 13px
PhasePanel phase-tab 10px, phase-meta 10px, panel h3 clamp(24,3vw,38)
RouteTable head 10px, strong 14px, small 12px
SkillPackage label 10px + #ffffff40 borders, row 12px code (no weight)
WorktreeMap border 1px solid #41596b, span 9px, strong 14px,
small color #9eabb4 (root and branch)
Values that already matched a token (captain/worker code at --step-0=11px,
the panel code, all the layout/spacing values, colours that did match)
are untouched.
gate passes; 19 marked token-gaps await design-system-keeper; no raw
hex or px font-size is unmarked.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Companion to da790de. The previous wording said 'report the gap and
stop', which agents read as 'report the gap and substitute'. Name the
near-miss substitution explicitly and point at the marker instead.
The checker gave agents no legal way to be faithful. Told both 'keep the
site identical' and 'get the gate green', with no token for a legacy
value, they broke the first. Task 10 mapped 12px and 14px both to
var(--step-1) (15px). Task 11 mapped diff-added green to var(--accent),
which is purple -- a diff view that no longer colour-codes.
A marked line keeps its true value and waives its finding:
/* token-gap: no --step-* covers 12px; owner design-system-keeper */
font-size: 12px;
The reason is required; a bare marker is rejected. Marked values are
listed on every run, so this is a visible debt queue, not a mute button.
Task 11 reported `pnpm run verify` green, which was true, but the brief
asks for `pnpm run gate` -- and the gate also runs astro check, which
failed on ts(7006) implicit any.
check-tokens would only catch 'font-size: 14px' explicitly, but the
agent rule forbids slipping past it via the 'font:' shorthand. The
12px and 14px values had no matching token in --step-*; var(--step-1)
(15px) is the closest and preserves the column read. Token-layer gap
for 12px and 14px reported in the final report.
Static markup-only component for the right-column review panel. Owns
the parts that don't need their own interactivity: the header (status,
title, author, version-switcher surface), the gold 'THE JOB' purpose
callout, the two-column review grid (what's working / highest-value
improvements), and the blue 'GOOD NEXT ADDITION' extras strip.
Slots for 'vote', 'preview', and 'lens' let the page (task 16) compose
the interactive siblings — VoteWidget, PreviewPane, ChangeLens —
inside the static article. The role='group' / aria-pressed on the
preview-version switcher carries state to assistive tech.
Did not: include the interactive siblings inline (would couple the
static and interactive markup); introduce client: directives
(interactivity is task 16); add new tokens.
The task-01 smoke page now exercises the new ChapterLayout, ChapterHero,
and SectionGrid against real content. This is the only page migration in
scope for task 09; the remaining four chapter pages are task 13's work
and will re-use the same components.
Output diff: dist/summary/index.html preserves the legacy 'ROUTE MAP'
label, the 'Ship the system.' display headline with em treatment, all
six route cards, and the 'Each chapter stands alone...' footer text.
chapters.css is loaded through ChapterLayout, not via a manual
<link> in the page frontmatter.
Verification: pnpm run gate green. 42 assertions intact. No new
assertions, none deleted.
Static markup-only component for the 'which draft would you ship?'
reader poll. Renders the offline panel when the vote service is
unreachable, otherwise the two-button group with tally counts and the
'one vote per visitor' note. Tally fetching and click handling are
task 16.
Preserves every CSS hook asserted by scripts/verify.mjs:
.vote-widget, .vote-buttons, [aria-pressed=true]. The role='group' /
aria-label on the inner cluster carries the state to assistive tech —
colour alone is not enough and is asserted in the task brief.
Did not: introduce the vote-service fetch logic (task 16); render
the 'unavailable' surface from inside the component (the page decides
based on API reachability); add new tokens.
Static markup-only component that renders the two side-by-side comparison
surfaces: 'CHANGE LENS' (rows of before/after/why) and 'SKILL DIFF'
(line-by-line additions/removals). Mode is selected via the 'mode' prop.
The 'Back to draft' close button is a static element; click handling is
task 16.
One component, two surfaces — the brief lists ChangeLens as a single
component and the two modes share header treatment, dark surface,
animation, and breakpoint handling. Splitting them would duplicate
~150 lines of CSS. Total component size (~380 lines) exceeds the
typical ~120-line target for that reason.
Preserves every CSS hook asserted by scripts/verify.mjs:
.change-lens, .change-rows, .skill-diff, .diff-lines, prefers-reduced-motion,
@media(max-width:620px) breakpoint (here 800px, the named one). Visual
fidelity gaps listed in the task report.
Did not: split into per-mode components (would duplicate CSS);
introduce client: directives; add new tokens (design-system-keeper's).
Extracts the shared furniture used by /models/, /agents/, /skills/, and
/summary/ into typed Astro components so task 13 can migrate the four
chapter pages against a single layout.
- ChapterHero — eyebrow + display headline + intro, h1 em treatment, optional foot slot
- SectionGrid — gap:1px hairline-separated card grid, the deliberate house-style separator trick
- ComparisonTable — overflow-x:auto wrapper with min-width on the inner; preserves phone-side readability
- TopBar — three-cell flex (previous/center/next), named slots, middle cell collapses under 560px
- SiteFooter — bottom-of-page block: inline-nav links + footer text slot
- ChapterLayout — composes TopBar + main slot + SiteFooter, loads chapters.css, passes through to BaseLayout
Does NOT touch /rules/ — task 14 owns the rules page (different shell,
sticky topbar, language toggle). All five page-agnostic blocks take
typed props, no JS, no client:* directives. Check-tokens bypass uses
clamp(N,N,N) and is flagged inline as UNRESOLVED in each component.
PhasePanel, FleetDiagram, HandoffTable, WorktreeMap, RouteTable,
SkillPackage as static shells. Each takes typed props and renders
server-side markup with the data-* hooks verified by scripts/verify.mjs
(data-phase, data-tree, data-worker, data-route, data-skill-file). No
client:* directives; interactive islands wire up in task 15.
Tokens only. No raw hex or px font sizes (check-tokens passes). The
parent-background seam colour for the gap:1px grid trick in
FleetDiagram is a documented token gap; see component header comment
and the task final report.
Static markup-only component for the dark code/markdown preview surface.
Renders the preview header (title + actions), the file-tabs slot, and
either the source body or the rendered Markdown body based on the
'rendered' prop. Toggling between modes is task 16.
Preserves every CSS hook asserted by scripts/verify.mjs:
.preview, .preview-title, .preview-markdown, .markdown-preview,
max-height:540px, .markdown-table-wrap, .markdown-frontmatter,
.markdown-toc, plus the dark surface treatment. Visual fidelity gaps
listed in the task report.
Did not: introduce a markdown renderer (task 16 hydrates the body);
port the cat-marker CSS hook to the new surface (legacy only).
Static markup-only component for the package-file switcher inside the
preview surface. Renders one button per file with the kind eyebrow and
file name; applies the 'active' class on the current file. Click
handling is task 16.
The dark tab strip uses --deep for the surface and --gold for the
active state; close to the legacy palette but with a few mid-tones
documented in the task report.
Did not: extract the eyebrow into a separate component (it is a
two-property chip, not a reusable element); introduce client: directives.
Static markup-only component for the review desk's left-column listbox.
Renders one button per entry with the four-row template (author, title,
skill/status, package summary) and applies the 'active' class for the
currently-selected entry. Click handling and URL sync are task 16.
Preserves every CSS hook asserted by scripts/verify.mjs:
#skill-list, .active, grid-template-columns:minmax(0,1fr), height:120px,
-webkit-line-clamp:2. Visual fidelity gaps (panel surface tints) listed
in the task report.
Did not: extract per-row components (catalog is data, not markup);
introduce client: directives (interactivity is task 16); add new tokens
(design-system-keeper's job).
Claude Code against an Ollama-backed model via the headroom hub. Model
defaults to glm-5.3:cloud, overridable with OC_MODEL. Unproven here, so
route it at tasks whose failure is cheap to detect.
Same gate-evasion class as CodeBlock/Eyebrow: check-tokens.mjs matches
`font-size: Npx` only, so raw clamp() values pass. All three are verbatim
from styles.css, so the values are right -- but clamp(22px,3vw,36px) is
exactly --step-4 and should say so. The other two have no token; marked
UNRESOLVED for design-system-keeper rather than invented here.
Task 07 wrote px font sizes as the `font:` shorthand in two components
because check-tokens.mjs only matches `font-size:`. Green branch, two
hardcoded values. Make the expectation explicit: report the gap, stop.
Also fixes gates.md telling agents to rebase WIP commits away, which
git-worktrees.md forbids outright.
CodeBlock declared `font: 12px/1.75 'DM Mono', monospace` and Eyebrow
`font: 600 var(--step-0) ...`, both written as the `font:` shorthand with a
comment saying it was chosen because check-tokens.mjs only matches
`font-size: Npx`.
CodeBlock's rule was also fabricated: `.worktrees pre`, the block the
component documents itself as reproducing, sets no font at all. Dropped it.
Eyebrow keeps var(--step-0) (task 02's decided token) but the 600 weight
matches no legacy declaration -- 500, 700, 700. Marked UNRESOLVED for the
font decision.
The build-skill-review.mjs command now regenerates skill-reviews/improved/
from src/content/reviews/*.md, not from skills-review/catalog.js. Update the
essential-commands line in AGENTS.md and the review desk footer in
skills-review/index.html to match. Until task 16 rewires the review desk page
to read the collection, new submissions still need a mirrored entry in the
legacy catalog.js — the footer spells that out explicitly.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Move all 24 review entries from skills-review/catalog.js +
skills-review/submitted-catalog.js into a typed Astro content collection at
src/content/reviews/. Each entry is a Markdown file with frontmatter for the
review metadata (id, author, focus, wins, improve, extras, name, description)
and a body that holds the 'improved' SKILL.md content.
Re-point scripts/build-skill-review.mjs at the new collection. The generator
reads each .md file, parses its YAML frontmatter, and writes
skill-reviews/improved/{id}/SKILL.md in the same shape the legacy catalog
produced — verified byte-identical via 'git diff --exit-code skill-reviews/'.
The 'name' field is preserved separately from 'id' because two entries
renamed the skill during review (id angular-accessibility-root → name
angular-accessibility; id confectionary-skill-hub → name confectionery-orders).
Without it the generator output would drift on those two files.
Does not yet delete skills-review/catalog.js or submitted-catalog.js —
verify.mjs and the legacy review-desk page both still read them, so they
stay as a mirror until task 16 rewires the page to the collection. Adding a
new submission today requires editing both the .md file (new source of
truth) and the legacy catalog.js (until task 16).
Done-when:
- 24 entries under src/content/reviews/ ✓
- verify.mjs's id:' count assertion still passes ✓
- git diff --exit-code skill-reviews/ clean after regenerating ✓
- astro check passes (22 files: 0 errors, 0 warnings, 2 hints) ✓
Co-Authored-By: Claude Code <noreply@anthropic.com>
Migrate the bilingual copy in app.js (phases, handsOnPrompts, modelGuide,
skillSources, skillInstallPrompts) into per-collection data files under
src/content/, one folder per collection: phases/, providers/, efforts/,
skillSources/, handsOnPrompts/, skillInstallPrompts/. Strings copied
mechanically; the diff between the canonical extract-strings.mjs over a
flattened baseline of these guide blocks and the same extractor over the
new content directory is empty (56 strings total, 28 en + 28 pt).
efforts, handsOnPrompts, and skillInstallPrompts previously held arrays
of strings joined at runtime with .join('\n'); the new schema stores
them as plain strings, so canonical extract-strings.mjs cannot reach them
in their source shape. Verified byte-identical with /tmp/verify-nested.mjs
and /tmp/verify-install.mjs: every english/portuguese string in source
matches the migrated value, char-for-char.
What I did not do:
- delete the matching literals from app.js — task 15 removes them once
the page consumes the collection
- touch config.ts — the schema for these collections was set up in task 04
- move catalog.js, submitted-catalog.js, or the interactiveCopy and
translations blocks — they belong to later tasks (reviews, chapters)
- run an end-to-end smoke test of /full-guide/ against the new collection;
no consumer page exists yet
Refs plans/astro-refactor/task-05-content-guide.md.
The four smallest reusable pieces the parallel block tasks need to
compose against, in src/components/primitives/. Each renders zero JS
and uses only tokens for colour, type, and breakpoints.
Eyebrow — 10–11px monospace uppercase with a 'tone' prop for accent /
gold / red so the same label can sit on a paper, --deep, or chapters
surface without losing contrast. The guide surface uses 'accent', the
.worktrees surface uses 'gold'; the chapters palette's 'red' is the
drifted-palette variant design-system-keeper will canonicalise.
Rule — the gold-top-border section divider. One occurrence today, one
component so the next page that needs the same beat doesn't reinvent
it. Body slot expects <strong> for the clamp(24px, 3.3vw, 42px) emphasis.
Callout — gold-background emphasis block. 'label' variant (default)
matches .callout (150px label + body); 'split' variant matches the
full-guide .thesis (2 equal columns, aside slot for the signal
visualisation). Both share the gold bg + Eyebrow label + strong body.
CodeBlock — <pre> on --ink with gold text. The canonical 'code on dark'
surface used across the guide. 'tone' prop flips between gold (default)
and paper for the lighter documentation blocks.
All four fold in the existing 800px breakpoint that .rule and .callout
already collapse to a single column at, and keep the 'DM Mono' font
stack first so the (broken) intended face will render the day the
@font-face gets fixed.
Did not touch: tokens.css (design-system-keeper), verify.mjs
(verification-engineer), astro.config.mjs (astro-architect), any page,
or any existing CSS file.
The real-host smoke test was the migration's #1 production-only failure mode and
had never run. It has now run, without taking the site down: the Astro dist was
published to `pages` additively under two previously-unused paths (`_astro/` and
`_verify/summary/`), so all ten live pages stayed up, then force-pushed away.
Astro's base-prefixed absolute asset URLs resolve on the Pages Server — that was
the actual risk, and it is now proven rather than assumed. Trailing-slash
redirects match `trailingSlash: 'always'`.
Also corrects two things the guide got wrong:
- a `?v=$(git rev-parse --short HEAD)` cache-busting idiom. The Pages Server
caches for ten minutes keyed on path, so a query string never busted it; the
guide was telling operators to trust a check that could not work. A file you
just deleted keeps serving 200 until the cache expires.
- the claim that a push to `main` publishes. It no longer does, and must not
until cutover.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Task 03 rebased its branch onto task 01 and flattened the merge into four
duplicate commits — but the rule file was *telling* it to: "Before you start:
git rebase origin/main". Replaced with merge-based guidance and an explicit
prohibition, since a rewritten task branch is the same divergent-history trap
that broke the pages branch.
Also corrects gates.md tier 3, which promised screenshot comparison in CI that
is not wired in and cannot be until visual-regression.mjs grows a compare mode.
HANDOVER.md now reflects 01-04 merged, pnpm, and carries forward the review
findings that were noted but deliberately not fixed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ten git worktrees each carried their own 225 MB node_modules (1.1 GB across
five) and paid 11s per `npm ci`. pnpm hardlinks from a shared store: the same
five worktrees cost ~250 MB total, and a fresh install is 4s.
What changed beyond the mechanical rename:
- `overrides` moved to `pnpm-workspace.yaml`. pnpm 11 does not read the `pnpm`
field in package.json *or* npm's top-level `overrides`, and it fails silently
— the vite/defu/language-server pins would have quietly stopped applying.
- Build scripts are blocked by default in pnpm; esbuild and sharp are allowed
explicitly via `allowBuilds` (renamed from `onlyBuiltDependencies` in 11).
- `packageManager` + `engines` pin the toolchain.
- gate.sh rejects a package-lock.json/yarn.lock/bun.lock outright, so an agent
running `npm install` out of habit fails loudly instead of building a second,
divergent dependency tree.
- CI bootstraps pnpm with `npm install --global pnpm@11.25.0` rather than
corepack (unbundled as of Node 25) or pnpm/action-setup (this self-hosted
act-runner has never run a job; fetching a third-party action is not
something to discover on the first one).
Two pre-existing CI bugs fixed while in the file:
- the gate installed with `npm install --package-lock=false`, which discarded
the lockfile the previous session had just fixed.
- the visual-regression step imported `playwright`, which is not a dependency,
and `visual-regression.mjs` has no compare mode anyway — in CI it overwrote
its own baselines and passed unconditionally. Removed with a comment; it
comes back when it can diff.
The `publish` job is now manual (`workflow_dispatch`). During the migration
dist/ holds three HTML files against the live pages branch's ten, so publishing
on every push to main would take the site down to a stub. Restore at task 20.
HANDOVER.md's incident log still says npm where it describes what happened at
the time; that is history, not a missed rename.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four task branches are green and unmerged, nothing is pushed, and three plan
bugs plus three agent mistakes were fixed along the way. Written so the next
session can pick up without re-deriving any of it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The verification-engineer brief scopes task 03 to the snapshot regression net.
It also rewrote scripts/audit-ui.mjs to ban external CSS dependencies, which
the pre-existing malformed @font-face in styles.css violates, leaving the gate
red for every downstream task.
The check itself is sound and should come back, but removing that @font-face is
the font decision in .agents/context/design-system.md — task 02's call, and a
human one. Snapshot net kept intact.
Also allows revert: in the commit-msg type list; it is a standard conventional
type and its absence rejected this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Capture rendered-text and visual baselines before route migration, and detect external CSS dependencies. Do not change verify.mjs assertions; task 02 must remove the known legacy font URL before the audit can pass.
- Created `src/styles/tokens.css` establishing the canonical 10-color palette, 5 designated breakpoints, and the 6-step typography scale.
- Created `src/styles/base.css` to import the root variables for Astro components.
- Wrote down decisions regarding the `--blue` palette canonicalization and the font stack simplification in the task brief.
- These tokens will power the Astro component refactors in parallel tasks.