Skip to main content
Phase: Phase 3 — Hybrid recall + Learning + Admin · Status: closed · Filed 2026-04-16

What Worked

  • RRF for hybrid recall — ranks-only fusion, zero normalization tuning needed
  • Generated tsvector column — Postgres recomputes on content change, zero app-layer sync
  • Idempotent candidate sync — checks existing (retro_id, lesson_index) before insert
  • Promote/reject in DB instead of docs — enforced in code, audit trail permanent
  • Dedicated audit session for last_used_at — decoupled from request semantics (ADR-020)
  • Smoke-test-as-you-go continued — caught candidate backfill gap immediately
  • Dogfooding the new endpoints — product is used to build itself

What Didn’t

  • global_fact_candidates was a Phase 0 stub that sat empty for three phases — stubs decay
  • PowerShell quoting tripped up in bash-spawned pipeline — use single quotes or here-doc
  • Forgot to commit Phase 2 retro to DB first time — PID-PGR01 wasn’t registered as project
  • First learning_service Write call failed because file existed as Phase 0 stub — always Read first
  • regex parameter on FastAPI Query deprecated in favor of pattern — trivial, deferred
  • MEMORY.md global feedback memory wasn’t checked at session start

Lessons

  • [project] L8 — Generated columns over application-maintained denorm. Prefer Postgres GENERATED ALWAYS AS … STORED
  • [project] L9 — Idempotency via composite key check before insert is the Prism idiom
  • [project] L10 — Audit-style writes own their own sessions. Don’t piggyback on the request session
  • [project] L11 — Stubs decay. If a model is in the registry, it should be a real table
  • [global] G5 — RRF (RRF_K=60) is the default for hybrid retrieval in agent-memory systems
  • [global] G6 — Cross-platform script parity from day one. Every .ps1 ships with a .sh
Last modified on April 20, 2026