Files
poimen-memory/tasks/M3.5.8-m3.5-gate.md
Story Crater Bot 631cbfa3e9 feat: complete M0.1-M0.4 phases
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
2026-08-22 23:13:42 -07:00

5.7 KiB
Raw Permalink Blame History

M3.5.8 — M3.5 composition gate — API end-to-end

Field Value
Phase M3.5 — Distributed API Layer
Size M — 13 days
Status Not started
Flags gate
Spec inlined below
Blocks M4, M5 (can start in parallel after this gate)
Depends M3.5.1, M3.5.2, M3.5.3, M3.5.4, M3.5.5, M3.5.6, M3.5.7

Goal

Verify that the API layer is a working facade. Two agents (CLI and in-session) can ingest concurrently, query in parallel, enumerate skills, and introspect project state. No blocking, no race conditions, idempotency holds.

Acceptance Criteria

All M3.5.x tasks complete, and the integration below passes.

Must work:

  1. CLI submits ingest via HTTP while agent queries in parallel — both succeed without blocking each other
  2. Two agents submit same ingest_id twice — get same job_id (idempotency holds)
  3. Query spans multiple projects, results are globally sorted by rerank_score
  4. Skills list excludes drafts; admin apikey sees drafts
  5. Project status endpoint reports correct memory metrics
  6. Rate limiting enforces per-endpoint, per-apikey limits
  7. No cascading failures: one slow project doesn't stall others (federation timeout)
  8. Logs are clean (no panics, no unhandled errors)

Verify

Harness: End-to-end test harness that simulates mixed workload.

Integration testtests/it_e2e_api.rs:

  1. a1_cli_ingest_and_agent_query_concurrent
    • Spawn HTTP server with test pgvector DB
    • CLI submits ingest batch (POST /ingest)
    • Agent submits query (GET /query) in parallel
    • Both complete within 30s, both return 200/202
  2. a2_ingest_idempotency_holds
    • CLI submits (ingest_id_a) → job_id_1
    • Agent submits same (ingest_id_a) → job_id_1 (identical)
    • Different (ingest_id_b) → job_id_2 (different)
  3. a3_multi_project_federation_sorts_globally
    • Ingest sample data into two projects (poimen, agent-rust)
    • Query "root cause" (no project specified)
    • Results include nodes from both projects
    • Sorted by rerank_score globally (not per-project)
  4. a4_skills_list_excludes_drafts_by_default
    • GET /memory/skills → returns promoted skills only
    • GET /memory/skills?loadable=false with admin key → includes drafts
  5. a5_project_status_metrics_accurate
    • Ingest 50 chunks
    • GET /memory/projects/poimen/status
    • Asserts: total_chunks ≈ 50, last_ingest_at is recent, standing_queries count > 0
  6. a6_rate_limit_enforced
    • Set rate limit to 5 req/hour for testing
    • Send 6 GET /query requests
    • First 5 succeed, 6th returns 429
  7. a7_federation_timeout_partial_results
    • Mock slow project (10s response time)
    • Query with timeout_seconds=2
    • Results from fast project, warning about slow project
  8. a8_no_cascading_failures
    • Inject error in embeddings service (simulate 500)
    • GET /query returns 503, not cascading to other endpoints
    • Other endpoints (ingest, skills) still work
  9. a9_logs_clean_no_panics
    • Capture stderr during test
    • Grep for "panic", "unwrap", "expect" — should not appear
    • All errors should be explicit Result types, not crashes
  10. a10_health_check_always_responds
  • Server is under heavy load (rate limit tests, concurrent ingest)
  • GET /health still returns 200 within 100ms

Command: cargo test -p mem-cli e2e_api -- --nocapture

Manual verification (smoke test):

# Start server
cargo run -p mem-cli -- serve --port 8080 &
sleep 2

# Ingest via HTTP
curl -X POST -H "apikey: test" http://localhost:8080/memory/ingest \
  -d '{
    "project": "poimen",
    "source": "manual:smoke",
    "records": [...],
    "ingest_id": "abc123"
  }'
# → expect 202, job_id

# Query
curl -H "apikey: test" "http://localhost:8080/memory/query?query=test"
# → expect 200, results array

# Skills
curl -H "apikey: test" http://localhost:8080/memory/skills
# → expect 200, skills array

# Project status
curl -H "apikey: test" http://localhost:8080/memory/projects/poimen/status
# → expect 200, metadata

# Rate limit test
for i in {1..11}; do
  curl -H "apikey: test" "http://localhost:8080/memory/query?query=test" \
    -w "HTTP %{http_code}\n"
done
# → expect first 10 to succeed, 11th to be 429

False Pass

  • Testing only happy path (all services available, no errors). Must include:
    • Embedding service down → 503
    • Slow project in federation → partial results + warning
    • Rate limit near boundary (9/10, 10/10, 11/10 reqs)
  • CLI and agent workloads not truly concurrent (sequential test masquerades as parallel). Use tokio::join_all or spy on timing to verify parallel execution.
  • Idempotency tested once; never tested with expiry or multiple projects.
  • Metrics never cross-checked against actual DB state. total_chunks reported but not verified against SELECT COUNT.
  • No error injection. If the API is untested with failures, cascading failures are invisible until production.

Traps

  • Server startup latency: tests must wait for port to be available (sleep or retry logic).
  • Test isolation: if tests share a DB, idempotency cache pollution breaks test N+1. Use separate test DB per test or reset cache between runs.
  • Timing: federation timeout at 2s is tight; if the machine is slow, test becomes flaky. Mock time instead of real delays.
  • Concurrent writes to JSONL log: if two ingest tasks write simultaneously, atomicity of the log is at risk. Ensure the log is single-writer or uses locking.

Gate outcome: All M3.5.x tasks green AND a1a10 pass → M3.5 gate is green. CLI and agents can work with the API concurrently without blocking, race conditions, or idempotency issues.

Background: DESIGN.md § Distributed API Layer