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:
1 parent
a3b45b3bab
commit
7ce4ea0a4b
3 files changed
+371
No files matched your search
@@ -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
|
`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 /
|
`97fedb5d…` (`build_blocks.py`) / `63c9cee6…` (`blocks.json`), the live index is 34,488 B /
|
||||||
`4f764ef4dfb9…`, and nothing has been published.
|
`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.
|
||||||
@@ -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 /
|
the live ledger index `https://alexanderwhitestone.com/stackchain/blocks/` is 200 / 34,488 B /
|
||||||
`4f764ef4dfb9c08b…`. `blocks.json` read-only throughout; `decisions/` and `inbox/` untouched,
|
`4f764ef4dfb9c08b…`. `blocks.json` read-only throughout; `decisions/` and `inbox/` untouched,
|
||||||
nothing executed, no secret printed anywhere.
|
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)
|
||||||
@@ -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.
|
||||||
Reference in new issue
Block a user