101 lines
4.0 KiB
Markdown
101 lines
4.0 KiB
Markdown
# M2.8 — M2 composition gate
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Phase | M2 — Projections |
|
||
| Size | M — 1–3 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
|