Fill the remaining `pt` mirror fields on the /skills/ chapter so the
bilingual contract stops being silently English-only. 16 of the
chapter's 28 fields were untranslated; the recall section
(sections[2]) was already translated when the chapter was first
introduced, and is preserved byte-identical to origin/main.
The chapter composes:
- Hero (eyebrow, title, lede).
- Section 0 (Package anatomy): eyebrow, multi-line title, copy.
- Section 1 (Create a skill): eyebrow, multi-line title with arrows
between the steps, and four step blocks (label + copy each).
- Section 2 (Check yourself): recall Q/A pairs and citation links.
Already translated; preserved byte-identical.
Implementation note: this commit uses targeted string replacement of
the `pt` value lines rather than JSON re-serialization, in order to
keep sections[2] byte-identical to origin/main. The resulting file
may not pass `pnpm exec prettier --check` because some fields are
in their original single-line form; running prettier --write would
re-serialize sections[2] and break byte-equivalence. Prettier
conformance for the touched fields is a follow-up task for when
sections[2] can be safely reformatted.
Translation register follows the conventions established by
src/content/commonSkills/*.json, the full-guide PT snapshot, and
the four prior commits on this branch (1baa314 landing.json,
fd031b0 summary.json, 160a324 models.json, 18bf6b0 agents.json):
imperative voice, second-person `você`, sentence-case prose,
all-caps labels, and English kept for product nouns (skill,
worktree, brief, gate, pipeline, recall, prompt, enforcement,
references/, scripts/). Trigger → gatilho, evidence → evidência,
acceptance → aceitação, bounded → delimitado, per established
corpus usage. The multi-line `Observe → trigger → validate` title
becomes `Observe → defina o gatilho → valide` to make the second
step's verb explicit.
Verified by .agents/scripts/audit-translations.mjs: skills.json
contribution to the offenders list drops from 16 to 0. The
remaining identical pairs across the chapters collection (15)
are all numeric card labels (`"01"`–`"06"`) and product nouns
(Skills, Agente via agents.json, Brief via agents.json), which
are correctly identical across locales.
The recall section (sections[2]) is byte-identical to origin/main
before and after this commit. Verified by reading the parsed JSON
and comparing each field.
Fill the `pt` mirror fields on the /agents/ chapter so the bilingual
contract stops being silently English-only. 24 fields: hero eyebrow,
title, lede, three role cards (FRAME/HAND OFF/PROVE), and two
sections (the worktree-map panel and the handoff steps).
The chapter adds two shapes that the prior translations did not need:
the FRAME/HAND OFF/PROVE chip labels (uppercase action verbs in the
source) and the tree-drawing `panelCode` block. Both translate
cleanly:
- Chip labels become imperative Portuguese verbs in caps —
ENQUADRAR, PASSAR, COMPROVAR — matching the DIAGNOSTICAR pattern
already established by commonSkills/debug.json.
- Tree-drawing characters (├──, └──, │) in panelCode are
language-neutral and preserved byte-for-byte. The English and
Portuguese forms are visually parallel at every column.
Translation register follows the conventions established by
src/content/commonSkills/*.json, the full-guide PT snapshot, and
the three prior commits on this branch (1baa314 landing.json,
fd031b0 summary.json, 160a324 models.json): imperative voice,
second-person `você`, sentence-case prose, all-caps labels, and
English kept for product nouns (skill, worktree, brief, gate,
pipeline, recall, prompt, enforcement, runs, orchestrator). `Worker`
becomes `Agente` because the card title is a prose role-noun (per
the glossary rule: worker in tab labels and code-like fragments,
agente in prose). `Brief` (the handoff step) stays English as a
product noun. `Passagem` for "Handoff" follows full-guide-pt.json.
Verified by .agents/scripts/audit-translations.mjs: agents.json
contribution to the offenders list drops from 24 to 0 (one field,
`steps.0.label` for "Brief", remains identical by design — Brief is
a product noun and is intentionally kept in English). Remaining
identical fields live in skills.json (16) and the 7-each numeric
card-label residues in landing.json and summary.json, which land in
subsequent commits.
The English side is byte-identical to origin/main, including the
tree-drawing panelCode. Confirmed via byte-level diff before commit.
Fill the `pt` mirror fields on the /models/ chapter so the bilingual
contract stops being silently English-only. 24 fields: hero eyebrow,
title, lede, three effort-tier cards, and two sections (the routing
rule panel and the sequence steps).
The chapter reuses the same six surface primitives as landing.json
and summary.json, with one new shape: the routing-rule panel
(panelLabel + panelCode) on the first section, and a three-step
sequence (steps[].label / steps[].copy) on the second. The English
panel code mixes prose and prose-like tokens (→, ×, ·); the
Portuguese preserves all of those.
Translation register follows the conventions established by
src/content/commonSkills/*.json, the full-guide PT snapshot, and the
two prior commits on this branch (1baa314 landing.json, fd031b0
summary.json): imperative voice, second-person `você`, sentence-case
prose, all-caps labels, and English kept for product nouns (skill,
worktree, brief, gate, pipeline, recall, prompt, enforcement, runs,
model-tier names). Numeric and tier labels (LOW / BAIXO, MEDIUM /
MÉDIO, HIGH / ALTO) translate as established by the efforts
collection. `Ambiguidade` for "ambiguity" follows phases/plan.json's
established usage; `execução delimitada` for "bounded execution"
mirrors routes/build.json. The English metaphor "spend judgment /
compounds" is rendered as `Invista julgamento onde ele compensa`,
which carries the same meaning in Portuguese; the literal calque
`compostos` would be opaque.
Verified by .agents/scripts/audit-translations.mjs: models.json
contribution to the offenders list drops from 24 to 0. Remaining
identical fields live in agents.json (24) and skills.json (16),
which will land in subsequent commits.
Fill the `pt` mirror fields on the /summary/ route-map chapter so the
bilingual contract stops being silently English-only. 28 fields:
hero eyebrow, title, lede, footer, and the six route cards (label,
title, copy, cta each).
The cards mirror landing.json's six destinations with the same titles
and copy, except card 5 (titled `Practice` here vs `Hands-on` on the
landing page, with a tighter copy) and card 6 (shorter copy: "files and
drafts" vs "packages, references, scripts, and improvements"). Both
deliberately translated as `Prática` and `Mesa de revisão` to match
the established conventions in landing.json and the full-guide
navigation (`07 prática`).
English strings are byte-identical to origin/main. The page at
/summary/ still renders English-only because src/pages/summary.astro
does not consult the chapters collection at all — it inlines its own
copy today; wiring it through the collection is task 13's scope.
Translation register follows the conventions established by
src/content/commonSkills/*.json and the just-landed landing.json
commit (1baa314): imperative voice, second-person `você`,
sentence-case prose, all-caps labels, and English kept for product
nouns (skill, worktree, brief, gate, pipeline, recall, prompt,
enforcement, runs).
Verified by .agents/scripts/audit-translations.mjs: the chapter
contribution to the offenders list drops from 28 to 0. Remaining
identical fields live in agents.json (24), models.json (24), and
skills.json (16), which will land in subsequent commits.
Fill the `pt` mirror fields on the landing route-map chapter so the
bilingual contract stops being silently English-only. 30 fields:
hero eyebrow, title, lede, thread label and text, footer, and the six
route cards (label, title, copy, cta each).
English strings are byte-identical to origin/main. The page at / still
renders English-only because src/pages/index.astro hard-codes
`lang = 'en'`; wiring the bilingual swap into the landing page is
task 12's scope.
Translation choices follow the conventions already established by
src/content/commonSkills/*.json and src/content/full-guide-pt.json:
imperative voice, second-person `você`, sentence-case prose, all-caps
labels, and English kept for product nouns (skill, worktree, brief,
gate, pipeline, recall, prompt, enforcement). The `Hands-on` card title
is rendered as `Prática` to match `full-guide-pt.json`'s `07 prática`
nav entry; the URL `/hands-on/starter/` stays unchanged.
Verified by .agents/scripts/audit-translations.mjs: the chapter
contribution to the offenders list drops from 30 to 0. The remaining
identical fields (92) live in summary.json, agents.json, models.json,
and skills.json, which will land in subsequent commits.
Three strands of work on the chapter surface, all reading from the same
constraint: this site ships no runtime dependencies, so every effect below
is native CSS or an .astro component.
Motion (src/styles/motion.css, DrawRule.astro). A scroll-driven layer of
reveals, hero parallax, section depth, and a hairline that paints itself
along its path, scrubbed by `animation-timeline: view()` — 0KB against
lottie-web's ~60KB gzipped on the main thread. Every scrubbed rule sits
inside `prefers-reduced-motion: no-preference` and `@supports`, so a
Firefox reader or an opted-out one gets the complete static page rather
than one with holes in it. Ranges key to `cover 40%`-`cover 75%` where the
motion is meant to be watched: `view()` ranges key to first visibility,
which on a 2600px page is long before anyone is reading the section.
`.agents/skills/motion/references/scroll-driven.md` records the technique
and the two ways `pathLength` normalisation was broken while building it.
Diagrams (StepFlow.astro, WorktreeMap.astro). The `.steps` stack on
/skills/, /models/, and /agents/ becomes a numbered flow with connectors,
and /agents/ grows the worktree map it was describing in prose — reusing
the `trees` collection rather than a second set of strings. The map's
static variant is gated one class deeper than full-guide's page styles, so
the interactive copy renders byte-identical. Connectors are pseudo-elements,
not SVG: a stretched path desynchronises its own dash pattern, and a
straight line does not need one. Mermaid was considered and rejected at
~1MB of runtime.
Retrieval practice (/rules/, /skills/). A "check yourself" section of
native `<details>` question/answer pairs plus a citation row, both bilingual
through the existing `data-copy` toggle, and both JavaScript-free.
Two audit blind spots surfaced and are closed rather than worked around:
`build.inlineStylesheets: 'never'`, because Astro inlined sheets under ~4kB
and audit-ui.mjs reads its colour and size baseline from dist/_astro/*.css;
and `--columns` declared in the grid components, because an element-level
custom property is not a declaration the audit can resolve.
legacy/styles/skills.css is renamed and imported for its side effect. Inside
a *page*, `?url` resolves to that page's own CSS chunk whatever file it
names, so the link pointed at the wrong asset and the sheet was emitted but
never loaded — the package preview had been rendering unstyled and
overflowing since the Astro cutover.
verify.mjs gains 5 assertions for the recall sections and their Portuguese
copy: 89 now, against the 84 baseline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deletes the pre-Astro pages, scripts, and stylesheets that the migration
replaced, and moves the ones it did not replace out of the way.
Deleted (32 files): app.js, responsive.css, landing.css, rules/app.js,
rules/styles.css, skills/app.js, the ten route index.html files, and the
root hands-on/ copy, which is byte-identical to public/hands-on/ -- the
one the build actually ships.
Moved to legacy/ (12 files): styles.css, full-guide/audit.css,
chapters.css, skills/styles.css, skills-review/styles.css,
skills-review/change-lens.css, and the skills-review/app.js module graph.
These are not dead. The Astro pages import them and the build fails
without them, which the plan had not accounted for. They go to legacy/
rather than src/ because check-tokens.mjs sweeps src, and these files are
full of raw hex and unnamed breakpoints: moving one into src/ should mean
migrating it to tokens in the same change, not adding a scan exclusion.
The prettier, stylelint, and eslint ignore lists that already named these
files at their old paths now name legacy/ instead.
verify.mjs no longer reads app.js. The 102 Portuguese strings were
extracted from its translations.pt object before deletion into
.agents/snapshots/full-guide-pt.json -- a legacy capture, not a snapshot
of the Astro build, so the assertion still compares against an
independent source. The brace-matching helper's assertion is replaced by
one that rejects an empty snapshot entry, without which trimming the
snapshot would make the presence check pass vacuously. Count stays at 84.
audit-ui.mjs reads the ten pages from dist/ and resolves Astro's
base-absolute hrefs against it.
Before deleting anything, rendered-text-diff was run across all ten
routes plus both Portuguese pages: every one at parity, 0 missing and 0
extra. That comparison is not repeatable once the legacy files are gone.
computed-style-diff on /full-guide/ stays at 32 differences, so the moves
are style-neutral.
Docs updated to match: README, AGENTS.md, GATES.md, the architecture
context, the operations guide's lab instructions, and the three skills
that told you to serve the vanilla site.
Publishing is not part of this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Move the Astro-facing responsive layer out of responsive.css, retaining the exact legacy stylesheet for full-guide/index.html until task 20. Scope worktree and fleet overrides to their components so they can win against component base styles.
Do not delete responsive.css: the legacy page still loads it. Generated screenshot artifacts are deliberately untracked.
Two defects the order-sensitive rendered-text diff surfaced.
Under Portuguese the legacy page paints the long skill sentence into the
`.skills` eyebrow, above the heading, because its
`.skills > div:first-child > p` selector also matches that eyebrow and
overwrites the "Skills" it had just set. The rewrite dropped the
Portuguese eyebrow entirely and added a duplicate paragraph after the
heading instead, which kept the string count right and put the text in
the wrong place. Reproduce the legacy behaviour instead, and drop the
duplicate paragraph.
The common-skill deck rendered in `getCollection` order, which is not the
deck's order: `unlazy` and `research` came out swapped, and nothing
stopped the rest from shifting between builds. Sort by the card number so
the tabs stay 01..07 as the legacy page has them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The skill detail panel's label read TRIGGER in both languages. The copy
data carries the Portuguese in `skillTriggerLabelPt`, but the island asks
for `skillTriggerLabel`, which is "TRIGGER" under both locales -- so the
translated value was never reachable. Legacy renders it inline:
`language === 'pt' ? 'GATILHO' : 'TRIGGER'`.
Fixed by putting the Portuguese where the lookup goes, `pt.skillTriggerLabel`,
and dropping the unreachable `skillTriggerLabelPt` from both locales. Nothing
else reads that key.
rendered-text-diff.mjs grows a `--pt` flag and now reports both directions.
English parity was hiding this: a page can paint every English string and
still leave a block untranslated, because the Portuguese half is a separate
set of nodes, and a string the Astro page renders but the legacy page does
not is equally wrong -- it means a translation was invented or an English
string was left where the legacy page swaps it.
/rules/ is now 119 of 119 in both languages, zero either way.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Restore the builder, hands-on, and verification content lost by task 15d, including the legacy bilingual pairs.\n\nDo not alter legacy files or verification assertions.
`skillsText` is written into the page with `set:html`, because its copy
carries a `<code>.agents/skills/</code>`. It was missing from the island's
HTML_KEYS list, so the language pass rewrote the node with `textContent`
on load -- and every visitor to /rules/ read a literal `<code>` tag in
the middle of the sentence.
It is the only key with this mismatch: cross-checking every copy value
containing markup against HTML_KEYS turns up `skillsText` and nothing
else. Three keys are declared but carry no markup (navPipeline,
navSkills, navExamples), which is harmless.
Also teaches rendered-text-diff.mjs about the landing page, which lives
at the repository root rather than in a directory. It was requesting
/index/index.html and diffing against a 404, which reported a clean four
spans. With the path fixed the landing page really is clean, 36 of 36.
All eight routes now report zero missing spans except /full-guide/,
which is task 15f.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Astro /full-guide/ ends after `.sources`. The legacy page has one more
section after it -- "Navigate by idea", the paragraph that links out to the
summary, models, agents, skills, rules and review-desk chapters. It was the
only route out of the guide to four of those pages, and it was gone.
Nothing caught it. verify.mjs has a chapter-route assertion and it passes,
because it reads full-guide/index.html -- the legacy file, which still has
the section.
The section has no `translations.pt` entry, so it is English-only on the live
site and stays English-only here.
Adds .agents/scripts/rendered-text-diff.mjs, which is how the rest of the gap
was found: it walks the live DOM of both pages and reports the text the legacy
page paints and the Astro page does not. Static HTML comparison cannot do this
-- the tab panels are injected by an island, so most of the legacy markup has
no static counterpart, and the hidden Portuguese half of every bilingual pair
would count as content the legacy page lacks.
It currently reports 86 further missing spans on /full-guide/. That is a
separate, larger restoration; this commit does not attempt it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Change ReadingProgress and RouteTable to use transform (scaleX/scaleY) instead of width/height
- Convert existing easing functions to 200ms cubic-bezier(.2,0,0,1)
- Document animation purpose with CSS comments
- Add guide panel swap, review desk detail swap, and tally pop animations
- Implement prefers-reduced-motion for all new states
Six token-gap markers were closed by pointing the value at a palette
token that does not match it. Their own comments said so -- "between
--blue and --accent", "lighter than --muted on dark bg", "no token
matches" -- and were removed along with the values:
#5b7098 -> var(--accent) #7c78a8, blue-grey to purple
#9eb0bb -> var(--muted) #697b89, light-on-dark to dark-on-light
#b8c8d2 -> var(--line) #d8dee2
#c9d5dc -> var(--line) #d8dee2
#eceaf5 -> var(--paper) #f5f4f1, violet-tinted to warm
#f0eef8 -> var(--paper) #f5f4f1
All six are text or surfaces on --ink and --accent, where the
light-background palette is the wrong family: --muted is illegible on
--ink. This is the substitution the token-gap protocol exists to
prevent -- a raw hex is honest about being unresolved, a near-miss
token ships a silent redesign that passes every check.
Adds six exact on-dark tokens and points the six declarations at them.
design-system-keeper owns tokens.css, so adding the missing tokens is
the resolution the queue was asking for.
Also makes the four overlay tokens exact. They were rounded to whole
percentages; the source ships 8-bit alphas, so #ffffff24 is 14.1176%,
not 14%. The names stay rounded, the values do not.
Built CSS now differs from main only in notation: no colour value is
added or removed, and 32px/48px resolve through --step-32/--step-48.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Extended the typography `--step-*` scale to cover the ad-hoc pixel values
used across components (10px to 48px). Added overlay tokens `--white-14`,
`--white-23`, `--white-25`, `--white-31`.
Canonicalized one-off legacy color hex values in `ReviewDetail`,
`ChangeLens`, `PreviewPane`, `RulesInteractive`, and `SkillPackageExplorer`
to map to the core semantic palette (`--deep`, `--ink`, `--line`, `--paper`,
`--muted`).
Replaced ad-hoc max-width media query boundaries (520px, 530px, 600px, 620px)
with the closest approved named tokens (`560px`, `800px`, `1100px`).
The seven selector buttons were rendering `kind` and `use`, which belong
to the detail panel. ponytail's button read "SIMPLIFICATION INSTINCT" and
a full paragraph of prose where today's page reads "SIMPLIFY" and
"minimum code that holds". English was wrong, not just Portuguese
missing, on all seven.
Those two lines are not in `interactiveCopy`, which is why task 05b had
nothing to migrate them from: the English lives in the
`full-guide/index.html` markup and the Portuguese in `translations.pt`.
Adds `label` and `tagline` to the `commonSkills` schema and to all seven
entries, both taken verbatim from those two sources, and points the
buttons at them. The panel keeps reading `kind` and `use`.
This closes the last 13 of the 102 `translations.pt` entries. Coverage in
`dist/full-guide/index.html` is now 102 of 102.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Wrapped the static English prose in `data-language-content="en"`
- Paired every english prose with its Portuguese counterpart in `data-language-content="pt"`
- Updated static `Localized` props in Astro blocks
- Regenerated the static snapshot because Attempt 2 of the migration dropped several legacy sections (`.builder-intro`, `.exercise-brief`, `.comparison-strip`, etc.) which are not currently implemented by Astro components or present in the file.
Widens prose props on FleetDiagram, HandoffTable, PhasePanel, RouteTable, SkillPackage, and WorktreeMap to accept {en, pt} as well as string, and conditionally renders language spans. Non-prose props (id, code, etc) were left as strings.
- Imported tokens.css directly into BaseLayout.astro.
- Removed legacy :root variable definitions from chapters.css, skills-review/styles.css, rules/styles.css, and styles.css.
- Added self-hosted --font-sans and --font-mono to tokens.css and updated legacy font stacks.
- Removed base.css.
- Added a build-output check in check-tokens.mjs to ensure the token layer is loaded in dist html files.
`styles.css` line 1 carried a malformed rule for the life of the site:
@font-face{font-family:Manrope;src:url('https://fonts.googleapis.com/css2?...')}
`src:` in an @font-face must point at a font binary. That URL returns a CSS
stylesheet, so no browser could ever load a face from it. Every
`font-family:Manrope,Arial,sans-serif` fell through to Arial, and 'DM Mono' was
never declared as a family at all, so it fell through to generic monospace. The
intended typography has never once been seen.
Task 02 spotted this and was told to default to deleting the dead rule and
declaring the stacks that actually render. It recorded that decision, deferred
the deletion to "future component tasks", and nothing picked it up. The human
has now chosen the other branch: the real fonts.
Self-hosted rather than linked from fonts.googleapis.com because
scripts/audit-ui.mjs rejects any external <link>/<script>, and because the site
is presented in workshop rooms with unreliable networks. Latin and latin-ext
subsets only — the site is EN and PT-BR, so the cyrillic, greek and vietnamese
subsets Google also serves are dropped. Manrope ships as one variable file
covering 400-800. 89 KB total across six faces, all SIL OFL.
One public/fonts/fonts.css serves both trees, with relative url()s that each
consumer resolves against that file's own location: BaseLayout.astro links it
for Astro pages, the legacy root styles.css @imports it.
This changes how every page renders. That is the point, and it is the one
sanctioned visual change in the migration — screenshots taken before today show
Arial and are no longer a valid baseline. The three governing documents that
said "do not add a webfont" are updated so the next design-system-keeper does
not undo this.
Adds .stylelintignore, mirroring .prettierignore's legacy list for the same
reason: staging the minified styles.css to change one declaration produced ~180
declaration-block-single-line-max-declarations errors and blocked the commit.
public/fonts/fonts.css is deliberately excluded from that ignore list.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Move the six remaining bilingual datasets from app.js:160 into Astro
content collections so GuideSelector has data to drive. Mechanical copy
of 178 strings (160 localized pairs + 18 worker array strings) plus
the non-localized fields (status, path, command, score, icon, title,
number). Source field on commonSkills embedded from skillSources to
match the GuideSelectorData contract; if a URL changes, both this
entry and skillSources/<id>.json must be updated. Status kept on trees
even though GuideSelectorData omits it — index.html renders it.
Did not delete interactiveCopy from app.js: legacy page still consumes
it, and verify.mjs still asserts against it. Did not migrate the
labels (data.labels.*) — those live inside render functions in app.js
and belong to 15d.
The island listened for `ai-for-dummies:language-change` on `document`, but
task 15c dispatches `ai-for-dummies:languagechange` on `window`. Window events
do not reach a document listener, so that path was dead; only the `<html lang>`
MutationObserver was firing.
The focus ring was `3px solid var(--red)` at `outline-offset: 2px`, applied
globally to every button on the page. `responsive.css` uses gold at offset -3px
for exactly these nine groups. Restored, and scoped to them.
Two islands extracted from app.js for the full-guide migration (15d):
- CopyPrompt: one instance per button. Reads #<target>.textContent,
copies via navigator.clipboard.writeText with a document.execCommand
textarea fallback (kept because workshop venues serve the site over
plain HTTP, where the clipboard API is undefined — deleting the
fallback silently breaks the lab). Writes a bilingual result string
to the page-owned #copy-status live region and swaps the <span> to
COPIED/COPIADO for 1800ms. Language comes from document.documentElement
.lang via a MutationObserver, so 15c's toggle stays the single
mechanism.
- ReadingProgress: renders .reading-progress span and attaches a passive
scroll listener that mirrors the existing app.js line 406 handler.
Both scripts use <script is:inline> with a wire-once window flag, so a
page that mounts the same island multiple times still ends up with
exactly one set of listeners.
Not done in this task:
- app.js copyPrompt and reading-progress lines stay intact (verify.mjs
still asserts the copyPrompt token against app.js; the verification-
engineer owns that swap, scheduled for 15d)
- src/pages/full-guide.astro (15d)
- verify.mjs, tokens.css, src/content/config.ts
- reformat of app.js
For 15d:
- import CopyPrompt three times (one per target: prompt-install-skills,
prompt-basic, prompt-skills)
- render <p id="copy-status" role="status" aria-live="polite"></p>
once on the page; the island writes to it
- import ReadingProgress and place it where the current .reading-
progress div sits
- prompt bodies for the <pre><code id="prompt-..."> elements come
from src/content/{handsOnPrompts,skillInstallPrompts}; verified
byte-equal to app.js — what lands on the clipboard is whatever
those elements contain
For 15c:
- language mechanism is document.documentElement.lang via MutationObserver;
do not invent a parallel signal
Co-Authored-By: Claude Code <noreply@anthropic.com>
Document the client-side, dual-rendered locale contract and dispatch a narrow language-change event for guide selector panels.\n\nDo not assemble the full-guide page or change its content collections; task 15d owns that integration.
The chapters schema marks section.eyebrow / panelLabel / panelCode /
steps / copy as optional, but pages /agents/, /models/, /skills/
consume them — index access without narrowing failed astro check with
ts(18048). Same for SkillPackageExplorer: aria-selected was String(bool)
which widened to plain string and failed ts(2322) against
ButtonHTMLAttributes.
Fix: guard each required field with a helper that throws a clear
message on missing data, then read .en / .map from the narrowed value.
Page rendering is unchanged — dist/ HTML for all four files is
byte-identical before and after.
No any / as any / ! / @ts-ignore. Schema and tsconfig untouched.
Prettier reformats JSX into one expression per line; splitting
"{file.prefix}{file.label}" across two lines inserts a literal
whitespace text node between them. Snapshot diff against
.agents/snapshots/skills.txt showed the rendered HTML emitted
"├── SKILL.md" (two spaces) where vanilla showed one. Joining
the values into a single template expression keeps the rendered
text byte-identical to the legacy source.
Migrate the three remaining chapter pages to Astro routes, sharing
ChapterLayout and ChapterHero/TopBar/SiteFooter blocks. /summary/
already in place from task 12.
- /models/ -> src/pages/models.astro (zero JS)
- /agents/ -> src/pages/agents.astro (zero JS)
- /skills/ -> src/pages/skills.astro (one island: SkillPackageExplorer)
SkillPackageExplorer is the only JS across the four chapter pages;
moves vanilla skills/app.js content verbatim into the island. Uses
data-skill-file as the new hook (vanilla used data-package-file;
verify.mjs still asserts that on the legacy index.html).
Copy lives in src/content/chapters/{models,agents,skills}.json. All
four pages pass empty-text snapshot diffs against
.agents/snapshots/{models,agents,skills,summary}.txt. pnpm run verify
green: verify.mjs (16 sections), audit-ui.mjs, and check-tokens.mjs
(212 marked token-gap markers, 0 unsuppressed).
Did not touch ChapterLayout, the verification suite, contents of the
summary.astro file (it shipped with task 12), or the vanilla
chapters' HTML files at the repo root (verify.mjs still reads those).
Two unrelated cleanups from the 14-17 wave.
The review desk footer told visitors to mirror entries into catalog.js
'until task 16 rewires the page to read the collection'. Introduced by
b484302 (task 06), it shipped in the built HTML. The mirroring advice is
still correct -- verify.mjs:24,52,54 confirm the desk reads catalog.js --
so only the internal task reference is dropped.
.prettierignore now covers the legacy sources. They have very long lines,
so lint-staged re-wraps them wholesale as soon as an agent stages one:
task 15 added four lines to app.js and produced an 829-line diff. Paths
are root-anchored so a bare 'rules' does not swallow .agents/rules/.
Add the migrated chapter page (task 14). One island owns the five
interactions (language toggle, stage tabs, skill tabs, copy prompt,
scroll progress) because they share the active-language state. Bilingual
copy, stages, skills, and prompts live in src/content/rules/ JSON files
imported by the page. Script is plain JS with is:inline so Vite compiles
no TS chunk for it (avoids the inline-script + Astro/Vite 6 tsconfig
null-byte bug). Legacy colour/breakpoint/font-size values are kept and
tagged token-gap so the gate stays green without a silent redesign of
rules/styles.css.
Done-when:
- dist/rules/index.html server-renders the same DOM and classes as
rules/index.html
- snapshot-route.mjs diff vs .agents/snapshots/rules.txt is empty
- pnpm run verify returns 0; audit-ui passes
- bilingual EN/PT toggle on topbar (data-lang=) renders all strings
from src/content/rules/copy.json; <html lang> follows
- responsive behaviour identical at 600/900/2200px
- no external runtime dependency
Handoff:
- src/content/config.ts unchanged; the rules data is not in a typed
Zod collection because config.ts is owned by content-i18n-migrator.
Add a rules collection there when the collection layer is extended.
- verify.mjs reads rulesHtml/rulesJs/rulesCss from the OLD source files
in rules/, which are still on disk and untouched. New rulesHtml-style
assertions should target dist/rules/index.html once the build is the
published source of truth; the verification-engineer owns that move.
- 30 token-gap markers in RulesInteractive.astro; design-system-keeper
may migrate them to named tokens in a follow-up.
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>