Wiki · Evidence & Verdicts
/lab-team-review MERGED VERDICT (v2, post-fix) — D-D3 Lineage.snapshot/1
How to read this page
Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.
Eighty-seven dated pages: receipts, pre-registrations, handoffs, validation records and review verdicts. A receipt is written at the moment a piece of work was checked. It names what was claimed, the commit and the seed, what was actually run, and the outcome in one of a small set of controlled words. Then it names what the work did not achieve. That last part is what makes it a receipt rather than an announcement. A pre-registration is the same discipline run in advance: the conditions that would count as a pass and the conditions that would falsify the claim are written down before the run, so neither can be adjusted once the numbers arrive.
That is why so many small dated stubs are an audit trail rather than noise. No one of them is meant to be a good read. The value is in the sequence and in the dates, because you can watch a prediction be registered, then the run happen, then the verdict land — sometimes against the prediction. Pages here record a falsified result, a rejected fix, a retracted overclaim, and a green receipt that turned out not to be reproducible from the commit that carried it. A record that carried only successes would be worth a good deal less than this one.
A gentle way in is to read a pre-registration first, so the shape becomes familiar, then a result page, then one of the corrections. This section sits off the main navigation on purpose: it is the record you check the rest of the site against, not the place to begin.
What it is not: documentation, and not a summary. Nothing here has been tidied in hindsight. Every entry reads as of its date, a later entry may overturn an earlier one, and the presence of a page is not a claim that its result stood.
Your browser cannot switch reading levels, so the document itself is shown.
Precise — the source document
This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.
verdict: PASS evidence_class: C supersedes: none (first review pass for this item)
/lab-team-review MERGED VERDICT (v2, post-fix) — D-D3 Lineage.snapshot/1
- Base SHA:
85b0e8c(working tree, spec-correction pass applied on top, uncommitted) - Mode: real (5 independent persona agents re-reviewing the corrected spec)
- Files reviewed:
production\mcp\SPEC_lineage_snapshot.md
Fix summary (what changed before this re-review)
All four findings verified against the live repo and fixed. No .ex/.exs/.py/.cjs files were touched — only production/mcp/SPEC_lineage_snapshot.md.
Re-verification against live repo (before editing)
All four findings checked out against current code, with two additional stale citations discovered during the re-read (not in the original findings list, fixed anyway per the "re-verify, don't silently leave a wrong citation" instruction):
- Finding 1 confirmed:
agent.ex:87stats/1is the only publicGenServer.call;MC.save/2(lib/sp/brain/mc.ex:552-554) isFile.write!/2, no tmp+rename. - Finding 2 confirmed:
Lineagestate has no pid/username field;spawn_next/2discardsSupervisor.spawn_agent/1's return.Lineage.name/1is atlineage.ex:72(exact match);Supervisor.list_agents/0is atsupervisor.ex:85-89(exact match). - Finding 3 confirmed: zero
grep -rni heartbeat lib/hits.heartbeat.shis a 60s systemd-timer shell script — and its own header even marks itstatus: pending (authored, not yet run on node hardware), strengthening the case against building a bridge to it now. - Finding 4 confirmed:
OS_SPOOL_POLICY.mdnamescolony_archive.shsole writer of/var/lib/uni/backups/colony/**(daily 03:30 UTC) and documents the exact 2026-07-12 EPERM two-writer crash in its "Why" section. - New stale citation found: the old spec's "Hot-file interaction" section cited
SP.Runtime.Agent.save/1— that function doesn't exist anywhere in the codebase; every save goes throughSP.Brain.MC.save/2. - New stale claim found: the old spec's cross-references claimed
colony_archive.sh"consumes these snapshots" — untrue today;colony_archive.shreads directly from/var/lib/uni/colony-memory/(or its fallback), never fromruns/colony/snapshot/. - The old "on Port exit (agent.ex:251-259)" citation was stale (that line range is now inside the metabolic death branch, not the generic Port-exit handler at
agent.ex:192-201/save at:195); corrected and expanded to list all current save call sites (:185,:195,:251,:259,:310,:318,:358).
What changed, section by section
- Header: added a Revision line summarizing the four gaps and pointing to the new "v1 Scope" section; noted the spec touches only
lineage.ex, notagent.ex. - Purpose: fixed the save-site citations (see above).
- New "v1 Scope" section: states all four re-scoping decisions explicitly, each naming the deferred prerequisite.
- Signature: unchanged (was already correct/buildable).
- Behaviour:
opts[:trigger]now:manual-only for v1, with:heartbeat_idle/:heartbeat_livereturning{:error, {:unsupported_trigger, trigger}}rather than silently degrading; addedopts[:kins](default0..9, the range named inLineage's own moduledoc) as the concrete enumeration input. - Snapshot mechanics: rewrote entirely — step 2 spells out the
Lineage.name/1+Process.whereis/1+Supervisor.list_agents/0composition; step 3 replaces the fictitious "ask Agent to atomically dump" with "read the existingkin-*.bin, write it into the snapshot dir via a local tmp+rename," with the residual source-side torn-read risk documented explicitly (chose option (b) for finding 1 — smaller, buildable, no new Agent surface); step 4 fixes the default path toruns/colony/snapshot/YYYYMMDD/HHMM/only (chose the non-shared-tree default for finding 4). - Hot-file interaction: corrected the fictitious
Agent.save/1citation; reframedsnapshot/1as a reader (not writer) ofkin-*.bin, so it needs no new livepatch-guard or spool-ledger entry. - Test coverage: replaced the idle/live-cadence tests (untestable against unbuilt behavior) with enumeration, local-atomicity, manifest, path-default, and unsupported-trigger tests; moved idle/live-cadence plus source-side atomicity and bind-mount-path tests to an explicit "Phase 2" list, each tied to its named prerequisite.
- Cross-references: corrected the false "colony_archive.sh consumes these snapshots" claim; added
OS_SPOOL_POLICY.mdandheartbeat.shas explicit cross-references for the two deferred items.
Findings not fully resolved
None of the four are unresolved — each was closed by picking the smaller/buildable option and naming the alternative as deferred, per the task's own instruction. The one thing left as a genuine open design decision (correctly out of scope for a spec-only pass): which option — new Agent.dump_atomic/1 vs. making MC.save/2 itself tmp+rename at the source — should actually close the Phase-2 atomicity gap. The spec now names both credibly but doesn't pick one, since picking would be an implementation decision, not a spec-correction one.
Persona verdicts (re-review)
math-breaker (Falsifier, Lab Team role 2/5) — docs/lab_team/01_math_breaker.md
- Verdict: SIGN_WITH_CHANGES
- Rationale: Independent re-review, done the way the original review should have been done: every citation the corrected SPEC makes against live code was individually re-traced (agent.ex, mc.ex, lineage.ex, supervisor.ex, colony.ex, colony_archive.sh, heartbeat.sh, OS_SPOOL_POLICY.md), plus a repo-wide grep to confirm the 'zero heartbeat hits' and 'no Agent.save/1 anywhere' claims. Every one of the four prior named gaps (fabricated atomic-write primitive, fabricated live-kin enumeration, fabricated heartbeat caller, second-writer spool collision) is now honestly closed: the SPEC either names the real composable primitive with an exact, verified citation, or explicitly defers the missing piece as named Phase-2/follow-on work rather than quietly building it or hand-waving it. This is Class-C engineering, not an FE-math proposal, so the 8-check gauntlet (VFE/EFE decay, gameability, clone-invariance, reward-smuggling) has no term to bite on — correctly so, and the SPEC does not try to dress itself up as FE math to get an easier pass. My own re-verification surfaced three small new items — one wrong line citation, one stale cross-reference in a sibling doc, one overstated self-cleanup claim in the owed test coverage — none of which reopens any of the four original gaps or introduces a reward-smuggling/unfalsifiable-percent problem. These are the kind of loose threads that, left alone, would erode the 'every claim carries a receipt' discipline this repo runs on, so I want them named and fixed, but they do not warrant blocking the SPEC from shipping. SIGN_WITH_CHANGES: land once the three items above are corrected (they are text-only fixes to this SPEC and one line in SPEC_livepatch_hot_files.md — no code, no re-scoping, no new review needed after).
- Concerns:
- Check 1 up front, honestly: this SPEC introduces ZERO F/G/C/E/precision/learning term — snapshot/1 is pure I/O (read an existing .bin, copy it, sha256 it). Per my own gauntlet's check 2, this is Class C engineering and I will not dress it as FE math or manufacture a fake VFE/EFE violation to look thorough. The 8-check FE gauntlet is vacuous here (no scalar objective, no decay/gameability/clone-invariance surface). Review below is the provenance/citation attack the task actually called for.
- All four prior findings ARE genuinely resolved, independently re-verified against live source (not just re-asserted): (1) atomicity — confirmed SP.Brain.MC.save/2 (lib/sp/brain/mc.ex:552-554) is a bare File.write!/2, no tmp+rename; v1 correctly scoped non-atomic-on-source, risk documented, Agent.dump_atomic/1 named as real deferred work not built now. (2) live-kin enumeration — confirmed Lineage's GenServer state (lineage.ex init/1, lines 76-93) carries no agent-pid/username field; confirmed Lineage.name/1 at line 72 verbatim; confirmed Supervisor.list_agents/0 at supervisor.ex:85-89 returns exactly [%{username,kin,mode}]; confirmed spawn_next/2 (lineage.ex:121-141) discards Supervisor.spawn_agent/1's return value. The composed enumeration path the SPEC spells out is real and buildable as written. (3) heartbeat — confirmed zero hits for 'heartbeat' anywhere under lib/ (grep -rniI); confirmed production/scripts/heartbeat.sh:2 literally reads 'status: pending (authored, not yet run on node hardware)'; v1 correctly restricted to :manual, with :heartbeat_idle/:heartbeat_live explicitly returning {:error,{:unsupported_trigger,_}} instead of silently degrading to :manual. (4) spool ownership — confirmed OS_SPOOL_POLICY.md:52-56 names colony_archive.sh sole writer of /var/lib/uni/backups/colony/**, confirmed the 'Why' EPERM-crash rationale it cites is real (line 9-11); the corrected SPEC's v1 output root (runs/colony/snapshot/YYYYMMDD/HHMM/) never touches that tree, and the bind-mount-shared path is correctly named as a deferred prerequisite gated on a ledger amendment, not silently built. Every other line-level citation I spot-checked (agent.ex:87/185/195/251/259/310/318/358; lineage.ex:3-4/25/72/123; supervisor.ex:60/85-89; colony.ex:76; colony_archive.sh:62-65 and its source/dest paths) matches the live repo exactly, including the honest cross-doc discrepancy the SPEC itself surfaces (Lineage moduledoc's '0..9' kin range vs Colony.start_evolution/2's actual default 0..3) rather than smoothing it over.
- Minor citation slip (fix before merge): 'Hot-file interaction' cites MC.load/2's 'own safe_read/1 ... lib/sp/brain/mc.ex:556-579' as the source for the 'corrupt file -> fresh start' claim. Verified against the live file: lines 556-585 are load/2's docstring + body; safe_read/1 itself is a separate private function actually defined at mc.ex:587-594 (rescue/catch both -> :error). The underlying claim is true (I traced it), but the citation points at the wrong function's line range — in a document whose entire methodology is exact line citations, that's a real, fixable provenance defect, not a nitpick.
- Cross-document drift left unsynced: production/docs/SPEC_livepatch_hot_files.md (untouched by this revision, confirmed via
git diff --stat) still says in its own Cross-references section: 'production/mcp/SPEC_lineage_snapshot.md — the BEAM-triggered atomic snapshot that increments the hot-file class.' That directly contradicts this corrected SPEC's own 'Hot-file interaction' conclusion ('snapshot/1 does not introduce a new hot file ... needs no new entry in SPEC_livepatch_hot_files.md's hot-files list'). A reader who opens hot_files.md first (its own listed use case: the livepatch router consulting it before a patch) gets the stale, contradicted claim. Sync that one line before/at merge. - Test-coverage claim overstates self-cleanup and should be corrected before the RED test is written to it: 'Local atomicity' bullet says a killed mid-copy run leaves 'at most an orphaned .tmp, which the next run overwrites.' Given v1 Scope item 4's design (each run gets its own runs/colony/snapshot/YYYYMMDD/HHMM/ directory, and the trigger is :manual only — no automatic recurring cadence in v1), 'the next run' almost never lands in the same dated directory, so the orphaned .tmp is NOT actually cleaned up by design in the general case; it just sits there forever (harmless — manifest.sha256 never references it — but not the self-healing property as worded). Either drop the 'which the next run overwrites' clause or name an actual reaper/retention mechanism for runs/colony/snapshot/** (none exists in this SPEC or elsewhere in the repo I could find).
aif-theorist (AIF Core Theorist, docs/lab_team/02_aif_core_theorist.md)
- Verdict: SIGN_WITH_CHANGES
- Rationale: Independent re-review, fresh from the live repo, focused on claim-fence discipline and framing honesty per my role.
Claim-fence / felt-state check (my specific charge): CLEAN. I grepped production/mcp/SPEC_lineage_snapshot.md against every regex family in production/schemas/claim_fence.json (proof, consciousness_family, life_family, experience_family, over_claim_family) -- zero hits. The only 'live'/'liv*' tokens in the doc ('live lineages', 'live_gap_ticks', 'still-live SOURCE') are process-liveness/technical terms (a running GenServer, a not-yet-dead file), never felt-state or over-claim language. This SPEC also has essentially zero surface area for felt-state language to begin with: snapshot/1 is a pure binary-copy + sha256-manifest utility over already-persisted kin-*.bin files -- it produces no narrative text, no public-facing description of agent state, nothing a felt-state word could attach to on any output surface (internal or public). The header correctly self-labels 'FE-adjacent' rather than FE-touching, which is honest: snapshot/1 touches no A/B/C/D/E/F/G term, no EFE/VFE computation, no Dirichlet learning update, and doesn't add a scalar anywhere near policy logits -- so my persona's generative-model-naming requirement (Required check #1) correctly does not apply here, and the SPEC doesn't pretend it does.
Independent re-verification of the four prior findings (I read the cited files myself, not trusting the SPEC's prose):
- Atomicity -- confirmed lib/sp/runtime/agent.ex exposes only stats/1 (GenServer.call diagnostics, line 87) publicly; every real save is SP.Brain.MC.save/2 (lib/sp/brain/mc.ex:552-554), a plain File.write! with no tmp+rename -- exactly as cited. v1 correctly scopes itself to a non-atomic-source read with a documented torn-read risk, and names Agent.dump_atomic/1 as real-but-not-built Phase-2 work rather than inventing it as already existing. Resolved.
- Live-kin enumeration -- confirmed lib/sp/runtime/lineage.ex's GenServer state (init/1, lines 82-90) carries no agent-pid/username field, and spawn_next/2 (121-141) discards Supervisor.spawn_agent's return. Confirmed Lineage.name/1 (line 72) and SP.Runtime.Supervisor.list_agents/0 (supervisor.ex:85-89, Registry.select) are real and exactly as described; the username pattern 'UNI-#{kin}-g#{gen}' at lineage.ex:123 matches verbatim. The composed enumeration path in 'Snapshot mechanics' step 2 is buildable from real primitives. Resolved.
- Heartbeat -- confirmed zero 'heartbeat' hits under lib/ via grep, and production/scripts/heartbeat.sh's own header (line 2) reads verbatim 'status: pending (authored, not yet run on node hardware)', matching the SPEC's citation exactly. v1 correctly drops to :manual-only with an explicit {:error, {:unsupported_trigger, _}} for the reserved atoms. Resolved.
- Spool ownership -- confirmed production/docs/OS_SPOOL_POLICY.md's ledger (lines 52-56) names colony_archive.sh as sole writer of /var/lib/uni/backups/colony/YYYYMMDD/, and confirmed colony_archive.sh itself never reads from or writes to runs/colony/snapshot/** (it sources only from /var/lib/uni/colony-memory or its broadcast-src fallback). v1's output path is scoped to the unshared runs/colony/snapshot/YYYYMMDD/HHMM/ tree, avoiding the two-writer collision, with the shared-path option correctly gated on an explicit named prerequisite (a ledger amendment) rather than silently written. Resolved.
Also confirmed the SPEC's self-correction is accurate: I grepped the whole lib/ tree for 'Agent.save' and 'def save(' and found no SP.Runtime.Agent.save/1 anywhere (only MC.save/2, Language.save/2, Reader.save/2) -- the prior revision's claim was indeed fictional and is now correctly retracted.
Net: this is a well-executed re-scope. Every load-bearing claim I checked against the live tree held up byte-for-byte (function names, line numbers, default ranges 0..9/0..3, the manifest.sha256 find|xargs incantation lifted from colony_archive.sh:63). The only defect is a single cosmetic line-citation range that points a few lines short of its target function while still describing that function's behavior correctly. That is a one-line fix, not a rework -- hence SIGN_WITH_CHANGES rather than REVISE.
- Concerns:
- Minor citation imprecision (trivial, named fix owed before merge): production/mcp/SPEC_lineage_snapshot.md line 49 cites 'MC.load/2's own safe_read/1 ... lib/sp/brain/mc.ex:556-579' for the corrupt-file-tolerance claim. I independently read lib/sp/brain/mc.ex: lines 556-585 are actually load/2's doc comment + body; safe_read/1 itself is defined at lines 587-594 (rescue/catch -> :error). The underlying behavioral claim is correct (a corrupt kin-*.bin yields a fresh brain via load/2's :error branch at ~582-583, not a crash) -- only the line-pointer is off by about one function's width. Given this repo's 'every claim carries a receipt' discipline (CLAUDE.md Honesty rail), the citation should point at 587-594 (or explicitly say 'load/2, which delegates to safe_read/1 at 587-594') before this SPEC ships.
- Out-of-scope FYI, not a blocker for this SPEC: the cross-referenced production/docs/SPEC_livepatch_hot_files.md (a different, pre-existing doc this SPEC only reads, does not edit) still lists the kin-*.bin hot-file's sole writer as 'SP.Runtime.Agent.terminate/2 + save_every tick (lib/sp/runtime/agent.ex:185-198,251-259)' -- it never names SP.Brain.MC.save/2 as the actual File.write!, and its cited line range does not actually contain terminate/2 (agent.ex:357) or the homeostatic death/save-every branches (agent.ex:259,310-319) that this corrected SPEC's own 'Purpose' section (accurately) enumerates. This SPEC's own citations are all correct; the staleness lives in the other doc and is worth a follow-up ticket, not a gate on D-D3.
systems-architect (docs/lab_team/03_systems_architect.md) — speaks third: can this be built, typed, validated, and inspected in pure Elixir without breaking the engine?
- Verdict: SIGN_WITH_CHANGES
- Rationale: I re-verified every named function/module/line-citation in the corrected spec directly against the live repo rather than trusting the spec's prose, and independently re-derived the four prior findings to confirm they're genuinely resolved, not just asserted resolved.
Findings, verified live:
- Atomicity: confirmed
SP.Runtime.Agentexposes onlystats/1(agent.ex:87, a GenServer.call diagnostics read) — no atomic-write primitive. ConfirmedMC.save/2(mc.ex:552-554) is a plainFile.write!/2, no tmp+rename. The spec correctly scopes v1 to reading MC.save/2's existing non-atomic output and namesAgent.dump_atomic/1explicitly as new, undone follow-on work — the more honest option, chosen correctly. - Live-kin enumeration: confirmed
Lineage's GenServer state carries no agent-pid/username field andspawn_next/2(lineage.ex:121-141) discardsSupervisor.spawn_agent/1's return value. ConfirmedLineage.name/1(lineage.ex:72,:\"sp_lineage_#{kin}\") andSupervisor.list_agents/0(supervisor.ex:85-89, returns[%{username, kin, mode}]sourced from the Registry metadata agents self-register inAgent.init/1, agent.ex:98) are both real. The composition the spec names (Process.whereis(Lineage.name(k))+ cross-reference againstlist_agents/0) is exactly buildable from real primitives, not invented. - Heartbeat: repo-wide grep for 'heartbeat' under lib/ returned zero hits, confirming no BEAM-side caller exists. Confirmed
production/scripts/heartbeat.sh's own header literally reads 'status: pending (authored, not yet run on node hardware)'. Dropping:heartbeat_idle/:heartbeat_liveto a named Phase-2 prerequisite, with:manualerroring out unsupported triggers rather than silently coercing them, is the correct and buildable scope. - Spool ownership: confirmed
production/docs/OS_SPOOL_POLICY.mddeclares/var/lib/uni/backups/colony/YYYYMMDD/sole-writerproduction/scripts/colony_archive.sh(daily 03:30 UTC) and documents the real 2026-07-12 EPERM two-writer crash. The spec's v1 output path (runs/colony/snapshot/YYYYMMDD/HHMM/) is a genuinely separate, unshared tree, correctly avoiding the collision and correctly naming the ledger amendment as a prerequisite for the shared path rather than silently writing into policy-owned territory.
I also confirmed the spec's self-correction is accurate: no Agent.save/1 exists anywhere in lib/ (grepped), so the prior revision's claim was indeed false and the correction to 'every save call site goes through SP.Brain.MC.save/2' is right, with all cited agent.ex call-site line numbers (185, 195, 251, 259, 310, 318, 358) matching exactly what's on those lines. Colony.start_evolution/2's default 0..3 (colony.ex:76) and the moduledoc's 'one per kin group 0..9' (lineage.ex:3-4) both check out.
Architecturally this is not an FE-term proposal — it's correctly marked 'FE-adjacent,' touches no A/B/C/D/E factor, no genome organ, no decider/Plan/efe.ex path — so most of my persona's seven FE-specific required checks (typed StateSpace/Observation/Action/Preference/Policy record, byte-identity gate over the depth-5 Plan path, coupling default 0.0, no-scalar-per-action-in-logits, monotonic decay) are correctly inapplicable, and the spec doesn't try to dress this up as one. snapshot/1 is a pure composition of already-existing, already-tested primitives, introduces no new hot file, and is honestly scoped as a manual-trigger-only library call with no claimed production invocation surface (no MCP tool, no boot-time registration) — which is consistent, not a gap, since it never claims otherwise.
The one substantive new problem I found (not on the prior findings list) is concrete and file-grounded: the test plan's choice of kin ids 0 and 2 sits inside the live colony's own default kin range and departs from the existing sibling test's out-of-band-kin convention, creating a real risk that running the new test suite against a checkout with live/dev learned models clobbers real kin-0.bin/kin-2.bin data via the ordinary terminate/2 save path — ironic for a spec whose whole purpose is preventing kin-memory data loss. That, plus one imprecise (though not wrong) line citation, is why I land on SIGN_WITH_CHANGES rather than a clean SIGN: the module design and re-scoping are sound and buildable as specified, but the test file as described should not be written verbatim.
- Concerns:
- Test-plan kin-id collision with live data: production/mcp/SPEC_lineage_snapshot.md's 'Enumeration' test (lines 65-66) proposes
Lineage.ensure_started/2on kin 0 and kin 2 — both insideSP.Brain.Colony.start_evolution/2's own default live kin range0..3(lib/sp/brain/colony.ex:76). The sibling testtest/sp/runtime/lineage_test.exs:38deliberately useskin = 8, outside that range, and I could find no acknowledgement in the spec that this convention exists or why the new test departs from it. BecauseSP.Runtime.Lineage'smemory_pathis alwaysPath.join(@repo_root, "runs/colony/kin-#{k}.bin")(lib/sp/runtime/lineage.ex:133) with no test-mode path override, andSP.Runtime.Agent.terminate/2unconditionallyMC.save/2s whenever a memory_path+brain are present (lib/sp/runtime/agent.ex:357-358, fires on plainGenServer.stop), running this test against any checkout where a live/dev colony has used kin 0 or kin 2 will load the realkin-0.bin/kin-2.binand overwrite it with test state on cleanup -- the exact class of learned-model data loss this whole spec exists to prevent. Fix: rename the test's kin ids to the same out-of-band convention (e.g. 8/9)lineage_test.exsalready uses, before landingtest/sp/runtime/lineage_snapshot_test.exs. - Minor citation imprecision (self-inconsistent with the spec's own stated purpose this revision): the 'Snapshot mechanics' step 3 / 'v1 Scope' item 1 cite
lib/sp/brain/mc.ex:556-579for the claim that 'MC.load/2's own safe_read/1 already treats a corrupt file as start fresh rather than crashing.' I verified the substance is true, but that line range covers only load/2's doc comment plus its happy-path case clause; the actual:error -> new(opts)fallback sits at lines 582-583 anddefp safe_read/1itself (with its rescue/catch) is defined at lines 587-594 -- both outside the cited range. Not fatal, but this spec's entire justification this pass is fixing prior imprecise citations, so its own new pointers should be tightened to the exact lines (e.g. 552-594).
- Test-plan kin-id collision with live data: production/mcp/SPEC_lineage_snapshot.md's 'Enumeration' test (lines 65-66) proposes
RED Experimentalist / World Auditor (docs/lab_team/04_red_experimentalist.md)
- Verdict: SIGN_WITH_CHANGES
- Rationale: I independently re-verified every citation in the corrected spec against live source (lib/sp/runtime/lineage.ex, agent.ex, supervisor.ex, lib/sp/brain/mc.ex, lib/sp/brain/colony.ex, production/scripts/{colony_archive,heartbeat}.sh, production/docs/OS_SPOOL_POLICY.md, production/docs/SPEC_livepatch_hot_files.md) -- not trusting the spec's prose. All four prior findings are genuinely, precisely resolved, down to exact line numbers: (1) Agent.stats/1 at agent.ex:87 confirmed to be the only public Agent call, MC.save/2 at mc.ex:552-554 confirmed plain File.write! with no tmp+rename, and v1 correctly scopes atomicity to the destination side only with the risk explicitly documented; (2) Lineage.name/1 (lineage.ex:72) + Process.whereis/1 + Supervisor.list_agents/0 (supervisor.ex:85-89, verified to actually return
[%{username,kin,mode}]via its match-spec) is a real, composable enumeration path, correctly spelled out; (3) grep of lib/ for 'heartbeat' returns zero hits (confirmed), heartbeat.sh's own header literally says 'status: pending (authored, not yet run on node hardware)' (confirmed verbatim), and v1 correctly drops to :manual-only with :heartbeat_idle/:heartbeat_live explicitly rejected rather than silently coerced; (4) OS_SPOOL_POLICY.md confirmed to declare colony_archive.sh sole writer of /var/lib/uni/backups/colony/YYYYMMDD/ with the documented EPERM 'Why', and v1's output path is correctly redirected to the unshared runs/colony/snapshot/** tree with the bind-mount path named as an explicit deferred prerequisite. The spec is honest, well-scoped, and its own self-corrections (the SP.Runtime.Agent.save/1-that-doesn't-exist correction, the colony_archive.sh-doesn't-consume-this correction) both check out against SPEC_livepatch_hot_files.md and colony_archive.sh's actual behaviour. Nothing here is fabricated. However, my independent pass surfaced a genuine new defect the fix introduced: the named test plan reuses live/production kin ids (0, 1, 2) for a Lineage-driven test, which -- because memory_path is hardcoded to the real repo tree and this repo has an established, persona-doc-cited convention (kin 10/11) specifically to avoid this -- risks silently destroying real colony learning data. That is squarely in-scope for a red-experimentalist ('same code, same world... the kin-10/kin-11 split... is the canonical pattern') and is concrete, cheap to fix, and does not require reworking the SPEC's core design. Combined with two smaller testability-completeness gaps (untested opts[:kins] override, untested live_agent field) that a fabricated-but-schema-valid implementation could sail through, this warrants SIGN_WITH_CHANGES rather than a clean SIGN: land once the kin-id collision is fixed in the (not-yet-written) test file, with the opts[:kins] and live_agent coverage gaps addressed as the same pass. - Concerns:
- CONFIRMED, primary — new test-isolation/data-safety defect the fix pass introduced: the named 'Enumeration' test (production/mcp/SPEC_lineage_snapshot.md:65-66, 'lineages started for kin 0 and 2... kin 1 never started') uses live-range kin ids.
Lineage.spawn_next/2hardcodes memory_path toPath.join(@repo_root, "runs/colony/kin-#{state.kin}.bin")(lib/sp/runtime/lineage.ex:133, NOT opts-overridable), and@repo_root(lineage.ex:25) resolves to the real checked-out repo tree — confirmed no sandboxing exists (test/test_helper.exs is justExUnit.start(exclude: [:skip])). Kin ids 0-2 sit inside the moduledoc's live 'one per kin group 0..9' range (lineage.ex:3-4) and inside SP.Brain.Colony.start_evolution/2's own default live-evolution range 0..3 (lib/sp/brain/colony.ex:76). This repo already has an established convention to avoid exactly this: test/sp/runtime/lineage_test.exs:38 deliberately picks kin=8 (not 0-3), and the canonical live-RED split this very persona doc cites ('the kin-10 / kin-11 split for Phase 1 is the canonical pattern', docs/lab_team/04_red_experimentalist.md:12, matching runs/curiosity_lineage.exs:2) uses kin 10/11 specifically to stay clear of the real 0..9 range. As specified, the new test would write/overwriteruns/colony/kin-0.binandkin-2.bin-- the exact path a real or locally-run colony persists its learned Dirichlet history to -- with throwaway fixture bytes on any checkout where that data exists. That is precisely the unrecoverable-memory-loss failure mode this whole SPEC (D-D3) exists to protect against, reintroduced by its own test plan. Required change before test/sp/runtime/lineage_snapshot_test.exs is written: use kin ids outside 0..9 (e.g. 10/11/12, matching the established RED convention). - Untested override path: none of the 6 named tests (SPEC_lineage_snapshot.md:65-70) ever passes an explicit
opts[:kins]value -- all exercise only the default 0..9 range (kin ids 0-2 fall inside it too). An implementation that hardcodes0..9and silently ignoresopts[:kins]-- directly contradicting the 'Behaviour' section's own stated contract -- would pass every named test. This is exactly the fabricated-but-schema-valid gap this review is supposed to catch. - No named test exercises the 'live_agent' manifest field (Snapshot mechanics step 2b, cross-referencing SP.Runtime.Supervisor.list_agents/0, verified real at lib/sp/runtime/supervisor.ex:85-89) -- an implementation that always emits
live_agent: falseor omits the field entirely would still pass every test in the 'Test coverage' section. - Minor/non-blocking: the 'Local atomicity: killing the snapshot process mid-copy' test (SPEC_lineage_snapshot.md:67) names no mechanism for deterministically triggering the kill at the right instant. The 'Behaviour' section states
snapshot/1runs 'immediately, synchronously, in the calling process' (no process of its own to kill), so the test must wrap the call in its own Task and pick a kill point across the per-kin tmp+rename sequence (mechanics step 3, lineage.ex-analogous) -- worth one added sentence so this test isn't timing-flaky or silently skipped. - Minor/framing: zero occurrences of 'FALSIFIES' anywhere in the doc. LAB_PROTOCOL.md SS II/VII scope the PASS+FALSIFIES RED-gate apparatus to 'cures'/FE-touching behavioural claims under full lab-team review, and this SPEC correctly self-scopes as non-FE, pure I/O composition (explicitly 'no change to lib/sp/runtime/agent.ex or lib/sp/brain/mc.ex in v1') -- so the classic paired-RED framework does not strictly transplant here, and I am not treating this as a blocking gap. Still, one explicit sentence naming the SPEC's own falsifier (e.g. 'not an FE/behavioural claim; falsified by any named test in lineage_snapshot_test.exs failing, or a manual snapshot landing outside runs/colony/snapshot/**') would keep it consistent with this repo's own admission-test culture instead of leaving it implicit.
- CONFIRMED, primary — new test-isolation/data-safety defect the fix pass introduced: the named 'Enumeration' test (production/mcp/SPEC_lineage_snapshot.md:65-66, 'lineages started for kin 0 and 2... kin 1 never started') uses live-range kin ids.
embodiment-designer (lab-team persona 5/5, docs/lab_team/05_embodiment_designer.md)
- Verdict: SIGN_WITH_CHANGES
- Rationale: Re-verified all four prior findings directly against the live source, independently of the spec's own citations — all four are genuinely resolved, not just asserted:
- Atomicity: confirmed SP.Runtime.Agent exposes only stats/1 (agent.ex:87, a GenServer.call diagnostics read) and every real save is SP.Brain.MC.save/2 (mc.ex:552-554), a plain File.write!/2 with no tmp+rename — matches the spec's claim exactly. v1 correctly re-scopes to read the existing non-atomic kin-*.bin as-is, documents the torn-read risk plainly, and names the exact deferred fix (Agent.dump_atomic/1) as new/unbuilt work. Resolved.
- Live-kin enumeration: confirmed Lineage's GenServer state (init/1, agent.ex-analog lineage.ex:82-90) has no agent-pid/username field, and spawn_next/2 (lineage.ex:121-141) discards Supervisor.spawn_agent's return value. Confirmed Lineage.name/1 (lineage.ex:72) and Supervisor.list_agents/0 (supervisor.ex:85-89, returns [%{username, kin, mode}] exactly as cited) are real and composable as described. Resolved.
- Heartbeat: repo-wide grep for 'heartbeat' under lib/ returned zero hits, confirming the claim; heartbeat.sh:2 does read 'status: pending (authored, not yet run on node hardware)' verbatim. v1 correctly drops :heartbeat_idle/:heartbeat_live to a named, gated Phase 2 rather than inventing an unbuilt bridge. Resolved.
- Spool conflict: confirmed OS_SPOOL_POLICY.md already names production/scripts/colony_archive.sh sole writer of /var/lib/uni/backups/colony/** (daily 03:30 UTC) and documents the real 2026-07-12 EPERM two-writer crash in its own 'Why' section. v1 defaults snapshot/1's output strictly to runs/colony/snapshot/YYYYMMDD/HHMM/, outside that tree, and correctly names the ledger amendment as an explicit prerequisite for the deferred bind-mount-shared path. Also confirmed the manifest.sha256-format citation (colony_archive.sh:62-65) is an exact match, and the corrected cross-reference (colony_archive.sh does NOT consume snapshot/1's output) is accurate — I read colony_archive.sh directly; its sources are /var/lib/uni/colony-memory and mcserver, never runs/colony/snapshot/. Resolved.
On my assigned focus (embodiment exposure/redaction, field-level allowlist, path/host-layout leak): this spec is not a new organ/drive and touches no A/B/C/D/E factor, no policy logits, no FE math — it stays correctly out of my checklist's organ-specific traps (no per-action scalar, no C-peak-as-drive, nothing to run the action-clone-invariance/allostasis/limit-cycle gates against), and the spec's own header states this plainly. On the actual redaction question: manifest.sha256 deliberately uses relative (cd-then-find) paths, never absolute — no host-layout leak there, matching the established colony_archive.sh pattern. There is no wiring in this spec (or anywhere I could find in the repo) that routes snapshot/1's output, its {:ok, dir} return, or its manifest into any public-facing surface (production/mcp/SPEC_uni_public_mcp.md's read_evidence_bundle whitelist is docs/receipts/ + production/docs/receipts/ only; runs/colony/snapshot/** is not in it, and the spec doesn't claim otherwise) — so I found no actual leak. What I did find is a dangling, unhomed field reference (the 'live_agent' manifest field that has no defined artifact to live in) — a concrete instance of exactly the kind of unallowlisted-field gap I was asked to check, even though its current blast radius is zero since nothing reads it yet. That's my one required change. Everything else is advisory. This is solid, honest re-scoping work — the corrected spec chose the smaller, buildable option at every one of the four gaps rather than inventing new unbuilt machinery, consistent with this repo's claim-fence discipline.
- Concerns:
- REQUIRED — production/mcp/SPEC_lineage_snapshot.md:46 says the Supervisor.list_agents/0 cross-reference (step 2b) is 'used for the manifest's live_agent field,' but the only manifest artifact the spec actually defines is manifest.sha256 (step 5, line 51; test 'Manifest integrity', line 68), which I verified is byte-for-byte the same shape as production/scripts/colony_archive.sh:62-65 — a plain sha256sum output (hash + filename, nothing else, confirmed by reading colony_archive.sh directly). No field-bearing artifact (no manifest.json, no per-kin record) exists anywhere in this spec for a live_agent field to land in. This is exactly the gap my checklist is meant to catch: you cannot allowlist a field that has no named destination. Before this lands: either name the destination explicitly (e.g. a small manifest.json sidecar with an explicit field list {kin, live_agent}) or cut the 'used for the manifest's live_agent field' line in step 2b and make that cross-reference purely diagnostic/logged, never promised to land in a written artifact.
- ADVISORY, non-blocking — opts[:kins] is caller-suppliable and step 2a calls SP.Runtime.Lineage.name/1 (lineage.ex:72, :"sp_lineage_#{kin}") once per candidate id; each call interns a new, permanent BEAM atom (atoms are never GC'd). I verified this mirrors an existing unguarded pattern already live in SP.Brain.Colony.start_evolution/2 (colony.ex:76-78, loops a caller-supplied kins Range through Lineage.ensure_started/2 -> name/1), so it is not a defect unique to this spec, and v1's :manual-only trigger keeps opts[:kins] operator-typed rather than reachable from any automated/public surface today — I'm not blocking on it. Still worth a one-line bound (cap opts[:kins] to the declared architectural 0..9 range, refuse wider) before any Phase-2 wiring makes opts[:kins] reachable from a less-trusted caller, since unbounded dynamic-atom creation can crash the whole BEAM node (atom-table exhaustion), which would take the live colony + broadcast down with it — a real internal-stability question, which is my domain.
- INFORMATIONAL, non-blocking, in the OTHER doc not this one — production/docs/SPEC_livepatch_hot_files.md:47 still describes this spec as 'the BEAM-triggered atomic snapshot that increments the hot-file class,' language that reads as if snapshot/1 were expected to register a new guarded hot-file entry. This spec's own 'Hot-file interaction' section reaches the opposite, correct conclusion (verified against OS_SPOOL_POLICY.md, whose binding rule is scoped to /var/lib/uni/** only, and runs/colony/snapshot/** is outside that scope) — no new hot-file entry is needed. Worth a one-line correction in SPEC_livepatch_hot_files.md so a future guard-reader doesn't take the stale phrase literally. Not a defect in the spec under review; flagging per CLAUDE.md's 'drift from the Tree is a defect; stop and surface it.'
MERGED VERDICT
SIGN_WITH_CHANGES
(Merge rule: the worst verdict wins.)
Honesty note
This is a v2 receipt following a spec-correction pass driven by the v1 review's own findings. This is the first formal review this spec has received. No FE source code (.ex/.exs/.py/.cjs) was written or modified by either the fix pass or this review -- only spec/schema/policy documents. If this verdict is SIGN or SIGN_WITH_CHANGES, implementation may proceed through this repo's normal ship gate; if REVISE or REJECT, further spec work is needed before any code diff.
Addendum — named changes applied (pass 3)
This is a direct-apply pass, not a fresh persona re-review. No independent verification round was run; the concerns named by the five personas above were re-verified individually against live source (where they cited a file:line) and then closed directly in the spec document(s). Treat this addendum as an implementer's changelog, not a sixth verdict.
Files touched: production/mcp/SPEC_lineage_snapshot.md (primary) and production/docs/SPEC_livepatch_hot_files.md (two stale cross-references into the sibling doc). No .ex/.exs/.py/.cjs file was touched.
Concern-by-concern (deduplicated across personas that raised the same item independently):
- FIXED: Wrong line-citation for the corrupt-file-tolerance claim (math-breaker, aif-theorist, systems-architect all flagged
lib/sp/brain/mc.ex:556-579). Re-read livemc.ex:load/2is:563-585,safe_read/1(the actual rescue/catch →:errorfallback) is:587-594, andload/2's own:error -> new(opts)branch is:582-583. Spec "Snapshot mechanics" step 3 now cites all three precisely. - FIXED: Cross-document drift in
production/docs/SPEC_livepatch_hot_files.md's own Cross-references section, which called this spec "the BEAM-triggered atomic snapshot that increments the hot-file class" — directly contradicting this spec's "Hot-file interaction" conclusion (math-breaker REQUIRED; embodiment-designer informational, same defect). Rewrote that line to state plainly thatsnapshot/1reads, not writes, and does not increment the hot-file class. - FIXED: Test-coverage "Local atomicity" bullet overstated self-cleanup ("orphaned
.tmp, which the next run overwrites") when v1's per-run dated-directory design (each:manualrun gets its ownYYYYMMDD/HHMM/) means that's not actually true in the general case, and no reaper exists (math-breaker). Reworded to state the.tmpis harmless but not reliably cleaned up, and named the absence of a reaper explicitly rather than asserting a false self-healing property. - FIXED: Stale writer citation in
SPEC_livepatch_hot_files.md's own hot-files list —runs/colony/kin-*.bin's sole writer was cited asSP.Runtime.Agent.terminate/2+ save_every tick atagent.ex:185-198,251-259, a range that (re-verified live) contains neitherterminate/2(actually:357-358) nor the homeostatic branches (:259is metabolic save-every,:310is the homeostatic death branch, not:251-259as a pair) — and never named the actual writer,SP.Brain.MC.save/2(aif-theorist, flagged non-blocking/informational but a genuine stale citation). Corrected the entry to nameMC.save/2(mc.ex:552-554) as sole writer and list all seven real call sites (agent.ex:185,195,251,259,310,318,357-358) accurately. - FIXED — CONFIRMED primary, treated as required: Test-plan kin-id collision with live/dev colony data (systems-architect REQUIRED; RED Experimentalist CONFIRMED primary, both independently re-derived from live
lineage.ex:133's hardcoded, non-overridablememory_pathandagent.ex:357-358's unconditionalterminate/2save). Re-verified both cited conventions live:test/sp/runtime/lineage_test.exs:38does usekin = 8;runs/curiosity_lineage.exs:2anddocs/lab_team/04_red_experimentalist.md:12do establish kin10/11as the paired-RED out-of-band convention. Rewrote the "Enumeration" test to use kin10/12(started) and11(never started) — fully outside the architectural0..9range — with an explicitopts[:kins]: 10..12override, and added an explicit "must not start lineages inside0..9" warning with the exact citations that make it dangerous. - FIXED: Untested
opts[:kins]override path (RED Experimentalist) — no named test ever passed an explicit value, so an implementation hardcoding0..9and ignoring the option would pass every test. Resolved as a side effect of fix #5: kin ids10..12sit outside the default0..9scan range, so the rewritten "Enumeration" test now requires (and thereby exercises) an explicitopts[:kins]override. - FIXED — REQUIRED: Dangling
live_agentmanifest field (embodiment-designer REQUIRED; RED Experimentalist independently flagged the same field as untestable for the same underlying reason — no artifact defines it). Verified live: the spec's only defined artifact,manifest.sha256, is a plain sha256sum listing with no room for extra fields (matchescolony_archive.sh:62-65byte-for-byte). Cut the "used for the manifest'slive_agentfield" claim from "Snapshot mechanics" step 2b; theSupervisor.list_agents/0cross-reference is now explicitly diagnostic/logged-only in v1, with amanifest.jsonsidecar named as deferred Phase-2 work if a real consumer ever needs the field. This also closes RED Experimentalist's "no test exerciseslive_agent" concern — there is no longer a promised field to leave untested. - FIXED (minor): RED Experimentalist's non-blocking note that the "Local atomicity" test names no mechanism for deterministically triggering a mid-copy kill. Added one sentence: since
snapshot/1runs synchronously in the calling process (no process of its own to kill), the test wraps the call in its ownTaskand kills at a chosen point inside the per-kin tmp+rename loop. - FIXED (minor/framing): RED Experimentalist's note that "FALSIFIES" appears nowhere in the doc. Re-verified the cited framework live (
docs/LAB_PROTOCOL.md§II "Pre-registered RED gates", §VII "Adversarial review by persona team") — confirmed real section numbers and content. Added a one-paragraph "Falsifier" note stating plainly that this spec makes no FE/behavioural claim, so the paired PASS/FALSIFIES RED-gate apparatus doesn't transplant, and naming the spec's own narrower falsifier (a named test failing, or a:manualsnapshot landing outsideruns/colony/snapshot/**). - NOT FIXED — genuine judgment call for the owner, named as a deferred Phase-2 prerequisite instead of enforced now: embodiment-designer's ADVISORY (explicitly "not blocking") concern that
opts[:kins]is unbounded and each candidate id interns a permanent BEAM atom viaLineage.name/1, risking atom-table exhaustion ifopts[:kins]ever becomes reachable from a less-trusted/automated caller. Implementing a hard0..9bound now would directly contradict fix #5/#6 above, which requires the v1 test to pass an explicit out-of-bandopts[:kins]: 10..12— and the persona's own rationale for not blocking (":manual-only trigger keepsopts[:kins]operator-typed... not reachable from any automated/public surface today") applies equally to that test call. Named explicitly in "Behaviour" (why v1 doesn't bound it) and added as a new Phase-2 list item (bound/reject onceopts[:kins]leaves the operator-typed:manualsurface) rather than silently dropped.
No concern in this pass required editing real source code (.ex/.exs/.py/.cjs); every item above was a spec-document (or sibling spec-document) fix. Consistent with the merged verdict's own honesty note, this addendum does not claim a fresh SIGN — the owner should treat items 1-9 as applied and item 10 as an open scoping decision to ratify or override.
sha256 ad32f56040795045 — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
A review of a specification for taking snapshots of stored state, coming back passing after four findings were fixed. Re-reading the code before editing turned up three more stale citations that nobody had listed, including a function the specification cited that does not exist anywhere. The corrected version narrows what a first release would do, names each deferred prerequisite, and leaves one open design decision for the owner rather than settling it quietly in either direction.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is ad32f56040795045
Clear — written for this website, not the source document
A review round over a corrected specification, with a passing verdict, covering one document, and no source code touched.
The most useful section is the re-verification done before any editing. All four original findings held against the current code, and the re-read turned up three further problems nobody had listed. A cited function does not exist anywhere in the codebase. A claim about what consumes the output is not true today. And a line citation had drifted into a different branch entirely. All were fixed anyway, under a stated rule about never leaving a wrong citation in place.
One confirmed finding is strengthened by something noticed while checking it. The mechanism the specification wanted to hook into is not merely absent from the code. Its own script header says it has never been run on the hardware, which makes the case against building a bridge to it now stronger rather than weaker.
The changes are then given section by section. A scope section is added stating four re-scoping decisions explicitly, each naming the prerequisite it defers. An option that would have quietly degraded is changed to return an explicit error instead, which is the right instinct: refusing loudly beats doing something other than what was asked.
The mechanics are rewritten entirely. A step that assumed a component could be asked to do something it cannot is replaced. Instead it reads what is already on disk and writes it out through a temporary file and a rename, with the residual risk of reading a file mid-write documented explicitly rather than papered over. The default location is changed to avoid a shared tree.
One reframing does real work. Describing the operation as a reader rather than a writer of those files means it needs no entry in a guard or a running list meant for writers, which removes a whole class of coordination.
The test coverage is rewritten to drop tests that could not be run against something that does not exist. A note is added saying plainly that this document makes no behavioural claim, so the paired apparatus of writing conditions down first does not transplant onto it. It names its own narrower way of being shown wrong instead: a named test failing, or a snapshot landing outside its declared directory.
The last item is the most interesting, because it is explicitly not fixed. One reviewer raised an advisory concern that an unbounded input permanently interns a name in a table that never shrinks, which would matter if that input ever became reachable from an automated caller. Bounding it now would contradict another fix, which requires a test to pass a value outside that bound, and the same reviewer's own reason for not blocking applies to that test too. So it is named in the document, and added as a later prerequisite for when the input leaves the operator-typed surface. It is left as a genuine open design decision for the owner to ratify or overrule, rather than being quietly dropped or quietly enforced. The addendum says outright that it does not claim a fresh signature on the strength of that.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is ad32f56040795045