18 Commits

Author SHA1 Message Date
Marcos Paulo e3ce8abe89 test: diff computed styles, because a ported rule can be inert
A media query can sit in the built stylesheet, match the viewport, and do
nothing. Astro scopes a component's rules as
`.tree-node[data-astro-cid-lsutp3lb]`, specificity 0,2,0. A responsive
rule that arrives unscoped as `.tree-node`, 0,1,0, loses to it. The
breakpoint is present, the selector matches, the declaration never wins.

Task 15e attempt 4 shipped exactly that: `@media (max-width: 1050px)
.tree-node { width: 145px }` is in dist and the node stays 180px. The
acceptance test I had written for that task -- diff the breakpoints in
responsive.css against the breakpoints in the built CSS -- passes on it.
Checking that a value appears in a stylesheet cannot catch this; only
asking the browser what it computed can.

This walks both pages at a list of widths and compares computed styles
for every element matching the classes the legacy responsive layer moves
at a breakpoint.

  node .agents/scripts/computed-style-diff.mjs full-guide
  node .agents/scripts/computed-style-diff.mjs full-guide --widths 880,1050

It reports 52 differences on main at 880px and 1050px, before task 15e
changes anything: importing responsive.css into an Astro page never fully
worked, for the same specificity reason. The responsive layer has been
partly inert in the build for as long as it has been imported.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 03:29:01 +00:00
Marcos Paulo 0c02780dd9 chore: merge main into task 19 2026-09-06 00:35:03 +00:00
Marcos Paulo c9796a3e7f test: count and order rendered spans, not just their presence
The rendered-text diff compared two *sets* of strings, so it stayed at
"missing 0 · extra 0" while the built page painted a string a different
number of times, or in a different place. That is the same shape of hole
that let task 15d ship a full-guide missing a fifth of its content behind
a green gate.

Three changes:

- tally occurrences instead of set membership, so a string the legacy
  page paints twice has to be painted twice here;
- compare the sequences positionally and report the first divergence,
  which is what caught the Portuguese eyebrow and the reordered skill
  deck fixed in the next commit;
- fail loudly on a non-200 response. A 404 rendered as four spans of
  python's error page and the diff then reported the entire route as
  missing, which reads exactly like a real regression.

Two robustness fixes behind those: ask the kernel for a free port rather
than pinning 4196/4197 (back-to-back runs collided with the previous
run's server, which was still holding the port after its staging
directory had been deleted), and read the DOM until two consecutive
reads agree instead of once after a fixed wait.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 00:33:44 +00:00
Marcos Paulo 6974800d2e fix(rules): show GATILHO in Portuguese, and diff the PT half too
verify-and-publish / gate (push) Successful in 29m29s
verify-and-publish / publish (push) Has been skipped
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>
2026-09-06 00:09:28 +00:00
Marcos Paulo a97c2a4034 fix(rules): stop rendering the skills paragraph's markup as text
verify-and-publish / gate (push) Successful in 16m6s
verify-and-publish / publish (push) Has been skipped
`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>
2026-09-05 23:53:14 +00:00
Marcos Paulo c2b35d5355 fix(full-guide): restore the chapter-route section 15d dropped
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>
2026-09-05 23:47:11 +00:00
Marcos Paulo 8c7ca2aded test: restore Astro verification contracts
Reinstate all 42 legacy facts as output or authoritative-source contracts, retain output snapshots, and set the 84-assertion floor. Extend the audit count without changing site content or components.
2026-09-05 23:41:23 +00:00
Marcos Paulo 054393f7af feat(15d): complete localization of full-guide page to PT 2026-09-05 22:30:50 +00:00
Marcos Paulo 64b506aa32 refactor(tokens): make token layer authoritative and wire to layout
- 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.
2026-09-05 19:31:03 +00:00
Marcos Paulo da790de20d feat(gates): add token-gap escape hatch to check-tokens
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.
2026-09-05 07:17:04 +00:00
Marcos Paulo 73ceae2aa8 feat(scripts): add oc CLI target to launch.sh
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.
2026-09-05 06:57:28 +00:00
Marcos Paulo 48c31dc1b3 build: migrate from npm to pnpm
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>
2026-09-05 04:29:42 +00:00
Marcos Paulo dcef196f25 merge: task 03-verification-net 2026-09-05 03:51:14 +00:00
Marcos Paulo db86edbc21 test: add vanilla regression baselines
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.
2026-09-05 03:25:56 +00:00
Marcos Paulo a45aa84318 fix: match agent names containing digits
The launcher read the agent out of each brief with [a-z-]*, which cannot match
content-i18n-migrator. Tasks 04, 05 and 06 silently fell back to
astro-architect. Now also fails loudly if the name is missing or has no agent
definition, rather than launching the wrong specialist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 02:42:58 +00:00
Marcos Paulo 88eecb1c71 fix: gate the launcher's npm ci on a lockfile, not package.json
The pre-existing root package.json has two scripts and no dependencies, and
there is no package-lock.json until task 01 scaffolds Astro, so every launch
died on `npm ci` before reaching the agent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 01:22:00 +00:00
Marcos Paulo 1cc9469d2d chore: add the task launcher for the refactor agents
Routes each task to its CLI per MODEL-ROUTING.md (Codex for 01/03/15/16/19,
Gemini for 02/18, MiniMax for the rest), creates the worktree, installs the
toolchain once task 01 has produced a package.json, and runs the agent headless
with permission prompts disabled — these run unattended, and a blocked edit
would just hang.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 01:19:29 +00:00
Marcos Paulo aae4d42229 docs: add .agents workspace and the Astro refactor plan
Adds the agent-facing workspace and a 20-task plan for migrating the site
to Astro. Nothing here implements the refactor; these are briefs, rules and
templates that the task agents read.

- .agents/ holds context, rules, checklists, skills, specialist agents,
  component/page/config templates and gate scripts. It is vendor-neutral so
  MiniMax, Gemini and Codex can all read it; CLAUDE.md just points at
  AGENTS.md.
- .husky/ plus .lintstagedrc.json wire the three gate tiers. gate.sh locks on
  the shared git-common-dir so parallel worktrees serialise, and guards the
  assertion count in scripts/verify.mjs against a coverage drop.
- plans/astro-refactor/ carries the phase graph, per-task briefs and the
  model-routing recommendation.

These files must be tracked before fanning out: a worktree only checks out
tracked files, so an untracked plan is invisible to every agent working in one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 01:18:27 +00:00