diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 74e9871..a361e89 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -3389,3 +3389,56 @@ prototype, the walk and the fixture harness. `c4127c6c` into the shared build tree first, then publish.** As of this clock the shared tree still reads `97fedb5d…` (`build_blocks.py`) / `63c9cee6…` (`blocks.json`), the live index is 34,488 B / `4f764ef4dfb9…`, and nothing has been published. + +--- + +**Status: DONE 2026-10-11 — `recoveries/render-site-channels.md` (Merlin), scratch tree +`/root/crucible/q28/`. 20 channels: 13 covered by fixture (19 fixtures), 7 excluded with a +measured command; every negative exits 1 with 0 builder writes; the no-token control is +byte-identical to the live `site-ledger` at `91ecf6bf`.** + +- **The guarantee, restated as one sentence and printed from the source:** any string containing + `{{` or `}}` anywhere inside a `blocks.json` entry — at any nesting depth, checked before a + single byte is written — kills the build; the only tokens that ever ship are well-formed + `{{x:HANDLE}}` tokens in the four prose panels of a summary-branch entry naming a cited handle. + Guards printed with line numbers: `check_tokens` (:192-225), `check_gaps` (:228-234), + `check_uncited` (:151-169), all above `OUT.mkdir` (:292-304). +- **Fixture table (19 fixtures, one mutated `blocks.json` per scratch tree).** 16 negatives, + every one exit 1 / 0 files: `coverage.gaps[0]`; `slug` (canonical href, sitemap `loc`, index + `li` id, pager hrefs — one fixture, and `slug_for("{{x:")` → `"x"`, which is why the die + prints `x:slug:`); `sort_date` (year heading `sortable[:4]`); `n` (pager text); + `body_source_url` both shapes (`safe_url` → `must be https, got '{{x:'`; sentinel scan); + `receipt.usd` (arithmetic formatted strings); `title`; `date` (JSON-LD `datePublished`); + `contributor.display_name` (JSON-LD author); `status`/`ledger` (entry validation — + `unknown status '{{x:'`); `block-5` body on the quote branch (genesis :435, panel set printed + without `body`); `block-5` uncertainty (genesis :448, `check_uncited` pre-write); a + research-only `title` token (label staged branch :385); a planted `index.html` in OUT + (PROTECTED guard — 1 planted file refused, 0 builder writes). 3 positives, all exit 0 / + 125 files: research-only without a token builds and prints `(staged, not published)` once on + the index (the branch is data-reachable; 121/121 are `cleared` today); `hi` + in `title` ships as `<\/script>` (the JSON-LD channel is watched by `json.dumps` + ` Screen. Every claim below carries a path, a hash, a URL, or a command with its output, or the word +> `unverified`. Nothing secret is printed anywhere in this check-in or in the files it lands. + +## Did + +Claimed and finished **Q28 — the channels the entry walk cannot see** (the top unclaimed item, +opened by the pipe 02:5xZ on the residue of its own Q27 verification tick; Q20 is +zephyrus-sparkborn's, Q9 blocked on the audio handover, Q13/Q19 gated on Alexander). + +Deliverable: `recoveries/render-site-channels.md` (**16,456 B / sha256 +`ea4b5e988a065dfd0bbc06f735cf7aead88e30030dfd9af4bcfdf5c05ec4c1bc`**), scratch tree +`/root/crucible/q28/`. The builder under test is the Q27 patched one, copied in and verified: +`build_blocks_hard.py` sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2` +(29,174 B); `blocks.json` `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d` +(278,459 B), read-only throughout. + +**The guarantee, now one sentence with the walk printed:** any string containing `{{` or `}}` +anywhere inside a `blocks.json` entry — at any nesting depth, checked before a single byte is +written — kills the build; the only tokens that ever ship are well-formed `{{x:HANDLE}}` tokens +in the four prose panels of a summary-branch entry naming a cited handle. Guards with line +numbers in the deliverable: `check_tokens` (:192-225), `check_gaps` (:228-234), +`check_uncited` (:151-169), all above `OUT.mkdir` (:292-304). + +**Result: 20 channels — 13 covered by fixture (19 fixtures), 7 excluded with a measured +command. Every negative exits 1 and writes 0 files; the one output directory holding a file at +failure holds the file the fixture planted, which the guard refused to clean.** Control: +unmodified `blocks.json` through the patched builder → exit 0, **125 files**, tree digest +`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`, `diff -rq` against the live +`site-ledger` silent. + +The 16 negatives, each its first stderr line in the deliverable: `coverage.gaps[0]`; `slug` +(one fixture covers canonical href, sitemap `loc`, index `li` id, pager hrefs — and +`slug_for("{{x:")` returns `"x"`, so the die prints `x:slug:`); `sort_date` (year heading); +`n` (pager text); `body_source_url` both shapes (`safe_url` → `must be https, got '{{x:'`; +sentinel scan); `receipt.usd`; `title`; `date`; `contributor.display_name`; `status`/`ledger` +(validation); `block-5` body on the quote branch (genesis :435); `block-5` uncertainty +(:448, pre-write); a research-only `title` token (label staged branch :385); a planted +`index.html` in OUT. The three positives: the staged branch builds and prints +`(staged, not published)` once when an entry takes it; `hi` in `title` ships as +`<\/script>` (the JSON-LD channel's guard is the `json.dumps` + ``, JSON-LD `headline`, `h1`, note, index label (both branches) | walk (`title`) | `title-sentinel` | 1 | 0 | `magazine-001:title: token sentinel {{ in a field that is not a prose panel` | +| 12 | `status` — badge class + `STATUS_LABEL` lookup | entry validation | `status-token` | 1 | 0 | `block[30] unknown status '{{x:'` | +| 13 | `ledger` — `LEDGER_LABEL` lookup | entry validation | `ledger-token` | 1 | 0 | `block[30] unknown ledger '{{x:'` | +| 14 | JSON-LD `datePublished` + the Date line | walk (`date`) | `date-sentinel` | 1 | 0 | `magazine-001:date: token sentinel {{ in a field that is not a prose panel` | +| 15 | JSON-LD `author` name + byline (`display_name`) | walk (`contributor.display_name`) | `jsonld-author-name` | 1 | 0 | `magazine-035:contributor.display_name: token sentinel {{ in a field that is not a prose panel` | +| 16 | **missing row 1** — `label()` staged branch (pristine :385) | walk (`title`) | `staged-label-token` (research-only + token) | 1 | 0 | `magazine-001:title: token sentinel {{ in a field that is not a prose panel` | +| 17 | **missing row 2** — ledger-index badges (pristine :399/:400) | validation | `status-token` / `ledger-token` | 1 | 0 | *(fixtures 12/13)* | +| 18 | **missing row 3** — genesis landing :435, `block-5` body on the quote branch | walk (`body`, panel set printed *without* `body`) | `genesis-quote-body` | 1 | 0 | `block-5:body: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty)` | +| 19 | genesis landing :448 — `uncertainty` via `expand_prose` | `check_uncited` (pre-write) | `genesis-uncited` | 1 | 0 | `block-5:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites` | +| 20 | static/protected archive files | `PROTECTED` guard | `protected-clash` (planted `index.html` in OUT) | 1 | 0 (1 planted, refused) | `refusing to clean …/site-ledger: it holds archive source files ['index.html']` | + +### Positive controls (three) + +| fixture | exit | files | what it proves | +|---|---|---|---| +| `staged-label-reachable` — `magazine-001` flipped to `research-only`, no token | 0 | 125 | the staged branch is **data-reachable**: the built index carries `(staged, not published)` exactly once. Q27's table called it unreachable because *no entry does* today — 121/121 are `cleared` — which is the one thing an exclusion may not say. | +| `jsonld-close-script` — `title` = `hi` | 0 | 125 | the JSON-LD channel's guard is the `json.dumps` + `` and no raw ``. A different defect class, watched by a different mechanism — outside the sentinel's declared scope, stated rather than silent. | +| `cited-genesis-positive` — cited token in `block-5`'s `body_provenance` | 0 | 125 | the token expands on **both** landings: exactly 2 files change (`block-5/index.html`, `genesis/index.html`), one `x.com/arizonanhodl` anchor each. Q26's third silent class stays closed under the patched builder. | + +### Control + +Unmodified `blocks.json` through the patched builder: exit 0, **125 files**, tree digest +`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8` (Q26's baseline, computed +with Q26's own digest definition), `diff -rq` against the shared `site-ledger` **silent**. + +## The structural exclusions — each with the command that measures it + +No fixture can place a token in these channels because **no `blocks.json` value reaches +them**. The reason is a measured command, never a reading. + +| # | channel | command | output | +|---|---|---|---| +| E1 | `CSS` / `FOOT` literals | `grep -n 'CSS\|FOOT' build_blocks_hard.py` | :45 `CSS = """…"""`, :324 `write_text(CSS)`, :379 `FOOT = """…"""`, :512/:570/:607 `parts.append(FOOT)` — module literals, emitted verbatim; no data is interpolated into them. Reinforced by `grep -c '\.format(' build_blocks_hard.py` → **0**: no emitted literal is ever `.format()`-ed with a value. | +| E2 | `esc(k)` — receipt row keys | `grep -n 'for k, v in' build_blocks_hard.py` | two sites: :219 `walk`'s `obj.items()` (values only) and :417 the receipt generator over `rows = [("Amount", …), ("Price line", …), ("Amount in sats", …), ("Arithmetic", check)]` — hardcoded at :415-416. The only key-rendering `esc()` in the builder renders hardcoded strings. | +| E3 | dict keys | `grep -n 'for k, v in obj.items()' build_blocks_hard.py` | :219 — `walk(v, …)` recurses on the value only; `walk()` never visits a key, and no `esc(k)` exists outside E2. A `blocks.json` field *name* cannot reach any emit site. | +| E4 | the `OUT`-is-`site/` guard | `grep -n 'OUT must not be\|refusing to clean\|PROTECTED =' build_blocks_hard.py` | :32 `PROTECTED = {…}`, :298 the `site/` comparison, :302 the clash `die()`. **Source-read, not fixture-tested**: `OUT` is hardcoded to `BASE/"site-ledger"` (:31), so the `site/` comparison cannot fire without editing the builder. | +| E5 | static/protected files — the write set | `python3`: sorted files under the control build's `site-ledger` | **125 files; intersection with `PROTECTED` = `[]`.** The builder's entire write set is enumerated, and none of the five hand-maintained names is in it. | +| E6 | `blocks-build.json` manifest | `python3`: `json.load` of the control build's manifest | keys `['cleared','files','pages','research_only','schema']`; **124 file entries, every value `{"sha256","bytes"}`** — e.g. `magazine-001/index.html` → `{"sha256": "aa550c2b…", "bytes": 4174}`. No entry prose reaches the manifest. | +| E7 | `coverage` keys other than `gaps` | `grep -n 'coverage' build_blocks_hard.py` | four lines, all `coverage.gaps` (:230, :232, :559, and the :229 docstring). The other keys (`block_numbers_held`, `dollar_receipts_held`, `documented`, `timeline_events`, …) are **never read by the builder** — unrendered data, outside the emit surface. | + +## Two corrections, stated in prose (Q27's file is corrected by reference, never by edit) + +1. **The pristine builder has 36 `esc()` call lines / 43 call occurrences, not 28.** Measured: + `python3` over `build_blocks.py` — lines containing `esc(` minus the `def esc(v):` at :87 → + 36; `sum(l.count("esc("))` minus the definition's own occurrence → 43. Q27's "28 `esc()` + calls" undercounts the emit surface its table claims to cover. (The pipe's correction `C3` + reproduces exactly; measured here independently.) +2. **Q27's stated fixture breakdown sums to 41 — 42 counting the omitted `excl:contributor.handle` + row — against its own 35-row log.** Measured: `Q27-RESULTS.json` holds **35 rows** (5 at + exit 0 / 125 files, 30 at exit 1 / 0 files); the record's 12 stated items + (4+12+4+10+2+3+1+1+1+1+1+1) sum to 41. The row table itself is right; the sentence is not. + +## Findings + +1. **The walk, not the site census, is the guarantee — and it is stronger than either record + says.** `check_tokens` recurses every string at any depth under an entry, so a sentinel in + a field *no entry has today* still dies before `OUT.mkdir`. Q26 §9 limit 2 ("a sentinel in + a field no entry has today cannot be enumerated from today's data") is answered by the + walk, not by a table of 32 sites: the 19 fixtures here each name a *channel*, and the + channel dies because its field is an entry string, not because the field is listed + anywhere. +2. **`slug_for()`'s sanitisation is real but irrelevant to the guard.** `slug_for("{{x:")` + returns `"x"` (the `[^a-z0-9-]+` run collapses to `-`, `.strip("-")` leaves the lone `x`) — + which is why the `slug-sentinel` die message prints `x:slug:` rather than a slug at all. + Q27's exclusion reason ("`slug_for()` sanitises `{{` out") is **falsified as the guard**: + the walk kills the token one step earlier, and the sanitised value never reaches an emit + site. The pipe's `C4` holds; re-measured here under the patched builder. +3. **The label-staged branch is the one row where "no entry does" was the stated reason and + the measurement disagrees.** 121/121 entries are `publication_status: "cleared"`, so the + branch is dead *today* — but flipping one entry to `research-only` builds it and the index + prints `(staged, not published)`. It is data-reachable, and the walk watches its field + (`title`) regardless: fixture 16. +4. **The JSON-LD channel is watched by a different mechanism than the sentinel**, and that + is worth stating rather than folding in: `json.dumps` + `` in a walked field ships as `<\/script>` — measured, exit 0. The sentinel does + not see it and does not need to; a future hardening could scan for it, but the item's + scope is the token classes, and the answer to "must a token in a URL field die" is + unchanged: **yes, measured both ways** (fixtures 8/9). + +## Limits + +- **13 fixtures of 16 negative ones each die at the sentinel walk by construction.** That is + the property being proven, but it means the fixtures demonstrate the *channels*, not a + census of malformed shapes — Q26's 12-fixture set is the shape census and is not re-run. +- **The `OUT`-is-`site/` guard is source-read** (E4): `OUT` cannot be redirected without + editing the builder, so the comparison is untested by fixture. +- **Nothing here re-tests Q25's census** (46 prose rows / 25 X fetches) — cited, not re-run; + no X page was fetched this tick. +- **All digests are dated readings** from this host at the run clocks below. The control's + byte-identity to the live `site-ledger` is measured, which is what makes the fixture set + anchored to a build matching production. +- **Scratch only.** The patched builder stays in `/root/crucible/q28/`; publishing it is + Alexander's, the same gate Q26/Q13/Q27 state. + +## Scripts (re-runnable, in `/root/crucible/q28/`) + +`q28-probe.py` (data facts: publication_status, ledger/status counts, sort_date/date/body_kind +coverage, gaps) · `q28-fixtures.py` (19 fixtures + control, emits `Q28-RESULTS.json`) · +`q28-exclusions.py` (7 exclusions + the 2 corrections, emits `Q28-EXCLUSIONS.json`) · +`q28-count-q27.py` (the Q27 breakdown recount) · `q28-which.py` (which entry is `n=5`). +Every fixture tree under `fixtures/`; the control build in the scratch root. + +## Run record + +- Builder `build_blocks_hard.py` sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2` + (copied from `/root/crucible/q27/`, verified before use). +- `blocks.json` sha256 `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`, + 278,459 B, read-only. +- 19 fixtures: 16 negative (all exit 1, 0 builder writes) + 3 positive (all exit 0, 125 files). +- Control: exit 0, 125 files, digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`, + `diff -rq` vs `/root/stackchain-legends-build/site-ledger` silent. +- Shared tree untouched: `build_blocks.py` still `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`. +- Live ledger index re-fetched: `https://alexanderwhitestone.com/stackchain/blocks/` **200 / + 34,488 B / sha256 `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`**. +- `decisions/` and `inbox/` untouched; nothing executed; no other party's file edited. + +## Defects of my own, logged first + +1. The first harness run died on `receipt-usd` / the genesis fixtures with + `SystemExit: not found: block-5 None` — the receipt entries carry **no `slug`** + (`slug_for` derives `block-5` from `n`), so the slug selector found nothing. Caught on the + first run; fixed with an `n=` selector. Nothing was published on the broken pass. +2. The first `protected-clash` fixture ran the build *before* planting the file, so it + reported exit 0 / 125 files and then died on `FileExistsError` when planting. Restructured + so the plant precedes the build; the reported row is the planted one. +3. `slug-sentinel`'s die message prints `x:slug:` because `slug_for("{{x:")` returns `"x"` — + an artifact of the fixture, not of the guard, and recorded above as finding 2 rather than + quietly normalised.