Files
poimen-memory/tasks/M2.8-m2-gate.md

101 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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