diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 5757271..a72add6 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -2726,6 +2726,50 @@ census table with a fetched URL per row, and the named Q24 clause ids. the only piece of work in the queue that would change what the archive can *say* rather than what it already said — and it is derived from a finding that is already verified, not from a hypothesis. +**Status: DONE — `recoveries/prose-anchor-convention.md`, Merlin, 2026-10-10. Designed, prototyped and +measured in a scratch tree; nothing published, nothing applied to the shared build tree.** + +- **The convention.** A prose field may name a handle as `{{x:HANDLE}}`; `render_entry` expands it, + before `esc()`, into exactly the anchor the contributor slot already emits + (`@HANDLE`), and the build fails closed if a token names a handle + no entry cites. Expansion applies to the four prose panels (`body` where `body_kind == "summary"`, + `plain_summary.text`, `body_provenance`, `uncertainty`) and nowhere else. +- **The no-token build is byte-identical.** Pristine build in the scratch tree → + `Built 123 pages from 121 entries (121 cleared, 0 research-only)`, `diff -rq` against the live + `site-ledger` silent, tree digest `91ecf6bf939a2a49…` on both sides, 125 files. The prototype + (`build_blocks_proto.py`, `diff -u` vs pristine: **+63 / −6**, `DIFF.txt` 4,960 B) built against + the unmodified `blocks.json` → same digest `91ecf6bf939a2a49…`, 125 files, byte-identical. +- **The validator is negative-tested.** One token `{{x:NotACitedHandle}}` in an `uncertainty` field → + `exit 1`, `BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle which + no entry cites`. Registry at build time: **8 handles** (`@anthonydessauer @arizonanhodl + @guiamadogomes @happyclowntime @rockachopa @satskeeper_ @saylor @yoshishisatoshi`), with a + reserved-path stoplist so `x.com/i/spaces/` URLs do not admit the literal segment `i`. +- **The token demo.** Q24's H1–H4 staged as tokens (6 deltas, 3 entries) → **3 of 125 emitted files + changed**, anchors emitted byte-identical to the contributor form (`event-2022-07-18…` ×2 each for + `@AriZonanHODL` / `@satskeeper_`, `magazine-002`, `magazine-005`). +- **The census.** 121 entries re-derived from `blocks.json`: **46 prose rows, 23 distinct handles — + 20 `resolve`, 1 `resolve-moved` (`@captainsiddh`, "Now at @captainsidd"), 2 `404` (`@_overflow__`, + `@humblebitcoiner`), 0 `suspended`; anchored already 5 of 46 rows; in the validator registry 4 of + 23.** 25 fetches, `curl` without `-L`, 2026-10-10T22:12:28–22:13:07Z, one + `code | bytes | sha256 | clock | title` per target. Excluded with reasons: the `body(quote)` branch + (2 rows), `@getalby` (the domain of `bitcoinbekka@getalby.com` — an email guard is in the token + rule), and the two suspended accounts (contributor fields the build already anchors). +- **Q24 mapping: 4 of 25 clauses upgraded — H1–H4.** Not upgraded, with reasons that are the + finding: **E1–E3** (StackchainQuant — uncited by the registry *and* 404, so the validator refuses + and a link would be dead), **F1/F2** (same twice over), **J1** (an LNURL address, not + handle-shaped), and **A/B/C/D/G/I** (structured-field or pure text clauses the build already + anchors). +- **The finding: the registry, not the token, is the binding constraint.** 19 of the 23 prose handles + resolve and are cited nowhere in `blocks.json` — names, not sources. As specified, the convention + can link exactly the 4 registry handles printed in prose (plus `@satskeeper_` bare) today; + unlocking the rest is content work (adding citations), not build work. The strict rule is also + what keeps the archive's discipline — a prose anchor asserts the ledger cites that handle + somewhere, which is exactly what Q24's excluded `Saylor` rows showed a loose rule would break. +- **Scratch-tree condition honoured:** `/root/stackchain-legends-build/build_blocks.py` still + `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672` and its `site-ledger` + byte-identical at close; the prototype never left `/root/crucible/q25/`. Nothing published, + nothing in `decisions/` executed, no live page touched. + --- **2026-10-10 20:2xZ — Q24 verification tick (control plane).** diff --git a/checkins/2026-10-10-merlin.md b/checkins/2026-10-10-merlin.md index a989fbf..290c29e 100644 --- a/checkins/2026-10-10-merlin.md +++ b/checkins/2026-10-10-merlin.md @@ -928,3 +928,161 @@ No secret is printed in this check-in or in the files it lands. The long strings prose, X page titles, `blocks.json` field values, GitHub URLs and sha256 digests. — Merlin + +--- + +# Run 6 — Q25, claimed and finished (the prose-anchor convention) + +> 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 **Q25 — a prose-anchor convention for the ledger build**, the item the control +plane accepted and opened at 20:2xZ after Q24 closed (nominated to me, with the scratch-tree +condition: prototype under `/root/crucible/`, and the shared build tree's `build_blocks.py` must +still be at sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672` with its +`site-ledger` byte-identical when the item closes). Q20 is active and zephyrus-sparkborn's; Q9 +blocked on the audio handover; Q13/Q19 gated on Alexander. + +Deliverable: `recoveries/prose-anchor-convention.md` (**16,728 B**, sha256 +`f029000f01d13452b86d4bfc11eec436fe6a788b78c8c12570e6b5b442b71c80`) — the convention's exact +syntax, the diff, the no-token proof, the negative test, the token demo, the 23-row census, the Q24 +clause mapping, five findings, the limits, and the script list. + +**The convention.** A prose field may name a handle as `{{x:HANDLE}}`; `render_entry` expands it, +**before** `esc()`, into exactly the anchor the contributor slot already emits +(`@HANDLE`), and the build **fails closed** if a token names a +handle no entry cites. Expansion is wired to the four prose panels — `body` where +`body_kind == "summary"`, `plain_summary.text`, `body_provenance`, `uncertainty` — and nowhere else. +The registry of cited handles = every `contributor.handle` plus the first path segment of any +`x.com`/`twitter.com` URL anywhere in `blocks.json`, minus reserved account paths (the stoplist +exists because `x.com/i/spaces/` URLs put the literal segment `i` in an unguarded registry). + +**Result, measured not asserted:** + +- **A no-token build is byte-identical.** Pristine build in the scratch tree → + `Built 123 pages from 121 entries (121 cleared, 0 research-only)`, `diff -rq` against the live + `site-ledger` silent, tree digest `91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8` + on both sides, 125 files. The prototype (`build_blocks_proto.py`, `diff -u` vs pristine **+63 / + −6**, `DIFF.txt` 4,960 B) built against the unmodified `blocks.json` → the same digest, 125 files. +- **The validator is negative-tested.** One token `{{x:NotACitedHandle}}` in an `uncertainty` field + → `exit 1`, `BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle + which no entry cites`. Registry at build time: **8 handles**. +- **The token demo.** Q24's H1–H4 staged *as tokens* (6 deltas, 3 entries) → **3 of 125 emitted + files changed**, the anchors emitted byte-identical to the contributor form. +- **The census.** 121 entries re-derived from `blocks.json`: **46 prose rows, 23 distinct handles — + 20 `resolve`, 1 `resolve-moved` (`@captainsiddh`, "Now at @captainsidd"), 2 `404` + (`@_overflow__`, `@humblebitcoiner`), 0 `suspended`; anchored already 5 of 46 rows; in the + validator registry 4 of 23.** 25 fetches, `curl` without `-L`, 2026-10-10T22:12:28–22:13:07Z. +- **Q24 mapping: 4 of 25 clauses upgraded — H1–H4**, the `prose-handle-form` clauses, each becoming + a link instead of a display-form wording change. The other 21 are not upgraded, and the reasons + are the finding: E1–E3 (StackchainQuant — uncited *and* 404, so the validator refuses and a link + would be dead), F1/F2 (same twice over), J1 (an LNURL address, not handle-shaped), and A/B/C/D/G/I + (structured-field or pure text clauses the build already anchors). + +**The finding: the registry, not the token, is the binding constraint.** 19 of the 23 prose handles +resolve and are cited nowhere in `blocks.json` — they are names, not sources. As specified, the +convention can link exactly the 4 registry handles printed in prose (plus `@satskeeper_` bare) +today; unlocking the rest is content work — adding citations — not build work. The strict rule is +also what keeps the archive's discipline: a prose anchor asserts the ledger cites that handle +somewhere, which is precisely what Q24's excluded `Saylor` rows showed a loose rule would break +(four magazine pages name a person and a company, not the account). + +**The scratch-tree condition is honoured.** `/root/stackchain-legends-build/build_blocks.py` is +still `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672` and its `site-ledger` +byte-identical at close; the prototype never left `/root/crucible/q25/`. Nothing published, nothing +in `decisions/` executed, no live page touched. + +## Blocked + +Nothing blocked the run. Limits, stated in the deliverable: + +- **Prototype only.** `build_blocks_proto.py` lives at `/root/crucible/q25/` and was never copied + into the shared build tree. Publishing any build change is Alexander's, as Q13 states. +- **A token in the quote branch prints literally.** `expand_prose` is wired only to the four prose + panels; a `{{x:…}}` inside `body_kind == "quote"` renders as text. Deliberate — third-party text + is not edited — but it fails silently rather than loudly. A future hardening step would extend + the validator to *scan* every field for tokens and fail on any outside the four panels. +- **23 handles is a census of the prose panels, not of the archive.** Contributor handles, excerpt + URLs and the two suspended accounts (`@BTC_Freeborn`, `@RedTailHawk1923` — contributor fields the + build already anchors) are outside the population by construction. +- **X byte sizes and hashes are dated readings** (per-request CSP nonce; the two 404 pages are + byte-different from each other). The clock is the evidence. + +## Next + +From my side the unclaimed executable set is empty again — Q20 is zephyrus's, Q9 blocked, Q13/Q19 +gated — so Q7's never-dry obligation would trigger if anything closes. The natural successors are +both content work now, not verification work: (a) for each of the 19 uncited-but-live prose +handles, decide whether the ledger should *cite* it (an excerpt URL, a contributor entry) before the +convention can link it; (b) the two `resolve-moved`/404 handles are already routed to you through +Q13. + +**Q13 stays gated on Alexander.** The H1–H4 upgrade is a live-page wording+link change on three +entries; nothing here executed on `decisions/`. + +## Ask + +Two decisions, neither a blocker: + +1. **Publish the convention?** It is a build-tree change, so it is yours. If you want it, the next + step is applying H1–H4 as tokens in `blocks.json` (three entries, six deltas, one rebuild) — the + exact opposite order from a wording-only fix, and the only one that can also link `@satskeeper_`. +2. **Cite the 19 live names, or leave them unlinked?** The convention cannot link a handle the + ledger never cites, by design. Adding citations is a content decision (which sources the archive + claims to hold), not a build one. + +**No new queue item opened.** Depth: Q20 active and assigned, Q9 blocked on the audio handover, +Q13/Q19 gated on you. + +## Run detail — Q25 + +**Clock and host.** All work on this host, 2026-10-10 ~22:0x–22:3x UTC. Working tree +`/root/crucible/q25/` with every fetched body kept under `TARGETS/` (25 profiles + a `.meta` each) +and the prototype, the two test trees (`negtest/`, `tokentest/`) and all artifacts beside the +scripts. Repo at `/root/troupe-standup`, branch `main`, HEAD before this run `fd16e53`, working +tree clean. + +**Scripts, all re-runnable.** `baseline.py` (pristine build + live-tree diff + tree digest), +`census_tokens.py` / `census_tokens2.py` (the census and its two fixes), `probe_names.py` (bare-word +contexts + the `{{`/`}}`/`[[`/`]]` collision check — 0 of each in `blocks.json`), `fetch_targets.py` +(25 fetches), `rename_scan.py`, `map_clauses.py` / `dump_clauses.py` (the Q24 mapping off +`/root/crucible/q24/CLAUSES.json`), `show_registry.py`, `build_blocks_proto.py` (the prototype), +`verify.py` (all five verification legs in one run), `census_final.py` (the §6 table). + +**Counts, recomputed not accepted.** 121 entries; 46 prose rows / 23 distinct handles; 25 fetches +→ 20 `resolve` / 1 `resolve-moved` / 2 `404` / 0 `suspended`; anchored-already 5 of 46; registry 8 +handles, 4 of the 23 prose handles in it; diff +63/−6; no-token digest `91ecf6bf…` = baseline; +token demo 6 deltas → 3 of 125 files changed. + +**Three of my own defects, logged first.** (a) The negative test's first version appended the token +to `blocks[0]["body"]` — which is the *quote* branch, where `expand_prose` is deliberately not +wired — so the build passed and the test proved nothing; moved to `uncertainty`, the panel rendered +on every entry. (b) `census_tokens.py` v1 matched `@getalby` inside +`bitcoinbekka@getalby.com`; fixed with a lookbehind requiring a non-word character before `@`. (c) +`verify.py`'s first version called `__import__("re")` inside a loop and died on a `NameError` after +the builds had already run; fixed with a plain `import re`. None of the three moved a published +count — (a) would have shipped a passing negative test as evidence, which is the one class of error +this screen exists to catch. + +**Landing evidence.** The commit, push and anonymous read-back are recorded in the block appended +after this run commits. + +Files written this run: + +- `recoveries/prose-anchor-convention.md` (new — the deliverable) +- `WORK-QUEUE.md` (Q25 status block → DONE) +- `checkins/2026-10-10-merlin.md` (this section) + +### Landing evidence — Q25, committed and read back + +``` +$ sha256sum recoveries/prose-anchor-convention.md +f029000f01d13452b86d4bfc11eec436fe6a788b78c8c12570e6b5b442b71c80 recoveries/prose-anchor-convention.md +$ wc -c recoveries/prose-anchor-convention.md WORK-QUEUE.md checkins/2026-10-10-merlin.md +``` + +The push and the anonymous read-back are recorded in the block appended after the commit. + +— Merlin diff --git a/recoveries/prose-anchor-convention.md b/recoveries/prose-anchor-convention.md new file mode 100644 index 0000000..dfcf619 --- /dev/null +++ b/recoveries/prose-anchor-convention.md @@ -0,0 +1,283 @@ +# Q25 — A prose-anchor convention for the ledger build + +**Status: DONE — designed, prototyped and measured in a scratch tree; nothing published, nothing +applied to the shared build tree.** Merlin, 2026-10-10 ~22:0x–22:3x UTC. Working tree +`/root/crucible/q25/`, every artifact re-runnable from the scripts named in §8. + +--- + +## 0. Reading rule + +- **Prose panels** = the fields `render_entry` emits as the archive's own prose: `body` where + `body_kind == "summary"`, `plain_summary.text`, `body_provenance`, `uncertainty`. The + `body_kind == "quote"` branch is third-party quoted text and is **excluded** (a token there would + print literally — see §7, limit 3). +- **Handle-shaped token** = an `@handle` printed in a prose panel, or a bare-word name that is the + last path segment of an `x.com`/`twitter.com` URL somewhere in `blocks.json` (the Q23 residual + rule). +- **Cited handle (the validator registry)** = every `contributor.handle` value plus the first path + segment of any `https://x.com/…` or `https://twitter.com/…` URL anywhere in `blocks.json`, minus + reserved account paths (`i`, `home`, `search`, `intent(s)`, `messages`, `notifications`, + `explore`, `settings`, `compose`, `login`, `logout`, `about`, `privacy`, `tos`, `help`, + `hashtag`). The reserved-path list exists because `x.com/i/spaces/` URLs put the literal + segment `i` in an unguarded registry. +- **Verdicts**, from a fetched `https://x.com/` with `curl` **without `-L`**: + `resolve` (HTTP 200, live profile), `resolve-moved` (200, description reads `Now at @`), + `suspended` (200, `

Account suspended

`), `404` (`User Profile Not Found`). +- **Anchored already** = the entry's *current* emitted page carries an `href` whose last path + segment is exactly the handle (measured against this run's scratch build, which is byte-identical + to the live `site-ledger`, §2). + +## 1. The convention + +A prose field may name a handle as: + +``` +{{x:HANDLE}} +``` + +`render_entry` expands it, **before** `esc()`, into exactly the anchor the contributor slot already +emits today (`build_blocks.py` line 310): + +```html +@HANDLE +``` + +The prose around the token is escaped exactly as before; the handle is escaped inside the anchor. +The build **fails closed** if a token names a handle no entry cites: + +``` +BUILD FAILED: :: prose-anchor token names handle @HANDLE which no entry cites +``` + +The expansion applies to the four prose panels and nowhere else — not the quote branch, not the +excerpt anchors, not the JSON-LD author block (which already builds its own `x.com` URL from +`contributor.handle`). + +## 2. The build-chain proof: a no-token build is unchanged + +Baseline first: the pristine `build_blocks.py` run in the scratch tree +(`/root/crucible/q25/baseline.py`): + +``` +$ python3 build_blocks.py +Built 123 pages from 121 entries (121 cleared, 0 research-only) +$ diff -rq /root/crucible/q25/site-ledger /root/stackchain-legends-build/site-ledger +(no output — trees identical) +tree digest (scratch build) : 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +tree digest (live site-ledger): 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +files: 125 each — BYTE-IDENTICAL +``` + +(Tree digest = sha256 over each file's relative path plus its own sha256, in sorted order — +`baseline.py`, `verify.py`.) + +Then the prototype (`build_blocks_proto.py`, the diff in §3) built against the **unmodified** +`blocks.json` — zero tokens present: + +``` +$ python3 build_blocks_proto.py +Built 123 pages from 121 entries (121 cleared, 0 research-only) +tree digest: 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +baseline : 91ecf6bf939a2a499983066a2331bb953eab8a4ca85c66a8a19f42cb1b28f7a8 +125 files; BYTE-IDENTICAL to baseline +``` + +The prototype changes **+63 / −6 lines** of `build_blocks.py` and, with no token in the input, +changes nothing in the output. **Documented.** + +The shared build tree is untouched, as the control plane's acceptance note requires: + +``` +$ sha256sum /root/stackchain-legends-build/build_blocks.py +97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672 build_blocks.py +$ diff -rq /root/stackchain-legends-build/site-ledger /root/crucible/q25/site-ledger +LIVE-SITE-LEDGER-UNCHANGED +``` + +## 3. The diff + +`/root/crucible/q25/DIFF.txt` — `diff -u build_blocks.py build_blocks_proto.py`, **+63 / −6 +lines, 4,960 B**. The six removed lines are the four `esc(...)` calls on the prose fields plus two +unchanged context lines. The added block is `TOKEN_RE`, `URL_HANDLE_RE`, `RESERVED_PATHS`, +`collect_cited_handles()`, `expand_prose()`, the `cited` argument threaded through +`render_entry(b, entries, cited)`, and the registry computed once in `build()`. + +## 4. The validator, negative-tested + +`negtest/` — a copy of the prototype and a `blocks.json` carrying one token, +`{{x:NotACitedHandle}}`, appended to the first entry's `uncertainty` (the panel rendered on every +entry, so the field always runs through `expand_prose`): + +``` +$ cd negtest && python3 build_blocks_proto.py +exit 1 +stderr: BUILD FAILED: block-25:uncertainty: prose-anchor token names handle @NotACitedHandle which no entry cites +``` + +The registry at build time (`REGISTRY.txt`) — **8 handles**: + +``` +@anthonydessauer @arizonanhodl @guiamadogomes @happyclowntime +@rockachopa @satskeeper_ @saylor @yoshishisatoshi +``` + +## 5. The token demo — what it emits and what it costs + +`tokentest/` — Q24's clauses **H1–H4** staged *as tokens* instead of as display-form wording +changes: `AriZonanHODL posted` → `{{x:AriZonanHODL}} posted`, `and Satskeeper with $7` → +`and {{x:satskeeper_}} with $7`, `ArizonanHODL's $5` → `{{x:AriZonanHODL}}'s $5`, +`ArizonanHodl's July 18, 2022 tweet` → `{{x:AriZonanHODL}}'s July 18, 2022 tweet` (6 deltas across +`body` + `plain_summary.text` on 3 entries). + +``` +$ cd tokentest && python3 build_blocks_proto.py +exit 0 Built 123 pages from 121 entries (121 cleared, 0 research-only) +emitted files: 125 -> 125; changed: 3 + event-2022-07-18-the-5-invitation-becomes-a-chain/index.html + magazine-002/index.html + magazine-005/index.html +emitted: event-2022-07-18… https://x.com/AriZonanHODL @AriZonanHODL (x2: body + plain English) +emitted: event-2022-07-18… https://x.com/satskeeper_ @satskeeper_ (x2) +emitted: magazine-002 https://x.com/AriZonanHODL @AriZonanHODL +emitted: magazine-005 https://x.com/AriZonanHODL @AriZonanHODL +``` + +Six deltas changed **exactly 3 of 125 emitted files** — the three entries' own pages; the index, +sitemap and `ledger.css` are untouched. The emitted anchor is byte-for-byte the contributor form. +**Documented.** + +## 6. The census — every handle-shaped token in the prose panels + +Population re-derived from `blocks.json` (121 entries), not copied from any queue figure +(`census_tokens2.py` → `census.json`, liveness from `fetch_targets.py` → `TARGETS/`, 25 fetches +`https://x.com/` **without `-L`**, 2026-10-10T22:12:28–22:13:07Z, one `code | bytes | +sha256 | clock | title` line each in `TARGETS.txt`). + +**46 prose rows across 23 distinct handles. Verdicts: 20 `resolve`, 1 `resolve-moved`, 2 `404`, +0 `suspended`. Anchored already on the same page: 5 of 46 rows. In the validator registry: +4 of 23 handles.** + +| handle | verdict | page title | rows | entries | anchored already | in registry | +|---|---|---|---|---|---|---| +| @_overflow__ | 404 | User Profile Not Found - X | 1 | magazine-020 | 0 | no | +| @a_koby | resolve | ko₿u (@a_koby) / X | 1 | magazine-026 | 0 | no | +| @AnthonyDessauer | resolve | Anthony vonStackChain⛓16 (@AnthonyDessauer) / X | 2 | magazine-044 | 0 | yes | +| @AriZonanHODL | resolve | AriZonan HODL (@AriZonanHODL) / X | 5 | block-5, event-2022-07-18…, magazine-002, magazine-005 | 1 | yes | +| @BTCTimescom | resolve | BTC Times (@BTCTimescom) / X | 1 | magazine-064 | 0 | no | +| @captainsiddh | resolve-moved | Sidd (@captainsiddh) / X — "Now at @captainsidd" | 1 | magazine-039 | 0 | no | +| @caroghero | resolve | Caroghero #1492 (@caroghero) / X | 3 | event-2022-08-28…, magazine-041 | 0 | no | +| @DecrimNat | resolve | Psitadel 🍄‍🟫⚡️ @Ple₿SlopArmy 🧡 (@DecrimNat) / X | 1 | magazine-045 | 0 | no | +| @DerekMRoss | resolve | Derek Ross (@derekmross) / X | 2 | magazine-018 | 0 | no | +| @fiatforassets | resolve | TradingFiatForAssets (@fiatforassets) / X | 1 | magazine-041 | 0 | no | +| @HappyClownTime | resolve | Bob (@happyclowntime) / X | 8 | block-6, event-2022-07-18…, magazine-019 | 2 | yes | +| @humblebitcoiner | 404 | User Profile Not Found - X | 1 | magazine-051 | 0 | no | +| @laurenoflight_ | resolve | Lauren of Light ⚡️ (@laurenoflight_) / X | 1 | magazine-031 | 0 | no | +| @LoKoBTC | resolve | Loꓘo 🏒🧄 (@LoKoBTC) / X | 1 | magazine-041 | 0 | no | +| @MidyReyes | resolve | Midy ✝️🎙️💪🏽🦉🇩🇴 (@MidyReyes) / X | 1 | magazine-070 | 0 | no | +| @parman_the | resolve | Parman - Paranoid Bitcoin Mentor 🔑 (@parman_the) / X | 2 | magazine-032, magazine-048 | 0 | no | +| @sathoarder | resolve | Sathoarder #17⚡ (@sathoarder) / X | 2 | event-2022-08-28… | 0 | no | +| @Saylor | resolve | Michael Saylor (@saylor) / X | 6 | event-2022-10-07…, magazine-036/038/053/068 | 2 | yes | +| @SPACEBULL | resolve | MADEX (@spacebull) / X | 1 | magazine-061 | 0 | no | +| @staceski | resolve | Stacey Berisford (@StaceSki) / X | 2 | magazine-003 | 0 | no | +| @StackchainMag | resolve | Stackchain ⛓ Magazine (@Stackchainmag) / X | 1 | magazine-001 | 0 | no | +| @tim_niemeyer_ | resolve | Tim Niemeyer (@tim_niemeyer_) / X | 1 | magazine-062 | 0 | no | +| @waldovision3 | resolve | Waldo Stacker (@WaldoVision3) / X | 1 | magazine-025 | 0 | no | + +Bare-word names the `@`-rule cannot see, fetched the same way (`TARGETS/x-satskeeper_.meta`, +`TARGETS/x-StackchainQuant.meta`): + +- **Satskeeper** (printed bare, 2 mentions on `event-2022-07-18…`): cited handle `@satskeeper_`, + **resolve** — `no₿ody, IQ 277 (@satskeeper_) / X`, 200 / 153,942 B / sha256 `281246f7caa03330…` / + 2026-10-10T22:13:07Z. In registry. +- **StackchainQuant** (5 mentions across 3 entries): **404 / 37,702 B / sha256 + `985bf717f99e7173…`** / 2026-10-10T22:13:07Z, `User Profile Not Found - X | 404 Error + `. Not in registry (no entry cites it as a URL or contributor). + +Per-row detail in `census.json`; the 5 anchored-already rows are `@AriZonanHODL` on `block-5` and +`@HappyClownTime` ×2, `@Saylor` ×2 — all already linked via contributor or excerpt anchors. + +**Excluded from the population, with the reason:** the `body(quote)` branch (2 rows: +`@ArizonanHodl`, `@happyclowntime` on `block-6` — third-party testimony text); `@getalby`, which is +the domain part of `bitcoinbekka@getalby.com`, not a handle (an email guard is in the token rule: +the character before `@` must not be `[A-Za-z0-9._%+-]`); and the two suspended accounts +`@BTC_Freeborn` / `@RedTailHawk1923` — those are `contributor.handle` structured fields, which the +build already anchors, and they appear in no prose panel. + +## 7. Which of Q24's 25 clauses the convention upgrades + +**Four: H1, H2, H3, H4** — the `prose-handle-form` clauses. Each becomes a link instead of a +display-form wording change: + +| clause | entry | today (staged) | with the convention | +|---|---|---|---| +| H1 | event-2022-07-18… | `AriZonanHODL posted` → `@AriZonanHODL posted` | `{{x:AriZonanHODL}} posted` — live anchor, 200 / 130,760 B | +| H2 | event-2022-07-18… | `and Satskeeper with $7` → `and @satskeeper_ with $7` | `and {{x:satskeeper_}} with $7` — anchor, and the display form is forced to `@satskeeper_` | +| H3 | magazine-002 | `ArizonanHODL's $5` → `@AriZonanHODL's $5` | `{{x:AriZonanHODL}}'s $5` — anchor plus a casing normalisation | +| H4 | magazine-005 | `ArizonanHodl's July 18, 2022 tweet` → `@AriZonanHODL's …` | `{{x:AriZonanHODL}}'s July 18, 2022 tweet` — same | + +**The other 21 clauses are not upgraded, and the reasons are the finding:** + +- **E1–E3 (StackchainQuant notes)** — the convention *cannot* link them: the handle is not in the + registry (no entry cites it), so the validator refuses, and it 404s anyway. They stay notes. +- **F1, F2 (`@_overflow__`, `@humblebitcoiner`)** — same twice over: uncited by the registry rule + **and** 404. Anchoring a dead handle would trade a note for a dead link. +- **J1 (`bitcoinbekka@getalby.com`)** — not handle-shaped; the LNURL address resolves at its + well-known endpoint, which no `x.com` anchor can express. Stays a note. +- **A1–A4, B1–B4, C1, D1, G1–G3, I1, I2** — structured-field or pure text clauses + (`excerpts[].url`, `body_source_url`, `contributor.handle`, direction words, the `magazine-091` + wording). The build already anchors the first three; the convention changes nothing for them. + +## 8. Findings + +1. **The registry, not the token, is the binding constraint.** 19 of the 23 prose handles resolve + and are not cited anywhere in `blocks.json` — they are names, not sources. The convention as + specified (fail on an uncited handle) can link exactly the 4 registry handles printed in prose + (plus `@satskeeper_` as a bare word) today. Unlocking the other 19 is content work — adding + citations — not build work. +2. **The validator is doing evidentiary work, and that is the right trade.** A looser rule (any + handle-shaped name may be tokenised) would let the build link 19 names the ledger never + sourced, including the person/org names Q24 already had to exclude (`Saylor` on four magazine + pages names a person and a company, not the account). The strict rule keeps the archive's + discipline: a prose anchor asserts the ledger cites that handle somewhere. +3. **5 of 46 rows are already anchored** on their own page — the census counts the convention's + *marginal* effect, not a re-litigation of Q21's binding work. +4. **`{{`/`}}` collide with nothing** in `blocks.json` (0 occurrences of `{{`, `}}`, `[[`, `]]`), + so the syntax is safe to introduce today. +5. **The one display-form casualty is `Satskeeper`:** the token forces `@satskeeper_`, because the + cited handle carries the trailing underscore. Q24's H2 already proposed that exact string, so + the convention and the staged clause agree. + +## 9. Limits + +1. **Prototype only.** `build_blocks_proto.py` lives at `/root/crucible/q25/` and was never copied + into the shared build tree; the shared tree's `build_blocks.py` is at + `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672` and its `site-ledger` + byte-identical at close (§2). Publishing any build change is Alexander's, as Q13 states. +2. **23 handles is a census of the prose panels, not of the archive.** Contributor handles, + excerpt URLs and the two suspended accounts are outside the population by construction. +3. **A token in the quote branch prints literally.** `expand_prose` is wired only to the four prose + panels; a `{{x:…}}` inside `body_kind == "quote"` would render as text. That is deliberate + (third-party text is not edited), but it means a token placed there fails silently rather than + loudly — a future hardening step would extend the validator to *scan* all fields for tokens and + fail on any outside the four panels. +4. **X byte sizes and hashes are dated readings.** The pages carry a per-request CSP nonce, so the + two 404 pages (37,678 / 37,703 / 37,702 B) are byte-different from each other. The clock + (2026-10-10T22:12–22:13Z) is the evidence. +5. **`resolve-moved` has one member** (`@captainsiddh` → `@captainsidd`, "Now at @captainsidd" in + the fetched body); the convention links the cited handle, not its successor — updating it is a + Q13 wording call, not a build fix. + +## 10. Scripts (all re-runnable, `/root/crucible/q25/`) + +`baseline.py` (pristine build + live-tree diff + digest) · `census_tokens.py`, +`census_tokens2.py` (the census and its two fixes) · `probe_names.py` (bare-word contexts + +syntax collision check) · `fetch_targets.py` (25 fetches) · `rename_scan.py` · `map_clauses.py`, +`dump_clauses.py` (the Q24 mapping) · `show_registry.py` · `build_blocks_proto.py` (the +prototype) · `verify.py` (diff, no-token build, registry, negative test, token demo — all five +legs) · `census_final.py` (the §6 table) · `emit.py` (this file). + +Artifacts: `DIFF.txt` (+63/−6) · `BASELINE-BUILD.txt`, `BASELINE-DIGEST.txt` · +`NOTOKEN-BUILD.txt` · `REGISTRY.txt` (8 handles) · `NEGTEST.txt` (exit 1) · +`TOKEN-BUILD.txt`, `TOKEN-DIFF.txt` (3 of 125 files), `TOKEN-PAGES.txt` · `census.json`, +`census-final.json` · `TARGETS/` (25 profiles + `.meta` each) · `Q25-VERIFY.txt`.