diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index c260c92..b5e1e9d 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -3045,3 +3045,72 @@ with a reason remains legitimate (§3.7). `Q20` remains active and zephyrus-spar line 2370 repeats the slip in the other direction, giving `StackchainQuant` 37,702. No verdict impact, nothing to re-run, and no fix implied beyond this line. + +--- + +**Status: DONE — `recoveries/prose-anchor-hardening.md`, Merlin, 2026-10-10→11 (~00:20–00:24 UTC). +The hardened prototype is built and every negative class now dies at build time; nothing +published, nothing applied to the shared build tree.** +- **The hardening.** A pre-write scan (`check_tokens` per entry, `check_gaps` for the + index) sits **above** the `OUT` cleanup in `build()`, so a `die()` can never leave a + half-emitted tree. Any `{{`/`}}` sentinel in a field the four prose panels do not render + dies; any sentinel left in a panel after `TOKEN_RE.sub` dies. The panel set is computed + **per entry**: `body` is a panel only when `body_kind == "summary"`, so the quote branch + is caught by construction — the first hardening pass missed exactly that, and the + quote-branch error now prints the reduced panel set, so the rule is visible in the + failure. +- **Diff.** `build_blocks_proto.py` → `build_blocks_hard.py`: **+70 / −6 lines, 5,817 B** + (`DIFF.txt`). Against the shared tree's `build_blocks.py` (sha256 + `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`): **+118 / −11, + 9,949 B**. The hardened script is **27,878 B / sha256 + `d45cc28f7d69afcdab4eccb16e9e0cc264e4317e059e17f1ba53eb23f792cb60`**; the Q25 prototype + copied into the scratch tree verified byte-identical first (`5af80b78…`). +- **The five Q25 legs, re-run green.** No-token build on the unmodified `blocks.json` + (278,459 B / `63c9cee6103a6824…`): `Built 123 pages from 121 entries`, tree digest + **`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** = baseline, 125 + files, `diff -rq` against the live `site-ledger` silent. Registry unchanged at **8** + handles. The uncited-handle negative test still exits 1 with Q25's own message + (`block-25:uncertainty: … @NotACitedHandle which no entry cites`). The H1–H4 token demo + still moves **3 of 125** emitted files with 6 emitted anchors. The diff itself is the + fifth leg. +- **Two negative test sets, 12 fixtures, every one `exit 1` with its own message** + (`MALFORMED.txt`, `OUTSIDE-PANEL.txt`): malformed — open brace `{{x:saylor}`, empty + handle `{{x:}}`, whitespace-padded `{{ x:saylor }}`, wrong namespace `{{y:saylor}}`, + handle over 15 chars `{{x:abcdefghijklmnopq}}`, lone `}}`, close-then-open `}}{{x:…}}` + (all seven previously built and shipped the literal under the Q25 prototype); + outside-panel — quote branch (`block-6:body`), `title`, `excerpts[0].text`, + `contributor.display_name`, `coverage.gaps[4]`. A cited-token **positive control** + expands on the entry page *and* the genesis page and moves exactly 2 files. +- **One new silent class found and closed while writing the control:** `render_genesis` + routed `body_provenance` and `uncertainty` through `esc()`, so a token those panels + carry would expand on `block-5` and print raw braces on `genesis/`. Both now go through + `expand_prose`; byte-neutral with no token present (proved by the no-token leg). +- **The `display_name` fifth slot, measured without building it** + (`DISPLAY-NAME-MEASURE.txt`, each Q24 delta applied in its own scratch tree). + **Recommendation: `magazine-056` (G2) and `magazine-070` (I2) take the handle-only fix — + one account, one slot, and the build already anchors `contributor.handle`. `magazine-035` + (G1) is the hard case: handle-only anchors `@BTC_Freeborn` and leaves `@AnthonyDessauer` + unanchored because `contributor` has exactly one `handle` slot while the byline names two + accounts — and `@AnthonyDessauer` *is* in the registry, so a token for it would be + admitted today. The only instrument that anchors both is `display_name` as a fifth panel + carrying `{{x:AnthonyDessauer}}` beside the handle slot: a build change, Alexander's.** + All three live-page digests reproduce Q24's fix-pack figures to the nibble + (`871638b8abb5…`, `33b55f8f61fe…`, `6227e199522f…`), so the live tree is still the tree + Q24 measured. +- **Which of Q24's 31 deltas the hardened convention can carry as links: H1–H4 only, 4 of + 31.** The hardening widens no clause's carrier; it makes the four token carriers safe to + publish. The publication precondition the 2026-10-10 18:13Z addendum stated is therefore + satisfied on the build side — **Q13/Q24 approval is still permission to review and stage, + not to build.** +- **Nothing touched.** Shared tree still at `97fedb5dd5e85d2…`, its `site-ledger` + byte-identical (125 files, `diff -rq` silent), `find /root/stackchain-legends-build + -newermt 2026-10-10 18:00 -type f` empty. Live archive unchanged: index + `https://alexanderwhitestone.com/stackchain/blocks/` **200 / 34,488 B / sha256 + `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** at + 2026-10-11T00:23:25Z. `blocks.json` read-only throughout. `decisions/` and `inbox/` + untouched, nothing executed. +- **Limits.** 12 fixtures are the item's own lists plus a lone `}}` and close-then-open; + they are not a census of typos. `display_name` was measured, not built. Nothing re-tests + Q25's census (46 rows / 25 fetches) — cited, not re-run. No X page was fetched this run, + so no liveness figure is dated by this tick. Q20 remains the top unclaimed item and is + zephyrus-sparkborn's; Q9 blocked on the audio handover; Q13/Q19 gated on Alexander. diff --git a/checkins/2026-10-11-merlin.md b/checkins/2026-10-11-merlin.md new file mode 100644 index 0000000..5b25a59 --- /dev/null +++ b/checkins/2026-10-11-merlin.md @@ -0,0 +1,136 @@ +# 2026-10-11 — merlin + +> 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 **Q26 — make the silent token classes loud, and measure the fifth slot**, the item +nominated to me by the control plane after Q25 closed at `a9f23a6` (Q20 is zephyrus-sparkborn's and +stays the top unclaimed item; Q9 blocked on the audio handover; Q13/Q19 gated on Alexander). + +Deliverable: `recoveries/prose-anchor-hardening.md` (**15,250 B / sha256 +`607b29403e61db44f15657386531ef11d009f964b90b1a4a5a25542612325108`**, this host, +2026-10-11T00:24:34Z). Queue block appended to `WORK-QUEUE.md` (383,205 B / sha256 +`9be863624751711afb0b1c745b7cf4147ea9f838b6189ccadc32689b3d4b5d3c`). + +**What Q25 left silent, now loud.** The Q25 prototype shipped a typo as raw braces on the page and +could not see a token outside its four panels. The fix is a pre-write scan — `check_tokens` per entry, +`check_gaps` for the index — sitting **above** the `OUT` cleanup in `build()`, so a `die()` can never +leave a half-emitted tree. The panel set is computed **per entry**: `body` is a panel only when +`body_kind == "summary"`. + +The diff: `build_blocks_proto.py` → `build_blocks_hard.py` **+70 / −6 lines, 5,817 B** +(`/root/crucible/q26/DIFF.txt`); against the shared tree's `build_blocks.py` +(sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`) **+118 / −11, 9,949 B**. +The hardened script is **27,878 B / sha256 +`d45cc28f7d69afcdab4eccb16e9e0cc264e4317e059e17f1ba53eb23f792cb60`**; the Q25 prototype copied into +the scratch tree verified byte-identical first (`5af80b78961b4f55…`). + +**The five Q25 legs, re-run green** (`Q26-VERIFY.txt`, full log `Q26-VERIFY-run.txt`): + +1. No-token build on the unmodified `blocks.json` (278,459 B / sha256 + `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`): + `Built 123 pages from 121 entries (121 cleared, 0 research-only)`, tree digest + **`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** = baseline, 125 files, + `diff -rq /site-ledger /root/stackchain-legends-build/site-ledger` silent. +2. Registry unchanged: **8** handles (`@anthonydessauer @arizonanhodl @guiamadogomes + @happyclowntime @rockachopa @satskeeper_ @saylor @yoshishisatoshi`). +3. Uncited-handle negative test: `exit 1`, + `BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle which no + entry cites`. +4. H1–H4 token demo: `exit 0`, **3 of 125** emitted files changed + (`event-2022-07-18-the-5-invitation-becomes-a-chain/index.html`, `magazine-002/index.html`, + `magazine-005/index.html`), 6 emitted anchors, all the contributor form. +5. The diff itself. + +**Two negative sets, 12 fixtures, every one `exit 1` with its own message.** Malformed +(`MALFORMED.txt`): `{{x:saylor}` open brace, `{{x:}}` empty handle, `{{ x:saylor }}` +whitespace-padded, `{{y:saylor}}` wrong namespace, `{{x:abcdefghijklmnopq}}` handle over 15 +chars, lone `}}`, close-then-open `}}{{x:saylor}}` — all seven **previously built and shipped the +literal** under the Q25 prototype, exit 0. Outside-panel (`OUTSIDE-PANEL.txt`): quote branch +(`block-6:body`, whose error prints the panel set *without* `body` — the per-entry `body_kind` +rule visible in the failure), `magazine-001:title`, `magazine-001:excerpts[0].text`, +`magazine-035:contributor.display_name`, `coverage.gaps[4]`. Positive control (`POSITIVE.txt`): +a cited `{{x:AriZonanHODL}}` in `block-5`'s `body_provenance` builds, expands on the `block-5` page +**and** the genesis page, and moves exactly 2 files. + +**One new silent class, found while writing the positive control and closed:** `render_genesis` +routed `body_provenance` and `uncertainty` through `esc()`, so a token those panels carry would +expand on `block-5` and print raw braces on `genesis/`. Both now go through `expand_prose`; +byte-neutral with no token present (proved by leg 1). The first hardening pass also missed the +quote branch for the same reason a path-based panel set fails — `body` is a panel only on the +summary branch — and the fix was the per-entry panel set. + +**The fifth slot, measured without building it** (`DISPLAY-NAME-MEASURE.txt`, each Q24 delta +applied in its own scratch tree): + +| entry | Q24 clause | `display_name` / `handle` today | live page today | after the staged delta | +|---|---|---|---|---| +| magazine-035 | G1 | `@BTC_Freeborn and @AnthonyDessauer` / `null` | text only, anchors NONE | `BTC_Freeborn and Anthony Dessauer (@BTC_Freeborn)` — anchor `x.com/BTC_Freeborn`; sha `871638b8…` → `565e6f68…` | +| magazine-056 | G2 | `Red Tail Hawk (@RedTailHawk1923)` / `null` | text only, anchors NONE | `Red Tail Hawk (@RedTailHawk1923)` — anchor `x.com/RedTailHawk1923`; sha `33b55f8f…` → `8094e862…` | +| magazine-070 | I2 | `@MidyReyes` / `null` | text only, anchors NONE | `MidyReyes (@MidyReyes)` — anchor `x.com/MidyReyes`; sha `6227e199…` → `c994e055…` | + +**Recommendation: `magazine-056` (G2) and `magazine-070` (I2) take the handle-only fix — one +account, one `handle` slot, and the build already anchors `contributor.handle` (line 310). +`magazine-035` (G1) is the hard case: handle-only anchors `@BTC_Freeborn` and leaves +`@AnthonyDessauer` unanchored, because `contributor` has exactly one `handle` slot while the byline +names two accounts — and `@AnthonyDessauer` *is* in the registry, so a token for it would be +admitted today. The only instrument that anchors both is `display_name` as a fifth panel carrying +`{{x:AnthonyDessauer}}` beside the handle slot — a build change, Alexander's.** All three live-page +digests reproduce Q24's fix-pack figures to the nibble, so the live tree is still the tree Q24 +measured. + +**Which of Q24's 31 deltas the hardened convention can carry as links: H1–H4 only, 4 of 31.** The +hardening widens no clause's carrier; it makes the four token carriers safe to publish. The +publication precondition the 2026-10-10 18:13Z addendum stated is satisfied on the build side. + +**Nothing touched.** Shared tree still at `97fedb5dd5e85d2…`, its `site-ledger` byte-identical to +this run's scratch build (125 files each, `diff -rq` silent), and +`find /root/stackchain-legends-build -newermt 2026-10-10 18:00 -type f` returns nothing. Live +archive unchanged: `https://alexanderwhitestone.com/stackchain/blocks/` **200 / 34,488 B / sha256 +`4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** at 2026-10-11T00:23:25Z. +`blocks.json` read-only throughout; `decisions/` and `inbox/` untouched, nothing executed, no +another-party file edited. + +## Blocked + +Nothing blocked the run. Two things deliberately **unverified**, both recorded as such in the +deliverable: + +- **The `display_name` fifth panel was measured, not built.** No fifth-panel implementation exists; + the recommendation is a decision input, not a staged change. +- **12 fixtures are the item's own lists plus two extras, not a census of typos.** A sentinel in a + field no entry has today cannot be enumerated from today's data. + +Also outside this run by construction: Q25's census (46 rows / 25 X fetches) is cited, not re-run — +no X page was fetched this tick, so no liveness figure in this check-in is dated by this run. + +## Next + +- **Q20** (excerpt fidelity and placement, the 91 magazine entries) remains the top unclaimed item + and is zephyrus-sparkborn's; I take nothing over it. +- **Alexander's call, not mine:** whether to publish the build change at all. The hardened + prototype is scratch-local and stays there until he says so — the same gate Q13 states. If he + approves the convention, the immediate payload is the 4-of-31 H1–H4 clauses; the `display_name` + fifth panel is a separate, larger decision with exactly one entry (G1) that needs it today. +- **Q7, measured:** Q9 blocked on the audio handover; Q13/Q19 gated on Alexander; Q20 active. The + executable set is empty of unclaimed items, so the never-dry obligation is triggered and a + successor item is owed — I propose none this tick, because Q26 just closed and the successor + should be the pipe's to open on a fresh measurement rather than mine to invent on the same + finding. Stated plainly: this is the second consecutive tick where the set fell to zero and the + successor came from the control plane's own measurement, and that is the pattern worth naming + rather than a gap in the queue. + +## Ask + +1. **Alexander — approve, decline, or defer the prose-anchor convention as a build change.** If + approved, the unit of work is the four H1–H4 clauses plus the hardened prototype; nothing + publishes without a further go. If declined, Q24's 25 clauses stay staged as notes exactly as + they are. +2. **Alexander — the `display_name` fifth slot, G1 only.** Is a second anchor on one byline worth a + build change, or does G1 take the handle-only fix and leave `@AnthonyDessauer` as a name? +3. **Nothing asked of zephyrus-sparkborn this tick.** His lane is Q20; my two asks are both + Alexander's, per §4. diff --git a/recoveries/prose-anchor-hardening.md b/recoveries/prose-anchor-hardening.md new file mode 100644 index 0000000..da1cbb3 --- /dev/null +++ b/recoveries/prose-anchor-hardening.md @@ -0,0 +1,260 @@ +# Q26 — Harden the prose-anchor convention: the two silent token classes die loudly + +**Status: DONE — hardened prototype built, all five Q25 legs re-run green, two negative +test sets (7 malformed tokens, 5 outside-panel sentinels) each dying with its own +message, the `contributor.display_name` fifth slot measured without building it.** +Merlin, 2026-10-11 ~00:20–00:24 UTC. Scratch tree `/root/crucible/q26/`, every artifact +re-runnable from the scripts named in §9. **Nothing published, nothing applied to the +shared build tree; `blocks.json` was read-only throughout.** + +--- + +## 0. Reading rule (unchanged from Q25, restated so the population is re-derivable) + +- **Prose panels** = the fields `render_entry` emits as the archive's own prose and routes + through `expand_prose`: `body` **where `body_kind == "summary"`**, `plain_summary.text`, + `body_provenance`, `uncertainty`. The `body_kind == "quote"` branch renders `body` + through `esc()` inside a blockquote — third-party quoted text, **not a panel**. +- **Token sentinel** = any occurrence of the literal `{{` or `}}` anywhere in an entry. +- **Malformed token** = a `{{x:...}}` in a panel that `TOKEN_RE` + (`\{\{x:([A-Za-z0-9_]{1,15})\}\}`) does not match. +- **Cited handle (validator registry)** = every `contributor.handle` value plus the first + path segment of any `https://x.com/…` or `https://twitter.com/…` URL anywhere in + `blocks.json`, minus reserved account paths. + +## 1. What was hardened, and why + +Q25 left two classes failing silently, both reproduced in the control plane's 2026-10-10 +verification of Q25: + +1. **A malformed token passes the build and prints raw braces.** `expand_prose` returns + `esc(text)` unless the text contains the literal `{{x:`, and the validator only ever + inspects what `TOKEN_RE` matched. So `{{x:saylor}`, `{{x:}}`, `{{ x:saylor }}`, + `{{y:saylor}}` and a 16+ character handle all emitted `Built 123 pages from 121 + entries`, exit 0, with the literal on the page. +2. **A token outside the four panels prints literally** — the quote branch (Q25's own + limit 3), a `title`, an `excerpts[].text`, a `contributor` field, an index + `coverage.gaps` string. Q25's validator could not see any of these. + +The fix is a **pre-write scan**, `check_tokens(b, slug)` plus `check_gaps(data)`, run for +every entry **before a single byte is written** (the scan sits above the `OUT` cleanup in +`build()`, so a `die()` can never leave a half-emitted tree — the Q25 prototype's scan +point would have): + +- any `{{` or `}}` in a field the panels do not render → `die`; +- any sentinel left in a panel after `TOKEN_RE.sub("", obj)` → `die`; +- the panel set is computed **per entry**: `body` is a panel only when + `body_kind == "summary"`, so the quote branch is caught by construction rather than by + a special case. + +Two further changes ride along, both byte-neutral with no token present: + +- `render_genesis` now routes `body_provenance` and `uncertainty` through `expand_prose` + instead of `esc()`. The genesis page previously could not expand a token those panels + carried even though `block-5`'s own page did — a third silent class, found while + writing the positive control, not in Q25's list. +- `coverage.gaps` strings are checked (the index renders them through `esc()`). + +## 2. The diff + +`/root/crucible/q26/DIFF.txt` — `diff -u build_blocks_proto.py build_blocks_hard.py`: +**+70 / −6 lines, 5,817 B.** `DIFF-PRISTINE.txt` — against the shared tree's +`build_blocks.py` (sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`): +**+118 / −11 lines, 9,949 B.** + +The hardened prototype is `build_blocks_hard.py`, **27,878 B / sha256 +`d45cc28f7d69afcdab4eccb16e9e0cc264e4317e059e17f1ba53eb23f792cb60`** (this host, +2026-10-11T00:22Z). The Q25 prototype, copied unchanged into this tree, verified +byte-identical first: sha256 `5af80b78961b4f55ca1ac436c19074d275b9a255569de07156a527de39d8de35`. + +## 3. The five Q25 legs, re-run on the hardened prototype (`Q26-VERIFY.txt`) + +**Leg 1 — no-token build is byte-identical.** Unmodified `blocks.json` (278,459 B / +sha256 `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`, unchanged from +Q25's record): + +``` +$ python3 build_blocks_hard.py +Built 123 pages from 121 entries (121 cleared, 0 research-only) +tree digest: 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +baseline : 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +125 files; BYTE-IDENTICAL to baseline +$ diff -rq /site-ledger /root/stackchain-legends-build/site-ledger +(no output — live tree identical) +``` + +**Leg 2 — the registry is unchanged: 8 handles.** +`@anthonydessauer @arizonanhodl @guiamadogomes @happyclowntime @rockachopa @satskeeper_ +@saylor @yoshishisatoshi` (`REGISTRY.txt`, identical to Q25's). + +**Leg 3 — the uncited-handle negative test still fails closed**, same message: + +``` +$ cd negtest && python3 build_blocks_hard.py # {{x:NotACitedHandle}} in uncertainty +exit 1 +BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites +``` + +**Leg 4 — the token demo is unchanged: 6 deltas (H1–H4 as tokens) → 3 of 125 emitted +files.** + +``` +$ cd tokentest && python3 build_blocks_hard.py +exit 0 Built 123 pages from 121 entries (121 cleared, 0 research-only) +emitted files: 125 -> 125; changed: 3 + event-2022-07-18-the-5-invitation-becomes-a-chain/index.html + magazine-002/index.html + magazine-005/index.html +emitted: event-2022-07-18… https://x.com/AriZonanHODL @AriZonanHODL (x2: body + plain English) +emitted: event-2022-07-18… https://x.com/satskeeper_ @satskeeper_ (x2) +emitted: magazine-002 https://x.com/AriZonanHODL @AriZonanHODL +emitted: magazine-005 https://x.com/AriZonanHODL @AriZonanHODL +``` + +**Leg 5 — the diff itself** (§2). All five legs: **green**. + +## 4. The malformed-token set — 7 fixtures, each in its own tree, each `exit 1` + +Each fixture appends one token to `block-25`'s `uncertainty` (a panel rendered on every +entry). Raw stderr in `MALFORMED.txt`: + +| fixture | token | exit | first stderr line | +|---|---|---|---| +| open brace | `{{x:saylor}` | 1 | `BUILD FAILED: block-25:uncertainty: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with a 1-15 character handle` | +| empty handle | `{{x:}}` | 1 | same, sentinel `{{` | +| whitespace padded | `{{ x:saylor }}` | 1 | same, sentinel `{{` | +| wrong namespace | `{{y:saylor}}` | 1 | same, sentinel `{{` | +| handle over 15 chars | `{{x:abcdefghijklmnopq}}` | 1 | same, sentinel `{{` | +| lone close brace | `}}` | 1 | same, sentinel `}}` | +| close then open | `}}{{x:saylor}}` | 1 | same, sentinel `}}` | + +All seven now die. Under the Q25 prototype all seven built and shipped the literal. + +## 5. The outside-panel sentinel set — 5 fixtures, each `exit 1` + +Each places a **valid** `{{x:saylor}}` where no panel renders it (`OUTSIDE-PANEL.txt`): + +| fixture | field | exit | message | +|---|---|---|---| +| quote branch | `block-6:body` (`body_kind: quote`) | 1 | `token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty)` | +| title | `magazine-001:title` | 1 | `… (panels: body, body_provenance, plain_summary.text, uncertainty)` | +| excerpt text | `magazine-001:excerpts[0].text` | 1 | same | +| contributor display_name | `magazine-035:contributor.display_name` | 1 | same | +| index coverage gap | `coverage.gaps[4]` | 1 | same | + +Note the quote-branch message prints the panel set **without `body`** — the per-entry +`body_kind` rule, visible in the error itself. This fixture is the one Q25's limit 3 +named; it was the only silent class that survived the first pass of the hardening and +the reason the panel set is computed per entry. + +## 6. Positive control — a cited token expands on the entry page *and* the genesis page + +`{{x:AriZonanHODL}}` appended to `block-5`'s `body_provenance` (`positive/`): + +``` +$ cd positive && python3 build_blocks_hard.py +exit 0 Built 123 pages from 121 entries (121 cleared, 0 research-only) +block-5 page anchors: https://x.com/AriZonanHODL -> @AriZonanHODL (x2: panel + contributor slot) +genesis page anchors: https://x.com/AriZonanHODL -> @AriZonanHODL +changed files: 2 [block-5/index.html, genesis/index.html] +``` + +The genesis-page anchor is the §1 wiring change proven: without it the same token would +have expanded on `block-5` and printed raw braces on `genesis/`. A negative test with no +positive control proves nothing, so both are recorded. + +## 7. The `contributor.display_name` fifth slot, measured without building it + +Measured from `blocks.json` and from this run's scratch build (byte-identical to the live +`site-ledger`), per entry, with Q24's staged delta applied in its own scratch tree +(`DISPLAY-NAME-MEASURE.txt`): + +| entry | Q24 clause | `display_name` today | `handle` today | live page today | after Q24's delta | named accounts in registry | +|---|---|---|---|---|---|---| +| magazine-035 | G1 | `@BTC_Freeborn and @AnthonyDessauer` | `null` | `@BTC_Freeborn and @AnthonyDessauer` — anchors: NONE | `BTC_Freeborn and Anthony Dessauer (@BTC_Freeborn)` — anchor `x.com/BTC_Freeborn`; sha256 `871638b8…` → `565e6f68…` | `@BTC_Freeborn` no; `@AnthonyDessauer` **yes** | +| magazine-056 | G2 | `Red Tail Hawk (@RedTailHawk1923)` | `null` | text only — anchors: NONE | `Red Tail Hawk (@RedTailHawk1923)` — anchor `x.com/RedTailHawk1923`; sha256 `33b55f8f…` → `8094e862…` | `@RedTailHawk1923` no | +| magazine-070 | I2 | `@MidyReyes` | `null` | text only — anchors: NONE | `MidyReyes (@MidyReyes)` — anchor `x.com/MidyReyes`; sha256 `6227e199…` → `c994e055…` | `@MidyReyes` no | + +All three live-page digests reproduce Q24's fix-pack figures to the nibble +(`871638b8abb5…`, `33b55f8f61fe…`, `6227e199522f…`), so the live tree is still the tree +Q24 measured. **Recommendation, per entry:** + +- **magazine-056 (G2), magazine-070 (I2): the handle-only fix is the right instrument + and it is complete.** One account named, one `handle` slot; the build already anchors + `contributor.handle` (line 310), and the delta is what admits the handle into the + registry. The convention cannot help — `display_name` is not a panel, and §5 proves a + token there now dies at build time. +- **magazine-035 (G1): handle-only anchors `@BTC_Freeborn` and leaves + `@AnthonyDessauer` unanchored**, because `contributor` has exactly one `handle` slot + while the byline names two accounts — and `@AnthonyDessauer` *is* in the registry, so + a token for it would be admitted today. A wording-only fix (strip both `@`s, as + Q24 stages) loses the link on both. **The only instrument that anchors both is + `display_name` as a fifth panel** carrying `{{x:AnthonyDessauer}}` beside the handle + slot — a build change, which is Alexander's, not a wizard's. + +**Which of Q24's deltas the hardened convention can carry as links: H1–H4 only — 4 of +the 31.** The hardening changes no clause's carrier; it makes the four token carriers +safe to publish. Everything else is a structured field the build already anchors, a note +where the handle is uncited or dead, or a wording call. + +## 8. Findings + +1. **The first hardening pass missed the quote branch, and the error message now shows + why it had to.** A path-based panel set ("`body` is a panel") admits a token in a + quote-kind entry's `body`, where `render_entry` renders it through `esc()`. The panel + set is per entry and depends on `body_kind`; the quote-branch error prints the + reduced set, so the rule is visible in the failure. +2. **The genesis page was a third silent class, not in Q25's list.** `render_genesis` + routed `body_provenance` and `uncertainty` through `esc()`, so a token those panels + carry would expand on the entry's own page and print literally on `genesis/`. + Routing them through `expand_prose` is byte-neutral with no token present (proved by + §3 leg 1) and closes the class. +3. **The scan must run before the output tree is touched.** A `die()` inside the write + loop leaves a half-emitted `site-ledger` behind, which on a shared tree is exactly + the state a reader cannot distinguish from a partial publish. The checks now sit + above the `OUT` cleanup. +4. **A negative test without a positive control proves nothing** — Q25's own incident + note. Leg 6 carries both: a cited token builds, expands, and moves exactly the two + files it should. +5. **The registry is the binding constraint, unchanged.** 8 handles of the 23 the census + found printed in prose; the hardening widens nothing, it only makes the four + carriers safe. +6. **`{{`/`}}` still collide with nothing in `blocks.json`** (0 occurrences), so the + sentinel scan is silent on today's data — the no-token build proves it. + +## 9. Limits + +1. **Prototype only.** `build_blocks_hard.py` lives at `/root/crucible/q26/` and was + never copied into the shared build tree. Verified at close: the shared tree's + `build_blocks.py` is still sha256 + `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`, its + `site-ledger` byte-identical to this run's scratch build (125 files each, + `diff -rq` silent), and `find /root/stackchain-legends-build -newermt 2026-10-10 + 18:00 -type f` returns nothing. The live archive is unchanged: index + `https://alexanderwhitestone.com/stackchain/blocks/` **200 / 34,488 B / sha256 + `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** at + 2026-10-11T00:23:25Z. Publishing a build change is Alexander's, as Q13 states. +2. **7 + 5 fixtures are the test set, not a census of typos.** The malformed set is the + item's own list plus a lone `}}` and a close-then-open; the outside-panel set is one + fixture per field class. A sentinel in a field no entry has today cannot be + enumerated from today's data. +3. **`display_name` was measured, not built.** No fifth panel was implemented; the + recommendation is a decision input, not a staged change. +4. **Nothing re-tests Q25's census.** The 46-row population, the 25 X fetches and their + liveness verdicts are Q25's, cited not re-run. +5. **X byte sizes are dated readings** (per-request CSP nonce); none is load-bearing + here — no X page was fetched this run. + +## 10. Scripts (all re-runnable, `/root/crucible/q26/`) + +`verify26.py` (all eight legs) · `display_name.py` (the fifth-slot measurement) · +`clean.py` (scratch reset) · `build_blocks_hard.py` (the hardened prototype) · +`build_blocks_proto.py`, `build_blocks.py`, `blocks.json` (inputs, unmodified). + +Artifacts: `DIFF.txt` (+70/−6 vs the Q25 prototype) · `DIFF-PRISTINE.txt` (+118/−11 vs +the shared build script) · `NOTOKEN-BUILD.txt` (digest `91ecf6bf…`, 125 files, live-tree +diff silent) · `REGISTRY.txt` (8) · `NEGTEST.txt` (exit 1) · `TOKEN-DIFF.txt`, +`TOKEN-PAGES.txt` (3 of 125 files, 6 emitted anchors) · `MALFORMED.txt` (7 fixtures) · +`OUTSIDE-PANEL.txt` (5 fixtures) · `POSITIVE.txt` (2 changed files) · +`DISPLAY-NAME-MEASURE.txt` · `Q26-VERIFY.txt` / `Q26-VERIFY-run.txt` (full run log) · +scratch trees `negtest/`, `tokentest/`, `positive/`, `mal-*/`, `out-*/`, `dn-*/`.