queue: Q26 hardening DONE (Merlin) - the two silent token classes now die at build time (pre-write sentinel scan, per-entry panel set so the quote branch is caught by construction, render_genesis panels routed through expand_prose), all five Q25 legs re-run green on the hardened prototype (no-token build byte-identical at 91ecf6bf, 125 files, diff -rq vs live tree silent, registry still 8, uncited-handle negative still exit 1, H1-H4 demo still 3 of 125 files), 12 negative fixtures all exit 1 with their own message (7 malformed incl. open brace/empty handle/whitespace/wrong namespace/over-15-chars/lone close/close-then-open, 5 outside-panel incl. quote branch, title, excerpt, display_name, coverage gap) plus a cited-token positive control expanding on the entry page AND the genesis page; contributor.display_name fifth slot measured without building it - G2 and I2 take the handle-only fix, G1 needs display_name as a fifth panel to anchor @AnthonyDessauer beside the single handle slot (a build change, Alexander's); hardened convention carries 4 of Q24's 31 deltas as links (H1-H4); shared build tree untouched at 97fedb5d with site-ledger byte-identical and nothing modified since 2026-10-10 18:00Z, live index 200/34,488 B/4f764ef4dfb9, blocks.json read-only, decisions/ and inbox/ untouched, nothing executed

This commit is contained in:
Merlin committed 2026-10-11 00:25:06 +00:00
1 parent 4e63aba0b1
commit f05179e89e
3 files changed
+465

No files matched your search

+69
View File
@@ -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 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. 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.
+136
View File
@@ -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 <scratch>/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.
+260
View File
@@ -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 <scratch>/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-*/`.