diff --git a/CHANGELOG.md b/CHANGELOG.md index 1baf86f..75cac3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,12 @@ Credit the person or project that surfaced the change — the credit line is the - process(skill-routing): `learned-css-that-never-applied` routed **baseline** for mdl/review/gate at stages 5–6, trigger-phrased on *"a style change that appears to have done nothing, or an app still grey after a design port every instrument called green"*. Baseline rather than situational on this repo's own rule that a skill living only in the situational table goes unnoticed by projects that are not hunting for it — and not being reached is precisely what this one records — Maurits Visser, from a MOC/PSSR app replacement ## 2026-09-09 +- fix(bin/sync-project.sh + bin/check-portability.sh): the retire-ledger-row rewrite passed its regex to awk as `-v re="^\\|..."`; gawk (the GitHub runner's awk) processes escapes in -v values, so the pattern became an alternation that matched every line and the whole CLAUDE.local.md was replaced with copies of one row — green under mawk locally, red only in CI. Bracket expressions now; check-portability flags any backslash inside an awk -v value — the toolkit merge queue +- process(tests/ab + process/token-path-ab-2026-09-09.md): the token-path A/B — answer-key corpus generator and scorer (synthetic Harbour Berth Booking, stdlib only), and the report: wave 1 Sonnet P–2 (branch 31% cheaper, recall 54%→81–94%), wave 2 Haiku P–4 on three corpora (4–8 min, <$1.10 each), the non-reproducing hollow run, the per-stage mandated reading load, and the proportionality finding — the toolkit merge queue +- process(skills/conversion-runbook.md → Entry Modes): **the docs-ready fast path for a requirements-driven, text-native corpus (Markdown + HTML, no legacy code, no Office/PDF containers)** — measured cause four on the same project: the ledger wanted one disposition per file, every sidecar png/css/js included, for a corpus nothing extracts. Stage 0 = `source-sufficiency.sh init` + CAC-1 + sign-off, triage rows written `N/A (text-native corpus)`; Stage 1 = `bin/html-to-md.sh` once, the KB IS the converted text + `documents-index.md`, ONE ledger mark (`mark
'sources/**' --artifact analysis/knowledge-base/documents-index.md --evidence ... --by ...`), images still read by vision with the index's count as denominator; Stage 2 = one use case per section with a `sourceRef`, rules lifted as stated, validation once; Stages 3–4 unchanged and not skippable (module boundaries, grants, script order). Every command was run against the real gates first, and two things had to change for it to pass: (1) `--adopt 1` is the wrong instrument — adoption waives the stages *before* the point (Stage 0, which ran) and leaves Stage 1 demanding an extraction report no extractor wrote — so the path records `--waive 1 --reason "text-native corpus: ..."` (Stage 2 still runs the ledger: index hidden → Stage 2 exits 1, verified); (2) `source-ledger.sh mark` now strips the source-root segment from a target, so `'sources/**'` — the natural spelling — matches the corpus instead of being refused. Verified that a glob mark whose artifact names every basename yields EXTRACTED for every row, css/js/png included, and that image rows owe no `--media`. `bin/lib/source-formats.tsv` gains route `chrome` for css|map|woff|woff2|ttf|otf|eot|ico ("web export chrome — listed, never content"; `.js` deliberately stays on the code route — one extension, one route, and a `.js` in a migration corpus is application source); `bin/html-to-md.sh` is routed baseline (ba, stages 0–1: "HTML in the source corpus — convert once before anyone reads it"), surfaces re-rendered, baseline 74,147 of 80,000 words. Fixture: tests/wave2/test-source-ledger.sh T12 — the toolkit merge queue, from a Markdown+HTML requirements project
+- new(bin/gate-check.sh + skills/conversion-runbook.md): **a stage run names the runbook lines to read — `Read for this gate: skills/conversion-runbook.md §"Stage N — …" (lines A–B) + §1b Live Checklist (lines C–D)` — instead of the whole 11,700-word file.** Measured cause three on the same Markdown+HTML requirements project: every project's CLAUDE.local.md says "read the runbook FIRST — every session", so every session read all of it. What a stage session needs is §1b (applies to every stage) plus its own stage's §2 section; the spans are derived on every run by grepping the runbook's actual headings (`### Stage N — `, `## 1b.`; keyed on the em dash because `### Stage 0 runs in every entry mode` also starts with `### Stage 0`), never hard-coded, and `build-ready` reads Stage 5's. The runbook's top now carries the matching "How to read this file: not whole" paragraph. Fixture: tests/wave2/test-bug03-gates.sh T10 (line numbers checked against the file's headings, span ends at the next heading, build-ready → Stage 5, whole-project run prints none); test-source-ledger.sh and test-stage-p.sh still pass — the toolkit merge queue, from a Markdown+HTML requirements project
+- fix(bin/sync-project.sh): **retires the always-on `bug-logs/mxcli-bugs.md` row in a project's CLAUDE.local.md → `bin/bug-lookup.sh`, and says so.** Measured cause two on the same Markdown+HTML requirements project: master replaced the 47,500-word ledger's baseline row with bin/bug-lookup.sh on 2026-09-08, but every project scaffolded before that still read the whole ledger every session. A marked routing block was already re-rendered by section 2d — silently; now the retirement is announced ("retired the 47k-word ledger row → bin/bug-lookup.sh"). A hand-written, UNMARKED `## Baseline routing` table (every project bootstrapped before 2026-08-18) got 2d's whole-table refusal and kept the row; new section 2e rewrites that ONE row in place with the row's own path prefix kept and every neighbouring row byte-identical (new `routing_row ` as ``, inline base64 images decoded to `
` is excluded from the text corpus because a wireframe's table cells are sample ROWS and a page that correctly BINDS them contains none of that literal text. The same is true of a bound value anywhere else on the screen, and there the structure gives nothing away — an ` ` holding a record's number and name looks exactly like an `
` holding page copy, and a chip holding a filename looks exactly like a chip holding a label. Measured on a MOC/PSSR app replacement's project detail page, 2026-09-09: **54%**, and all three misses were sample values the page could not contain — the record's own title, and a mocked attachment's filename, twice. The page was right; the denominator was wrong, and the number was about to be read off as a gate verdict. So the marker is **DECLARED, not guessed**: an element carrying `bound` leaves both the text corpus and the class denominator, and guessing was the alternative and does not work — a heading is bound or it is not, and only the person who drew the screen knows which. Put it on the smallest element that holds only the value (`
` leaves no heading behind; `` inside a chip leaves the chip). Fixture grows to **18 assertions** including that a bound heading leaves the DENOMINATOR rather than merely stopping being reported as missed — otherwise the score would be 1 of 2 and still look clean. Known-bad control without the marker: **5 of 18 fail**. Same page scores 100% (3/3 headings, 2/2 content) with it — Maurits Visser, from a MOC/PSSR app replacement
- process(bug-logs): BUG-114 filed upstream as mendixlabs/mxcli#1076 with BUG-118 as its second reproduction; both drafts and the ledger header stamped FILED — the toolkit merge queue
- fix(project-bin/page-fidelity.js): **structure classed as bound data, and the score of record silently going `null%` again.** A wireframe's own `\n\n\n'
+ % (page['file'], esc(page['title']), rel, rel, ''.join('.inl-%d{padding:%dpx}' % (i, i % 7) for i in range(150)), rel))
+ meta = '' % (page['file'][:2], 'reference only' if page['chrome'] else 'functional description')
+ body = ('\n
%s
\n%s\n%s%s\n