3.5 KiB
M0.8 — M0 composition gate
| Field | Value |
|---|---|
| Phase | M0 — Read-only spine |
| Size | M — 1–3 days |
| Status | ✅ Done |
| Flags | gate |
| Spec | inlined below |
| Blocks | all of M0 |
Goal
Prove the parts compose and that the swappable part is genuinely swappable — the properties no single M0 task owns.
Facts (inlined — no spec read needed)
The claim this phase makes: a new input kind is added by implementing
RecordSource, and nothing downstream changes. If that is false, the crate
split bought nothing and the streaming work later will be a rewrite.
The gate proves it by adding a third source that resembles nothing already supported, and asserting the rest of the pipeline is untouched.
Second claim: the whole phase is free. No model calls, so the gate is a CI job that runs on every push without a gateway or credentials.
Steps
- Implement
SyntheticSourcein the test tree only — generates records from a seed, has no file format, and deliberately produces a record larger than the chunk budget and a run of empty-text records. - Assert
chunks()handles it with no change tomem-chunk. - Assert dependency direction still holds (M0.1 assertion 3) after three sources exist — this is when someone is tempted to reach backwards.
- Run
mem ingest --dry-runover all three sources for one project and diff the summary against a committed expected file. - Wire the whole thing as a required CI job.
Acceptance
- Three sources, one
RecordSource, zero source-specific branches inmem-chunkormem-cli. - Dry-run summary diffs empty against the committed expectation.
- CI job passes with no network and no credentials.
Verify
Harness: committed expected-output file, diffed. The script's output is the review artifact.
Integration test — tests/it_m0_gate.rs:
a1_third_source_needs_no_downstream_change—SyntheticSourceflows throughchunks(); assertgit diff --stat crates/mem-chunk crates/mem-cliis empty for the commit that added it (enforced by a CI step, not by the test binary).a2_no_source_specific_branches— grepcrates/mem-chunkandcrates/mem-clifor the stringspi:,claude:,sessionId,toolResult; assert none appear outsidemem-ingest.a3_dry_run_golden— run the dry run over all three sources, diff againstexpected/m0-gate.txt; empty diff is the only pass.a4_offline— the entire gate runs with networking disabled.a5_lossless_end_to_end— records in equals records out, across all three sources composed.
Command: cargo test --workspace m0_gate
False pass:
- Adding
SyntheticSourcein a way that mirrors the pi format. It then exercises the same code path and proves nothing about generality. It must have no file, no header line, and an oversized record. - Assertion 3 passing because the expected file was regenerated in the same
commit. A changed
expected/file in a diff is a claim that the contract changed, and must be reviewed as one.
Traps
- Skipping assertion 2 because "obviously there are no source-specific branches".
There will be — the first
if provenance.starts_with("pi:")gets added to fix a real bug and is entirely reasonable in isolation. - Letting the gate need credentials. The value of an offline gate is that it runs on every push; the moment it needs a gateway key it becomes a nightly job that nobody watches.
Background: DESIGN.md — mem-chunk, Verification