95 lines
3.5 KiB
Markdown
95 lines
3.5 KiB
Markdown
# M0.7 — `mem ingest --dry-run`
|
|||
|
|
|
||
|
|
| Field | Value |
|
||
|
|
|---|---|
|
||
|
|
| Phase | M0 — Read-only spine |
|
||
|
|
| Size | S — under 1 day |
|
||
|
|
| Status | ⬜ Not started |
|
||
|
|
| Flags | — |
|
||
|
|
| Spec | inlined below |
|
||
|
|
| Blocks | M0.4, M0.6 |
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
|
||
|
|
See the chunk plan for a real project before spending a single model call on it.
|
||
|
|
|
||
|
|
## Facts (inlined — no spec read needed)
|
||
|
|
|
||
|
|
`--dry-run` makes **zero network calls**. That is the property, not a side
|
||
|
|
effect: this is the last checkpoint before inference, and its value is telling
|
||
|
|
you the corpus is sane while feedback is still free.
|
||
|
|
|
||
|
|
Output shape:
|
||
|
|
|
||
|
|
```
|
||
|
|
project /Users/rockliang/workplace/Poimen/agent-rust
|
||
|
|
sources pi:4 files claude:2 files
|
||
|
|
records 3118 (assistant 1445 toolResult 1261 user 196 system 216)
|
||
|
|
chunks 412 over-budget 3
|
||
|
|
tokens min 84 p50 4870 p95 5000 max 11204
|
||
|
|
```
|
||
|
|
|
||
|
|
`over-budget` counts single records exceeding the chunk budget (M0.3). A nonzero
|
||
|
|
count is expected — large tool results — and is worth surfacing because it
|
||
|
|
predicts requests the gateway may reject.
|
||
|
|
|
||
|
|
Numbers to sanity-check against: a real pi session in this project has 2902
|
||
|
|
messages with the role split above, and toolResult being ~43% is the signal that
|
||
|
|
the update gate has something to discriminate.
|
||
|
|
|
||
|
|
## Steps
|
||
|
|
|
||
|
|
1. `mem ingest --project <path-or-key> --dry-run`.
|
||
|
|
2. Resolve sources: scan both source roots for directories whose `cwd` matches
|
||
|
|
the project. Report which files matched.
|
||
|
|
3. Stream records through `mem-chunk` with the real tokenizer; accumulate stats
|
||
|
|
without retaining chunk bodies.
|
||
|
|
4. Print the table above. Machine-readable variant behind `--format json`.
|
||
|
|
5. `--limit <n>` to stop after n chunks, for iterating on a large project.
|
||
|
|
6. Exit non-zero if zero sources matched — a silent empty plan reads like success.
|
||
|
|
|
||
|
|
## Acceptance
|
||
|
|
|
||
|
|
- No network syscall occurs during `--dry-run`.
|
||
|
|
- Stats are computed streaming; memory does not scale with corpus size.
|
||
|
|
- Zero matched sources exits non-zero with a message naming the project key.
|
||
|
|
|
||
|
|
## Verify
|
||
|
|
|
||
|
|
**Harness:** the fixtures from M0.5/M0.6, plus a network guard.
|
||
|
|
|
||
|
|
**Integration test** — `tests/it_dry_run.rs`:
|
||
|
|
1. `a1_no_network` — run the command with outbound TCP blocked (inject a
|
||
|
|
`reqwest` client that panics on use, or set an unroutable proxy); assert exit 0.
|
||
|
|
2. `a2_counts_match_sources` — record and role counts equal the sum of what the
|
||
|
|
two adapters yield independently.
|
||
|
|
3. `a3_chunk_count_matches_chunker` — the reported chunk count equals
|
||
|
|
`chunks(...).count()` computed separately.
|
||
|
|
4. `a4_over_budget_reported` — fixture with one oversized record; assert
|
||
|
|
`over-budget 1`.
|
||
|
|
5. `a5_empty_project_fails` — unknown project key exits non-zero, message names
|
||
|
|
the key.
|
||
|
|
6. `a6_constant_memory` — run against a 50 MB fixture; assert peak RSS stays
|
||
|
|
under a bound well below file size.
|
||
|
|
|
||
|
|
**Command:** `cargo test -p mem-cli dry_run`
|
||
|
|
|
||
|
|
**False pass:**
|
||
|
|
- Asserting the command exits 0 and printing looks right. A dry run that matched
|
||
|
|
no sources also exits 0 and prints a tidy table of zeros — assertion 5 is what
|
||
|
|
separates them.
|
||
|
|
- Computing stats by collecting chunks into a `Vec` first. Every assertion here
|
||
|
|
passes and assertion 6 is the only one that fails, which is why it is present.
|
||
|
|
|
||
|
|
## Traps
|
||
|
|
|
||
|
|
- Making `--dry-run` construct the LLM client "but not call it". Construction
|
||
|
|
reads credentials and can fail; the guarantee is no network, and the cheapest
|
||
|
|
way to keep it is to not build the client at all.
|
||
|
|
- Reporting p50 chunk size only. The max is the interesting number — it predicts
|
||
|
|
which requests will be rejected downstream.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
Background: [DESIGN.md](../DESIGN.md) — Verification, P1
|