258 lines
16 KiB
Markdown
258 lines
16 KiB
Markdown
# 2026-10-11 — merlin
|
||
|
||
> Screen. Every claim below carries a path, a hash, a URL, or a command with its output, or the word
|
||
> `unverified`. Nothing secret is printed anywhere in this check-in or in the files it lands.
|
||
|
||
---
|
||
|
||
## Did
|
||
|
||
Claimed and finished **Q26 — make the silent token classes loud, and measure the fifth slot**, the item
|
||
nominated to me by the control plane after Q25 closed at `a9f23a6` (Q20 is zephyrus-sparkborn's and
|
||
stays the top unclaimed item; Q9 blocked on the audio handover; Q13/Q19 gated on Alexander).
|
||
|
||
Deliverable: `recoveries/prose-anchor-hardening.md` (**15,250 B / sha256
|
||
`607b29403e61db44f15657386531ef11d009f964b90b1a4a5a25542612325108`**, this host,
|
||
2026-10-11T00:24:34Z). Queue block appended to `WORK-QUEUE.md` (383,205 B / sha256
|
||
`9be863624751711afb0b1c745b7cf4147ea9f838b6189ccadc32689b3d4b5d3c`).
|
||
|
||
**What Q25 left silent, now loud.** The Q25 prototype shipped a typo as raw braces on the page and
|
||
could not see a token outside its four panels. The fix is a pre-write scan — `check_tokens` per entry,
|
||
`check_gaps` for the index — sitting **above** the `OUT` cleanup in `build()`, so a `die()` can never
|
||
leave a half-emitted tree. The panel set is computed **per entry**: `body` is a panel only when
|
||
`body_kind == "summary"`.
|
||
|
||
The diff: `build_blocks_proto.py` → `build_blocks_hard.py` **+70 / −6 lines, 5,817 B**
|
||
(`/root/crucible/q26/DIFF.txt`); against the shared tree's `build_blocks.py`
|
||
(sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`) **+118 / −11, 9,949 B**.
|
||
The hardened script is **27,878 B / sha256
|
||
`d45cc28f7d69afcdab4eccb16e9e0cc264e4317e059e17f1ba53eb23f792cb60`**; the Q25 prototype copied into
|
||
the scratch tree verified byte-identical first (`5af80b78961b4f55…`).
|
||
|
||
**The five Q25 legs, re-run green** (`Q26-VERIFY.txt`, full log `Q26-VERIFY-run.txt`):
|
||
|
||
1. No-token build on the unmodified `blocks.json` (278,459 B / sha256
|
||
`63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`):
|
||
`Built 123 pages from 121 entries (121 cleared, 0 research-only)`, tree digest
|
||
**`91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8`** = baseline, 125 files,
|
||
`diff -rq <scratch>/site-ledger /root/stackchain-legends-build/site-ledger` silent.
|
||
2. Registry unchanged: **8** handles (`@anthonydessauer @arizonanhodl @guiamadogomes
|
||
@happyclowntime @rockachopa @satskeeper_ @saylor @yoshishisatoshi`).
|
||
3. Uncited-handle negative test: `exit 1`,
|
||
`BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle which no
|
||
entry cites`.
|
||
4. H1–H4 token demo: `exit 0`, **3 of 125** emitted files changed
|
||
(`event-2022-07-18-the-5-invitation-becomes-a-chain/index.html`, `magazine-002/index.html`,
|
||
`magazine-005/index.html`), 6 emitted anchors, all the contributor form.
|
||
5. The diff itself.
|
||
|
||
**Two negative sets, 12 fixtures, every one `exit 1` with its own message.** Malformed
|
||
(`MALFORMED.txt`): `{{x:saylor}` open brace, `{{x:}}` empty handle, `{{ x:saylor }}`
|
||
whitespace-padded, `{{y:saylor}}` wrong namespace, `{{x:abcdefghijklmnopq}}` handle over 15
|
||
chars, lone `}}`, close-then-open `}}{{x:saylor}}` — all seven **previously built and shipped the
|
||
literal** under the Q25 prototype, exit 0. Outside-panel (`OUTSIDE-PANEL.txt`): quote branch
|
||
(`block-6:body`, whose error prints the panel set *without* `body` — the per-entry `body_kind`
|
||
rule visible in the failure), `magazine-001:title`, `magazine-001:excerpts[0].text`,
|
||
`magazine-035:contributor.display_name`, `coverage.gaps[4]`. Positive control (`POSITIVE.txt`):
|
||
a cited `{{x:AriZonanHODL}}` in `block-5`'s `body_provenance` builds, expands on the `block-5` page
|
||
**and** the genesis page, and moves exactly 2 files.
|
||
|
||
**One new silent class, found while writing the positive control and closed:** `render_genesis`
|
||
routed `body_provenance` and `uncertainty` through `esc()`, so a token those panels carry would
|
||
expand on `block-5` and print raw braces on `genesis/`. Both now go through `expand_prose`;
|
||
byte-neutral with no token present (proved by leg 1). The first hardening pass also missed the
|
||
quote branch for the same reason a path-based panel set fails — `body` is a panel only on the
|
||
summary branch — and the fix was the per-entry panel set.
|
||
|
||
**The fifth slot, measured without building it** (`DISPLAY-NAME-MEASURE.txt`, each Q24 delta
|
||
applied in its own scratch tree):
|
||
|
||
| entry | Q24 clause | `display_name` / `handle` today | live page today | after the staged delta |
|
||
|---|---|---|---|---|
|
||
| magazine-035 | G1 | `@BTC_Freeborn and @AnthonyDessauer` / `null` | text only, anchors NONE | `BTC_Freeborn and Anthony Dessauer (@BTC_Freeborn)` — anchor `x.com/BTC_Freeborn`; sha `871638b8…` → `565e6f68…` |
|
||
| magazine-056 | G2 | `Red Tail Hawk (@RedTailHawk1923)` / `null` | text only, anchors NONE | `Red Tail Hawk (@RedTailHawk1923)` — anchor `x.com/RedTailHawk1923`; sha `33b55f8f…` → `8094e862…` |
|
||
| magazine-070 | I2 | `@MidyReyes` / `null` | text only, anchors NONE | `MidyReyes (@MidyReyes)` — anchor `x.com/MidyReyes`; sha `6227e199…` → `c994e055…` |
|
||
|
||
**Recommendation: `magazine-056` (G2) and `magazine-070` (I2) take the handle-only fix — one
|
||
account, one `handle` slot, and the build already anchors `contributor.handle` (line 310).
|
||
`magazine-035` (G1) is the hard case: handle-only anchors `@BTC_Freeborn` and leaves
|
||
`@AnthonyDessauer` unanchored, because `contributor` has exactly one `handle` slot while the byline
|
||
names two accounts — and `@AnthonyDessauer` *is* in the registry, so a token for it would be
|
||
admitted today. The only instrument that anchors both is `display_name` as a fifth panel carrying
|
||
`{{x:AnthonyDessauer}}` beside the handle slot — a build change, Alexander's.** All three live-page
|
||
digests reproduce Q24's fix-pack figures to the nibble, so the live tree is still the tree Q24
|
||
measured.
|
||
|
||
**Which of Q24's 31 deltas the hardened convention can carry as links: H1–H4 only, 4 of 31.** The
|
||
hardening widens no clause's carrier; it makes the four token carriers safe to publish. The
|
||
publication precondition the 2026-10-10 18:13Z addendum stated is satisfied on the build side.
|
||
|
||
**Nothing touched.** Shared tree still at `97fedb5dd5e85d2…`, its `site-ledger` byte-identical to
|
||
this run's scratch build (125 files each, `diff -rq` silent), and
|
||
`find /root/stackchain-legends-build -newermt 2026-10-10 18:00 -type f` returns nothing. Live
|
||
archive unchanged: `https://alexanderwhitestone.com/stackchain/blocks/` **200 / 34,488 B / sha256
|
||
`4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** at 2026-10-11T00:23:25Z.
|
||
`blocks.json` read-only throughout; `decisions/` and `inbox/` untouched, nothing executed, no
|
||
another-party file edited.
|
||
|
||
## Blocked
|
||
|
||
Nothing blocked the run. Two things deliberately **unverified**, both recorded as such in the
|
||
deliverable:
|
||
|
||
- **The `display_name` fifth panel was measured, not built.** No fifth-panel implementation exists;
|
||
the recommendation is a decision input, not a staged change.
|
||
- **12 fixtures are the item's own lists plus two extras, not a census of typos.** A sentinel in a
|
||
field no entry has today cannot be enumerated from today's data.
|
||
|
||
Also outside this run by construction: Q25's census (46 rows / 25 X fetches) is cited, not re-run —
|
||
no X page was fetched this tick, so no liveness figure in this check-in is dated by this run.
|
||
|
||
## Next
|
||
|
||
- **Q20** (excerpt fidelity and placement, the 91 magazine entries) remains the top unclaimed item
|
||
and is zephyrus-sparkborn's; I take nothing over it.
|
||
- **Alexander's call, not mine:** whether to publish the build change at all. The hardened
|
||
prototype is scratch-local and stays there until he says so — the same gate Q13 states. If he
|
||
approves the convention, the immediate payload is the 4-of-31 H1–H4 clauses; the `display_name`
|
||
fifth panel is a separate, larger decision with exactly one entry (G1) that needs it today.
|
||
- **Q7, measured:** Q9 blocked on the audio handover; Q13/Q19 gated on Alexander; Q20 active. The
|
||
executable set is empty of unclaimed items, so the never-dry obligation is triggered and a
|
||
successor item is owed — I propose none this tick, because Q26 just closed and the successor
|
||
should be the pipe's to open on a fresh measurement rather than mine to invent on the same
|
||
finding. Stated plainly: this is the second consecutive tick where the set fell to zero and the
|
||
successor came from the control plane's own measurement, and that is the pattern worth naming
|
||
rather than a gap in the queue.
|
||
|
||
## Ask
|
||
|
||
1. **Alexander — approve, decline, or defer the prose-anchor convention as a build change.** If
|
||
approved, the unit of work is the four H1–H4 clauses plus the hardened prototype; nothing
|
||
publishes without a further go. If declined, Q24's 25 clauses stay staged as notes exactly as
|
||
they are.
|
||
2. **Alexander — the `display_name` fifth slot, G1 only.** Is a second anchor on one byline worth a
|
||
build change, or does G1 take the handle-only fix and leave `@AnthonyDessauer` as a name?
|
||
3. **Nothing asked of zephyrus-sparkborn this tick.** His lane is Q20; my two asks are both
|
||
Alexander's, per §4.
|
||
|
||
---
|
||
|
||
## Landing evidence (appended after push, 2026-10-11T00:25:14Z)
|
||
|
||
Deliverable commit **`f05179e`** (Merlin, `merlin@agents.invalid`, 2026-10-11), three files, pushed
|
||
to `origin/main` (`git log --oneline -1 origin/main` → `f05179e`). Read back over the anonymous raw
|
||
path (`…/raw/branch/main/<path>`), no credential, each **HTTP 200 and `cmp` byte-identical to
|
||
disk**:
|
||
|
||
| file | status / bytes | sha256 (first 16) |
|
||
|---|---|---|
|
||
| `checkins/2026-10-11-merlin.md` | 200 / 9,153 | `5b5e94b885313c1e` |
|
||
| `recoveries/prose-anchor-hardening.md` | 200 / 15,250 | `607b29403e61db44` |
|
||
| `WORK-QUEUE.md` | 200 / 383,205 | `9be863624751711a` |
|
||
|
||
Re-verified in the same breath: the shared build tree's `build_blocks.py` is still sha256
|
||
`97fedb5dd5e85d2…`, its `site-ledger` byte-identical to the scratch build, nothing under
|
||
`/root/stackchain-legends-build` modified since 2026-10-10 18:00Z, and the live ledger index
|
||
`https://alexanderwhitestone.com/stackchain/blocks/` is 200 / 34,488 B /
|
||
`4f764ef4dfb9c08b…`. `blocks.json` was read-only throughout; `decisions/` and `inbox/` were not
|
||
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.
|
||
|
||
### Landing evidence (appended after push, 2026-10-11 ≈02:36 UTC)
|
||
|
||
Deliverable commit **`08013ba`** (Merlin, `merlin@agents.invalid`, 2026-10-11; parent `179adc3`),
|
||
3 files, pushed to `origin/main` (`git log --oneline -1 origin/main` → `08013ba`). Read back over
|
||
the anonymous raw path (`…/raw/branch/main/<path>`), no credential — each HTTP 200 and `cmp`
|
||
byte-identical to disk:
|
||
|
||
| file | status / bytes | sha256 (first 16) |
|
||
|---|---|---|
|
||
| `checkins/2026-10-11-merlin.md` | 200 / 15,667 | `8ab0221e7f7065fe` |
|
||
| `recoveries/render-site-coverage.md` | 200 / 20,865 | `34716145492bd265` |
|
||
| `WORK-QUEUE.md` | 200 / 398,374 | `0b19045f3c961830` |
|
||
|
||
Re-verified in the same breath: shared `build_blocks.py` still `97fedb5dd5e85d2…`, `blocks.json`
|
||
`63c9cee6…`, nothing under `/root/stackchain-legends-build` modified since 2026-10-10 18:00Z, and
|
||
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.
|