Files

101 lines
4.0 KiB
Markdown
Raw Permalink Normal View History

2026-08-19 09:52:07 -07:00
# M2.8 — M2 composition gate
| Field | Value |
|---|---|
| Phase | M2 — Projections |
| Size | M — 13 days |
| Status | ⬜ Not started |
| Flags | gate |
| Spec | inlined below |
| Blocks | all of M2 |
## Goal
Prove the authority model: the log is sufficient, and both projections are
genuinely derived.
## Facts (inlined — no spec read needed)
The claim under test — poimen's own principle, applied here:
> Nothing derived is authoritative. If it cannot be dropped and rebuilt
> byte-identically, it has hidden inputs and that is a bug.
The gate is destructive by design: it **deletes** the vault and truncates the
database, rebuilds from the log alone, and diffs. Anything that survives only
because it was already there is a hidden input, and this is the only test that
finds it.
```sh
rm -rf vault/poimen
psql -c "delete from memory_node where project = 'poimen'"
mem rebuild --from-log --project poimen
git -C vault diff --exit-code # empty diff is the only pass
```
`git diff --exit-code` on a tracked vault is the assertion. It compares against
what was committed, so it also catches a projector change that was not intended.
Run it twice: once from empty (sufficiency) and once on top of itself
(idempotence). Both must produce the same bytes.
## Steps
1. `verify/m2.8.sh` performing the destructive rebuild above.
2. Assert the vault diff is empty and the database node counts match the log.
3. Run `mem verify` and assert zero violations.
4. Second rebuild without clearing; assert still empty diff and unchanged row
count.
5. Assert no controller model calls (embeddings are allowed and expected).
6. Commit `expected/m2.8.txt` with the count summary; diff against it.
## Acceptance
- Vault rebuilt from nothing is byte-identical to the committed vault.
- Database node/edge counts match the log's records exactly.
- `mem verify` reports zero violations.
- Second rebuild changes nothing.
## Verify
**Harness:** disposable database, git-tracked vault, real log. Long-running; a
nightly or on-demand job.
**Integration test**`verify/m2.8.sh`, output diffed against `expected/m2.8.txt`:
1. `a1_vault_from_empty` — delete vault, rebuild, `git diff --exit-code` empty.
2. `a2_db_from_empty` — truncate, rebuild, counts per level equal the log's.
3. `a3_verify_clean``mem verify` exits 0.
4. `a4_rebuild_idempotent` — rebuild again, diff still empty, row count unchanged.
5. `a5_no_controller_calls` — assert zero calls to the chat route during rebuild
(count via the record dir from M1.1, or a proxy).
6. `a6_projection_independence``--vault-only` then `--db-only` produces the
same end state as a combined rebuild.
7. `a7_log_alone_suffices` — move the log to a fresh checkout with no vault and no
database, rebuild, diff against the committed vault. The strongest form of
the claim.
**Command:** `bash verify/m2.8.sh | diff - expected/m2.8.txt`
**False pass:**
- Running the gate without deleting the vault first. A projector that only writes
changed files produces an empty diff trivially, and the hidden input survives.
- Diffing an untracked vault. `git diff` on untracked files reports nothing, so
the assertion passes vacuously. The vault must be committed, or the script must
compare against a committed golden tree explicitly.
- Allowing controller calls "because it is easier". Rebuild then produces new
memory text each run and the gate can never pass — at which point the usual fix
is to weaken the gate.
## Traps
- Treating a non-empty diff as a projector bug by default. It is equally likely to
be a *hash* bug: if `sha256` includes a timestamp (M0.2), every rebuild produces
new nodes and the vault churns. Check identity before blaming rendering.
- Running against production data with the destructive script and no backup. The
log is the record; if that is intact, everything is recoverable — which is
exactly why the log must be tracked in git before this gate is first run.
---
Background: [DESIGN.md](../DESIGN.md) — Authority model, Verification