queue: Q28 render-site channels DONE (Merlin) - 20 channels, 13 by fixture (19 fixtures, every negative exit 1 with 0 writes), 7 measured exclusions; the walk is the guarantee restated in one sentence; the no-token control byte-identical at 91ecf6bf with 125 files; two corrections in prose (36 esc call lines / 43 occurrences, not 28; Q27's fixture breakdown sums to 41-42 against its own 35-row log); shared tree untouched at 97fedb5d / 63c9cee6, live index 200 / 34,488 B / 4f764ef4dfb9; nothing executed

This commit is contained in:
Merlin committed 2026-10-11 04:40:31 +00:00
1 parent a3b45b3bab
commit 7ce4ea0a4b
3 files changed
+371

No files matched your search

+53
View File
@@ -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); `</script><b>hi</b>`
in `title` ships as `<\/script>` (the JSON-LD channel is watched by `json.dumps` + `</`-escape,
not the sentinel — a different class, stated); a cited token in `block-5`'s `body_provenance`
expands on **both** landings — exactly 2 files change, 1 anchor each.
- **Control:** unmodified `blocks.json` (`63c9cee6…`) through the patched builder
(`c4127c6c…`): exit 0, 125 files, tree digest
`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`, `diff -rq` against the
shared `site-ledger` silent.
- **Two corrections, stated in prose (Q27's file corrected by reference, never by edit):**
the pristine builder has **36 `esc()` call lines / 43 call occurrences**, not 28 (measured:
lines containing `esc(` minus the `def esc(v):` at :87 → 36; occurrence count minus the
definition's → 43); and Q27's stated fixture breakdown sums to **41 — 42 counting the omitted
`excl:contributor.handle` row — against its own 35-row log** (`Q27-RESULTS.json`: 35 rows,
5 × exit 0 / 125 files, 30 × exit 1 / 0 files).
- **The one Q27 exclusion reason falsified by measurement:** `slug_for()`'s sanitisation is
real but irrelevant — the walk kills the token one step earlier, so "sanitised out" is not
the guard (the pipe's C4 holds; re-measured here). Conversely the label-staged branch's "no
entry takes it" is true today and false as an exclusion reason: flipping one entry builds it.
- **Nothing touched:** shared tree still `97fedb5d…` / `63c9cee6…` (nothing modified since
2026-10-11 02:00Z), live index **200 / 34,488 B / `4f764ef4dfb9c08b…`** re-fetched this run,
`decisions/` and `inbox/` untouched, nothing executed, no other party's file edited. The
publish precondition stands unchanged: **adopt `c4127c6c` into the shared build tree first,
then publish** — Alexander's call, not this item's.
- **Limits:** the 16 negatives die at the sentinel walk by construction, so they demonstrate
the channels, not a shape census (Q26's 12-fixture set is the shape census); the `OUT`-is-`site/`
guard is source-read only (`OUT` is hardcoded, so the comparison cannot fire without editing
the builder); Q25's census is cited, not re-run; no X page fetched this tick.
+133
View File
@@ -255,3 +255,136 @@ Re-verified in the same breath: shared `build_blocks.py` still `97fedb5dd5e85d2
the live ledger index `https://alexanderwhitestone.com/stackchain/blocks/` is 200 / 34,488 B /
`4f764ef4dfb9c08b…`. `blocks.json` read-only throughout; `decisions/` and `inbox/` untouched,
nothing executed, no secret printed anywhere.
---
# Run 3 — Q28, claimed and finished (the channels the entry walk cannot see)
> 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; `</script><b>hi</b>` in `title` ships as
`<\/script>` (the JSON-LD channel's guard is the `json.dumps` + `</`-escape, not the sentinel —
a different class, stated); a cited token in `block-5`'s provenance expands on **both** landings,
2 files changed, 1 anchor each.
The 7 exclusions, each measured: `CSS`/`FOOT` literals (grep of definition + usage sites, plus
`grep -c '\.format(' build_blocks_hard.py` → **0**); receipt row keys (the only `esc(k)`, over a
hardcoded tuple); dict keys (`walk(v, …)` recurses on values only); the `OUT`-is-`site/` guard
(source-read — `OUT` is hardcoded to `BASE/"site-ledger"`, so the comparison cannot fire without
editing the builder); the write set (**125 files, intersection with `PROTECTED` = `[]`**); the
manifest (124 file entries, every value `{"sha256","bytes"}` only); `coverage` keys other than
`gaps` (four grep lines, all `coverage.gaps` — the rest is unrendered data).
Two corrections stated in prose, Q27's file corrected by reference only: the pristine builder
has **36 `esc()` call lines / 43 call occurrences**, not 28 (measured — 37 lines contain `esc(`
including the definition, 44 occurrences including it); and Q27's stated fixture breakdown sums
to **41 — 42 with the omitted `excl:contributor.handle` row — against its own 35-row log**
(`Q27-RESULTS.json`: 35 rows, 5 × exit 0 / 125 files, 30 × exit 1 / 0 files). One Q27 exclusion
reason is falsified by measurement: `slug_for()`'s sanitisation is real but irrelevant — the walk
kills the token one step earlier.
## Blocked
Nothing blocked the run. Limits, stated in the deliverable: the 16 negatives die at the sentinel
walk *by construction*, so they demonstrate the channels, not a shape census (Q26's 12-fixture
set is the shape census and is not re-run); the `OUT`-is-`site/` guard is source-read, not
fixture-tested; Q25's census (46 rows / 25 X fetches) is cited, not re-run — no X page was
fetched this tick; all digests are dated readings from this host at the run clocks, and the
control's byte-identity to the live `site-ledger` is what anchors the fixture set to production.
Three defects of my own, logged first in the deliverable: the first harness run died
`not found: block-5 None` because the receipt entries carry no `slug` (`slug_for` derives
`block-5` from `n`) — fixed with an `n=` selector; the first `protected-clash` fixture ran the
build before planting the file and reported exit 0 / 125 files — restructured so the plant
precedes the build; and `slug-sentinel`'s `x:slug:` die message is an artifact of the fixture,
recorded as finding 2 rather than normalised away.
## Next
- **Alexander's call, not mine:** publish, hold, or decline the patched builder. The ordering
guard is now checkable rather than a wait — **adopt `c4127c6c` into the shared build tree
first, then publish** — and Q28's result is the one-sentence guarantee that publish decision
can be taken on.
- **Q20** remains the top unclaimed item and is zephyrus-sparkborn's; I take nothing over it.
- **Q7, measured:** Q20 open (zephyrus's); Q9 blocked on the audio handover; Q13/Q19 gated on
Alexander; Q26/Q27/Q28 all gated on the same publish decision. The unclaimed executable set
is empty again; a successor is owed, and this record opens none — the successor should come
from a fresh measurement, not from this run's own finding.
## Ask
1. **Alexander — adopt `c4127c6c` into the shared build tree, or hold?** It is the difference
between an uncited-token failure leaving 20 files on disk and leaving 0, plus Q28's
one-sentence guarantee. Scratch until you say so.
2. **Nothing asked of zephyrus-sparkborn this tick.** His lane is Q20.
## Run detail — Q28
**Clock and host.** All fixtures and the control from this host, 2026-10-11 ~04:0x–04:2x UTC.
Working tree `/root/crucible/q28/` (19 fixture trees under `fixtures/`, control build in the
scratch root, every body kept beside the scripts). Repo at `/root/troupe-standup`, branch
`main`, HEAD before this run `a3b45b3`, working tree clean.
**Scripts, all re-runnable.** `q28-probe.py` (data facts), `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`.
**Data facts measured before any fixture** (`q28-probe.py`): 121 entries; publication_status
121 × `cleared`, 0 research-only; ledger 5 block / 3 dollar_receipt / 22 timeline / 91 magazine;
status 115 documented / 5 testimony_only / 1 corroborated; 113 entries carry `sort_date`, 112
`date`, 113 are `body_kind: summary`, 1 is the quote branch; `coverage.gaps` holds 4 strings.
**Counts, recomputed not accepted.** 19 fixtures (16 negative / 3 positive); 7 exclusions; 2
corrections. Negatives: 16 × exit 1, 0 builder writes. Positives: 3 × exit 0, 125 files.
Control: exit 0, 125 files, digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`,
`diff -rq` vs `/root/stackchain-legends-build/site-ledger` silent.
**Live archive, re-measured this run:**
`https://alexanderwhitestone.com/stackchain/blocks/` → **200 / 34,488 B / sha256
`4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`**. Shared tree:
`build_blocks.py` still `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`,
`blocks.json` `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`,
`find /root/stackchain-legends-build -newermt '2026-10-11 02:00' -type f` → nothing.
`decisions/` and `inbox/` untouched; nothing executed; no other party's file edited.
Files written this run:
- `recoveries/render-site-channels.md` (new — the deliverable)
- `WORK-QUEUE.md` (Q28 status block → DONE)
- `checkins/2026-10-11-merlin.md` (this section)
+185
View File
@@ -0,0 +1,185 @@
# Q28 — The channels the entry walk cannot see
*Merlin, 2026-10-11. Scratch tree `/root/crucible/q28/`; builder `build_blocks_hard.py`
(sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2`, 29,174 B — the
Q27 scope-clause patch, copied in byte-identical and verified). `blocks.json`
(`63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`, 278,459 B) read-only.
Nothing published, nothing staged, no shared-tree edit, no `decisions/` or `inbox/` action.*
## The guarantee, in one sentence
**Any string containing `{{` or `}}` anywhere inside a `blocks.json` entry — at any nesting
depth, in any field, checked before a single byte is written — kills the build; the only
tokens that ever ship are well-formed `{{x:HANDLE}}` tokens inside the four prose panels of
a summary-branch entry naming a handle the ledger cites somewhere.**
The three guards that enforce it, printed from `build_blocks_hard.py`:
```
:192-225 check_tokens(b, slug) — walk(b, "") recurses dicts/lists; a string with a
sentinel dies unless its path is in panels_for(b),
then dies again if TOKEN_RE leaves residue.
:228-234 check_gaps(data) — the one non-entry string channel: coverage.gaps[i].
:151-169 check_uncited(b, slug, cited)
— same TOKEN_RE scan, same message as expand_prose's
die(), run above OUT.mkdir so no partial tree.
:204 walk(v, ...) — recurses on the VALUE only; keys are never visited.
:292-304 build() — check_gaps, then check_tokens and check_uncited over
every entry, all above OUT.mkdir / the rmtree.
```
## Result
**20 channels: 13 covered by fixture (19 fixtures), 7 excluded with a measured command.**
Every negative fixture exits 1 and writes **0 files**; the one fixture whose output directory
holds a file at failure (`protected-clash`) holds the file *it planted*, which the guard
refused to clean — the builder itself wrote nothing. The no-token control is byte-identical
to the live `site-ledger` (digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`,
125 files, `diff -rq` silent).
## The channel table
Each fixture is a fresh scratch tree: patched builder + one mutated `blocks.json`. Columns:
channel · guard · fixture · exit · files written · first stderr line. Malformed token `{{x:`
unless stated; cited token `{{x:arizonanhodl}}`; uncited `{{x:NotACitedHandle}}`.
| # | channel | guard | fixture | exit | files | first stderr line |
|---|---|---|---|---|---|---|
| 1 | `coverage.gaps[i]` — index Known-gaps list | `check_gaps` | `gaps-sentinel` | 1 | 0 | `coverage.gaps[0]: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty)` |
| 2 | `slug_for()` → canonical href | walk (`slug`) | `slug-sentinel` | 1 | 0 | `x:slug: token sentinel {{ in a field that is not a prose panel` |
| 3 | `slug_for()` → sitemap `loc` | walk (`slug`) | `slug-sentinel` | 1 | 0 | *(same fixture — one slug feeds all four slug-derived landings)* |
| 4 | `slug_for()` → index `li` id | walk (`slug`) | `slug-sentinel` | 1 | 0 | *(same fixture)* |
| 5 | `slug_for()` → pager hrefs | walk (`slug`) | `slug-sentinel` | 1 | 0 | *(same fixture)* |
| 6 | `sortable[:4]` → index year heading | walk (`sort_date`) | `sortdate-sentinel` | 1 | 0 | `magazine-001:sort_date: token sentinel {{ in a field that is not a prose panel` |
| 7 | `esc(prev/nxt["n"])` → pager link text | walk (`n`) | `pager-n` | 1 | 0 | `magazine-002:n: token sentinel {{ in a field that is not a prose panel` |
| 8 | `safe_url()` → `body_source_url`, non-https shape | `safe_url` | `url-nonhttps` | 1 | 0 | `block[30]: source URL must be https, got '{{x:'` |
| 9 | `body_source_url`, https-with-token shape | walk | `url-https-token` | 1 | 0 | `magazine-001:body_source_url: token sentinel {{ in a field that is not a prose panel` |
| 10 | receipt arithmetic formatted strings (`f'${usd}'`, `f'{price}'`, `f'{calc:,} sats'`) | walk (`receipt.usd`) | `receipt-usd` | 1 | 0 | `block-5:receipt.usd: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty)` |
| 11 | `title` — head `<title>`, 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` = `</script><b>hi</b>` | 0 | 125 | the JSON-LD channel's guard is the `json.dumps` + `</`-escape, **not** the sentinel: the page carries `<\/script>` and no raw `</script><b>`. 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` + `</`-escaping (:362) means a
`</script>` 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.