queue: Q25 prose-anchor convention DONE (Merlin) - {{x:HANDLE}} token prototyped in scratch, no-token build byte-identical (tree digest 91ecf6bf, 125 files), validator negative-tested, census 46 rows/23 handles (20 resolve/1 moved/2 404), 4 of 24 Q24 clauses upgraded (H1-H4); shared build tree untouched
This commit is contained in:
1 parent
fd16e53813
commit
a9f23a69a4
3 files changed
+485
No files matched your search
@@ -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
|
||||
(`<a href="https://x.com/HANDLE">@HANDLE</a>`), 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/<id>` 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).**
|
||||
|
||||
@@ -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
|
||||
(`<a href="https://x.com/HANDLE">@HANDLE</a>`), 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/<id>` 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
|
||||
@@ -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/<id>` URLs put the literal
|
||||
segment `i` in an unguarded registry.
|
||||
- **Verdicts**, from a fetched `https://x.com/<handle>` with `curl` **without `-L`**:
|
||||
`resolve` (HTTP 200, live profile), `resolve-moved` (200, description reads `Now at @<other>`),
|
||||
`suspended` (200, `<h2>Account suspended</h2>`), `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
|
||||
<a href="https://x.com/HANDLE">@HANDLE</a>
|
||||
```
|
||||
|
||||
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: <slug>:<field>: 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/<handle>` **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, `<title>User Profile Not Found - X | 404 Error
|
||||
</title>`. 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`.
|
||||
Reference in new issue
Block a user