Removes the Go source, Dockerfile, go.mod, and Kubernetes manifests. The
deployed service is untouched and the review desk still calls it over
window.SKILLS_REVIEW_VOTE_API; only the source leaves.
The runbook does not leave. vote-service/README.md moves to
docs/vote-service.md, because it carries the parts that are hard to
rediscover: why the ingress overwrites X-Forwarded-For and Caddy stamps
X-Client-IP instead, why the image is side-loaded into containerd rather
than pulled, and why the PVC pins the Deployment to one node.
This drops verify.mjs from 84 assertions to 83. The removed one read
vote-service/main.go for X-Forwarded-For and 'one active vote per skill'
-- the review desk's only anti-abuse control -- and there is no file left
to read. It is the first assertion this repository has ever lost.
Rather than lower the gate's floor and leave a bare number behind,
gate.sh now subtracts the number of entries in
.agents/context/assertion-removals.md from the baseline. A removal costs
a written reason in a tracked file, in the same commit, as a visible
diff. Tested at 82 assertions: still refused.
Also drops the 22 MB of PNG baselines under .agents/snapshots/before/ and
before-reduced-motion/. They pictured the hand-written site, which no
longer exists; visual-regression.mjs has no compare mode to diff them
against; and they are recoverable from d88d8b8.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merges refactor/task-20-cutover. Task 20 steps 1, 2, and 5; publishing is
not included.
The hand-written site is gone: 32 files deleted, including app.js,
responsive.css, and all ten route index.html files. Twelve more could not
be deleted -- the Astro pages import them and the build fails without
them -- so they moved to legacy/ verbatim, outside the reach of
check-tokens.mjs, which sweeps src/ and would demand a token migration
these files have not had.
Before anything was deleted, rendered-text-diff swept all ten routes plus
both Portuguese pages at full parity, 0 missing and 0 extra. That
comparison stops being possible once the legacy files are gone, which is
why it ran first. computed-style-diff on /full-guide/ is unchanged at 32.
verify.mjs no longer reads app.js and holds at 84 assertions.
audit-ui.mjs reads dist/. Docs across README, AGENTS.md, GATES.md, the
architecture context, and the operations guide now describe the built
site rather than the hand-written one.
origin/pages is unchanged at 37a1e480c6.
The publish job is still gated to manual dispatch.
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>
The value baseline was satisfied by the string appearing anywhere in the
built CSS. Task 15e attempt 3 exploited exactly that: it dropped the 880px
and 1050px media queries, then added `--legacy-audit-width-880` and
`--legacy-audit-width-1050`, referenced by nothing, purely to put the
strings back in the sheet. The audit reported success.
Two changes close it:
- Custom-property declarations nothing references via `var()` are stripped
before the value scan. A declaration nothing reads cannot style anything,
so it should not be able to satisfy a styling contract.
- A `breakpoints` bucket, scanned from `@media` preludes only, so a
breakpoint has to be an actual query condition. Baselined to the nine
breakpoints in the legacy stylesheets; extra ones are allowed, losing one
is not.
Both were tested against a rebuilt dist with the 880px queries removed:
the dead-token form fails on `sizes`, and the live-but-outside-a-query form
fails on `breakpoints`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two of task 19's re-pointed assertions were checking the built page for
tokens only the legacy page has, and both were hidden behind the
full-guide snapshot failure because verify.mjs stops at the first throw.
- The catalog count looked for `data-skill-id=`, which the desk's island
writes at runtime. Count the entries in the inline JSON payload the
page actually ships instead. Still 24.
- The vote-widget CSS check looked for `[aria-pressed="true"]`; the
minifier drops the quotes, so the built sheet carries
`[aria-pressed=true]`. Match either form.
Also re-baselines the full-guide rendered-text snapshot. It had been
taken from the build as it stood, which was the build missing a fifth of
the page, so it pinned the regression rather than the contract. The new
baseline is the build task 15f restored, verified against the legacy page
by .agents/scripts/rendered-text-diff.mjs: en 432/432 and pt 431/431,
missing 0, extra 0, order clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Verify rendered routes, translations, CSS dependencies, variables, and built CSS values. Keep the original assertion count; do not alter site components or fixtures.
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>
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.
The skills-review desk is static, so "which draft would you ship?" needs a
stateful counterpart. vote-service is a small Go API on its own pod backed by
a JSON file on a ReadWriteOnce PVC, with one active vote per skill per source
IP as the anti-abuse rule and CORS (ALLOWED_ORIGIN) as the caller boundary.
Deployment notes that differ from the obvious path, all confirmed against the
live cluster: the image is side-loaded with `ctr image import` plus
`imagePullPolicy: Never` because kubelet has no credentials for the Nexus ref;
the pod is pinned to `kubernets` because the hostpath PV takes a nodeAffinity
for whichever node first binds it; and public exposure is Caddy on the VPS,
not the cloudflared tunnel.
The ingress controller runs with `use-forwarded-headers` off, so nginx
overwrites X-Forwarded-For with its own peer — every visitor would collapse
into one voter and each skill would cap at one vote overall. Caddy stamps the
true remote address into X-Client-IP, which nginx forwards untouched, and
clientIP() reads that first. Scoped to this app rather than flipping the
global flag, which would change client-IP handling for every other ingress.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Add 'Source on Gitea' link next to every 'Open the X lab' link,
pointing to https://git.marcospaulo.dev.br/netcracker/ai-for-dummies/...
- Same download links added to both SilverBullet guides (Preview +
Source on Gitea) under Path A and Path B.
- Tighten standalone verify rule: only block external <script src> and
<link rel=stylesheet href>. Plain <a href=https://...> hyperlinks are
not runtime dependencies.
- Unslop pass across all deck text, SilverBullet EN/PT, hands-on/rules
header/label/README: kill triplets, dramatic single-word sentences,
'matrix below / looks good / cuts the opposite failure' rhetoric.
Header subtitle now reads 'Toggle rules. Same task, different
coverage.' (was 'different leash').
verify: all six checks pass.