Conversation
…query.yaml first, search parity counts, --new coverage rows, optimize source parity Five defects observed on two recorded hands-off runs of the same 36-page source site (one at an older skills commit, one at current main), verified against their artifacts. - A5 served sitemap indexes chrome documents (P1). The served /sitemap.xml listed every page plus the 22 nav/footer documents (58 urls for 36 pages); assemble.mjs wrote a correct local sitemap under stardust/rollout/site/, which .hlxignore keeps unserved, and Phase D read that file. Rule: chrome and fragment documents (nav, footer, per-locale nav-*/footer-*, locale shells that are not pages) carry a `Robots | noindex` metadata row at write time (Phase C); `assemble.mjs --verify-origin <live-origin>` compares the SERVED sitemap with the assembled set and exits 1 on any extra or missing path (network only with the flag; a sitemap index is followed; result recorded in manifest.json); the D-site ledger end names the SERVED count. helix-sitemap.yaml + helix-query.yaml exclude globs are documented as the additive alternative. - B1 query index: wrong remedy for a 404 (P1). /query-index.json stayed 404; the run probed the admin configuration service, read its 403 as "no index can be configured" and built a sheet-backed interim index. Rule: the FIRST remedy is helix-query.yaml in the code branch (skeleton in dynamics/reference/listings.md), push, publish live, poll no more often than every 5 s for at most 10 minutes; no configuration write is involved; the sheet-backed index is the fallback only when the code branch is not writable (rollout Phase D2, dynamics triage rule 8, patterns.md). - B2 search relevance and duplicates (P1). The typeahead returned 10 unbounded entries (section pages, two home pages under one title) where the source returned 3 title matches. Rule: title matches rank first, description and body text only while fewer than N title hits (N = the source's visible count, read during detect), dedupe by title + description, cap the dropdown at N; dynamics-check.mjs `search-query` compares result COUNT and the top-3 titles with the source's recorded values (`expectCount`, `expectTitles`) and fails on a count mismatch — pure `compareSearchResults()` with a fixture test. - B3 D2-built pages cannot enter coverage (P2). A search page built in D2 stayed outside coverage/pages.json, verify --all and the sitemap. Rule: `update-coverage.mjs --new <slug> --path --template --origin [--title] [--status]` adds a schema-shaped row under the coverage lock (the pages schema allows no origin property: the origin is recorded in source.migratedHtml as `<origin>:<slug>`), creates or extends the template row, is idempotent, refuses captured slugs and taken paths; assemble.mjs includes such rows. - E1 optimize findings that mirror the source (P2). All 63 findings (JSON-LD, title length, meta description, duplicate titles) mirrored the source and were accepted by hand. Rule: with the extract capture present (stardust/current/pages/<slug>.json + rendered sidecar; --current <dir>), optimize.mjs tags a finding whose condition the source shares `fixability: out-of-scope` + evidence prefix `source parity:` (the findings schema has no parity property), autofix unavailable; such findings are listed in their own report section and excluded from the health score, the open P1/P2/P3 counts and the gate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…gap listing per locale root, thumb size cap, uploader --token-env/--token-file
Five defects observed on two recorded hands-off replica runs of the same
36-page source site.
- D2 — ledger `start` written at phase end. A recorded run wrote a phase's
`start` and `end` one second apart after 109 minutes of work, so a
supervisor tailing the ledger saw an idle run. ledger.mjs: an `end` now
needs an open `start` for the same skill + phase (a start with no later
end); missing → warning in plain mode; under --strict exit 2, nothing
written, one stderr line naming the missing start command. Lines pair in
their canonical forms (aliases, case). run-status.md § Rules: the `start`
line is the FIRST command of a phase, before any script runs.
- D3 — journal without sections for early phases. `ledger.mjs … end` warns
when <dir>/journal.md has no `## ` heading naming the phase (case- and
separator-insensitive; absent file skipped; never an exit-code change).
replica/SKILL.md bookkeeping: every phase, extract and preserve-direction
included, opens with the start line and closes with the end line plus a
journal section `## <Phase name> — <what happened> (<date>)`.
- C1 — locale root captured, its subtree not, found six hours later in the
rollout link audit (15 × 404, then repointed). crawl.mjs post-pass: for
every captured locale root (a one- or two-segment path of locale codes)
the same-origin links on that page under its own path are listed and the
ones the crawl never captured are written to _crawl-log.json#captureGaps
({roots: [{root, slug, linked, uncaptured[]}], detail}) with one stderr
line; `detail` is the ready ledger string ("uncaptured first-level
targets: ca/en 15, fr/fr 0"). crawl.mjs is now importable (playwright
imported inside main, real-path main guard), so the helpers have a
fixture-HTML unit test without a browser. extract/SKILL.md Prep mode: copy
roots[] to state.json.site.captureGaps and carry `detail` in the extract
`end` ledger line.
- C2 — thumbnails read into context at full size (eight of 268–608 KB,
3.2 MB in one context). thumb.mjs --max-bytes <n> (default 150000): a
thumbnail over the cap is re-encoded at a lower --max-height (the same
bottom crop) until it fits; the line carries the crop, the cap and the
final size; exit 1 when one row still exceeds it. extract/SKILL.md Phase
2.5: a thumbnail enters the context only after thumb.mjs (≤ 150 KB), or
the vision check runs in a subagent returning one line per thumbnail.
- E7 — token source per driver. da-media-upload.mjs --token-env <NAME>
(default DA_TOKEN) and --token-file <path> (read once at start; never
both); the value is never printed, never in the re-run command, never in
the ledger; the expiry, HALT and re-run lines name the variable or file.
JWT-expiry preflight and the 401 policy unchanged. deploy/SKILL.md token
paragraph names both flags.
Tests: ledger.test.mjs (+4 checks), thumb.test.mjs (+3, the size on every
line), da-media-upload.test.mjs (+2), new extract/scripts/test/crawl.test.mjs;
state, deploy-batch and file-lock suites unchanged and green; both lints
clean; --help of every changed script prints and writes nothing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…attributes, rendition and box-sizing as lifted values, media-reconcile off the prototype gate, capture retry
Six items observed on two recorded hands-off replica runs of the same 36-page
source site, each verified against artifacts and independent screenshots.
- A2 horizontal overflow at 360 accepted as a residual (P1): measure.mjs prints
a root line per width per side (scrollWidth beside scrollHeight and the
viewport, "◄◄ OVERFLOW +n px"; root / rootDeltas in the JSON); gate.sh runs it
on the build side every round and fails the round (exit 2) on overflow
whatever the pixel number says; gate-evidence.mjs records "FAIL: horizontal
overflow" over a PASS pixel line, withholds pixel-gate-<w>, shows /ovf+<px> on
the row and overflowX in the ledger; source-fidelity-gate.md § Iteration
discipline gains the HARD assert no iteration cap waives.
- A3 content-diff compares text nodes only (P1): a second in-page inventory
(placeholder, aria-label, title; icons — small <img> by file name, inline svg,
icon-font glyphs by ::before/::after content, css mask/background icons, empty
icon boxes) and a pure differ: MISSING/EXTRA <ATTR>, MISSING ICON, ICON DIFF,
ICON KIND, EXTRA ICON — 🔴 on interactive elements, 🟡 otherwise. Output format
and exit codes unchanged; --json gains findings[]; playwright is imported lazily
and the module has a main-module guard so the differ is unit-tested without a
browser; new skills/diff/scripts/test/content-diff.test.mjs (the fixture e2e
skips with a line where playwright is not importable).
- E3 image rendition per breakpoint (P2): measure.mjs reports img { naturalWidth,
naturalHeight, currentSrc } per <img>/<picture> match and img.naturalWidth /
img.file deltas; recreation-procedure.md § Image renditions per breakpoint —
record the rendition live selects per gate width, author the same
srcset/sizes, read a sub-3 px root delta with equal boxes as a rendition-ratio
symptom, not a layout bug.
- E4 media-reconcile demanded on prototype files (P2): gate-evidence.mjs
--content <dir> (default content); without the page's delivered content file
the gate reads "n/a: no delivered content file yet" (never OPEN), leaves the
sibling acceptance set and --check, and is required again once the file
exists; source-fidelity-gate.md places media-reconcile in the delivery chain
(row C), not in the prototype gate.
- E5 box model lifted as a first-class value (P2): boxSizing joins measure.mjs's
default props so --against names a content-box / border-box fork per box;
recreation-procedure.md § Box model is a lifted value — lifted per container,
declared per block, the boilerplate reset scoped on a replica, never universal.
- E6 capture exit 1 under parallel Chromium load (P2): gate.sh retries a capture
that exits 1 (live, build, overflow probe) ONCE; two exit-1 attempts end the
round with exit 1 "re-queue, not a verdict"; 3 / 4 / 124 stay final; run-bg
slot defaults untouched; source-fidelity-gate.md names capture exit 1 as
re-queue.
Tests: measure, gate (50 checks), gate-evidence (28), content-diff, run-bg,
foundation-freeze (19) pass; lint:stardust clean; every changed script answers
--help without writing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… unused import Three follow-ups the recorded hands-off runs asked for after the bookkeeping, rollout and gate fixes landed. - deploy-batch.mjs takes `--token-file <path>` with exactly the uploader's semantics: read once at start and trimmed, never together with `--token-env`, a missing or empty file is a usage error (exit 2) naming the path; the expiry and HALT lines name the file, and the file-mode re-run command carries no `<var>=<fresh token>` prefix. Header, --help and the deploy card's token paragraph say both drivers take both flags. deploy-batch.test.mjs: two checks (file read + HALT/expiry lines + resume; the three usage errors). - inventory.mjs keeps the rows `update-coverage.mjs --new` added (a page built outside the migrated tree; `source.migratedHtml` is the origin marker `<origin>:<slug>`) on a re-run, status untouched, instead of dropping them — the page is registered once. A marker row gives way only when the migrated tree now holds a file for its slug or a migrated page owns its path. One `Kept` report line. inventory.test.mjs: kept across a re-run (template row, counts, report line), replaced once the slug is migrated. The "re-run the same --new line after inventory" caveat is removed from rollout/SKILL.md, coverage-model.md and the update-coverage header. - da-media-upload.mjs: the unused `renameSync` import is removed. Tests: deploy-batch (12), inventory (7), update-coverage, da-media-upload, ledger all pass; lint:stardust clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…low-ups; migrate render as recorded units The shared documents the three fix commits (rollout + dynamics, bookkeeping + extract + uploader, replica gates) were not allowed to touch, plus the recorded-units pattern for migrate. - replica/reference/handoff-contract.md: § 1 row 4 (content-diff pairs placeholder / aria-label / title and icons), row 5 (horizontal-overflow assert every round, capture exit 1 = re-queue), row 9 (migrate runs as recorded units), the acceptance paragraph (media-reconcile required only once the delivered content file exists; collector sentence) and a new migrate unit-ledger paragraph; § 3 rows D (served sitemap verified, chrome `Robots | noindex`, `D-site end` names the SERVED count), D2 (helix-query.yaml first, search parity by count + titles, coverage row for pages built there), E2 (site.captureGaps decided at Phase 1); § 4 rows for the uploader and the batch driver (`--token-env | --token-file`), gate-evidence (`--content`, `/ovf`, `n/a:`, pixel shape), new rows for measure.mjs, ledger.mjs and thumb.mjs, the three rollout writer rows replaced, inventory keeps `--new` rows; § 5 ledger rule (start first, journal section per end) and the migrate-units checkpoint block. No runner endpoint anywhere in the card. - migrate/SKILL.md Phase 2: "Recorded units" — plan / render per template cluster of at most ~8 siblings / assets / report in stardust/migrate/progress.json with the C-deliver ledger's shape; progress write, checkpoint commit, next unit; a resumed session runs only the units not done (the driver is idempotent). A recorded run rendered 31 siblings through five parallel builders as one unit inside one session — its most expensive — with no resume point between plan and report. - stardust/reference/scripts-index.md: usage lines for content-diff, dynamics-check, crawl, thumb, gate-evidence, gate.sh, measure, assemble, inventory, optimize, update-coverage, ledger, the uploader and the batch driver; 76 index lines unchanged, 8799 bytes. - state-machine.md: `site.captureGaps`. journal-format.md: in a stardust phase the one-line summary starts with the phase name; ledger.mjs accepts either heading shape. - replica/SKILL.md: the overflow assert beside the pass bar; Phase 5 names media-reconcile as required once the delivered content file exists (+381 bytes). - CHANGELOG.md: `## Unreleased` above 0.25.0 — intro plus three groups (gates that passed a broken site; index, sitemap, search; bookkeeping, capture, tooling), the migrate-units item and the deploy-batch --token-file / inventory keep items included. lint:stardust clean (harness-neutral 100 files, script-paths 304 references, scripts-index 76/76, script-help 58 ok). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
Tessl Plugin Lint
|
…ome roots by default, title is 🟡 — measured on a delivered replica Measured on a delivered 36-page replica (5 page pairs), the attribute/icon layer found the regressions it was built for on 4 of 5 pages — share links without aria-labels and icons, dropped CTA aria-labels, a dropped localized search placeholder — and two false-red sources of its own: - Anchor-only icon pairing: an FAQ page kept all seven accordion glyphs, but the build hosts them in text-less <button>s (anchored button#1…#7) while the source anchors each to its question text — 7 × MISSING ICON 🔴 + 7 × EXTRA ICON 🟡 on a page whose icons were right. After the anchor passes, leftover icons now pair by identity (glyph code point / file name / svg signature) and document order, within the same nearest block first, then the root — a pair made this way is ICON MOVED 🟡, never MISSING + EXTRA. - Chrome outside the default root: `main` excluded header and footer, so the search placeholder and the locale flag were invisible unless the caller passed --main header. --main takes a comma-separated selector list; --chrome (default on) adds the header and footer roots — the first <header>/[role=banner] and <footer>/[role=contentinfo] outside the main root(s) — and --no-chrome disables. One report block per root, every finding line carries its root ([header]), --json findings carry `root`; the Findings: line gate.sh and gate-evidence read is unchanged. - A missing `title` is 🟡 always (tooltips are not read by most assistive tech and are commonly dropped by design); placeholder and aria-label on interactive elements stay 🔴. Severity table in the script header. Docs: source-fidelity-gate.md and handoff-contract.md § 1 row 4 say content-diff covers main AND chrome roots on every gate page; the recreate and C-deliver commands need no new flag. diff/SKILL.md flags + reading guide, scripts-index, CHANGELOG. Tests: FAQ shape → 7 × ICON MOVED, a truly missing icon beside moved ones stays MISSING, block-scoped pairing, title downgrade, --main list parsing, per-root tagging, --help names the flags. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This branch is waiting to be deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups from two recorded hands-off replica runs of one 36-page source site — one at 0.22.1, one at 0.25.0 — each item verified against the run artifacts (ledger, journal, coverage, served origin) before it was written. Five commits, one theme each; every script change carries a test, every rule change names the recorded fact behind it in the changelog (
## Unreleased).What changes
Gates that passed a broken site
measure.mjsprints the rootscrollWidthper width per side,gate.shruns it on the build side every round and fails the round on overflow whatever the pixel number says,gate-evidence.mjsrecords it over a PASS pixel line. Two delivered pages had rendered 373 and 400 px wide at a 360 viewport and passed as "logged, not iterated further".content-diff.mjscomparesplaceholder,aria-label,titleand icons (small images by file name, inline svg, icon-font glyphs), 🔴 on interactive elements — a dropped search placeholder, a wrong flag in a locale link and empty social-icon boxes had read as 0 🔴.box-sizingper container are lifted values (measure.mjsreports both); media-reconcile leaves the prototype gate until the delivered content file exists; a capture that exits 1 is retried once and otherwise re-queued, never read as a verdict.Index, sitemap, search
Robots | noindex;assemble.mjs --verify-origincompares the SERVED sitemap with the coverage rows and fails on a mismatch. The served sitemap had listed every page plus 22 chrome documents while the report said "36 urls" from the local file./query-index.jsonis answered byhelix-query.yamlin the code branch first (skeleton in the dynamics reference), the sheet-backed index only when the code branch is not writable.dynamics-check.mjs compareSearchResults, fixture-tested); the search pattern ranks title matches first, dedupes and caps at the source's visible count.update-coverage.mjs --newlets a page built in D2 enter coverage;inventory.mjskeeps such rows on a re-run.Bookkeeping, capture, tooling
ledger.mjsrefuses anendwithout an openstartunder--strictand warns when the journal has no section for the phase; thestartline is the first command of a phase.crawl.mjslists the uncaptured first-level targets under every captured locale root (_crawl-log.json#captureGaps, copied tostate.json site.captureGaps, counts in the extractendline) — two runs learned about 15 uncaptured locale pages six hours later from the link audit.thumb.mjs --max-bytes(default 150 KB);optimize.mjstags findings the source shares as source parity and keeps them out of the score (63 hand-accepted findings on both runs); both deploy drivers take--token-env/--token-file.stardust/migrate/progress.json, same shape as the C-deliver unit ledger): plan, one render unit per template cluster of ≤ ~8 siblings, assets, report — the one long phase that still had no resume point.Checks
qa/scripts/test/dropdown-unreachable.test.mjs, which needs Playwright installed in the checkout. Tests that need a browser skip with a line and test their pure functions directly.lint:stardustclean (harness-neutral, script-paths, scripts-index 8799 bytes, script-help 58/0).Follow-ups not in this PR
🤖 Generated with Claude Code