Adapts docs/SCRUM.md framework (originally written for the matrix-agent-validated repo) to the Go rewrite. Five deliverables: golang-lakehouse-scrum-test.md top-line + scoring + verdict risk-register.md 12 findings, R-001..R-012 claim-coverage-table.md claim/test/risk for Sprint 2 sprint-backlog.md 5 sprints, ~2 weeks of work acceptance-gates.md DoD as runnable commands Every claim cites file:line, command output, or "missing evidence." Smoke chain ran clean (33s wall, all 9 PASS) and is captured in reports/scrum/_evidence/smoke_chain.log (gitignored — runtime artifact). Scoring: Reproducibility 7/10 9 smokes deterministic, no just/CI gate Test Coverage 6/10 internal/ packages tested, 6/7 cmd/ aren't Trust Boundary 7/10 escapes ok, zero auth, /sql is RCE-eq off-loopback Memory Correctness 3/10 pathway/playbook/observer not yet ported Deployment Readiness 4/10 no REPLICATION, no env template, no systemd Maintainability 8/10 no god-files, 7 lean binaries, ADRs current Top three risks: R-001 HIGH queryd /sql + DuckDB + non-loopback bind = RCE-equivalent R-002 HIGH internal/shared (server.go + config.go) zero tests R-003 HIGH internal/storeclient zero tests, used by 2 services R-004 MED 9-smoke chain green but not gated (no justfile/hook) The audit is the work; refactors come after. Sprint 0 owns coverage + CI gating; Sprint 1 owns trust-boundary decisions; Sprints 2-3 are mostly design-bar work for unbuilt agent components. .gitignore exception: /reports/* + !/reports/scrum/ keeps reports/ a runtime-artifact directory while exposing reports/scrum/ as tracked documentation. Mirrors the pattern future audit passes will land in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.8 KiB
golangLAKEHOUSE — Claim-Coverage Table
Per SCRUM.md §3, mapping each agent / memory claim from the upstream system to its current status in the Go rewrite. Many rows are "not yet ported" — those become Sprint 2 design bars rather than current-state failures. Risk IDs reference risk-register.md.
Format
| Claim | Code Location | Existing Test | Missing Test | Risk |
A claim with status "not yet ported" in Code Location means the upstream Rust system implements it but the Go rewrite has not. These rows define design bars for when the port lands.
Vector retrieval
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| HNSW search returns top-K by cosine similarity | internal/vectord/index.go (Add/Search/Lookup with RWMutex per memory b8c072c) |
internal/vectord/index_test.go (13 funcs, including recall search per g1_smoke.sh:7) |
Concurrent-search-during-add stress test (RWMutex contention behavior); cross-binary search via gateway latency budget | LOW (covered) |
| Index recall = 1.0 on round-trip with same vectors | cmd/vectord/main.go add+search handlers |
g1_smoke.sh line 7 (recall-search assertion); g2_smoke.sh end-to-end at distance 5.96e-8 |
None — covered by 2 smokes | LOW (covered) |
| Cross-corpora retrieval (multi-index search in one query) | not yet ported — Rust vectord had federated-corpus search, Go vectord is per-index only |
— | All — design bar | DESIGN-BAR (Sprint 2) |
| Dimension mismatch on add → 400 | internal/vectord/index.go (Validates per memory) |
g1_smoke.sh:7 (dim-mismatch-400 assertion) |
Unit test with explicit dimension assertion | MED (smoke covers, no go-test) |
| Zero-norm vector under cosine → reject | internal/vectord/index.go (Validates per memory b8c072c) |
internal/vectord/index_test.go (13 funcs — likely covers; not verified by reading every test) |
Audit which of the 13 funcs covers this; if none, add | LOW |
Vector persistence (G1P)
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Save → kill → restart → search returns dist=0 | internal/vectord/persistor.go + cmd/vectord/main.go boot path |
g1p_smoke.sh (kill+restart preserves state, 8/8 PASS per memory 8b92518); internal/vectord/persistor_test.go (5 funcs) |
None — covered | LOW (covered) |
| Single-Put framed format prevents torn-write half-state | internal/vectord/persistor.go LHV1 single-Put per memory (3-way convergent scrum fix) |
persistor_test.go likely covers |
Failure-injection test: PUT-fails-mid-stream → Load returns "no state" rather than half-loaded state | MED |
| Persistence above 256 MiB single-key (≈150K vectors @ d=768) | NOT IMPLEMENTED — storaged's MaxBytesReader 256 MiB caps single-file LHV1 (cited in head commit 1f700e7 and memory) |
— | Test asserting persistence works at 200K+ vectors | DESIGN-BAR (Sprint 2 / G3) |
| Save failure logged-not-fatal (in-memory still source of truth) | cmd/vectord/main.go boot per memory 8b92518 |
not verified by reading test | Unit test injecting storaged-down → Save returns nil error, log line emitted | MED |
Embedding (G2)
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Text → 768-d vector via Ollama nomic-embed-text | internal/embed/ollama.go + cmd/embedd/main.go:59 |
internal/embed/ollama_test.go (6 funcs); g2_smoke.sh end-to-end |
None — covered | LOW (covered) |
| Provider interface allows swap (OpenAI/Voyage/etc.) | internal/embed/embed.go:20 (Embed interface) per memory 9ee7fc5 |
Interface-only — provider selection in cmd/embedd/main.go not unit-tested |
Test that wiring swaps providers based on config | LOW |
| Bad model → 502 from upstream | cmd/embedd/main.go error mapping |
g2_smoke.sh:103-106 (bad-model → 502 assertion) |
Unit test on the error-mapping branch | LOW (smoke covers) |
| Float64 → float32 narrowing at boundary | internal/embed/ollama.go per memory 9ee7fc5 |
ollama_test.go likely covers |
Verify test with adversarial near-overflow inputs | LOW |
SQL truth path
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Query catalog list → CREATE OR REPLACE VIEW per manifest | internal/queryd/registrar.go:139 |
internal/queryd/registrar_test.go (7 funcs incl. drop-before-create order, idempotency) |
None — covered | LOW |
| Updated_at as implicit etag prevents repeated CREATE | internal/queryd/registrar.go:114 (prior.Equal(m.UpdatedAt)) |
registrar_test.go covers Skipped count |
None — covered | LOW |
| Schema-drift CSV → 409, view unchanged | cmd/ingestd/main.go + cmd/queryd/main.go |
d4_smoke.sh (schema-drift 409); d5_smoke.sh (view unchanged through drift) |
None — covered | LOW |
| Arbitrary SQL via /sql is safe (it isn't — by design) | cmd/queryd/main.go:142 |
none | Auth boundary test (R-001) | HIGH (R-001) |
Mem0-style memory semantics (ADD / UPDATE / REVISE / RETIRE / HISTORY)
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| ADD a new pathway trace | not yet ported — Rust has pathway_memory crate, Go does not |
— | All | DESIGN-BAR (Sprint 2) |
| UPDATE replaces existing trace by uid | not yet ported | — | All | DESIGN-BAR |
| REVISE creates a new revision linked via history chain | not yet ported | — | All | DESIGN-BAR |
| RETIRE marks a trace excluded from retrieval | not yet ported | — | All — including retrieval-must-not-return-retired test | DESIGN-BAR |
| HISTORY chain is cycle-safe | not yet ported | — | All — explicit cycle injection + detection test | DESIGN-BAR |
| Replay count increments on duplicate ADD | not yet ported | — | All | DESIGN-BAR |
| Corrupted memory row recovery | not yet ported | — | All — fixture with poison row | DESIGN-BAR |
Sprint 2 design bar: when pathway memory ports to Go, the test fixture must include all 7 rows above on day one. This is the lesson from the Rust system having shipped these features ahead of their tests.
Observer / hand-review
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Observer gates candidates before they reach playbook seal | not yet ported — Rust mcp-server/observer.ts exists, Go does not |
— | All | DESIGN-BAR (Sprint 3) |
| Observer review failure does NOT auto-accept | not yet ported — but R-007 verdict pre-decided: Go observer must default degraded=true, verdict=cycle on internal error. ADR-002 design bar. |
— | Test injecting observer-side error → response has degraded: true, never verdict: "accept" |
DESIGN-BAR (Sprint 3) |
Health endpoint content-type matches consumer expectation (the Rust r.json() on text/plain crash-loop bug from memory) |
internal/shared/server.go:61 returns plain string "<service> ok" per the existing pattern |
none — but the bug it would catch already exists in the Rust system's history (memory 54689d5) |
Regression test: consumer of /health accepts text/plain or 502s loudly, never silently nulls |
MED (Sprint 3) |
Playbook seal + retrieval
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Successful playbooks are sealed for later retrieval | not yet ported | — | All | DESIGN-BAR (Sprint 3) |
| Second-run retrieval surfaces prior playbook | not yet ported | — | All | DESIGN-BAR (Sprint 3) |
| Negative case: observer rejects hallucinated claim | not yet ported | — | All | DESIGN-BAR (Sprint 3) |
| Agent claims verifiable against SQL truth | partial — cmd/queryd/main.go is the SQL truth surface; no agent layer above it yet |
none for the agent layer | All | DESIGN-BAR (Sprint 3) |
Cloud-only adaptation
| Claim | Code Location | Existing Test | Missing Test | Risk |
|---|---|---|---|---|
| Embed works without local Ollama (cloud Provider) | internal/embed/embed.go:20 interface allows it; no cloud Provider implemented yet |
none | All | DESIGN-BAR (Sprint 4 — once cloud Provider lands) |
| Persistence works without local MinIO (real S3 / R2) | internal/storaged/bucket.go uses aws-sdk-go-v2 — should work against real S3 with no code changes |
not exercised in smokes | Smoke variant pointing at AWS S3 in addition to MinIO | LOW |
Summary counts
- Claims covered by existing tests + smokes: 14
- Claims partially covered (smoke only, no go-test): 5
- Claims uncovered but component built: 2 (concurrent-search stress, large LHV1 persistence)
- Claims marked "not yet ported" (design bars): 14
- Claims with HIGH-risk gaps in current code: 1 (R-001, the queryd /sql boundary)
The 14 design-bar rows are the primary Sprint 2-3 backlog. The 5 partially-covered + 2 uncovered rows are Sprint 0 follow-ups. The 1 HIGH-risk gap is Sprint 1's anchor.