---
name: ledger-append-etiquette
description: >
  Run BEFORE you append a row to agi-proof/failure-ledger.md, or write to any of this repo's
  append-heavy shared files — agi-proof/evidence-manifest.json, RESULTS.md, or the live
  SESSION-COORDINATION.md — and whenever a task adds/edits a failure-ledger row, records a
  NO-GO/candidate result, claims/releases work in the coordination ledger, or regenerates the
  evidence manifest. These files are touched concurrently by many Claude/Copilot/GLM/human
  sessions on ONE checkout; two sessions hand-editing the same one collide, a bad Status string
  silently flips OPEN→resolved, and a stale manifest fails CI. Use even if the edit "looks like
  one line".
  ALSO fires the instant you are about to `>>` / append / "add a row to" the failure ledger:
  the table ENDS at the first `## ` section (~line 530 of ~6900), so a row appended at
  end-of-file is parsed as section prose and SILENTLY DROPPED while
  `validate_failure_ledger.py` still exits 0 and prints `structural validity: OK`. Verify an
  append by the CHANGE IN `tableRows`/`openCount`, never by the exit code — see §2b.
metadata:
  short-description: "Serialize + union-resolve appends to the shared ledger/manifest/coordination files without collisions or a fail-closed Status"
---

# Ledger / manifest append etiquette (this repo)

> **See also `ci-artifact-drift`** (the ledger is a CI-validated artifact; the evidence manifest
> is regenerable-**not-committed**, see §3), `session-handover` §1 (`SESSION-COORDINATION.md` is
> the live ownership ledger), and `git-discipline` §4 (isolate your changes; never `git add -A`).

Several files here are **append-heavy and shared**: every session adds rows/sections to the same
tail. Because 5+ sessions run on one checkout, the recurring waste is (a) two sessions editing the
same file in parallel PRs → merge conflict or a clobbered append, and (b) a Status string that
fails CI *after* the GPU work is already done. This skill is the cheap pre-flight.

The files this governs:

| File | Shape | Gate |
|---|---|---|
| `agi-proof/failure-ledger.md` | append `## <id>` sections + a table row | `tools/validate_failure_ledger.py --check` |
| `agi-proof/evidence-manifest.json` | **generated + gitignored** — never hand-edit, never commit | regenerate locally with `python tools/build_agi_proof_package.py`; CI rebuilds it (see §3) |
| `RESULTS.md` | **generated** from `published-results.json` — never hand-edit | `tools/build_results_page.py --check` |
| `SESSION-COORDINATION.md` | live, **untracked** CLAIM/OWNS/DONE ledger | none (ephemeral) — but still collision-prone |

## 1. Route the append through the serializer — don't hand-race the tail

Two sessions writing the tail of the same shared file in parallel PRs is the #1 collision. Before
appending:

- **Prefer the append-serializer MCP tool** (the sophia-agi MCP server, `.mcp.json` →
  `sophia_mcp/server.py`) when it is enabled — it takes a per-file lock, appends your block, and
  regenerates the dependent artifact atomically, so two sessions can't interleave.
- If you are hand-editing, **first claim the file in `SESSION-COORDINATION.md`** (append an
  `OWNS: failure-ledger.md — <session-id>` line, read the existing OWNS lines first). Never open a
  second PR that touches a shared file another live session already claimed.
- **One shared file per PR.** Do NOT hand-edit two of these files in the same branch/PR — split
  them so each lands (and conflict-resolves) independently.
- This pairs with the **one-GPU-job invariant** (`spark-cluster-ops`): finish and land the ledger
  row for a run before the next session launches over it.

## 2. The Status cell must NEVER contain the substring `closed`

`tools/validate_failure_ledger.py` classifies a row by **substring**:
`_RESOLVED_MARKERS = ("closed", "cleared", "superseded", "resolved", "fixed", …)` and resolved
**beats** open. So a Status like **`fail-closed`**, `gate closed`, or `closed-loop` on an item that
is actually still OPEN is silently reclassified **resolved** — it drops off the "what still blocks
the AGI claim" list. Footgun, not a feature.

- For an open item use `OPEN`, `PARTIAL`, `BLOCKED`, `PENDING`, `NOT YET` (these hit `_OPEN_MARKERS`).
- Describe fail-closed *behavior* in the body prose, never in the **Status** cell/`**Status:**` line.
- To actually mark something done, use `RESOLVED`/`CLEARED`/`SUPERSEDED` — a word, deliberately.

## 2b. The row must land INSIDE the table — appending at EOF is a silent no-op

`_parse_table` stops at the **first `## ` heading**:

```python
cutoff = next((i for i, ln in enumerate(lines) if ln.startswith("## ")), len(lines))
```

`agi-proof/failure-ledger.md` is a short table (ends ~line 530) followed by **hundreds** of
`## <id>` write-up sections. So the "tail" of the file is *not* the tail of the table. A row
appended with `>>` at end-of-file is parsed as prose inside the last section, and:

- `validate_failure_ledger.py` exits **0**,
- prints `structural validity: OK`,
- and the row **does not exist** as far as every consumer is concerned.

**Nothing reports this.** A clean exit means "nothing parsed", not "row accepted" — the same
dishonest-failure shape as the `:LINE` citation trap at the top of the ledger. Measured
2026-08-03: a row appended at EOF left `tableRows` at 491 and `openCount` at 437, unchanged.

**Append here instead** — as the last line of the table, immediately before the first `## `:

```bash
CUT=$(grep -n "^## " agi-proof/failure-ledger.md | head -1 | cut -d: -f1)
awk -v c="$CUT" 'NR<c && /^\|/ {last=NR} END{print "insert after line", last}' agi-proof/failure-ledger.md
```

**Then verify by COUNT, never by exit code** (this is the check that would have caught it):

```bash
python3.12 tools/validate_failure_ledger.py --json   # before and after
# tableRows and openCount MUST each rise by exactly 1, and your id MUST appear in openItems
```

If the counts did not move, your row is not in the ledger no matter what the exit code said.

## 3. The evidence manifest is regenerated, NOT committed — never `git add` it

`agi-proof/evidence-manifest.json` reads the ledger's OPEN/RESOLVED summary, so a new/edited row
makes it stale. It used to be committed and regenerated in every PR — which made it the **#1
recurring merge conflict** in this repo: concurrent PRs each regenerated it and collided on its
machine-generated body, and it **cannot be auto-merged** (its content is a function of the *whole*
merged ledger, which git doesn't have while merging line-by-line). So it is now **gitignored and
untracked**: CI (`ci.yml` `validate-build`, `pages.yml`) rebuilds it, and readers tolerate its
absence. After touching the ledger:

```bash
python tools/validate_failure_ledger.py --check     # structure + Status sanity (see §2)
python tools/build_agi_proof_package.py             # regenerate the manifest LOCALLY (optional)
make claim-check                                     # the no-overclaim contract (must stay green)
```

- **Only stage the ledger** — `git add agi-proof/failure-ledger.md` (explicit path). The manifest
  is gitignored; do **NOT** `git add`/`git add -f` it back. Force-adding it re-tracks the file and
  re-introduces the exact conflict this design killed.
- Regenerating locally is only for *your own* inspection (the web build, a local `bench` read). It
  is never part of a commit and never needs to match anyone else's copy.
- Never hand-edit `evidence-manifest.json` or `RESULTS.md` — `RESULTS.md` is still committed, so
  regenerate it from `published-results.json` and stage it; the manifest is not.
- Do **not** wire `python tools/build_agi_proof_package.py --check` into any workflow — `--check`
  fail-closes on the (now normally-absent) file and would red the required checks.

## 4. On conflict, UNION-resolve — never drop a sibling's append

These are append-only logs: a conflict means two sessions each added a block at the tail.

- **Keep BOTH sides.** Resolve by concatenating the two appends (union), then re-sort/renumber ids
  if the format requires it — never take "ours" and discard the other session's row.
- After a union resolve, re-run `tools/validate_failure_ledger.py --check` (a merged table can
  duplicate an id). The manifest no longer needs conflict-resolving (§3) — it is gitignored, so a
  ledger merge never touches it; regenerate it locally only if you want a fresh local copy.
- For `SESSION-COORDINATION.md` (untracked, so no git conflict) union by hand: read the whole file
  fresh, append your line, keep every existing OWNS/DONE line.

## Rules

- Faithful reporting only: a NO-GO/candidate result goes in the ledger **as** NO-GO/candidate —
  never soften it, never lower a gate to make it pass (`ci-artifact-drift`). This is dev-workflow
  etiquette; it makes **no capability/AGI claim** and `canClaimAGI` stays false.
- If your edit changes what is *claimed* (a result's status, "validated"), that is the no-overclaim
  contract — stop and follow `sophia-agi`/`ci-artifact-drift`, not just this skill.
