queue: Q24 the Q13 fix pack DONE (Merlin) - 25 clauses / 31 deltas staged unrun, 1 decided + 24 undecided, blast radius 20 of 125 emitted files; the finding is that the ledger build has no anchor mechanism for the prose panels, so every 'anchor it' clause naming a source in body/plain_summary cannot be staged as a link by any blocks.json field; Q25 proposed per Q7 (a prose-anchor convention, implemented in the build tree and left unpublished)

This commit is contained in:
Merlin committed 2026-10-10 20:07:48 +00:00
1 parent afc6ec3ae6
commit 3c8623fda4
4 files changed
+1181

No files matched your search

+114
View File
@@ -2611,3 +2611,117 @@ is what has kept them waiting.
**Status: open and unclaimed. Opened by the pipe 2026-10-10** because Q23 closed at `8b56abe` and the unclaimed
executable set fell to one. Nominated to Merlin, who holds the four fix lists — but any member may claim it, and
**declining it with a reason is a legitimate answer** (§3.7).
**Status: DONE — `docs/q13-fix-pack.md`, Merlin, 2026-10-10. 25 clauses (31 deltas): 1 `DECIDED`
(`D1` `magazine-091`, publication blocked by its own decided note) and 24 `undecided-for-Alexander`
(2 of them conditional rows). Combined blast radius 20 of 125 emitted files, measured by a real scratch
build; per-clause radius 1 file for all 25. Staged file `docs/q13-fix-pack/apply_fix_pack.py`
(25,361 B / sha256 `2d39df3cdfe466b33e45b19b8741f43b536d93e7ccde90f871e50e5cd6ffd1cd`), committed
unrun — every clause exercised in check mode, none applied to the build tree.**
- **The build chain was measured end to end before anything was staged**, not assumed:
`blocks.json` 278,459 B / sha256 `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`,
`build_blocks.py` 22,256 B / sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`,
a scratch build `Built 123 pages from 121 entries`, and `diff -rq` of that output against the build
tree's own `site-ledger` — **no output, 125 files each, byte-identical**. Then **every page fetched
HTTP 200 and byte-identical to the freshly emitted file**: the 20 entries the pack touches plus 5
controls, 25 pages, ~18:5x UTC. Ledger index unchanged at 200 / 34,488 B / sha256
`4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`. So
`blocks.json → build_blocks.py → site-ledger/<slug>/index.html → the live page` is verified
byte-for-byte at all four legs. **Documented.**
- **Population rule followed exactly, with two deviations flagged in the table.** Rows are one per
clause a closed audit routed to Q13, deduped by (entry, current string), re-testing nothing:
`A1`–`A4` (Q12 §6.1 = Q21 finding 1, same clause), `B1`–`B4` (Q21 verification addendum's
*"quoted below"* pointer defect), `C1` (the `plebiolira → flav1000` ownership note),
`E1`–`E3` (Q23's 3-entry StackchainQuant fix set, not Q22's 1), `F1`–`F2` and `G1`–`G3` (Q22's
anchor-or-strike set), `H1`–`H2` (Q23 + the `Satskeeper` addendum), `D1` (the one decided clause).
Deviations, both disclosed in-row: `I1` `magazine-026` (Q12 §6.3, outside the stated rule which
names findings 1–2) and `I2` `magazine-070` (admitted by rule 3a per the pipe's Q23 correction).
- **The structural finding, and it is the item's real result: the ledger build has no anchor
mechanism for the prose panels.** `build_blocks.py` emits `<a href>` in exactly three places —
`contributor.handle` (line 310), `body_source_url` (323), `excerpts[].url` (333). `body`,
`plain_summary.text`, `body_provenance` and `uncertainty` go through `esc()` with no anchor
support. **So every "anchor it" clause naming a source printed inside prose — `StackchainQuant`
×3, `AriZonanHODL` ×4, `Satskeeper`, the Lightning address — cannot be staged as a link by any
`blocks.json` field**, and is staged instead as a dated `uncertainty` append or a handle-form
wording change. Only the five `contributor-anchor` rows are real links. `contributor` also has
**one** `handle` slot, so `G1` anchors `BTC_Freeborn` and leaves `@AnthonyDessauer` unanchored on
a byline that names both. A prose-anchor convention would be a build change — Alexander's, not a
wizard's.
- **Four rows excluded with the reason stated, and one of them is a detector defect.** The
`Saylor` rows (`magazine-036/038/053/068`) fired only because `x.com/saylor/status/1578479561750110208`
is an excerpt URL on `event-2022-10-07-gui-s-2079-and-saylor-s-2080`; in the four pages the word is
*"Saylor Academy's free Bitcoin for Everyone course"* and *"Michael Saylor"* — a person and an
organisation named in the narrative, not a citation of the account. **No dead source was missed; the
residual sweep cannot tell the two apart.** `block-5` needs no action (resolves, prose already
discloses the capture date). The `x.com/i/…` addition is withdrawn per the pipe's 18:13Z addendum.
- **Proposed new values validated, not assumed.** `stackchainmagazine.net` detags to 5,024 chars with
`Skinner` **0** and the passage absent; `/a-conversation-with-burnchainers/` (200 / 155,367 B /
sha256 `33af2c4d78c7642db9a935cd9852ac22fffb151b443db3f49b097bc3964d9d8f`) carries `Skinner` **1**
and the passage **verbatim**; `github.com/plebiolira/stackchainsiggy_nostr` → **301**,
`Location: https://github.com/flav1000/stackchainsiggy_nostr`, and the flav1000 URL → 200 / 279,677 B.
- **The decided note conflict is surfaced, not resolved.** `decisions/2026-09-26.md` item 13 is
approved (2026-09-26T14:51:11.019Z) with `proposed_action` *publish the corrected wording* against a
`decided note` *add our note and escalate to the author and mag publisher*. Per the item's rule the
decided note controls, so `D1` is staged and not published. Nothing in `decisions/` was executed.
The pre-existing `EDITS/apply_editorial_fix_091.py` was re-run in check mode and still passes
(`entries: 121`, `note carried by entries: [91]`), so `D1` is that delta restated, not a second staging.
- **Own defects logged first, in the deliverable's §10.** (a) The first verifier searched each entry's
whole JSON region and reported `body` old-strings occurring **2×** on `event-2022-07-18`, because
`body` and `plain_summary.text` share the sentence; field-span scoping is what makes `H1`'s two
deltas land in two places. (b) The staged script's first version parsed arguments so `--decision`'s
value was read as the clause id (every apply failed with the usage message) and spliced
region-relative offsets into the full file text, producing `json.decoder.JSONDecodeError`. Both were
caught by the blast-radius run — the only step that would have caught them — and fixed before any
count was published.
- **Guard against an unapproved apply:** a clause marked `undecided-for-Alexander` refuses to apply
unless **both** `--force` and `--decision <artifact path>` are passed, so no clause can be staged in
a form that applies without the approval being named.
- **Limits.** 25 clauses is not 121 entries: no rate is claimed, and the 96 untouched entries were not
swept. Every byte count and sha256 is a dated reading from this host at the printed clock. Whether
the proposed wording reads well in the archive's voice is an editorial call and was not made.
Evidence files `/root/crucible/q24/{LIVE-READS,TARGET-READS,CHECK-RUN,BLAST-RADIUS,BLAST-ALL,
CONTROL-091}.txt` plus `mkclauses.py`, `gen_apply.py`, `blast.py`, `blast_all.py`, `emit_pack.py`,
all re-runnable.
- **Nothing touched:** no live page, no rebuild, no publish, no third-party contact, no other party's
file, nothing in `decisions/`, and the build tree's `blocks.json` was read-only throughout.
- **Lane after Q24:** the unclaimed executable set is empty (Q20 active and zephyrus-sparkborn's,
Q9 blocked on the audio handover, Q13/Q19 gated on Alexander), so **Q7's never-dry obligation is
triggered** — see the proposal at the foot of this file.
---
## Q25 — A prose-anchor convention for the ledger build *(archive-side; proposed 2026-10-10 by Merlin, per Q7's never-dry obligation — Q24 closed and the unclaimed executable set fell to zero)*
Q24 staged 25 verified live-page fixes and found the thing that stops ten of them being links rather than
disclosures: `build_blocks.py` emits an `<a href>` in exactly three places — `contributor.handle`
(`render_entry` line 310), `body_source_url` (line 323) and `excerpts[].url` (line 333). Everything in
`body`, `plain_summary.text`, `body_provenance` and `uncertainty` goes through `esc()` with no anchor
support at all. So `StackchainQuant` on three entries, `AriZonanHODL` on four, `Satskeeper`, the
`bitcoinbekka@getalby.com` address — every one of them a source the archive names to the reader — **cannot
be linked by any `blocks.json` field**. Q24 staged them as dated `uncertainty` notes instead, which is
honest and is the only form the build supports today.
**Do this:** design and implement a minimal prose-anchor convention in the build tree
(`/root/stackchain-legends-build/`), unpublished — a markup token `render_entry` expands into the same
`<a href="https://x.com/<handle>">@<handle></a>` it already emits for `contributor.handle`, plus a
validator that fails the build if a token names a handle no entry cites. Then measure what it would buy:
a census of every handle-shaped token in the 121 entries' prose panels, how many resolve, how many are
already anchored elsewhere on the same page, and which of Q24's 25 clauses it would convert from a note
into a link.
**Scope boundary:** the convention is **implemented and measured in the build tree only**. No rebuild of
the live site, no publish, no `blocks.json` edit, no third-party contact — publishing a build change is
Alexander's, exactly as Q13 states. This item produces a design, a diff, and a census; it does not ship one.
**Done means:** a record naming the convention's exact syntax, the `render_entry` change as a diff against
the current `build_blocks.py` (sha256 `97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`),
a build that still emits byte-identical output for the 121 entries when no token is present, the
handle-token census with resolve/404/suspended verdicts, and the list of Q24 clauses the convention would
upgrade.
**Evidence:** the diff, the before/after emitted-tree digests proving a no-token build is unchanged, the
census table with a fetched URL per row, and the named Q24 clause ids.
**Why it earns a slot:** Q24 closed with zero unclaimed executable items, which is Q7's trigger. This is
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.
+164
View File
@@ -719,3 +719,167 @@ byte-checkable from outside this host. No secret is printed in this check-in or
the long strings in them are X page titles, LNURL JSON, archive prose and sha256 digests.
— Merlin
---
# Run 5 — Q24, claimed and finished (the Q13 fix pack)
> 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 **Q24 — the Q13 fix pack: stage every verified live-page fix as one reviewable
approval**, the item the pipe opened at 18:0xZ, nominated to me, and the top unclaimed executable item
(Q20 is active and zephyrus-sparkborn's; Q9 blocked on the audio handover; Q13/Q19 gated on Alexander).
Deliverables: `docs/q13-fix-pack.md` (**32,942 B**, sha256
`77faaaa5f8939f5ecde7f46d7acfcd5b535321dbbc31f688a02ec66a14616b4e`) — the build-chain evidence, the
25-row clause table in the fixed column order `entry | live page | panel | current string | proposed string
| authority (artifact + clock) | decided / undecided | staged file`, the counts, the `decisions/`
reconciliation, the structural finding, the excluded rows, the alternative remedies, the staging record,
the method and the limits — and `docs/q13-fix-pack/apply_fix_pack.py` (**25,361 B**, sha256
`2d39df3cdfe466b33e45b19b8741f43b536d93e7ccde90f871e50e5cd6ffd1cd`), the staged script, **committed unrun**.
**Result: 25 clauses, 31 deltas — 1 `DECIDED` and 24 `undecided-for-Alexander` (2 of them conditional
rows).** Every clause is one explicit `old → new` delta against `/root/stackchain-legends-build/blocks.json`,
located by its entry's unique title and scoped to a single field's own JSON span.
**The build chain was measured end to end before anything was staged.** `blocks.json` 278,459 B / sha256
`63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`; `build_blocks.py` 22,256 B / sha256
`97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672`; a build on a scratch copy at
`/root/crucible/q24/build/` → `Built 123 pages from 121 entries (121 cleared, 0 research-only)`, and
`diff -rq` of that output against the build tree's own `site-ledger` → **no output, 125 files each,
byte-identical**. Then **every page fetched HTTP 200 and byte-identical to the freshly emitted file** — the
20 entries the pack touches plus 5 controls, 25 pages (`/root/crucible/q24/LIVE-READS.txt`), e.g.
`magazine-091` 200 / 4,559 B / sha256 `8b00bbb09a13a47679a7082cf915b97d2c66f16dcbd5fdfe4fba945da5f14377`.
Ledger index unchanged at 200 / 34,488 B / sha256 `4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`.
So `blocks.json → build_blocks.py → site-ledger/<slug>/index.html → the live page` holds byte-for-byte at
all four legs.
**The structural finding, which is the item's real result: the ledger build has no anchor mechanism for the
prose panels.** `build_blocks.py` emits `<a href>` in exactly three places — `contributor.handle`
(`render_entry` line 310), `body_source_url` (323), `excerpts[].url` (333). `body`, `plain_summary.text`,
`body_provenance` and `uncertainty` are emitted through `esc()` with no anchor support. **Every "anchor it"
clause naming a source printed inside prose — `StackchainQuant` on three entries, `AriZonanHODL` on four,
`Satskeeper`, the Lightning address — cannot be staged as a link by any `blocks.json` field**, so those are
staged as dated `uncertainty` appends or handle-form wording changes instead. Only the five
`contributor-anchor` rows are real links. `contributor` also has **one** `handle` slot, so `G1` anchors
`BTC_Freeborn` and leaves `@AnthonyDessauer` unanchored on a byline naming both.
**Blast radius, measured by a real scratch build, not inferred.** Per clause: **25 of 25 change exactly one
emitted file — the entry's own `index.html`**; no clause touches `blocks/index.html`, `sitemap.xml` or
`ledger.css`. Combined: **20 of 125** emitted files (`/root/crucible/q24/BLAST-RADIUS.txt`,
`BLAST-ALL.txt`). Spot checks on the applied scratch pages: `block-25` carries the
`a-conversation-with-burnchainers` permalink, no longer carries the bare site root as an anchor, and reads
*"quoted above"*; `magazine-091` no longer contains *"Comparing Strategy"*, contains *"Comparing Twenty
One"*, and carries the correction note; `magazine-039` carries `href="https://x.com/captainsiddh"` and the
move note; `magazine-070` carries `href="https://x.com/MidyReyes"`.
**The proposed new values were validated, not assumed.** `https://www.stackchainmagazine.net` detags to
5,024 characters with `Skinner` **0** times and the passage absent;
`https://www.stackchainmagazine.net/a-conversation-with-burnchainers/` (200 / 155,367 B / sha256
`33af2c4d78c7642db9a935cd9852ac22fffb151b443db3f49b097bc3964d9d8f`) carries `Skinner` **1** time and the
passage **verbatim**; `https://github.com/plebiolira/stackchainsiggy_nostr` → **301**,
`Location: https://github.com/flav1000/stackchainsiggy_nostr`, and the flav1000 URL → **200 / 279,677 B**
(`/root/crucible/q24/TARGET-READS.txt`).
**Four candidate rows excluded with the reason stated, one of them a detector defect.** The `Saylor` rows
(`magazine-036/038/053/068`) fired only because `https://x.com/saylor/status/1578479561750110208` is an
excerpt URL on `event-2022-10-07-gui-s-2079-and-saylor-s-2080`; in the four pages the word is *"Saylor
Academy's free Bitcoin for Everyone course"* and *"Michael Saylor and Nayib Bukele"* — a person and an
organisation named in the narrative, not a citation of the account. **No dead source was missed; the
residual sweep cannot tell the two apart.** `block-5` needs no action. The `x.com/i/…` addition is
withdrawn per the pipe's 18:13Z addendum.
## Blocked
Nothing blocked the run. One thing is **deliberately unresolved rather than executed**: `decisions/2026-09-26.md`
item 13 (`magazine-091`) is approved at 2026-09-26T14:51:11.019Z with `proposed_action` *"publish the
corrected wording to the live magazine-091 page"* against a `decided note` *"Do we even have authority to fix
the publication? Add our note and escalate it to the author and mag publisher."* Per the item's own rule the
**decided note controls**, so `D1` is staged and not published. Nothing in `decisions/` was executed.
Limits, stated in the deliverable:
- **25 clauses is not 121 entries.** No rate is claimed and the 96 untouched entries were not swept.
- **The staged script is committed unrun.** Every clause was exercised in **check mode** (locator, field
span, and `old` occurring exactly once inside it) and **none was applied to the build tree's
`blocks.json`**. The scratch applications used for blast radius ran against copies under
`/root/crucible/q24/blast/`. `/root/crucible/q24/CHECK-RUN.txt` holds all 25 runs with exit codes.
- **Every byte count and sha256 is a dated reading** from this host at the printed clock. The site root is
byte-stable at 215,8xx B but has carried two digests today; X pages carry a per-request CSP nonce.
- **Whether the proposed wording reads well in the archive's voice is an editorial call and was not made.**
The note texts are drafts in the archive's register, staged for you to accept, edit or reject.
## Next
**Q25 — a prose-anchor convention for the ledger build**, proposed at the foot of `WORK-QUEUE.md` because
Q24 closed and the unclaimed executable set fell to **zero**, which is Q7's never-dry trigger. It is the
direct successor to this run's structural finding: design and implement the convention in the build tree
**unpublished**, prove a no-token build still emits byte-identical output for all 121 entries, and census
which handle-shaped tokens in the prose panels it would anchor and which of Q24's 25 clauses it would
upgrade from a note into a link. Scope boundary stated in the item so it cannot drift into a publish.
**Q13 stays gated on you.** Every clause in the pack is either a live-page text change or a link change, and
the one decided clause is blocked by its own decided note. Nothing executed on `decisions/`.
## Ask
Three decisions, none of them blockers:
1. **Release `D1` (`magazine-091`) or hold it?** The approval and the note disagree, and the note is the
one that controls. If you want the wording published, say so against the note; if you want the courtesy
note and the escalation first, `D1` stays staged. Either way it is one rebuild of one page.
2. **The 24 undecided clauses — approve as a pack, or clause by clause?** The pack exists so the answer can
be one line. `A1`–`A4` and `B1`–`B4` are the lowest-risk eight (a URL that does not contain its quote,
and a direction word pointing the wrong way, on four pages); `E1`–`E3` change what three entries assert
about a source that no longer exists and are the ones worth reading in full.
3. **Build the prose-anchor convention (Q25), or leave the archive's unlinked-prose style as-is?** Until it
exists, ten of these clauses can only ever be disclosures rather than links.
## Run detail — Q24
**Clock and host.** All fetches from this host, 2026-10-10 ~18:40–19:1x UTC. Working tree at
`/root/crucible/q24/` (scratch build at `build/`, 25 live pages at `live/`, four target bodies at
`targets/`, per-clause scratch applies at `blast/<id>/`, the combined one at `blast/ALL/`). Repo at
`/root/troupe-standup`, branch `main`, HEAD before this run `afc6ec3`, working tree clean.
**Scripts, all re-runnable.** `mkclauses.py` (the clause table and its field-span verifier),
`gen_apply.py` (the staged-script generator), `blast.py` (per-clause radius), `blast_all.py` (combined
radius + applied-page spot checks), `fetch_live.py`, `fetch_targets.py`, `run_checks.py`,
`emit_pack.py` (writes the deliverable), plus `explore*.py`, `rawfmt.py`, `contexts*.py`, `dbg.py`.
**Counts, recomputed not accepted.** 121 entries; entry titles unique across all of them (checked — that is
what makes the title locator safe); the bare site root appears as an excerpt URL exactly **4** times in the
whole file, so the `A` group is a complete census of that defect, not a sample. 25 clauses / 31 deltas;
kinds 6 `uncertainty-append`, 5 `excerpt-url`, 5 `contributor-anchor`, 4 `direction-word`,
4 `prose-handle-form`, 1 `body-clause`. Verdicts 1 decided / 23 undecided / 2 undecided-conditional.
25/25 check-mode runs exit 0. Blast radius 1 file × 25; combined 20 of 125.
**Four of my own defects, logged first in the deliverable's §10.** (a) The first verifier searched each
entry's whole JSON region and reported `body` old-strings occurring **2×** on `event-2022-07-18`, because
`body` and `plain_summary.text` share the sentence — field-span scoping is what makes `H1`'s two deltas
land in two places and nothing else. (b) The staged script's first version parsed arguments so
`--decision`'s value was read as the clause id, and every apply failed with the usage message. (c) The same
version spliced **region-relative** offsets into the **full file** text, producing invalid JSON
(`json.decoder.JSONDecodeError: Expecting ',' delimiter`). (b) and (c) were caught by the blast-radius run,
which is the only step that would have caught them, and both were fixed before any count was published.
(d) `magazine-070` was missing from the first live-fetch list, which surfaced as an empty cell in the
emitted table rather than as a silent gap.
**The control that mattered.** The build tree's pre-existing `EDITS/apply_editorial_fix_091.py` was re-run
in check mode and still passes against today's `blocks.json` (`entries: 121`, `note carried by entries:
[91]`, body now reads *"Comparing Twenty One, …"*, `CHECK ONLY — blocks.json not written`,
`/root/crucible/q24/CONTROL-091.txt`). So `D1` is that delta restated in the pack's format, not a second
staging, and the pack's one decided clause is the one the archive already agreed to.
**Files written this run:**
- `docs/q13-fix-pack.md` (new — the deliverable)
- `docs/q13-fix-pack/apply_fix_pack.py` (new — the staged script, committed unrun)
- `WORK-QUEUE.md` (Q24 status block → DONE; Q25 proposed per Q7)
- `checkins/2026-10-10-merlin.md` (this section)
**Landing evidence.** The commit, push and anonymous read-back are recorded in the block appended after
this run commits.
+260
View File
@@ -0,0 +1,260 @@
# The Q13 fix pack — every verified live-page fix, staged as one reviewable approval
**Run by Merlin, 2026-10-10, from this host.** Deliverable for queue item **Q24**. Nothing in this run
applied a fix, rebuilt the ledger, published a page, touched a live page, edited another party's file, or
executed anything in `decisions/`. The only writes were to this file and to the staged script.
**Result: 25 clauses — 1 `DECIDED` (with a conflict that blocks publication) and 24
`undecided-for-Alexander`.** Combined blast radius, measured by a real scratch build: **20 of 125 emitted
files** change if all 25 were applied. Every clause is one explicit `old → new` delta against
`/root/stackchain-legends-build/blocks.json`, located by its entry's unique title and scoped to a single
field's own JSON span, so a string shared by `body` and `plain_summary.text` cannot be double-edited.
## 1. The build chain, measured end to end before anything was staged
`blocks.json` is the build source; `build_blocks.py` emits the pages; the live site serves a copy of that
output. All three legs were checked on this run, not assumed:
```
$ sha256sum /root/stackchain-legends-build/blocks.json
63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d blocks.json (278,459 B)
$ sha256sum /root/stackchain-legends-build/build_blocks.py
97fedb5dd5e85d2b10071e8e4904b3a9b1573072149e722fbece93eaf0774672 build_blocks.py (22,256 B)
$ python3 build_blocks.py # run on a scratch COPY at /root/crucible/q24/build/
Built 123 pages from 121 entries (121 cleared, 0 research-only)
$ diff -rq /root/crucible/q24/build/site-ledger /root/stackchain-legends-build/site-ledger
(no output — 125 files each, byte-identical)
```
The build tree's own emitted output is therefore current with its source, which is what makes a
blast-radius measurement on a scratch build meaningful. Then the live pages:
**Every page fetched: HTTP 200 and byte-identical to the freshly emitted file.** That is the 20 entries
this pack touches plus 5 controls (`event-2022-07-18-anthony-enters-at-16-names-the-hill-at-24`,
`magazine-036/038/053/068`) — 25 pages, `cmp`/sha256, 2026-10-10 ~18:5x UTC. The ledger index is unchanged at **200 / 34,488 B / sha256
`4f764ef4dfb9c08b2654ff0783550d20ad1bb7a31cb0c32070974a5fe451557e`** — the same figure every earlier run
today recorded. Full per-page list in `/root/crucible/q24/LIVE-READS.txt`.
So the chain is `blocks.json → build_blocks.py → site-ledger/<slug>/index.html → the live page`, verified
byte-for-byte at all four legs. **Documented.**
## 2. Shared strings, quoted once
`UNC_MAG` — the `uncertainty` value carried by all 91 magazine entries, verbatim:
> `Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.`
Three entries have their own `uncertainty` text and are quoted in full in their rows. `magazine-091`'s
is `UNC_MAG`.
## 3. The clause table
Fixed column order, as the item specifies: `entry | live page | panel | current string | proposed string |
authority (artifact + clock) | decided / undecided | staged file`. `\|` inside a cell is an escaped pipe.
| entry | live page | panel | current string | proposed string | authority (artifact + clock) | decided / undecided | staged file |
|---|---|---|---|---|---|---|---|
| `A1` | block-25 | `https://alexanderwhitestone.com/stackchain/block-25/` (200 / 3,582 B / sha256 `b0bdc88b6fe2…`) | From the sources | `"https://www.stackchainmagazine.net"` | `"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/"` | recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `A1`; blast radius 1 file: `block-25/index.html`) |
| `A2` | block-88 | `https://alexanderwhitestone.com/stackchain/block-88/` (200 / 3,315 B / sha256 `de910b3d698c…`) | From the sources | `"https://www.stackchainmagazine.net"` | `"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/"` | recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `A2`; blast radius 1 file: `block-88/index.html`) |
| `A3` | block-89 | `https://alexanderwhitestone.com/stackchain/block-89/` (200 / 3,181 B / sha256 `3534dce9ea99…`) | From the sources | `"https://www.stackchainmagazine.net"` | `"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/"` | recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `A3`; blast radius 1 file: `block-89/index.html`) |
| `A4` | block-90 | `https://alexanderwhitestone.com/stackchain/block-90/` (200 / 3,408 B / sha256 `2575fa6e52e6…`) | From the sources | `"https://www.stackchainmagazine.net"` | `"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/"` | recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `A4`; blast radius 1 file: `block-90/index.html`) |
| `B1` | block-25 | `https://alexanderwhitestone.com/stackchain/block-25/` (200 / 3,582 B / sha256 `b0bdc88b6fe2…`) | Provenance | `quoted below` | `quoted above` | WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `B1`; blast radius 1 file: `block-25/index.html`) |
| `B2` | block-88 | `https://alexanderwhitestone.com/stackchain/block-88/` (200 / 3,315 B / sha256 `de910b3d698c…`) | Provenance | `quoted below` | `quoted above` | WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `B2`; blast radius 1 file: `block-88/index.html`) |
| `B3` | block-89 | `https://alexanderwhitestone.com/stackchain/block-89/` (200 / 3,181 B / sha256 `3534dce9ea99…`) | Provenance | `quoted below` | `quoted above` | WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `B3`; blast radius 1 file: `block-89/index.html`) |
| `B4` | block-90 | `https://alexanderwhitestone.com/stackchain/block-90/` (200 / 3,408 B / sha256 `2575fa6e52e6…`) | Provenance | `quoted below` | `quoted above` | WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `B4`; blast radius 1 file: `block-90/index.html`) |
| `C1` | event-2023-05-00-siggy-reaches-nostr | `https://alexanderwhitestone.com/stackchain/event-2023-05-00-siggy-reaches-nostr/` (200 / 3,393 B / sha256 `b7fb05fee1b7…`) | From the sources | `"https://github.com/plebiolira/stackchainsiggy_nostr"` | `"https://github.com/flav1000/stackchainsiggy_nostr"` | recoveries/excerpt-binding-audit.md fetch note (301 observed) + recoveries/summary-fidelity-nonmagazine.md ev-017 row 1 + recoveries/ledger-audit-pass2.md row 19; 301 re-observed this run | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `C1`; blast radius 1 file: `event-2023-05-00-siggy-reaches-nostr/index.html`) |
| `D1` | magazine-091 | `https://alexanderwhitestone.com/stackchain/magazine-091/` (200 / 4,559 B / sha256 `8b00bbb09a13…`) | What happened + Uncertainty | body: `Comparing Strategy, Twenty One, Nakamoto, Metaplanet, Coinsilium and Smarter Web returns and drawdowns against Bitcoin, they find none consistently outperform,`<br>uncertainty: `Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.` | body: `Comparing Twenty One, Nakamoto, Metaplanet, Coinsilium and Smarter Web against Bitcoin — with earlier pioneers such as Strategy set aside as not a fair comparison — they find none consistently outperform,`<br>uncertainty: `Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Correction 2026-09-26: this summary previously listed Strategy among the firms compared. The article sets Strategy aside (“not a fair comp for these newcomers”) and excludes it from the comparison; the listing was the archive’s error, not the article’s. Strategy has been removed from the compared set.` | decisions/2026-09-26.md item 13, approved 2026-09-26T14:51:11.019Z; staged record /root/stackchain-legends-build/EDITS/2026-09-26-magazine-091-correction.md | DECIDED (approved) — decided note conflicts with proposed_action; see §5 | `docs/q13-fix-pack/apply_fix_pack.py` (clause `D1`; blast radius 1 file: `magazine-091/index.html`) |
| `E1` | event-2022-08-18-the-bitcoin-beach-campaign-closes-and-hodlon | `https://alexanderwhitestone.com/stackchain/event-2022-08-18-the-bitcoin-beach-campaign-closes-and-hodlon/` (200 / 4,397 B / sha256 `3b3002d4d5fc…`) | Uncertainty | `Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.` | `Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.` + ` Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date.` | recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `E1`; blast radius 1 file: `event-2022-08-18-the-bitcoin-beach-campaign-closes-and-hodlon/index.html`) |
| `E2` | event-2022-08-28-the-fork-of-1492 | `https://alexanderwhitestone.com/stackchain/event-2022-08-28-the-fork-of-1492/` (200 / 4,380 B / sha256 `a55da02af6a3…`) | Uncertainty | `Event status as recorded by the history research: event corroborated; tactics from participant retrospective. The date basis is the reported event date, not necessarily a verified post timestamp.` | `Event status as recorded by the history research: event corroborated; tactics from participant retrospective. The date basis is the reported event date, not necessarily a verified post timestamp.` + ` Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date.` | recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `E2`; blast radius 1 file: `event-2022-08-28-the-fork-of-1492/index.html`) |
| `E3` | event-2022-10-05-the-community-documents-its-scale-and-charit | `https://alexanderwhitestone.com/stackchain/event-2022-10-05-the-community-documents-its-scale-and-charit/` (200 / 3,929 B / sha256 `a1e2eb193c83…`) | Uncertainty | `Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.` | `Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.` + ` Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date.` | recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `E3`; blast radius 1 file: `event-2022-10-05-the-community-documents-its-scale-and-charit/index.html`) |
| `F1` | magazine-020 | `https://alexanderwhitestone.com/stackchain/magazine-020/` (200 / 4,123 B / sha256 `88ae01d3aba8…`) | Uncertainty | UNC_MAG (see §2) | UNC_MAG (see §2) + ` Note 2026-10-10: the byline handle @_overflow__ returns HTTP 404 at https://x.com/_overflow__ (X: “User Profile Not Found”). The name is retained as printed and is not currently linkable.` | recoveries/named-source-liveness.md row 1 (2026-10-10T15:39:17Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `F1`; blast radius 1 file: `magazine-020/index.html`) |
| `F2` | magazine-051 | `https://alexanderwhitestone.com/stackchain/magazine-051/` (200 / 4,529 B / sha256 `2e3065c6c7a7…`) | Uncertainty | UNC_MAG (see §2) | UNC_MAG (see §2) + ` Note 2026-10-10: the byline handle @humblebitcoiner returns HTTP 404 at https://x.com/humblebitcoiner (X: “User Profile Not Found”). The name is retained as printed and is not currently linkable.` | recoveries/named-source-liveness.md row 2 (2026-10-10T15:39:33Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `F2`; blast radius 1 file: `magazine-051/index.html`) |
| `G1` | magazine-035 | `https://alexanderwhitestone.com/stackchain/magazine-035/` (200 / 4,543 B / sha256 `871638b8abb5…`) | Contributor | contributor.display_name: `"@BTC_Freeborn and @AnthonyDessauer"`<br>contributor.handle: `null` | contributor.display_name: `"BTC_Freeborn and Anthony Dessauer"`<br>contributor.handle: `"BTC_Freeborn"` | recoveries/named-source-liveness.md row 3 (2026-10-10T15:39:21Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `G1`; blast radius 1 file: `magazine-035/index.html`) |
| `G2` | magazine-056 | `https://alexanderwhitestone.com/stackchain/magazine-056/` (200 / 4,346 B / sha256 `33b55f8f61fe…`) | Contributor | contributor.display_name: `"Red Tail Hawk (@RedTailHawk1923)"`<br>contributor.handle: `null` | contributor.display_name: `"Red Tail Hawk"`<br>contributor.handle: `"RedTailHawk1923"` | recoveries/named-source-liveness.md row 4 (2026-10-10T15:39:33Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `G2`; blast radius 1 file: `magazine-056/index.html`) |
| `G3` | magazine-039 | `https://alexanderwhitestone.com/stackchain/magazine-039/` (200 / 4,272 B / sha256 `65e07c4e638a…`) | Contributor + Uncertainty | contributor.handle: `null`<br>uncertainty: `Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.` | contributor.handle: `"captainsiddh"`<br>uncertainty: `Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Note 2026-10-10: the handle @captainsiddh resolves, but its own profile description reads “Now at @captainsidd” and https://x.com/captainsidd resolves; the byline above is one handle behind the account’s current home.` | recoveries/named-source-liveness.md row 5 (2026-10-10T15:39:22Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `G3`; blast radius 1 file: `magazine-039/index.html`) |
| `H1` | event-2022-07-18-the-5-invitation-becomes-a-chain | `https://alexanderwhitestone.com/stackchain/event-2022-07-18-the-5-invitation-becomes-a-chain/` (200 / 4,281 B / sha256 `f208a26cd154…`) | What happened + In plain English | body: `AriZonanHODL posted a $5 bitcoin purchase`<br>plain_summary.text: `AriZonanHODL posted a $5 bitcoin purchase` | body: `@AriZonanHODL posted a $5 bitcoin purchase`<br>plain_summary.text: `@AriZonanHODL posted a $5 bitcoin purchase` | recoveries/named-source-liveness-unlinked.md finding 2 (2026-10-10T17:49:31Z); https://x.com/AriZonanHODL 200 / 130,908 B | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `H1`; blast radius 1 file: `event-2022-07-18-the-5-invitation-becomes-a-chain/index.html`) |
| `H2` | event-2022-07-18-the-5-invitation-becomes-a-chain | `https://alexanderwhitestone.com/stackchain/event-2022-07-18-the-5-invitation-becomes-a-chain/` (200 / 4,281 B / sha256 `f208a26cd154…`) | What happened | `and Satskeeper with $7` | `and @satskeeper_ with $7` | WORK-QUEUE.md §Q24 addendum 2026-10-10 18:13Z (Satskeeper resolves as @satskeeper_, already linked on block-7) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `H2`; blast radius 1 file: `event-2022-07-18-the-5-invitation-becomes-a-chain/index.html`) |
| `H3` | magazine-002 | `https://alexanderwhitestone.com/stackchain/magazine-002/` (200 / 4,433 B / sha256 `13a31d232159…`) | What happened | `ArizonanHODL's $5` | `@AriZonanHODL's $5` | WORK-QUEUE.md §Q23 verification correction (rule 3b yields 8 bare-and-unlinked mentions across 6 entries) — CONDITIONAL on step 5’s filter | undecided-for-Alexander (conditional row) | `docs/q13-fix-pack/apply_fix_pack.py` (clause `H3`; blast radius 1 file: `magazine-002/index.html`) |
| `H4` | magazine-005 | `https://alexanderwhitestone.com/stackchain/magazine-005/` (200 / 4,287 B / sha256 `5681dc960dfe…`) | What happened | `ArizonanHodl's July 18, 2022 tweet` | `@AriZonanHODL's July 18, 2022 tweet` | WORK-QUEUE.md §Q23 verification correction (rule 3b) — CONDITIONAL on step 5’s filter | undecided-for-Alexander (conditional row) | `docs/q13-fix-pack/apply_fix_pack.py` (clause `H4`; blast radius 1 file: `magazine-005/index.html`) |
| `I1` | magazine-026 | `https://alexanderwhitestone.com/stackchain/magazine-026/` (200 / 4,554 B / sha256 `67f141e2b1c1…`) | Contributor | `null` | `"a_koby"` | recoveries/evidence-tier-audit.md §6.3 (2026-10-10) — OUTSIDE the Q24 population rule, which names findings 1–2; included and flagged | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `I1`; blast radius 1 file: `magazine-026/index.html`) |
| `I2` | magazine-070 | `https://alexanderwhitestone.com/stackchain/magazine-070/` (200 / 4,599 B / sha256 `6227e199522f…`) | Contributor | contributor.display_name: `"@MidyReyes"`<br>contributor.handle: `null` | contributor.display_name: `"MidyReyes"`<br>contributor.handle: `"MidyReyes"` | WORK-QUEUE.md §Q23 verification correction (rule 3a admits MidyReyes on magazine-070) — OUTSIDE the Q24 population rule; included and flagged | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `I2`; blast radius 1 file: `magazine-070/index.html`) |
| `J1` | magazine-024 | `https://alexanderwhitestone.com/stackchain/magazine-024/` (200 / 4,150 B / sha256 `076df5d248de…`) | Uncertainty | UNC_MAG (see §2) | UNC_MAG (see §2) + ` Note 2026-10-10: the tipping address bitcoinbekka@getalby.com resolves at its canonical LNURL-pay endpoint https://getalby.com/.well-known/lnurlp/bitcoinbekka (HTTP 200); the vanity web path https://getalby.com/bitcoinbekka returns 404. It is not linked here because the ledger build emits anchors only for contributor handles, body sources and excerpt URLs.` | recoveries/named-source-liveness-unlinked.md finding 3 (2026-10-10T17:49:31Z) | undecided-for-Alexander | `docs/q13-fix-pack/apply_fix_pack.py` (clause `J1`; blast radius 1 file: `magazine-024/index.html`) |
## 4. Counts
| state | count |
|---|---|
| `DECIDED` (approved, publication blocked by its own decided note) | **1** — `D1` `magazine-091` |
| `undecided-for-Alexander` | **23** |
| `undecided-for-Alexander` (conditional row — enters only if step 5's *named as a source of record* filter is **not** written into Q23's header) | **2** — `H3` `magazine-002`, `H4` `magazine-005` |
| **total clauses** | **25** (31 deltas) |
By remedy shape: 6 `uncertainty-append`, 5 `excerpt-url`, 5 `contributor-anchor`, 4 `direction-word`, 4 `prose-handle-form`, 1 `body-clause`. (`G3` carries an `uncertainty` note alongside its
`contributor.handle` delta, which is why its panel reads *Contributor + Uncertainty*.)
## 5. Reconciliation against `decisions/` — one conflict, and it blocks the one decided clause
`decisions/2026-09-26.md` item 13 (`magazine-091`) is **approved**, `decided_at 2026-09-26T14:51:11.019Z`,
relayed by `2eb50b7`. Its two halves disagree:
- **`proposed_action`:** *"Approve: publish the corrected wording to the live magazine-091 page."*
- **`decided note`:** *"Do we even have authority to fix the publication? Add our note and escalate it to
the author and mag publisher."*
Per the item's own rule the **decided note controls**, so `D1` is staged and **not** published: applying it
would put corrected wording on a live third-party-summarised page while Alexander's note asks for a
courtesy note and an escalation instead. This is the same conflict Q13's record already carries; it is
surfaced here rather than resolved. **This is the one clause in the pack that a decision could release
immediately, and the decision that would release it is the one currently holding it.**
`decisions/2026-10-06-human-gates.md` was read and bears on nothing in this pack (repository visibility,
G2i skip). `decisions/2026-10-07.md` and `2026-10-07-cassian-write-grant.md` are cassian's write grant and
bear on nothing here. **Nothing in `decisions/` was executed.**
The pre-existing staged clause was re-checked, not re-staged: the build tree's
`EDITS/apply_editorial_fix_091.py` in check-only mode still passes against today's `blocks.json`
(`entries: 121`, `note carried by entries: [91]`, body now reads *"Comparing Twenty One, …"*,
`CHECK ONLY — blocks.json not written`). `D1` in this pack is that same delta restated in the pack's own
format, not a second staging.
## 6. The structural finding: the ledger build has no anchor mechanism for the prose panels
`build_blocks.py` emits an `<a href>` in exactly three places — `contributor.handle`
(`render_entry` line 310), `body_source_url` (line 323) and `excerpts[].url` (line 333). `body`,
`plain_summary.text`, `body_provenance` and `uncertainty` are emitted through `esc()` with no anchor
support at all.
**Consequence for this pack:** of the clauses the four closed audits routed here as *"anchor it"*, only the
six `contributor-anchor` rows can be staged as a link. Every name printed inside `body` or
`plain_summary` — `StackchainQuant` on three entries, `AriZonanHODL` on four, `Satskeeper`, the Lightning
address — **cannot be anchored by any `blocks.json` field**. Those are staged in the only form the build
supports today: a dated `uncertainty` append, or a wording change that makes the handle form explicit.
Two things follow, both for Alexander and neither for this run:
1. A prose-anchor convention (a markup token `render_entry` expands into a link) would convert roughly ten
of these clauses from a disclosure into a link. It is a build change, so it is outside this item's scope
and outside a wizard's initiative.
2. `contributor` has **one** `handle` slot. `magazine-035`'s byline names two accounts
(`@BTC_Freeborn and @AnthonyDessauer`); `G1` anchors the first and leaves the second unanchored, and no
`blocks.json` edit can do better without a schema change.
## 7. Rows deliberately NOT in the pack, with the reason
| candidate | source that raised it | why it is not a row |
|---|---|---|
| `magazine-036`, `magazine-038`, `magazine-053`, `magazine-068` — the bare word `Saylor` | Q23's verification correction: rule 3b yields 8 bare-and-unlinked mentions across 6 entries, and names these four | **Over-match.** The token fired only because `https://x.com/saylor/status/1578479561750110208` is an excerpt URL on `event-2022-10-07-gui-s-2079-and-saylor-s-2080`. In the four pages the word is *"Saylor Academy's free Bitcoin for Everyone course"* (`magazine-036`) and *"Michael Saylor and Nayib Bukele"* / *"Michael Saylor"* (`magazine-038`, `053`, `068`) — a person and an organisation named in the narrative, not a citation of the X account. No dead source was missed; the detector cannot tell the two apart. |
| `block-5` — the bare Wayback URL in Provenance prose | Q22/Q23 both graded it `resolve` and both said *no action* | It resolves (200, fetched with `-L`, 0 redirects) and the prose already discloses the capture date. Anchoring it would need the same missing prose mechanism. No defect. |
| the `x.com/i/…` "nine-segment" addition | Q24's own step 5, as first drafted | **Withdrawn by the pipe** in the 2026-10-10 18:13Z addendum: no `<a href>` on any page the index links points at `x.com/i/…`. Adds nothing. |
| `event-2022-07-18-anthony-enters-at-16-names-the-hill-at-24` | fetched as a control | No clause. `StackchainQuant` is not named on it; its named-source state is Q12's `event-2022-08-18` row. |
## 8. Alternative remedy shapes, named but not staged
Each of these is a real, explicit delta on the same entry. They are recorded rather than staged so that
Alexander's choice is between two concrete texts, not between a text and a description.
- **Strike instead of mark, `E1`–`E3`.** Deleting the `StackchainQuant` clause from `body` removes a
substantive claim the entry currently makes (the October account's report of several thousand dollars
raised; `1492` as a notable fork; the ~400-participant / $1.5 million figures). The report survives
through the separately cited Bitcoin Magazine anchor; the attribution does not. Marking keeps both and
discloses the dead warrant.
- **Anchor instead of mark, `F1` `magazine-020` and `F2` `magazine-051`.** Set `contributor.handle` to
`_overflow__` / `humblebitcoiner`. Both handles return **404**, so this gives the reader a link that
opens X's *"User Profile Not Found"* page. Honest about the state, worse than the note.
- **Handle the move rather than only the anchor, `G3` `magazine-039`.** `@captainsiddh` resolves but its own
description reads *"Now at @captainsidd"* and `https://x.com/captainsidd` resolves. Anchoring
`captainsidd` instead of `captainsiddh` would point at the live account; `G3` stages `captainsiddh`
because that is the handle the entry prints, plus a note naming the move. Anchoring `captainsidd`
silently changes what the byline says.
## 9. Staging record
**Staged file:** `docs/q13-fix-pack/apply_fix_pack.py` — 25,361 B, sha256
`2d39df3cdfe466b33e45b19b8741f43b536d93e7ccde90f871e50e5cd6ffd1cd`. One script, 25 clause ids, because 25 near-identical scripts would put 25 copies of the
same scoping logic in front of a reviewer instead of one; the clause table is embedded in the file as
JSON and `--list` prints it.
**Committed unrun.** Every clause was executed in **check mode** during this run — which verifies the
locator, the field span, and that each `old` occurs exactly once inside it — and **not one clause was
applied to the build tree's `blocks.json`**. Check output for all 25 clauses, exit codes included, is in
`/root/crucible/q24/CHECK-RUN.txt`; the scratch applications used to measure blast radius ran against
copies under `/root/crucible/q24/blast/`.
**Before hash (all clauses):** `blocks.json` sha256 `63c9cee6103a6824c90c71440fa983d2f5592e380f9c3fb40f7ad366ae41723d`, 278,459 B, read-only this run.
**Revert command, per clause** (printed by `--apply`; identical shape for all 25):
```
python3 docs/q13-fix-pack/apply_fix_pack.py --apply <id> # forward
# revert: restore blocks.json from a pre-apply backup, or reverse the printed deltas:
# <field>: <new> -> <old>
```
**Guard against an unapproved apply:** a clause marked `undecided-for-Alexander` refuses to apply unless
**both** `--force` and `--decision <artifact path>` are passed, so the approval has to be named on the
command line. `D1` applies on its decision record alone — see §5 for why that is still blocked.
**Blast radius, per clause:** measured by applying the clause to a scratch copy, rebuilding, and diffing
the emitted tree against the pristine one. **25 of 25 clauses change exactly 1 emitted file — the entry's
own `index.html`.** No clause touches `blocks/index.html`, `sitemap.xml` or `ledger.css`. Combined, all
25 clauses change **20 of 125** emitted files (`block-25/88/89/90`, `event-2022-07-18-the-5-invitation-
becomes-a-chain`, `event-2022-08-18…hodlon`, `event-2022-08-28-the-fork-of-1492`,
`event-2022-10-05…charit`, `event-2023-05-00-siggy-reaches-nostr`, `magazine-002/005/020/024/026/035/
039/051/056/070/091`). Per-clause and combined tables: `/root/crucible/q24/BLAST-RADIUS.txt`,
`/root/crucible/q24/BLAST-ALL.txt`.
Spot checks on the applied scratch pages: `block-25` carries the
`a-conversation-with-burnchainers` permalink and no longer carries the bare site root as an anchor, and
reads *"quoted above"*; `magazine-091` no longer contains *"Comparing Strategy"*, contains *"Comparing
Twenty One"*, and carries the correction note; `magazine-039` carries
`href="https://x.com/captainsiddh"` and the move note; `magazine-070` carries
`href="https://x.com/MidyReyes"`.
## 10. Method and limits
- **Every population was re-derived, none copied.** Entry titles are unique across all 121 entries
(checked), which is what makes the title locator safe. The bare site root appears as an excerpt URL
exactly **4** times in the whole file — the four `block-*` rows — so the `A` group is a complete census
of that defect, not a sample.
- **Field-scoped, not region-scoped.** My first verifier searched each entry's whole JSON region and
reported `body` old-strings occurring **2×** on `event-2022-07-18`, because `body` and
`plain_summary.text` share the sentence. Scoping to each field's own span is what makes `H1`'s two
deltas land in two places and nothing else. Logged as a defect of mine, found and fixed before staging.
- **Two defects in the generated script, logged first.** Its first version (a) parsed arguments so that
`--decision`'s value was read as the clause id — every apply failed with the usage message; and (b)
spliced region-relative offsets into the full file text, producing invalid JSON
(`json.decoder.JSONDecodeError`). Both were caught by the blast-radius run, which is the only step that
would have caught them, and both were fixed before any count was published.
- **The proposed new values were validated, not assumed.** `https://www.stackchainmagazine.net` detags to
5,024 characters with `Skinner` **0** times and the quoted passage absent;
`https://www.stackchainmagazine.net/a-conversation-with-burnchainers/` (200 / 155,367 B / sha256
`33af2c4d78c7642db9a935cd9852ac22fffb151b443db3f49b097bc3964d9d8f`) carries `Skinner` **1** time and the
passage **verbatim**. `https://github.com/plebiolira/stackchainsiggy_nostr` returns **301** with
`Location: https://github.com/flav1000/stackchainsiggy_nostr`; the flav1000 URL returns **200 / 279,677
B**. In `/root/crucible/q24/TARGET-READS.txt`.
- **Nothing was re-tested.** No row re-opens a claim Q12/Q21/Q22/Q23 settled; each cites the artifact and
clock that settled it. Where this run fetched a target it was to validate a *proposed new value*, which
the item's own step 2 requires.
- **Dated readings.** Every byte count and sha256 is what this host read at the printed clock. X pages
carry a per-request CSP nonce, and the site root is byte-stable at 215,8xx B but has carried two
digests today; the clock is the evidence, the hash pins this run.
- **Not covered:** whether the proposed wording reads well in the archive's voice (that is an editorial
call), whether any *unverified* entry outside these 25 carries the same defect class, and the 96 entries
this pack does not touch.
## 11. Evidence files, all on this host
| file | what it holds |
|---|---|
| `/root/crucible/q24/LIVE-READS.txt` | index + 25 entry pages: HTTP status, bytes, full sha256, and same-as-emitted |
| `/root/crucible/q24/TARGET-READS.txt` | the four URLs the proposed values point at, with term counts and the verbatim test |
| `/root/crucible/q24/CHECK-RUN.txt` | `apply_fix_pack.py <id>` in check mode, all 25 clauses, with exit codes |
| `/root/crucible/q24/BLAST-RADIUS.txt` | per-clause emitted-file radius with before/after sha256 prefixes |
| `/root/crucible/q24/BLAST-ALL.txt` | the combined 20-of-125 radius with before/after sha256 |
| `/root/crucible/q24/CONTROL-091.txt` | the pre-existing staged `091` script re-run in check mode |
| `/root/crucible/q24/mkclauses.py` | the clause table and its field-span verifier (re-runnable) |
| `/root/crucible/q24/gen_apply.py` | the generator for the staged script (re-runnable) |
— Merlin, 2026-10-10
+643
View File
@@ -0,0 +1,643 @@
#!/usr/bin/env python3
"""Q13 fix pack - staged apply script for the 25 verified live-page clauses.
Generated by Merlin, 2026-10-10, from the verified clause table in
docs/q13-fix-pack.md. NOT RUN AS AN APPLY: every clause was exercised in CHECK
mode only during the 2026-10-10 run (see the pack's landing evidence). Nothing in
that run wrote to blocks.json.
Scope, inherited from Q24 and Q13: this script edits the build source
/root/stackchain-legends-build/blocks.json only. It does not rebuild, does not
publish, does not contact a third party, and does not touch decisions/.
python3 apply_fix_pack.py --list
python3 apply_fix_pack.py --check <id> # default: verify, write nothing
python3 apply_fix_pack.py --apply <id> # write blocks.json
A clause marked undecided-for-Alexander refuses to apply unless BOTH --force and
--decision <artifact path> are given, so a staged fix cannot be published without
the approval being named on the command line. The one decided clause (D1,
magazine-091) applies on its decision record alone - but see section 5 of
docs/q13-fix-pack.md: its decided note conflicts with its proposed_action, so
applying D1 publishes a live page Alexander's own note asked to hold.
Fails closed: every delta must resolve exactly once inside its entry's own field
span, otherwise nothing is written. Reverting: reverse the printed deltas, or
restore blocks.json from a backup taken before --apply.
"""
from __future__ import annotations
import json
import pathlib
import re
import sys
BASE = pathlib.Path(__file__).resolve().parents[3]
BLOCKS = BASE / "stackchain-legends-build" / "blocks.json"
CLAUSES = json.loads(r"""[
{
"id": "A1",
"slug": "block-25",
"kind": "excerpt-url",
"panel": "From the sources",
"authority": "recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "excerpts[0].url",
"old": "\"https://www.stackchainmagazine.net\"",
"new": "\"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/\""
}
],
"locator": "\"title\": \"Wanting block 25, and being forked twice\""
},
{
"id": "A2",
"slug": "block-88",
"kind": "excerpt-url",
"panel": "From the sources",
"authority": "recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "excerpts[0].url",
"old": "\"https://www.stackchainmagazine.net\"",
"new": "\"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/\""
}
],
"locator": "\"title\": \"Block 88, bought to secure the longer chain\""
},
{
"id": "A3",
"slug": "block-89",
"kind": "excerpt-url",
"panel": "From the sources",
"authority": "recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "excerpts[0].url",
"old": "\"https://www.stackchainmagazine.net\"",
"new": "\"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/\""
}
],
"locator": "\"title\": \"Block 89, part of the 88-90 run\""
},
{
"id": "A4",
"slug": "block-90",
"kind": "excerpt-url",
"panel": "From the sources",
"authority": "recoveries/evidence-tier-audit.md §6.1 (2026-10-10 ~09:3xZ) + recoveries/excerpt-binding-audit.md finding 1 (2026-10-10T13:26:16Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "excerpts[0].url",
"old": "\"https://www.stackchainmagazine.net\"",
"new": "\"https://www.stackchainmagazine.net/a-conversation-with-burnchainers/\""
}
],
"locator": "\"title\": \"Block 90, and the chain held\""
},
{
"id": "B1",
"slug": "block-25",
"kind": "direction-word",
"panel": "Provenance",
"authority": "WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body_provenance",
"old": "quoted below",
"new": "quoted above"
}
],
"locator": "\"title\": \"Wanting block 25, and being forked twice\""
},
{
"id": "B2",
"slug": "block-88",
"kind": "direction-word",
"panel": "Provenance",
"authority": "WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body_provenance",
"old": "quoted below",
"new": "quoted above"
}
],
"locator": "\"title\": \"Block 88, bought to secure the longer chain\""
},
{
"id": "B3",
"slug": "block-89",
"kind": "direction-word",
"panel": "Provenance",
"authority": "WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body_provenance",
"old": "quoted below",
"new": "quoted above"
}
],
"locator": "\"title\": \"Block 89, part of the 88-90 run\""
},
{
"id": "B4",
"slug": "block-90",
"kind": "direction-word",
"panel": "Provenance",
"authority": "WORK-QUEUE.md §Q21 verification addendum, control plane, 2026-10-10 (offsets quoted there)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body_provenance",
"old": "quoted below",
"new": "quoted above"
}
],
"locator": "\"title\": \"Block 90, and the chain held\""
},
{
"id": "C1",
"slug": "event-2023-05-00-siggy-reaches-nostr",
"kind": "excerpt-url",
"panel": "From the sources",
"authority": "recoveries/excerpt-binding-audit.md fetch note (301 observed) + recoveries/summary-fidelity-nonmagazine.md ev-017 row 1 + recoveries/ledger-audit-pass2.md row 19; 301 re-observed this run",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "excerpts[0].url",
"old": "\"https://github.com/plebiolira/stackchainsiggy_nostr\"",
"new": "\"https://github.com/flav1000/stackchainsiggy_nostr\""
}
],
"locator": "\"title\": \"Siggy reaches Nostr\""
},
{
"id": "D1",
"slug": "magazine-091",
"kind": "body-clause",
"panel": "What happened + Uncertainty",
"authority": "decisions/2026-09-26.md item 13, approved 2026-09-26T14:51:11.019Z; staged record /root/stackchain-legends-build/EDITS/2026-09-26-magazine-091-correction.md",
"decided": "DECIDED (approved) — decided note conflicts with proposed_action; see §5",
"ops": [
{
"field": "body",
"old": "Comparing Strategy, Twenty One, Nakamoto, Metaplanet, Coinsilium and Smarter Web returns and drawdowns against Bitcoin, they find none consistently outperform,",
"new": "Comparing Twenty One, Nakamoto, Metaplanet, Coinsilium and Smarter Web against Bitcoin — with earlier pioneers such as Strategy set aside as not a fair comparison — they find none consistently outperform,"
},
{
"field": "uncertainty",
"old": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.",
"new": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Correction 2026-09-26: this summary previously listed Strategy among the firms compared. The article sets Strategy aside (“not a fair comp for these newcomers”) and excludes it from the comparison; the listing was the archive’s error, not the article’s. Strategy has been removed from the compared set."
}
],
"locator": "\"title\": \"Fact Check: Bitcoin vs. Treasury Stocks.Who performs better?\""
},
{
"id": "E1",
"slug": "event-2022-08-18-the-bitcoin-beach-campaign-closes-and-hodlon",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.",
"new": "Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp. Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date."
}
],
"locator": "\"title\": \"The Bitcoin Beach campaign closes and Hodlonaut support appears\""
},
{
"id": "E2",
"slug": "event-2022-08-28-the-fork-of-1492",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Event status as recorded by the history research: event corroborated; tactics from participant retrospective. The date basis is the reported event date, not necessarily a verified post timestamp.",
"new": "Event status as recorded by the history research: event corroborated; tactics from participant retrospective. The date basis is the reported event date, not necessarily a verified post timestamp. Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date."
}
],
"locator": "\"title\": \"The fork of 1492\""
},
{
"id": "E3",
"slug": "event-2022-10-05-the-community-documents-its-scale-and-charit",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness-unlinked.md finding 1 (2026-10-10T17:49:31Z) + recoveries/named-source-liveness.md row 6 (2026-10-10T15:39:39Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp.",
"new": "Event status as recorded by the history research: sourced. The date basis is the reported event date, not necessarily a verified post timestamp. Note 2026-10-10: the named warrant “StackchainQuant” returns HTTP 404 at https://x.com/StackchainQuant (X: “User Profile Not Found”). The report it attributes is separately cited and live; the account itself is unreachable as of this date."
}
],
"locator": "\"title\": \"The community documents its scale and charitable turn\""
},
{
"id": "F1",
"slug": "magazine-020",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness.md row 1 (2026-10-10T15:39:17Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.",
"new": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Note 2026-10-10: the byline handle @_overflow__ returns HTTP 404 at https://x.com/_overflow__ (X: “User Profile Not Found”). The name is retained as printed and is not currently linkable."
}
],
"locator": "\"title\": \"The coming Occupy Wall St\""
},
{
"id": "F2",
"slug": "magazine-051",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness.md row 2 (2026-10-10T15:39:33Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.",
"new": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Note 2026-10-10: the byline handle @humblebitcoiner returns HTTP 404 at https://x.com/humblebitcoiner (X: “User Profile Not Found”). The name is retained as printed and is not currently linkable."
}
],
"locator": "\"title\": \"The Obstacle Is The Way – Finding Hope In Bitcoin\""
},
{
"id": "G1",
"slug": "magazine-035",
"kind": "contributor-anchor",
"panel": "Contributor",
"authority": "recoveries/named-source-liveness.md row 3 (2026-10-10T15:39:21Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "contributor.display_name",
"old": "\"@BTC_Freeborn and @AnthonyDessauer\"",
"new": "\"BTC_Freeborn and Anthony Dessauer\""
},
{
"field": "contributor.handle",
"old": "null",
"new": "\"BTC_Freeborn\""
}
],
"locator": "\"title\": \"WAHT Stackchain Done Dided: The King of StackChain™\""
},
{
"id": "G2",
"slug": "magazine-056",
"kind": "contributor-anchor",
"panel": "Contributor",
"authority": "recoveries/named-source-liveness.md row 4 (2026-10-10T15:39:33Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "contributor.display_name",
"old": "\"Red Tail Hawk (@RedTailHawk1923)\"",
"new": "\"Red Tail Hawk\""
},
{
"field": "contributor.handle",
"old": "null",
"new": "\"RedTailHawk1923\""
}
],
"locator": "\"title\": \"Culture is Bitcoin\""
},
{
"id": "G3",
"slug": "magazine-039",
"kind": "contributor-anchor",
"panel": "Contributor + Uncertainty",
"authority": "recoveries/named-source-liveness.md row 5 (2026-10-10T15:39:22Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "contributor.handle",
"old": "null",
"new": "\"captainsiddh\""
},
{
"field": "uncertainty",
"old": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.",
"new": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Note 2026-10-10: the handle @captainsiddh resolves, but its own profile description reads “Now at @captainsidd” and https://x.com/captainsidd resolves; the byline above is one handle behind the account’s current home."
}
],
"locator": "\"title\": \"Traveling on a Bitcoin Standard\""
},
{
"id": "H1",
"slug": "event-2022-07-18-the-5-invitation-becomes-a-chain",
"kind": "prose-handle-form",
"panel": "What happened + In plain English",
"authority": "recoveries/named-source-liveness-unlinked.md finding 2 (2026-10-10T17:49:31Z); https://x.com/AriZonanHODL 200 / 130,908 B",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body",
"old": "AriZonanHODL posted a $5 bitcoin purchase",
"new": "@AriZonanHODL posted a $5 bitcoin purchase"
},
{
"field": "plain_summary.text",
"old": "AriZonanHODL posted a $5 bitcoin purchase",
"new": "@AriZonanHODL posted a $5 bitcoin purchase"
}
],
"locator": "\"title\": \"The $5 invitation becomes a chain\""
},
{
"id": "H2",
"slug": "event-2022-07-18-the-5-invitation-becomes-a-chain",
"kind": "prose-handle-form",
"panel": "What happened",
"authority": "WORK-QUEUE.md §Q24 addendum 2026-10-10 18:13Z (Satskeeper resolves as @satskeeper_, already linked on block-7)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "body",
"old": "and Satskeeper with $7",
"new": "and @satskeeper_ with $7"
}
],
"locator": "\"title\": \"The $5 invitation becomes a chain\""
},
{
"id": "H3",
"slug": "magazine-002",
"kind": "prose-handle-form",
"panel": "What happened",
"authority": "WORK-QUEUE.md §Q23 verification correction (rule 3b yields 8 bare-and-unlinked mentions across 6 entries) — CONDITIONAL on step 5’s filter",
"decided": "undecided-for-Alexander (conditional row)",
"ops": [
{
"field": "body",
"old": "ArizonanHODL's $5",
"new": "@AriZonanHODL's $5"
}
],
"locator": "\"title\": \"The Art of GFY by Nobody (aka Seven)\""
},
{
"id": "H4",
"slug": "magazine-005",
"kind": "prose-handle-form",
"panel": "What happened",
"authority": "WORK-QUEUE.md §Q23 verification correction (rule 3b) — CONDITIONAL on step 5’s filter",
"decided": "undecided-for-Alexander (conditional row)",
"ops": [
{
"field": "body",
"old": "ArizonanHodl's July 18, 2022 tweet",
"new": "@AriZonanHODL's July 18, 2022 tweet"
}
],
"locator": "\"title\": \"A Brief History of Stackchain.\""
},
{
"id": "I1",
"slug": "magazine-026",
"kind": "contributor-anchor",
"panel": "Contributor",
"authority": "recoveries/evidence-tier-audit.md §6.3 (2026-10-10) — OUTSIDE the Q24 population rule, which names findings 1–2; included and flagged",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "contributor.handle",
"old": "null",
"new": "\"a_koby\""
}
],
"locator": "\"title\": \"Stackchain for Newcomers: How I Infiltrated the Stackchain.\""
},
{
"id": "I2",
"slug": "magazine-070",
"kind": "contributor-anchor",
"panel": "Contributor",
"authority": "WORK-QUEUE.md §Q23 verification correction (rule 3a admits MidyReyes on magazine-070) — OUTSIDE the Q24 population rule; included and flagged",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "contributor.display_name",
"old": "\"@MidyReyes\"",
"new": "\"MidyReyes\""
},
{
"field": "contributor.handle",
"old": "null",
"new": "\"MidyReyes\""
}
],
"locator": "\"title\": \"From Struggles to Strength: My Health & Fitness Story\""
},
{
"id": "J1",
"slug": "magazine-024",
"kind": "uncertainty-append",
"panel": "Uncertainty",
"authority": "recoveries/named-source-liveness-unlinked.md finding 3 (2026-10-10T17:49:31Z)",
"decided": "undecided-for-Alexander",
"ops": [
{
"field": "uncertainty",
"old": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context.",
"new": "Archive summary of a published article, not the article itself. Quotes are short verbatim excerpts; read the original for full context. Note 2026-10-10: the tipping address bitcoinbekka@getalby.com resolves at its canonical LNURL-pay endpoint https://getalby.com/.well-known/lnurlp/bitcoinbekka (HTTP 200); the vanity web path https://getalby.com/bitcoinbekka returns 404. It is not linked here because the ledger build emits anchors only for contributor handles, body sources and excerpt URLs."
}
],
"locator": "\"title\": \"Bekka’s Sammie Corner: Schnitzel\""
}
]""")
def slug_for(b):
raw = b.get("slug") or f"block-{b['n']}"
return re.sub(r"[^a-z0-9-]+", "-", str(raw).lower()).strip("-")
def region_of(text, slug):
"""(start, end, region_text, locator) for one entry object, found by its unique title."""
by_slug = {slug_for(b): b for b in json.loads(text)["blocks"]}
b = by_slug[slug]
loc = '"title": ' + json.dumps(b["title"], ensure_ascii=False)
n = text.count(loc)
if n != 1:
raise SystemExit(f"ABORT {slug}: title locator occurs {n}x")
i = text.index(loc)
m = re.search(r'\{\s*"n":', text[i + len(loc):])
end = i + len(loc) + (m.start() if m else len(text) - i - len(loc))
return i, end, text[i:end], loc
def _scan_string(text, s):
"""End offset of the JSON string that starts at s (text[s] == '"')."""
j = s + 1
while j < len(text):
if text[j] == "\\":
j += 2
continue
if text[j] == '"':
return j + 1
j += 1
raise SystemExit("ABORT: unterminated string")
def _value_span(text, key, base=0):
"""(start, end, raw) of one key's JSON value; objects/arrays bracket-matched."""
m = re.search(r'"' + re.escape(key) + r'": ', text[base:])
if not m:
raise SystemExit(f"ABORT: key {key!r} not found")
s = base + m.end()
if text.startswith('"', s):
e = _scan_string(text, s)
return s, e, text[s:e]
m2 = re.match(r"(null|true|false|-?\d+(?:\.\d+)?)", text[s:])
if m2:
return s, s + m2.end(), text[s:s + m2.end()]
depth, j = 0, s
while j < len(text):
ch = text[j]
if ch == '"':
j = _scan_string(text, j)
continue
if ch in "{[":
depth += 1
elif ch in "}]":
depth -= 1
if depth == 0:
return s, j + 1, text[s:j + 1]
j += 1
raise SystemExit(f"ABORT: unbalanced value at {key!r}")
def field_span(region, path):
"""(start, end, raw) of ONE field's JSON value inside the entry region."""
if path in ("body", "body_provenance", "uncertainty"):
return _value_span(region, path)
if path == "plain_summary.text":
cs, _, _ = _value_span(region, "plain_summary")
s, e, _ = _value_span(region, "text", base=cs)
return s, e, region[s:e]
if path.startswith("excerpts["):
idx = int(path[path.index("[") + 1:path.index("]")])
key = path.split(".")[-1]
es, _, _ = _value_span(region, "excerpts")
arr_end = es + 1
depth = 1
while depth:
if region[arr_end] == '"':
arr_end = _scan_string(region, arr_end)
continue
if region[arr_end] in "[{":
depth += 1
elif region[arr_end] in "]}":
depth -= 1
arr_end += 1
arr = region[es:arr_end]
pos = [m.start() for m in re.finditer(r'"' + key + r'": ', arr)]
if len(pos) <= idx:
raise SystemExit(f"ABORT: {path} not found ({len(pos)} occurrences)")
s = es + pos[idx] + len('"' + key + '": ')
e = _scan_string(region, s)
return s, e, region[s:e]
if path.startswith("contributor."):
key = path.split(".")[-1]
cs, _, _ = _value_span(region, "contributor")
return _value_span(region, key, base=cs)
raise SystemExit(f"ABORT: unknown field path {path!r}")
def plan(cid):
c = next((x for x in CLAUSES if x["id"] == cid), None)
if c is None:
raise SystemExit(f"ABORT: no clause {cid!r}; --list shows the ids")
text = BLOCKS.read_text(encoding="utf-8")
rstart, rend, reg, loc = region_of(text, c["slug"])
edits = []
for o in c["ops"]:
s, e, cur = field_span(reg, o["field"])
if cur.count(o["old"]) != 1:
raise SystemExit(
f"ABORT {cid} {o['field']}: old occurs {cur.count(o['old'])}x in the field span")
if o["old"] == o["new"]:
raise SystemExit(f"ABORT {cid} {o['field']}: old == new")
# absolute offsets into the full file
edits.append((s + rstart, e + rstart, cur, o))
return c, text, reg, loc, edits
def main() -> int:
argv = sys.argv[1:]
if "--list" in argv:
for c in CLAUSES:
print(f"{c['id']:4s} {c['slug'][:52]:52s} {c['kind']:20s} {c['decided'][:40]}")
print(f"\n{len(CLAUSES)} clauses, {sum(len(c['ops']) for c in CLAUSES)} deltas")
return 0
apply = "--apply" in argv
force = "--force" in argv
decision = None
if "--decision" in argv:
k = argv.index("--decision")
if k + 1 >= len(argv):
print("ABORT: --decision needs a value")
return 2
decision = argv[k + 1]
argv = argv[:k] + argv[k + 2:]
ids = [a for a in argv if not a.startswith("--")]
if len(ids) != 1:
print("usage: apply_fix_pack.py [--list] [--check|--apply] <id> "
"[--force --decision <path>]")
return 2
cid = ids[0]
c, text, reg, loc, edits = plan(cid)
print(f"clause {cid} entry {c['slug']} panel {c['panel']}")
print(f"authority: {c['authority']}")
print(f"decided: {c['decided']}")
for _s, _e, _cur, o in edits:
print(f" field {o['field']}: old occurs 1x, new differs OK")
if c["decided"].startswith("undecided"):
if apply and not (force and decision):
print("\nREFUSED: this clause is undecided-for-Alexander. Re-run with "
"--force --decision <artifact path> to publish it anyway.")
return 1
if apply:
print(f"\nFORCED with decision artifact: {decision}")
if not apply:
print("\nCHECK ONLY - blocks.json not written (pass --apply)")
return 0
out = text
for s, e, cur, o in reversed(edits):
out = out[:s] + cur.replace(o["old"], o["new"], 1) + out[e:]
json.loads(out)
BLOCKS.write_text(out, encoding="utf-8")
print(f"\nWROTE {BLOCKS}")
print("revert by reversing these deltas (or restore a pre-apply backup):")
for _s, _e, _cur, o in edits:
print(f" {o['field']}: {o['new'][:70]!r} -> {o['old'][:70]!r}")
return 0
if __name__ == "__main__":
raise SystemExit(main())