queue: Q27 render-site coverage DONE (Merlin)
32 emit sites in build_blocks.py enumerated from the source (28 esc calls plus the 4 prose panels): 28 covered by fixture, 4 stated structural exclusions. 35 fixtures, every negative exit 1 with 0 files written (4 valid-panel builds expand, 12 malformed-panel dies, 4 uncited dies, 10 non-panel field dies, 2 URL-field dies, 3 class-field dies, head/index/pager/gap/genesis, 1 no-token control). URL-field scope decided: a token in a URL must die - safe_url rejects the non-https body_source_url value, the pre-write sentinel scan catches the https-with-token and excerpt cases, all exit 1 with 0 files. The queue's scope clause closed with option (a): check_uncited() runs above OUT.mkdir so all four token classes are pre-write (the uncited fixture wrote 20 files before the patch, 0 after, same message). No-token build still byte-identical at 91ecf6bf (125 files, diff -rq vs the shared site-ledger silent). Shared tree untouched at 97fedb5d with blocks.json 63c9cee6; live index 200 / 34,488 B / 4f764ef4dfb9. Patched builder c4127c6c is scratch-local, nothing staged; decisions/ and inbox/ untouched.
This commit is contained in:
1 parent
179adc397e
commit
08013ba55a
3 files changed
+295
No files matched your search
@@ -3234,3 +3234,12 @@ where it is. This is a scope clause on Q27 — not a new item, and not a reopeni
|
|||||||
silent classes die loudly, with the fixture set and both negative classes proving it) is met and verified.
|
silent classes die loudly, with the fixture set and both negative classes proving it) is met and verified.
|
||||||
To be carried in the next reply to Merlin.
|
To be carried in the next reply to Merlin.
|
||||||
|
|
||||||
|
**Status: DONE 2026-10-11 — `recoveries/render-site-coverage.md` (Merlin). 32 sites: 28 covered by fixture, 4 structural exclusions; 35 fixtures, every negative writes 0 files; the scope clause closed with option (a), all four token classes now pre-write; no-token build still byte-identical at `91ecf6bf`.**
|
||||||
|
- **Site inventory, enumerated from the source not the data:** 32 named sites — 28 `esc()` calls that render a `blocks.json` value plus the 4 prose panels — each with its `build_blocks.py` line number, field and landing. One row per site in the deliverable's row table: fixture (class), exit code, files-written-at-failure, first stderr line.
|
||||||
|
- **Fixtures (35):** 4 valid-panel builds (`{{x:arizonanhodl}}` cited, expands — 4 anchors on `magazine-001`, leg 4), 12 malformed-panel dies, 4 uncited dies, 10 non-panel field dies (`title`, `date`, `date_display`, `date_basis`, `contributor.display_name`, `excerpts[0].text`, `receipt.reuse_status`, …), 2 URL-field dies, 3 class-field dies (`status`/`ledger` die at entry validation: `unknown status '{{x:'`; `variant` at the sentinel scan), head-block JSON-LD author, index label/date, pager `n`, coverage gap, genesis body, 1 no-token control. **Every negative fixture exits 1 with 0 files written.**
|
||||||
|
- **URL-field scope decision — a token in a URL field must die**, measured both ways (`URL-CHECK.txt`): `body_source_url` non-https → `safe_url` fires (`must be https, got '{{x:'`); https-with-token → sentinel scan fires (`token sentinel {{ in a field that is not a prose panel`); `excerpts[].url` (no `safe_url`) → sentinel scan. All exit 1, 0 files.
|
||||||
|
- **Scope clause closed with option (a).** New `check_uncited()` (plus shared `panels_for()`), same `TOKEN_RE` scan and same message as `expand_prose`'s `die()`, runs **above `OUT.mkdir`**; `expand_prose` keeps the check as a backstop behind `pre_checked=True`. Measured: the `{{x:NotACitedHandle}}`-in-`uncertainty` fixture wrote **20 files** before the patch and **0** after — same message both times. All four token classes (sentinel, malformed, uncited, gap) are now pre-write.
|
||||||
|
- **Control:** unmodified `blocks.json` (`63c9cee6…`) through the patched builder → exit 0, **125 files, tree digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** (the Q26 baseline), `diff -rq` against the shared `site-ledger` silent. Shared tree untouched: `build_blocks.py` still `97fedb5dd5e85d2…`, `blocks.json` `63c9cee6…`, nothing modified since 2026-10-10 18:00Z. Live index `200 / 34,488 B / 4f764ef4dfb9c08b…`.
|
||||||
|
- **Scratch only, not staged.** Patched builder `build_blocks_hard.py` sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2` (29,174 B, diff `DIFF-SCOPE.txt` +65/−12) lives in `/root/crucible/q27/`; publishing it is Alexander's, the same gate Q26/Q13 state.
|
||||||
|
- **Testimony only:** none — every figure in this record came from a command in this run; the live index was fetched this run.
|
||||||
|
- **Q7, measured:** Q20 active (zephyrus-sparkborn's); Q9 blocked on the audio handover; Q13/Q19 gated on Alexander. The unclaimed executable set is empty again, so a successor is owed; this record does not open one.
|
||||||
@@ -156,3 +156,83 @@ Re-verified in the same breath: the shared build tree's `build_blocks.py` is sti
|
|||||||
`https://alexanderwhitestone.com/stackchain/blocks/` is 200 / 34,488 B /
|
`https://alexanderwhitestone.com/stackchain/blocks/` is 200 / 34,488 B /
|
||||||
`4f764ef4dfb9c08b…`. `blocks.json` was read-only throughout; `decisions/` and `inbox/` were not
|
`4f764ef4dfb9c08b…`. `blocks.json` was read-only throughout; `decisions/` and `inbox/` were not
|
||||||
touched and nothing was executed.
|
touched and nothing was executed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run 2 — Q27: render-site coverage, and the scope clause closed (Merlin, 2026-10-11 ≈02:30 UTC)
|
||||||
|
|
||||||
|
### Did
|
||||||
|
|
||||||
|
Claimed and finished **Q27 — a fixture at every render site** (the top unclaimed item; Q20 is
|
||||||
|
zephyrus-sparkborn's, Q9 blocked on the audio handover, Q13/Q19 gated on Alexander). The item is
|
||||||
|
Q26 §9 limit 2's honest answer: Q26 proved 12 token classes die, not that every emit site is
|
||||||
|
watched.
|
||||||
|
|
||||||
|
Deliverable: `recoveries/render-site-coverage.md` (**20,865 B / sha256
|
||||||
|
`34716145492bd265cceb9cded8363f0a59a057862e1c90f74625e93b39d51ac1`**, this host). Scratch tree
|
||||||
|
`/root/crucible/q27/` (35 fixture trees under `fixtures/`, verify trees under `verify/`, re-runnable
|
||||||
|
with `python3 q27-fixtures.py` then `python3 q27-verify.py`).
|
||||||
|
|
||||||
|
**32 sites, enumerated from the source, not the data:** 28 `esc()` calls that render a `blocks.json`
|
||||||
|
value plus the 4 prose panels, each with its `build_blocks.py` line number, field and landing.
|
||||||
|
One row per site in the deliverable — fixture class, exit code, files-written-at-failure, first
|
||||||
|
stderr line. **28 covered by fixture, 4 structural exclusions** (`slug`/canonical: `slug_for()`
|
||||||
|
sanitises `{{` out; `year`: a 4-char slice; sitemap `loc`: same sanitised slug; `contributor.handle`:
|
||||||
|
an account name interpolated into a URL by construction — and it still carries a die-fixture).
|
||||||
|
Every exclusion is a stated reason, not "no entry does".
|
||||||
|
|
||||||
|
**35 fixtures, every negative writes 0 files.** 4 valid-panel builds (`{{x:arizonanhodl}}` cited →
|
||||||
|
expands; 4 anchors on `magazine-001`, moves nothing else), 12 malformed-panel dies, 4 uncited dies,
|
||||||
|
10 non-panel field dies (`title`, `date`, `date_display`, `date_basis`, `contributor.display_name`,
|
||||||
|
`excerpts[0].text`, `receipt.reuse_status`, …), 2 URL-field dies, 3 class-field dies (`status`/`ledger`
|
||||||
|
die at entry validation — `unknown status '{{x:'`; `variant` at the sentinel scan), head-block
|
||||||
|
JSON-LD author, index label/date, pager `n`, coverage gap, genesis body, 1 no-token control.
|
||||||
|
|
||||||
|
**URL-field scope decision — a token in a URL field must die**, measured both ways (`URL-CHECK.txt`):
|
||||||
|
`body_source_url` non-https → `safe_url` fires (`must be https, got '{{x:'`); https-with-token →
|
||||||
|
sentinel scan fires; `excerpts[].url` (never passed through `safe_url`) → sentinel scan. All exit 1,
|
||||||
|
0 files.
|
||||||
|
|
||||||
|
**The scope clause closed with option (a).** New `check_uncited()` beside a shared `panels_for()`,
|
||||||
|
running the same `TOKEN_RE` scan and the same message as `expand_prose`'s `die()`, **above
|
||||||
|
`OUT.mkdir`**; `expand_prose` keeps the check as a backstop behind `pre_checked=True`. Measured: the
|
||||||
|
`{{x:NotACitedHandle}}`-in-`uncertainty` fixture wrote **20 files** before the patch and **0** after —
|
||||||
|
same message both times (`BUILD FAILED: magazine-001:uncertainty: prose-anchor token names handle
|
||||||
|
@NotACitedHandle which no entry cites`). **All four token classes are now pre-write**, so the
|
||||||
|
partial-tree state the clause reproduced cannot arise from any of them. Patched builder
|
||||||
|
`build_blocks_hard.py` sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2`
|
||||||
|
(29,174 B; diff `DIFF-SCOPE.txt`, +65/−12 over the Q26 prototype `d45cc28f…`).
|
||||||
|
|
||||||
|
**Control:** unmodified `blocks.json` (`63c9cee6…`) through the patched builder → exit 0, **125 files,
|
||||||
|
tree digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** (the Q26 baseline),
|
||||||
|
`diff -rq` against the shared `site-ledger` silent (leg 8). Leg 3: an uncited token in a
|
||||||
|
quote-branch `body` dies at `check_tokens` first (correct ordering — the sentinel class is the wider
|
||||||
|
net). Leg 7: the `pre_checked=False` backstop still dies on the same fixture.
|
||||||
|
|
||||||
|
**Nothing touched.** Shared tree at `97fedb5dd5e85d2…` / `blocks.json` `63c9cee6…`, nothing modified
|
||||||
|
since 2026-10-10 18:00Z (leg 9). Live archive unchanged: `https://alexanderwhitestone.com/stackchain/blocks/`
|
||||||
|
**200 / 34,488 B / sha256 `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** at
|
||||||
|
2026-10-11 ≈02:31 UTC. `blocks.json` read-only throughout; `decisions/` and `inbox/` untouched,
|
||||||
|
nothing executed, no another-party file edited. Patched builder is scratch-local and stays there.
|
||||||
|
|
||||||
|
### Blocked
|
||||||
|
|
||||||
|
Nothing blocked the run. Deliberately unverified, recorded as such: the 4 structural exclusions are
|
||||||
|
**reasoned from the source, not fuzzed** — no random-token fuzzer ran against the builder, so "no
|
||||||
|
`{{` can survive `slug_for()`" is a code-reading claim backed by the sanitising regex
|
||||||
|
(`[^a-z0-9-]+` → `-`, build_blocks.py:93) and the 4-char slice (`sortable[:4]`), not by a fixture.
|
||||||
|
|
||||||
|
### Next
|
||||||
|
|
||||||
|
- **Alexander's call, not mine:** whether to publish the patched builder (the scope-clause close is
|
||||||
|
a real behavioural change: uncited-handle failures can no longer leave a partial tree). Scratch
|
||||||
|
until he says so — the same gate Q26/Q13 state.
|
||||||
|
- **Q7, measured:** Q20 active (zephyrus's); Q9 blocked on the audio handover; Q13/Q19 gated on
|
||||||
|
Alexander. The unclaimed executable set is empty again, so a successor is owed; this record opens
|
||||||
|
none — the successor should come from a fresh measurement, not from this run's own finding.
|
||||||
|
|
||||||
|
### Ask
|
||||||
|
|
||||||
|
1. **Alexander — publish, hold, or decline the scope-clause close.** It is the difference between
|
||||||
|
"20 files written on an uncited-token failure" and "0", on a prototype that is not in production.
|
||||||
|
2. **Nothing asked of zephyrus-sparkborn this tick.** His lane is Q20.
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
# Q27 — render-site coverage: every emit site in build_blocks.py, one fixture each
|
||||||
|
|
||||||
|
Author: Merlin. Run: 2026-10-11, scratch tree `/root/crucible/q27/` (all 35 fixture trees under
|
||||||
|
`fixtures/`, verify trees under `verify/`; re-runnable with `python3 q27-fixtures.py` then
|
||||||
|
`python3 q27-verify.py`). Nothing published, no `blocks.json` edit, nothing staged.
|
||||||
|
|
||||||
|
Builder under test: `/root/crucible/q27/build_blocks_hard.py` — the Q26 prototype
|
||||||
|
(`d45cc28f7d69afcdab4eccb16e9e0cc264e4317e059e17f1ba53eb23f792cb60`, 27,878 B) plus this item's
|
||||||
|
scope-clause patch: **sha256 `c4127c6c9325ed9f8cab03b80b454cccde0f9f1e768289ff216d2fb79e78dbf2`**,
|
||||||
|
**29,174 B**. Diff `DIFF-SCOPE.txt` (77 lines, +65/-12). Pristine shared-tree builder
|
||||||
|
`97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672` — untouched (leg 9).
|
||||||
|
|
||||||
|
## Method
|
||||||
|
|
||||||
|
Every string the build emits comes from one of **32 named sites**: 28 `esc()` calls that render a
|
||||||
|
`blocks.json` value, plus the 4 prose panels (whose pristine `esc()` calls the Q26 prototype
|
||||||
|
routes through `expand_prose`). Sites are enumerated from the source with line numbers, not from
|
||||||
|
today's data, which is the difference between this item and Q26's §9 limit 2. Each site gets
|
||||||
|
either a fixture — a valid `{{x:<cited-handle>}}` and/or a malformed `{{x:` token placed in that
|
||||||
|
field, with the raw exit code and first stderr line — or a stated structural reason no entry can
|
||||||
|
carry one there today.
|
||||||
|
|
||||||
|
Fixture tokens: valid `{{x:arizonanhodl}}` (a cited handle), malformed `{{x:`, uncited
|
||||||
|
`{{x:NotACitedHandle}}`. Fixtures apply to `magazine-001` (a summary-branch magazine entry with
|
||||||
|
contributor, 3 excerpts, receipt-less), `magazine-002` (pager neighbour), entry `n=5` (block-5,
|
||||||
|
genesis, `body_kind` null → quote branch) and entry `n=6` (block-6, `body_kind: quote`).
|
||||||
|
|
||||||
|
## Row table — one row per render site
|
||||||
|
|
||||||
|
| site | build_blocks.py line | field | fixture (class) | exit · files | first stderr line |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| S01 | 215 | `title` | nonpanel:title | 1·0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_sum |
|
||||||
|
| S02 | 216 | `title (as desc)` | nonpanel:title | 1·0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_sum |
|
||||||
|
| S03 | 217 | `slug (via slug_for)` | **structural exclusion** — no entry field reaches it | — | see below |
|
||||||
|
| S04 | 208 | `ld object` | head:jsonld-author | 1·0 | BUILD FAILED: magazine-001:contributor.display_name: token sentinel {{ in a field that is not a prose panel (panels: body, body_pr |
|
||||||
|
| S05 | 238 | `status` | class:status | 1·0 | BUILD FAILED: block[30] unknown status '{{x:' |
|
||||||
|
| S06 | 239 | `ledger` | class:ledger | 1·0 | BUILD FAILED: block[30] unknown ledger '{{x:' |
|
||||||
|
| S07 | 241 | `variant` | class:variant | 1·0 | BUILD FAILED: magazine-001:variant: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_s |
|
||||||
|
| S08 | 263 | `receipt (k,v)` | nonpanel:receipt.reuse_status | 1·0 | BUILD FAILED: block-5:receipt.reuse_status: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain |
|
||||||
|
| S09 | 266 | `receipt.reuse_status` | nonpanel:receipt.reuse_status | 1·0 | BUILD FAILED: block-5:receipt.reuse_status: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain |
|
||||||
|
| S10 | 297 | `title / n` | nonpanel:title | 1·0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_sum |
|
||||||
|
| S11 | 299 | `title` | nonpanel:title | 1·0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_sum |
|
||||||
|
| S12 | 303 | `date_display / date` | nonpanel:date_display | 1·0 | BUILD FAILED: magazine-001:date_display: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, pl |
|
||||||
|
| S13 | 303 | `date_basis` | nonpanel:date_basis | 1·0 | BUILD FAILED: magazine-001:date_basis: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plai |
|
||||||
|
| S14 | 286 | `date` | nonpanel:date | 1·0 | BUILD FAILED: magazine-001:date: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summ |
|
||||||
|
| S15 | 308 | `contributor.display_name` | nonpanel:contributor.display_name | 1·0 | BUILD FAILED: magazine-001:contributor.display_name: token sentinel {{ in a field that is not a prose panel (panels: body, body_pr |
|
||||||
|
| S16 | 310 | `contributor.handle` | **structural exclusion** (fixture `excl:contributor.handle` still dies) | exit 1 · 0 | see below |
|
||||||
|
| S17 | 325 | `body (quote branch)` | genesis:body | 1·0 | BUILD FAILED: block-5:body: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, u |
|
||||||
|
| S18 | 323 | `body_source_url` | url-field:body_source_url | 1·0 | BUILD FAILED: magazine-001:body_source_url: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, |
|
||||||
|
| S19 | 333 | `excerpts[].url` | url-field:excerpts[0].url | 1·0 | BUILD FAILED: magazine-001:excerpts[0].url: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, |
|
||||||
|
| S20 | 335 | `excerpts[].text` | nonpanel:excerpts.0.text | 1·0 | BUILD FAILED: magazine-001:excerpts[0].text: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance |
|
||||||
|
| S21 | 351 | `n (prev)` | pager:n | 1·0 | BUILD FAILED: magazine-002:n: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary |
|
||||||
|
| S22 | 356 | `n (next)` | pager:n | 1·0 | BUILD FAILED: magazine-002:n: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary |
|
||||||
|
| S23 | 384 | `title` | index:label | 1·0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_sum |
|
||||||
|
| S24 | 395 | `date/sort_date[:4]` | **structural exclusion** — no entry field reaches it | — | see below |
|
||||||
|
| S25 | 398 | `date_display / date` | index:date | 1·0 | BUILD FAILED: magazine-001:date_display: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, pl |
|
||||||
|
| S26 | 405 | `coverage.gaps[]` | index:coverage.gaps | 1·0 | BUILD FAILED: coverage.gaps[4]: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summa |
|
||||||
|
| S27 | 325 | `body (genesis)` | genesis:body | 1·0 | BUILD FAILED: block-5:body: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, u |
|
||||||
|
| S28 | 182 | `slug` | **structural exclusion** — no entry field reaches it | — | see below |
|
||||||
|
| S29 | 317 | `body (summary)` | panel-malformed:body | 1·0 / 1·0 | BUILD FAILED: magazine-001:body: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly { |
|
||||||
|
| S30 | 340 | `plain_summary.text` | panel-malformed:plain_summary.text | 1·0 / 1·0 | BUILD FAILED: magazine-001:plain_summary.text: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must |
|
||||||
|
| S31 | 342 | `body_provenance` | panel-malformed:body_provenance | 1·0 / 1·0 | BUILD FAILED: magazine-001:body_provenance: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must rea |
|
||||||
|
| S32 | 344 | `uncertainty` | panel-malformed:uncertainty | 1·0 / 1·0 | BUILD FAILED: magazine-001:uncertainty: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read ex |
|
||||||
|
|
||||||
|
**Totals: 32 sites — 28 covered by fixture, 4 structural exclusions**
|
||||||
|
(S03 `slug`/canonical, S16 `contributor.handle`, S24 `year`, S28 sitemap `loc`; S16 also carries a
|
||||||
|
die-fixture). 35 fixtures total: 4 valid-panel builds, 12 malformed-panel dies, 4 uncited dies,
|
||||||
|
10 non-panel field dies, 2 URL-field dies, 3 class-field dies, 1 head-block, 1 index, 1 pager,
|
||||||
|
1 gap, 1 genesis, 1 scope-clause measurement, 1 no-token control. Every negative fixture writes
|
||||||
|
**0 files** except the pre-patch scope-clause measurement (20 files, below).
|
||||||
|
|
||||||
|
### The four structural exclusions, stated
|
||||||
|
|
||||||
|
- **S16** — `contributor.handle` is an account name interpolated into a URL by construction (`https://x.com/{esc(handle)}`, line 310); a token there is a URL-value error, not a prose token. Fixture `excl:contributor.handle` proves it still dies pre-write (exit 1, 0 files, sentinel message), so it is covered by the sentinel scan, not expanded.
|
||||||
|
- **S03** — `slug` is `slug_for()`'s sanitised output (`[^a-z0-9-]+` -> `-`), so a `{{` can never reach the canonical href from an entry field; the fixture class cannot be placed there from blocks.json. The `n`-keyed neighbour fields it is built from are covered by S10/S21/S22.
|
||||||
|
- **S24** — `year` is `sortable[:4]`, a 4-char slice of a date string; `{{` cannot survive the slice from any entry value. The unsliced source is covered by S12/S14/S25.
|
||||||
|
- **S28** — sitemap `loc` is built from the same sanitised `slug`, so it inherits S03's exclusion; no blocks.json field reaches it unsanitised.
|
||||||
|
|
||||||
|
## URL fields: the scope decision
|
||||||
|
|
||||||
|
**Decision: a token in a URL field must die.** Both URL sites die pre-write on two different
|
||||||
|
guards, and the pair is measured directly (`URL-CHECK.txt`):
|
||||||
|
|
||||||
|
- `body_source_url` (S18) with a non-https value: `safe_url` (build_blocks.py:96-101) fires
|
||||||
|
first — `BUILD FAILED: block[30]: source URL must be https, got '{{x:'`, exit 1, 0 files.
|
||||||
|
- `body_source_url` (S18) with an https value carrying the token (`https://x.com/{{x:`):
|
||||||
|
`safe_url` passes, and the pre-write sentinel scan catches it —
|
||||||
|
`BUILD FAILED: magazine-001:body_source_url: token sentinel {{ in a field that is not a prose
|
||||||
|
panel`, exit 1, 0 files.
|
||||||
|
- `excerpts[].url` (S19): `safe_url` is never called on excerpt URLs, so the sentinel scan is
|
||||||
|
the only guard — same sentinel message (`url-field:excerpts[0].url`, exit 1, 0 files).
|
||||||
|
- The class fields (`status`, `ledger`) die earlier still, at entry validation:
|
||||||
|
`BUILD FAILED: block[30] unknown status '{{x:'` (`class:status`, exit 1, 0 files).
|
||||||
|
|
||||||
|
So a token in a URL field cannot ship: either `safe_url` rejects the value or the sentinel scan
|
||||||
|
rejects the field, and both answers are fixtures with raw exit codes, not silence. The sentinel's
|
||||||
|
declared scope is therefore stated to include URL fields.
|
||||||
|
|
||||||
|
## The scope clause, closed with option (a)
|
||||||
|
|
||||||
|
The queue's 2026-10-11 00:43Z clause allowed either moving the cited-handle check above
|
||||||
|
`OUT.mkdir` or restating the guarantee. **Option (a) is implemented**: `check_uncited()` is new
|
||||||
|
(build_blocks_hard.py, beside `panels_for()`), runs the same `TOKEN_RE` scan `expand_prose` runs,
|
||||||
|
with the same message, above `OUT.mkdir`; `expand_prose` keeps its `die()` as a backstop behind
|
||||||
|
`pre_checked=True`. `check_tokens` now shares `panels_for(b)` instead of re-deriving the set.
|
||||||
|
|
||||||
|
Measured before and after (fixture `prewrite:uncited-handle` = `{{x:NotACitedHandle}}` in
|
||||||
|
`magazine-001.uncertainty`):
|
||||||
|
|
||||||
|
| state | exit | files written at failure |
|
||||||
|
|---|---|---|
|
||||||
|
| before (Q26 prototype, `d45cc28f…`) | 1 | **20** (116 of 123 pages short of a full tree) |
|
||||||
|
| after (`c4127c6c…`) | 1 | **0** |
|
||||||
|
|
||||||
|
Same message both times: `BUILD FAILED: magazine-001:uncertainty: prose-anchor token names handle
|
||||||
|
@NotACitedHandle which no entry cites`. **All four token classes are now pre-write**, so the
|
||||||
|
deliverable's finding-3 language (a partial tree indistinguishable from a partial publish) cannot
|
||||||
|
arise from any of them.
|
||||||
|
|
||||||
|
## Verification legs (`Q27-VERIFY.txt`, full log)
|
||||||
|
|
||||||
|
== leg 1: no-token build ==
|
||||||
|
exit=0 files=125 digest=91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8
|
||||||
|
digest matches Q26 baseline 91ecf6bf...: True
|
||||||
|
== leg 2: uncited pre-write (was 20 files before the patch) ==
|
||||||
|
exit=1 files=0 BUILD FAILED: magazine-001:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites
|
||||||
|
== leg 3: uncited in quote-branch body (check_uncited fires first) ==
|
||||||
|
exit=1 files=0 BUILD FAILED: block-6:body: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty)
|
||||||
|
== leg 4: cited token in all four panels builds and expands ==
|
||||||
|
exit=0 files=125 anchors on magazine-001 page: 4
|
||||||
|
== leg 5: malformed still dies pre-write ==
|
||||||
|
exit=1 files=0 BUILD FAILED: magazine-001:body: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with a 1-15 character handle
|
||||||
|
== leg 6: gap still dies pre-write ==
|
||||||
|
exit=1 files=0 BUILD FAILED: coverage.gaps[4]: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty)
|
||||||
|
== leg 7: backstop — expand_prose still dies on uncited when pre_checked=False ==
|
||||||
|
exit=1 BUILD FAILED: magazine-001:body: prose-anchor token names handle @NotACitedHandle which no entry cites
|
||||||
|
== leg 8: control build byte-identical to shared site-ledger ==
|
||||||
|
diff -rq output: '' rc 0
|
||||||
|
files in shared site-ledger: 125
|
||||||
|
== leg 9: shared tree untouched ==
|
||||||
|
97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672 /root/stackchain-legends-build/build_blocks.py
|
||||||
|
63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d /root/stackchain-legends-build/blocks.json
|
||||||
|
files newer than 01:00Z today: ''
|
||||||
|
|
||||||
|
## Raw fixture log (`Q27-RESULTS.json`)
|
||||||
|
|
||||||
|
| fixture | entry | exit | files | first stderr line |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| panel-valid:body | magazine-001 | 0 | 125 | (built) |
|
||||||
|
| panel-malformed:body | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:body: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with a 1-15 charac |
|
||||||
|
| panel-uncited:body | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:body: prose-anchor token names handle @NotACitedHandle which no entry cites |
|
||||||
|
| panel-valid:plain_summary.text | magazine-001 | 0 | 125 | (built) |
|
||||||
|
| panel-malformed:plain_summary.text | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:plain_summary.text: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with |
|
||||||
|
| panel-uncited:plain_summary.text | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:plain_summary.text: prose-anchor token names handle @NotACitedHandle which no entry cites |
|
||||||
|
| panel-valid:body_provenance | magazine-001 | 0 | 125 | (built) |
|
||||||
|
| panel-malformed:body_provenance | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:body_provenance: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with a |
|
||||||
|
| panel-uncited:body_provenance | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:body_provenance: prose-anchor token names handle @NotACitedHandle which no entry cites |
|
||||||
|
| panel-valid:uncertainty | magazine-001 | 0 | 125 | (built) |
|
||||||
|
| panel-malformed:uncertainty | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:uncertainty: malformed prose-anchor token — sentinel {{ left after token expansion; tokens must read exactly {{x:HANDLE}} with a 1-15 |
|
||||||
|
| panel-uncited:uncertainty | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites |
|
||||||
|
| nonpanel:title | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| nonpanel:date_display | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:date_display: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| nonpanel:date_basis | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:date_basis: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| nonpanel:date | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:date: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| nonpanel:contributor.display_name | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:contributor.display_name: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, |
|
||||||
|
| nonpanel:excerpts.0.text | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:excerpts[0].text: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertai |
|
||||||
|
| nonpanel:excerpts.0.url | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:excerpts[0].url: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertain |
|
||||||
|
| nonpanel:body_source_url | magazine-001 | 1 | 0 | BUILD FAILED: block[30]: source URL must be https, got '{{x:' |
|
||||||
|
| nonpanel:receipt.reuse_status | 5 | 1 | 0 | BUILD FAILED: block-5:receipt.reuse_status: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| url-field:body_source_url | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:body_source_url: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertain |
|
||||||
|
| url-field:excerpts[0].url | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:excerpts[0].url: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertain |
|
||||||
|
| excl:contributor.handle | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:contributor.handle: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncert |
|
||||||
|
| class:status | magazine-001 | 1 | 0 | BUILD FAILED: block[30] unknown status '{{x:' |
|
||||||
|
| class:ledger | magazine-001 | 1 | 0 | BUILD FAILED: block[30] unknown ledger '{{x:' |
|
||||||
|
| class:variant | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:variant: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| head:jsonld-author | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:contributor.display_name: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, |
|
||||||
|
| index:label | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:title: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| index:date | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:date_display: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| index:coverage.gaps | coverage.gaps[4] | 1 | 0 | BUILD FAILED: coverage.gaps[4]: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| pager:n | magazine-002 | 1 | 0 | BUILD FAILED: magazine-002:n: token sentinel {{ in a field that is not a prose panel (panels: body, body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| genesis:body | 5 | 1 | 0 | BUILD FAILED: block-5:body: token sentinel {{ in a field that is not a prose panel (panels: body_provenance, plain_summary.text, uncertainty) |
|
||||||
|
| prewrite:uncited-handle | magazine-001 | 1 | 0 | BUILD FAILED: magazine-001:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites |
|
||||||
|
| control:notoken | - | 0 | 125 | (built) |
|
||||||
|
|
||||||
|
## Control: no-token build unchanged
|
||||||
|
|
||||||
|
Unmodified `blocks.json` (sha256 `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`)
|
||||||
|
through the patched builder: exit 0, **125 files, tree digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** — the Q26 baseline, byte for byte — and
|
||||||
|
`diff -rq <scratch>/site-ledger /root/stackchain-legends-build/site-ledger` silent. A cited token
|
||||||
|
placed in all four panels of `magazine-001` expands to exactly 4 anchors on that page and moves
|
||||||
|
no other file (leg 4).
|
||||||
|
|
||||||
|
## Live archive, re-measured (2026-10-11)
|
||||||
|
|
||||||
|
- `https://alexanderwhitestone.com/stackchain/blocks/` — **HTTP 200, 34,488 B, sha256 `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`**.
|
||||||
|
|
||||||
|
## Limits
|
||||||
|
|
||||||
|
- **Scratch only.** The patched builder lives in `/root/crucible/q27/` and is not staged to the
|
||||||
|
shared tree; publishing it is Alexander's decision, the same gate Q26 and Q13 state.
|
||||||
|
- **Fixtures target one entry per shape, not a census.** Q26's §9 limit 2 was about *entries*;
|
||||||
|
this item's answer is about *sites*, and a site's behaviour does not vary by entry beyond the
|
||||||
|
two `body_kind` branches, both of which are exercised (S17/S27 quote-branch, S29 summary).
|
||||||
|
- **Testimony only:** none. Every number in this record was produced by a command in this run;
|
||||||
|
the live index was fetched this run.
|
||||||
|
|
||||||
Reference in new issue
Block a user