M0.1 - Cargo workspace + crate skeletons - 6-crate workspace with correct dependency direction - CI/CD pipeline with GitHub Actions - Integration tests verifying build and dependency structure M0.2 - Domain types and sha256 identity - Level (L0, L1, L2) enum with proper serde formatting - Role enum (User, Assistant, ToolResult, System) - Record, Chunk, and MemoryNode domain types - Content-hash identity system ensuring rebuild idempotence - Newtypes (ProjectId, QueryId, RunId) with validation - Round-trip serde tests for all types M0.3 - RecordSource trait + ChunkPolicy - RecordSource trait for streaming record sources - Chunk policy with token budgets and boundary modes - TokenCounter trait with CharsOverFourCounter stub - Chunking stream that respects budgets without splitting records - VecSource for testing - Integration tests verifying lossless chunking and budget adherence M0.4 - Tokenizer-backed chunk sizing - Vendored Qwen2 tokenizer with hash verification - QwenTokenCounter implementing proper token counting - Hash guard that fails on modified tokenizer - mem tokens CLI subcommand for token counting - Integration tests with known string counts, hash guards, and budget verification Total: 19 integration tests passing, all phases verified to compose correctly Workspace builds cleanly with no clippy warnings
193 lines
10 KiB
Markdown
193 lines
10 KiB
Markdown
# poimen-memory — task board
|
|
|
|
43 tasks — 36 build tasks plus **7 composition gates**, one per phase. One file
|
|
per task, **self-contained**: inlined design facts, executable steps, acceptance
|
|
criteria, a `Verify` section written for someone who did not build the thing, and
|
|
the traps worth naming. Reading `DESIGN.md` is not required to do a task — it is
|
|
linked as background only.
|
|
|
|
Each `Verify` section names the harness, the integration test with numbered
|
|
assertions, the command to run, and the **false pass** — the shape of test that
|
|
goes green while the feature is broken. Treat the false-pass list as part of the
|
|
acceptance criteria, not commentary.
|
|
|
|
## Ordering — declared, never derived
|
|
|
|
**Phase order is the list below. Task ids are opaque and frozen.**
|
|
|
|
`M0.3` is `M0.3` forever, in whatever phase it currently sits, because its
|
|
artifacts and cross-references key on that id. New tasks take new ids rather than
|
|
renumbering neighbours. This is the `StepId` rule applied to the board itself —
|
|
a board that renumbers to reorder has the bug it warns its own users about.
|
|
|
|
No phase starts until its predecessor's gate is green. The `gate` task at the end
|
|
of each phase **is** that gate: it proves the phase's parts compose and that its
|
|
swappable parts are genuinely swappable. Every build task is verified alone; the
|
|
gate verifies the properties no single task owns.
|
|
|
|
## Two rules this board exists to protect
|
|
|
|
**1. The JSONL log is authoritative; the vault and the vector index are
|
|
projections.** Anything that cannot be dropped and rebuilt byte-identically from
|
|
the log has hidden inputs, and that is a bug. `M2.8` is the gate that enforces it.
|
|
|
|
**2. The update gate must discriminate, not summarize.** Agent transcripts are
|
|
~43% tool results and mostly evidence-free. A gate that accepts most chunks is an
|
|
expensive summarizer that will reproduce the memory-explosion failure the whole
|
|
design exists to avoid. `M1.8` is the gate that enforces it, and **update-rate is
|
|
the single number to watch.**
|
|
|
|
## Verification practice — script first, source second
|
|
|
|
A task is verified by running its command and reading the output, then opening
|
|
the source. Reviewing the diff first is how an assertion that was quietly dropped
|
|
still gets called done: the code looks right, and nothing proves the test ran.
|
|
|
|
Numbered assertion N in a `Verify` section is test fn `aN_<slug>`. The numbering
|
|
is the contract — a test fn that does not exist should report missing rather than
|
|
be silently absent from a green summary.
|
|
|
|
`cargo test` reporting `ok` with zero tests run is not a pass.
|
|
|
|
## Progress
|
|
|
|
**Source of truth is the `Status` field in each task file.** The tables below
|
|
mirror it; a status changed here and not there is a lie.
|
|
|
|
Legend: ⬜ not started · 🟡 in progress · ✅ done · ⛔ blocked
|
|
|
|
| # | Phase | Ids | Tasks | ✅ | 🟡 | ⬜ | Gate |
|
|
|---|---|---|---|---|---|---|---|
|
|
| 1 | Read-only spine | M0.x | 8 | 0 | 0 | 8 | ⬜ M0.8 |
|
|
| 2 | Gated loop at L1 | M1.x | 8 | 0 | 0 | 8 | ⬜ M1.8 |
|
|
| 3 | Projections | M2.x | 8 | 0 | 0 | 8 | ⬜ M2.8 |
|
|
| 4 | L2 synthesis + retrieval | M3.x | 4 | 0 | 0 | 4 | ⬜ M3.4 |
|
|
| 4.5 | Distributed API Layer | M3.5.x | 8 | 0 | 0 | 8 | ⬜ M3.5.8 |
|
|
| 5 | Skills | M4.x | 3 | 0 | 0 | 3 | ⬜ M4.3 |
|
|
| 6 | Post-training | M5.x | 6 | 0 | 0 | 6 | ⬜ M5.6 |
|
|
| 7 | agent-manager migration | M6.x | 6 | 0 | 0 | 6 | ⬜ M6.6 |
|
|
| | **Total** | | **51** | **0** | **0** | **51** | 0/8 green |
|
|
|
|
**Where the line is — 2026-08-20.** Nothing started. No crate exists yet: there
|
|
is no `Cargo.toml` under `memory/`, so every task below is design only. M0.1 is
|
|
the first thing that has to happen. `M2.2` (the CNPG manifest), `M5.4` (vLLM
|
|
with LoRA), `M3.5.x` (API layer), and all of `M6.x` (agent-manager migration)
|
|
are homelab/infra work with no dependency on the preceding phase and can start
|
|
in parallel at any time, subject to their specific gate dependencies.
|
|
|
|
**M6 is a different repo, not a dependency of M0-M5.** It migrates
|
|
`github.com/Riotpiaole/agent-manager`'s session store (a separate Go CLI tool,
|
|
unrelated to this project's own memory system) from local sqlite to its own
|
|
dedicated CNPG cluster. It rides in this board because it's homelab work
|
|
happening alongside M2.2/M5.4, and because the two projects' Postgres schemas
|
|
landing in the same cluster around the same time need to look like siblings,
|
|
not strangers — see M6.6's convention-consistency check.
|
|
|
|
## 1 — Read-only spine · M0.x
|
|
|
|
No model calls anywhere in this phase. The point is to prove the corpus parses
|
|
and chunks sanely before spending inference on it.
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M0.1](M0.1-cargo-workspace.md) | Cargo workspace + crate skeletons | S | — | ⬜ |
|
|
| [M0.2](M0.2-domain-types.md) | Domain types and sha256 identity | S | — | ⬜ |
|
|
| [M0.3](M0.3-recordsource-and-chunkpolicy.md) | `RecordSource` trait + `ChunkPolicy` | M | — | ⬜ |
|
|
| [M0.4](M0.4-tokenizer-sizing.md) | Tokenizer-backed chunk sizing | M | — | ⬜ |
|
|
| [M0.5](M0.5-pi-session-adapter.md) | pi session adapter | M | — | ⬜ |
|
|
| [M0.6](M0.6-claude-transcript-adapter.md) | Claude transcript adapter | S | — | ⬜ |
|
|
| [M0.7](M0.7-ingest-dry-run.md) | `mem ingest --dry-run` | S | — | ⬜ |
|
|
| [M0.8](M0.8-m0-gate.md) | **M0 composition gate** | M | gate | ⬜ |
|
|
|
|
## 2 — Gated loop at L1 · M1.x
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M1.1](M1.1-llm-chat-client.md) | `mem-llm` chat client | M | — | ⬜ |
|
|
| [M1.2](M1.2-standing-query-loader.md) | Standing-query YAML loader | M | — | ⬜ |
|
|
| [M1.3](M1.3-prompt-template.md) | GRU-Mem prompt template | M | — | ⬜ |
|
|
| [M1.4](M1.4-gate-response-parser.md) | Gate-response parser | M | — | ⬜ |
|
|
| [M1.5](M1.5-gated-loop.md) | The gated loop | L | — | ⬜ |
|
|
| [M1.6](M1.6-jsonl-event-log.md) | JSONL event log writer | M | — | ⬜ |
|
|
| [M1.7](M1.7-ingest-end-to-end.md) | `mem ingest` end to end | M | — | ⬜ |
|
|
| [M1.8](M1.8-m1-gate.md) | **M1 composition gate** | M | gate | ⬜ |
|
|
|
|
## 3 — Projections · M2.x
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M2.1](M2.1-embeddings-client.md) | Embeddings client | S | — | ⬜ |
|
|
| [M2.2](M2.2-memory-db-manifest.md) | CNPG `memory-db` + pgvector | M | homelab | ⬜ |
|
|
| [M2.3](M2.3-schema-and-migrations.md) | Schema + sqlx migrations | M | — | ⬜ |
|
|
| [M2.4](M2.4-pgvector-repo.md) | pgvector repository | M | — | ⬜ |
|
|
| [M2.5](M2.5-obsidian-projector.md) | Obsidian projector | M | — | ⬜ |
|
|
| [M2.6](M2.6-rebuild-from-log.md) | `mem rebuild --from-log` | M | — | ⬜ |
|
|
| [M2.7](M2.7-verify-edges.md) | `mem verify` — edge closure | S | — | ⬜ |
|
|
| [M2.8](M2.8-m2-gate.md) | **M2 composition gate** | M | gate | ⬜ |
|
|
|
|
## 4 — L2 synthesis and retrieval · M3.x
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M3.1](M3.1-l2-synthesis.md) | L2 synthesis pass | M | — | ⬜ |
|
|
| [M3.2](M3.2-rerank-client.md) | Rerank client | S | — | ⬜ |
|
|
| [M3.3](M3.3-mem-query.md) | `mem query` with provenance | M | — | ⬜ |
|
|
| [M3.4](M3.4-m3-gate.md) | **M3 composition gate** | M | gate | ⬜ |
|
|
|
|
## 4.5 — Distributed API Layer · M3.5.x
|
|
|
|
Homelab frontend integration: HTTP facade via `api.riotpiao.com`. Runs in parallel with M4 and M5 after M3.4 green.
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M3.5.1](M3.5.1-http-server.md) | HTTP server + router, Kong auth, metrics | M | — | ⬜ |
|
|
| [M3.5.2](M3.5.2-ingest-endpoint.md) | POST /ingest async queue, idempotency | M | — | ⬜ |
|
|
| [M3.5.3](M3.5.3-query-endpoint.md) | GET /query HNSW + rerank + edge-walk | M | — | ⬜ |
|
|
| [M3.5.4](M3.5.4-query-federation.md) | Query federation across projects | M | — | ⬜ |
|
|
| [M3.5.5](M3.5.5-skills-endpoint.md) | GET /skills and /skills/{name} | M | — | ⬜ |
|
|
| [M3.5.6](M3.5.6-projects-endpoint.md) | GET /projects and /projects/{id}/status | S | — | ⬜ |
|
|
| [M3.5.7](M3.5.7-rate-limiting.md) | Rate limiting + idempotency by sha256 | M | — | ⬜ |
|
|
| [M3.5.8](M3.5.8-m3.5-gate.md) | **M3.5 composition gate** | M | gate | ⬜ |
|
|
|
|
## 5 — Skills · M4.x
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M4.1](M4.1-skill-draft.md) | `mem skill draft` | M | — | ⬜ |
|
|
| [M4.2](M4.2-derived-filter.md) | `derived: true` ingest filter | M | — | ⬜ |
|
|
| [M4.3](M4.3-m4-gate.md) | **M4 composition gate** | M | gate | ⬜ |
|
|
|
|
## 6 — Post-training · M5.x
|
|
|
|
Python, separate from the Rust workspace. The boundary is the JSONL log.
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M5.1](M5.1-evidence-labeler.md) | `mem label` — evidence labeler | M | — | ⬜ |
|
|
| [M5.2](M5.2-labeler-calibration.md) | Labeler calibration | M | — | ⬜ |
|
|
| [M5.3](M5.3-training-corpus-export.md) | Training corpus export | M | — | ⬜ |
|
|
| [M5.4](M5.4-vllm-lora-serving.md) | vLLM + `--enable-lora` | L | homelab | ⬜ |
|
|
| [M5.5](M5.5-verl-training-loop.md) | verl training loop | L | — | ⬜ |
|
|
| [M5.6](M5.6-m5-gate.md) | **M5 composition gate** | L | gate | ⬜ |
|
|
|
|
## 7 — agent-manager migration · M6.x
|
|
|
|
Separate repo (`github.com/Riotpiaole/agent-manager`, fork branch
|
|
`add-headless-spawn`), separate cluster resource, no Rust/GRU-Mem
|
|
dependency. Moves its session store off local sqlite onto a dedicated CNPG
|
|
Postgres, reachable from the Mac client through a dedicated nginx route —
|
|
durability-of-location, not a multi-host requirement.
|
|
|
|
| Task | Title | Size | Flags | Status |
|
|
|---|---|---|---|---|
|
|
| [M6.1](M6.1-agent-manager-db-manifest.md) | CNPG `agent-manager-db` manifest | M | homelab | ⬜ |
|
|
| [M6.2](M6.2-schema-port.md) | Postgres schema for agent-manager sessions | M | — | ⬜ |
|
|
| [M6.3](M6.3-store-query-port.md) | store.go query port to Postgres | L | — | ⬜ |
|
|
| [M6.4](M6.4-nginx-stream-routing.md) | nginx TCP routing to `agent-manager-db` | S | homelab | ⬜ |
|
|
| [M6.5](M6.5-credentials-secret.md) | Postgres credentials for the Mac client | S | homelab | ⬜ |
|
|
| [M6.6](M6.6-m6-gate.md) | **M6 composition gate** | M | gate | ⬜ |
|
|
|
|
---
|
|
|
|
Background: [DESIGN.md](../DESIGN.md) · GRU-Mem, arXiv 2602.10560 · `internal/store/store.go` (agent-manager, `add-headless-spawn` branch)
|