# M1 — Gated Loop at L1 · Phase Overview ## What M1 produces ``` crates/mem-llm/src/chat.rs ChatClient → POST /v1/qwen/chat/completions crates/mem-core/src/query.rs QuerySet::load() → queries/poimen.yaml crates/mem-core/src/prompt.rs PromptBuilder → paper Fig 10a template crates/mem-core/src/gate_parser.rs parse_gate_response() → GateResponse crates/mem-core/src/gated_loop.rs run_loop() → LoopEvent stream → RunOutcome crates/mem-store/src/event_log.rs LogWriter → log///.jsonl crates/mem-cli/src/main.rs mem ingest --project P --query Q (extend existing stub) tests/it_chat_client.rs 6 assertions (1 ignored, live smoke) tests/it_query_loader.rs 7 assertions tests/it_prompt.rs 7 assertions tests/it_gate_parser.rs 9 assertions tests/it_gated_loop.rs 10 assertions (scripted LLM, no network) tests/it_event_log.rs 8 assertions tests/it_ingest.rs 7 assertions (1 ignored, live smoke) tests/it_m1_gate.rs 7 assertions (all ignored, live gateway) ``` ## Existing code this phase builds on | Crate | Module | Lines | What M1 uses from it | |---|---|---|---| | `mem-core` | `domain.rs` | 402 | `Chunk`, `Level`, `Sha256Hash`, `ProjectId`, `QueryId`, `RunId`, `Role`, `Record`, `MemoryNode` | | `mem-core` | `lesson.rs` | 871 | **Not used by M1 directly.** Already has signature extraction, normalisation, tier lookup. M3.7 extends it. | | `mem-chunk` | `chunker.rs` | 186 | `chunks()` — stream of `Chunk` from `RecordSource` | | `mem-chunk` | `token_counter.rs` | 123 | `TokenCounter` trait, `CharsOverFourCounter`, `QwenTokenCounter` | | `mem-chunk` | `record_source.rs` | 50 | `RecordSource` trait, `VecSource` | | `mem-ingest` | `pi_session.rs` | 251 | `PiSessionSource` — parse pi session JSONL | | `mem-ingest` | `claude_transcript.rs` | 178 | `ClaudeTranscriptSource` — parse claude transcript JSONL | | `mem-cli` | `main.rs` | 184 | `Commands::Ingest` stub — replace body, keep CLI struct | | `mem-llm` | `lib.rs` | 1 | **Empty placeholder** — replace entirely | | `mem-store` | `lib.rs` | 1 | **Empty placeholder** — replace entirely | ## Task order and blocking ``` M1.1 (chat client) — no deps, start immediately M1.2 (query loader) — no deps, start immediately (parallel with M1.1) ↓ M1.3 (prompt template) — needs M1.2 for Query type ↓ M1.4 (gate parser) — needs M1.3 for expected output format ↓ M1.5 (gated loop) — needs M1.1 + M1.3 + M1.4 ↓ M1.6 (event log) — needs M1.5 for LoopEvent types ↓ M1.7 (end-to-end) — needs all above ↓ M1.8 (gate) — needs M1.7, runs against live gateway ``` **Parallel starts:** M1.1 and M1.2 can start immediately and in parallel. ## Key numbers | Metric | Target | Source | |---|---|---| | Update-rate | < 30% | M1.8 gate, paper §4.2 | | Memory budget | ≤ 1024 tokens | M1.5 config, paper default | | Parse-failure rate | < 5% | M1.8 gate | | Prompt budget | < 32768 - 2048 = 30720 tokens | Gateway OLLAMA_CONTEXT_LENGTH | ## Test convention All integration tests live in workspace root `tests/` directory (matching `it_chunking.rs`, `it_pi_source.rs`, etc. from M0). Test command is always: ```bash cargo test --test ``` Not `cargo test -p ` — that only finds tests inside the crate's own `tests/` directory, which this project doesn't use.