Record the live re-check of the forge's exit surfaces

14232e02caf6 · AtlantisPleb · · parent 8cd9cad5c0b3

Record the live re-check of the forge's exit surfaces

#187 found one cause behind six live failures: main held the exit surfaces
and the deployed revision did not, so every invariant stayed green while the
forge served none of them. A release carrying them is now promoted, and each
row was measured again against the live forge rather than inferred from the
release.

Rehearsal 1's step 1 is the one the document asked to be rerun. A full
anonymous clone of this repository now completes, carries 417 commits, and
passes git fsck; the clone is grafted rather than truncated, which is what
EXIT-004 states a servable boundary looks like. Cloning that copy re-serves
the same head with no forge in the path, which is step 2. Steps 3 through 5
were not performed and the document says so.

Rehearsal 2's steps 1 and 3 were performed against this repository's log. It
verifies clean over 376 entries with chained_from 279, a wrong anchor reports
anchor_mismatch, and a sequence past the end reports anchor_unreachable, so
verify/2's :anchor option is honored rather than accepted and ignored. The
chain claim changed shape rather than flipping: 0 links across 275 entries
became 97 across 376, the contiguous suffix EXIT-005 describes.

That rehearsal's preamble said no anchor was published. One is, at
/.well-known/openagents-forge-anchor.json, and the correction keeps the
distinction the invariant makes: publishing a commitment is not having one
witnessed, and #151 still carries the witness.

What the re-check does not close is that nothing reported the gap. A person
found it by rehearsing six surfaces by hand, and this release removes today's
gap rather than the next one. #246 carries that, with the note that EXIT-006's
proof turns red when a commit sha reaches the disclosure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KnhfrafYx5ZGaMbzZEJQ2d
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

pushed
by user · WAL seq 378 · 2026-08-25T14:28:58.340350Z

Changed files

  • modified docs/forge-exit-rehearsals.md

Diff

1 file changed, +101 -8

docs/forge-exit-rehearsals.md modified +101 -8

@@ -27,15 +27,45 @@ that reads as executable.

27 27
28 28
| Rehearsal | Executable proof | Performed against the live forge |
29 29
| --- | --- | --- |
30
| 1. Restore a repository and its work history | `EXIT-004`, `EXIT-001` | 2026-08-23 — **failed**, see #179 |
31
| 2. Detect a forged, missing, reordered, or mismatched receipt | `EXIT-002`, `EXIT-005` | No |
30
| 1. Restore a repository and its work history | `EXIT-004`, `EXIT-001` | 2026-08-23 — **failed**, see #179; steps 1 and 2 re-run 2026-08-25 and passed |
31
| 2. Detect a forged, missing, reordered, or mismatched receipt | `EXIT-002`, `EXIT-005` | Steps 1 and 3 performed 2026-08-25 |
32 32
| 3. Mirror divergence | `EXIT-003` | No |
33 33
| 4. Key rotation | None | No |
34 34
| 5. Operator loss | `EXIT-003` | No |
35 35
| 6. Partial export | `EXIT-001` | No |
36 36
37
Five of the six have never been run outside the test suite, which #180 carries.
38
That is the honest state, and the one that was run failed.
37
Four of the six have never been run outside the test suite, which #180 carries.
38
That is the honest state.
39
40
## Release re-check, 2026-08-25
41
42
#187 found one cause behind six live failures on 2026-08-23: `main` held the
43
exit surfaces and the deployed revision did not, so every invariant stayed
44
green while the forge served none of them. A release carrying them was
45
promoted, and each row was measured again against the live forge on revision
46
`46cf8a5aea3791936c22e82c145a9a8dd734374d`.
47
48
| Surface | Invariant | 2026-08-23 | 2026-08-25 |
49
| --- | --- | --- | --- |
50
| `GET /data/export/account` | `EXIT-001` | `404` | `302` to sign-in, so the route exists |
51
| `GET /api/v3/repos/{owner}/{repo}/pushes` | `EXIT-005` | `404` | `200`, and `200` at the `/api/v1` path the route moved to |
52
| `independence` section of `GET /api/status` | `EXIT-006` | absent | present, `degraded: true`, all four subsections served |
53
| `OpenAgents.Forge.WAL.chain_link/2`, `OpenAgents.Forge.WAL.entry_link/1` | `EXIT-005` | not exported | both exported on the node |
54
| `OpenAgents.Forge.Verification.verify/2` `:anchor` option | `EXIT-005` | `verify/1` only | `verify/2` exported, and a wrong anchor reports `anchor_mismatch` |
55
| The `shallow` graft reconciliation | `EXIT-004` | absent, clone aborted | present, and a full anonymous clone completes |
56
57
The chain claim is the one that changed shape rather than flipping. On
58
2026-08-23 the log carried 0 links across 275 entries. It now carries 97
59
across 376: the contiguous suffix 279 through 375, with `chained_from: 279`.
60
That is what `EXIT-005` describes rather than a partial fix — a chain that
61
starts in the middle is history, and no entry written since the chain shipped
62
is missing a link. Rehearsals 1 and 2 above record the measurements.
63
64
**What the re-check does not close.** Nothing reported this gap; a person
65
found it by rehearsing six surfaces by hand, and the release that closed #187
66
removes today's gap rather than the next one. #246 carries that, and the
67
obvious home for it is not free: `EXIT-006`'s proof turns red when a commit
68
sha reaches the disclosure.
39 69
40 70
## 1. Restore a repository and its bounded work history
41 71

@@ -127,6 +157,30 @@ actually holds, so a repository that cannot be walked repairs itself from the

127 157
WAL. The pre-seed history remains outside this forge and is not recoverable
128 158
from it. Rerun step 1 to confirm the live forge serves a full clone.
129 159
160
### Result, 2026-08-25
161
162
**Steps 1 and 2 pass.** Live revision
163
`46cf8a5aea3791936c22e82c145a9a8dd734374d`, which carries the reconciliation.
164
An anonymous clone of `OpenAgentsInc/openagents.com` over the published
165
transport completes, checks out `adafa83`, carries 417 commits, and passes
166
`git fsck --no-progress` with no output. The clone is grafted rather than
167
truncated: it writes a `shallow` file, which is `EXIT-004`'s stated outcome,
168
because history that says where it stops is servable and history that dangles
169
is not. Cloning that copy with `--no-local` produces the same head and passes
170
`git fsck` with no forge in the path, which is step 2.
171
172
The repair is visible on the node rather than inferred from the clone. The
173
bare projection holds five reconciled boundaries in its `shallow` file, its
174
`OpenAgents.Forge.Repos.graft_seq_at/1` marker equals its applied sequence,
175
and the walk
176
`upload-pack` performs — `git rev-list --objects --quiet --all` — exits `0`.
177
178
Steps 3 through 5 were not performed. `GET /data/export/account` answers `302`
179
to an unauthenticated request, which is the route reached rather than the
180
export read, and the document itself stays covered by
181
`test/openagents/data_rights/account_export_test.exs`. Rehearsal 1 is
182
therefore performed for the source half and not for the work-history half.
183
130 184
## 2. Detect a forged, missing, reordered, or mismatched receipt
131 185
132 186
**Proves:** a verifier holding only the WAL and the bare repository — no

@@ -135,10 +189,14 @@ disagree with the record.

135 189
136 190
**Cannot prove:** that a *consistent* rewrite happened. `EXIT-005` chains every
137 191
entry to its predecessor, so a rewrite cannot be confined to one entry, but an
138
operator who rewrites the whole suffix produces a self-consistent log. Only an
139
anchor held somewhere the operator does not control refutes that, and none is
140
published yet (#168). `GET /api/status` reports this as
141
`independence.verification.anchor_published: false`.
192
operator who rewrites the whole suffix produces a self-consistent log. Only a
193
commitment held somewhere the operator does not control refutes that. One is
194
published now, at `/.well-known/openagents-forge-anchor.json` (#168), and
195
`GET /api/status` reports
196
`independence.verification.anchor_published: true`. Publishing a commitment is
197
not having one witnessed: the operator serves that document and could serve
198
any document, so it refutes a rewrite only for a reader who kept a copy.
199
`anchor_witnessed` stays `false`, and #151 carries the witness.
142 200
143 201
### Steps
144 202

@@ -162,6 +220,41 @@ published yet (#168). `GET /api/status` reports this as

162 220
   A rewritten prefix reports `anchor_mismatch`. Without the anchor argument
163 221
   the same log reports clean, which is the whole point of publishing one.
164 222
223
### Result, 2026-08-25
224
225
**Steps 1 and 3 pass** against this repository's log, storage key
226
`ecd89cf6-f602-479f-9f47-266307345aaa`, on live revision
227
`46cf8a5aea3791936c22e82c145a9a8dd734374d`.
228
229
Step 1 reports `findings: []` over 376 entries, with
230
`head: %{seq: 375, link: "19c7a2c5…"}` and `chained_from: 279`. Ninety-seven
231
entries carry a link, which is the contiguous suffix 279 through 375. The
232
entries before 279 predate the chain and carry none, which `EXIT-005` states
233
is history rather than tampering: a chain that stops in the middle is a
234
finding, and a chain that starts in the middle is not. No entry written since
235
the chain shipped is unlinked.
236
237
Step 3 was performed three ways against the same log. The head link the log
238
itself reports verifies clean. A `link` of 64 zeroes at the head sequence
239
reports one finding, `anchor_mismatch`, naming the anchored and recorded
240
values. A sequence past the end of the log reports `anchor_unreachable`. The
241
option is therefore honored rather than accepted and ignored, which is what a
242
pusher holding a `remote: openagents wal-receipt` line depends on.
243
244
Two of the surfaces the step needs were confirmed on the node rather than
245
assumed: `OpenAgents.Forge.WAL` exports `chain_link/2` and `entry_link/1`, and
246
`OpenAgents.Forge.Verification` exports `verify/2` beside `verify/1`.
247
`GET /api/v1/repos/OpenAgentsInc/openagents.com/pushes` answers `200` and
248
serves the same head link and `chained_from` the verifier reports.
249
250
The bound in this rehearsal's own preamble still holds, with one correction:
251
an anchor **is** published now, at
252
`/.well-known/openagents-forge-anchor.json`, and `GET /api/status` reports
253
`independence.verification.anchor_published: true` with `anchor_witnessed:
254
false`. A consistent rewrite is refuted only for a reader who kept a copy of
255
that document or a receipt line; nobody is attesting to it on the operator's
256
behalf, and #151 carries the witness.
257
165 258
## 3. Mirror divergence
166 259
167 260
**Proves:** the GitHub mirror is never an input to recovery, and divergence is

This page updates live while a promote is in flight · changelog