Files
self-directed-learning/state/PHASE_3_REPORT.md
T
Krystie dc5dc94d79 Initial commit: Adaptive Recall sidecar for UMP (Phase 5)
Multi-channel retrieval sidecar over Universal Memory Protocol:
- 3-channel RRF (UMP FTS5 + Qdrant vector + knowledge graph)
- ACT-R re-ranking (Anderson 1983) with access tracking
- Co-occurrence graph edges (Phase 6) for dense traversal
- Memory lifecycle decay (Phase 4) with per-kind confidence
- MCP shim routes recall through sidecar, falls back to canonical UMP

Architecture:
- src/server.js      HTTP sidecar on port 4380
- src/graph.js       2592-node / 111-edge graph from UMP (or +cooccur: 13k+)
- src/actr.js        A_i = -d*ln(age) + beta*log1p(freq) + epsilon*conf
- src/access_log.js  per-URN counter + last_accessed_at
- src/ump-recall-mcp.js  MCP shim (recall via sidecar, others passthrough)

Eval results (851-record UMP corpus):
- 2ch RRF over baseline: +50pp recall@10
- 3ch RRF (+graph): +60pp, 12 unique wins
- ACT-R re-rank: 4/20 #1 changes, 84% top-5 retention

Tests: 76/76 passing across graph (27), actr (27), access_log (28),
decay (20), mcp-shim (sidecar + fallback). Run with: npm test

Inspired by AIAppsAPI/adaptive-recall but built from scratch against
existing DNS2 infrastructure (UMP at :4317, Qdrant at :6333,
Ollama at :11434). No paid SaaS, MIT-licensed.
2026-07-12 19:24:47 -07:00

4.7 KiB
Raw Blame History

Adaptive Recall — Full Build Final Report

Build date: 2026-07-12 Sidecar: http://127.0.0.1:4380 — Phase 3 (3-channel RRF + ACT-R re-rank)


What was built

Phase 1 — Foundation (already shipped)

  • src/server.js, src/qdrant.js, src/entities.js, src/rrf.js, src/embed.js
  • 768/846 records in Qdrant memories_ump collection (90.6% backfill)
  • 2-channel RRF (UMP FTS5 + Qdrant cosine) with +50pp hit-rate lift over baseline

Phase 1G — MCP wire-up (already shipped)

  • src/ump-recall-mcp.js — shim that routes recall to sidecar, falls back to canonical UMP
  • Both Hermes and Krystie configs point at the shim

Phase 2 — Knowledge Graph Channel (shipped earlier this session)

  • src/graph.js (414 lines): Graph class with BFS neighbors, search entities, persistence
  • scripts/build_graph.js: 2592 nodes / 111 edges / 719 URNs in 553ms
  • state/graph.json: persisted graph artifact
  • runGraphChannel(): extracts query entities, BFS up to 2 hops, score=1/hops
  • Wired into /recall as 3rd channel in RRF

Eval: 12 unique-to-3ch hits across 20 queries; zero regressions; +176ms latency

Phase 3 — ACT-R Re-ranker (this session)

  • src/actr.js: pure activation() (Anderson 1983 formula) + minMaxNormalize() + rerank()
    • Formula: A_i = -d·ln(age) + β·log1p(freq) + ε·conf
    • Defaults: d=0.5, β=1.0, ε=1.0, α=0.3 (blend with RRF)
  • lookupMeta(): fetches UMP time+confidence, sums graph node frequencies
  • Wired into /recall between RRF fusion and hydration
  • Per-call cache for metadata (fresh per request)

Eval: 4/20 queries had #1 changed (20%); 84% top-5 set retention; avg latency 1482ms

Phase 4 — Memory Lifecycle Decay (shipped earlier this session)

  • scripts/ump_decay.py: pure apply_decay() with 6 per-kind rates
    • identity λ=0.0001, semantic 0.001, note 0.003, procedural 0.005, episodic 0.01, working 0.05
    • Floor 0.05, never deletes
    • Atomic writes with timestamped backups
  • 20/20 tests pass
  • Cron eaff2d9683fc runs nightly at 3am

Self-improvement framework (shipped earlier today)

  • 5 cron scripts: skill_gap_detector, spaced_repetition, forage, reflective_journal, self_measure
  • All wired and scheduled

Test summary

Suite Tests Status
test_graph.js 27 PASS
test_actr.js 27 PASS (new)
test_ump_decay.py 20 PASS
test-mcp-shim.js 2 scenarios PASS (sidecar + fallback)
Total 76 76/76 pass

Eval summary

Channel combination Hit-rate lift Latency
Baseline UMP 0% (reference) 146ms
2-channel RRF (ump+vector) +50pp recall@10 780ms
3-channel RRF (+graph) +60pp, 12 unique wins 903ms
3-channel + ACT-R re-rank 4/20 #1 changes, 84% top-5 retention 1482ms

Files created/modified this session

Created:

  • src/graph.js (414 lines)
  • src/actr.js (130 lines)
  • scripts/build_graph.js (82 lines)
  • scripts/ump_decay.py (~600 lines)
  • scripts/eval_3ch_vs_2ch.py
  • scripts/eval_channel_contribution.py
  • scripts/eval_actr.py
  • test/test_graph.js
  • test/test_actr.js
  • test/test_ump_decay.py
  • test/smoke_recall.py
  • test/smoke_phase3.py
  • state/SCHEMA.md
  • state/graph.json (589KB, 2592 nodes)
  • state/PHASE_2_AND_4_REPORT.md
  • state/PHASE_3_REPORT.md (this file)

Modified:

  • src/server.js (398 → 482 lines): graph channel + ACT-R + health/recall upgrades
  • /root/.hermes/config.yaml (patched via terminal): ump block points at MCP shim
  • /root/.hermes/profiles/krystie/config.yaml (already patched): same

Live endpoints

GET  /health   — phase, upstreams, graph stats, ACT-R config
POST /recall   — 3-channel RRF + ACT-R re-rank
POST /embed    — Ollama → Qdrant upsert (existing, unchanged)

Config via env:

  • PORT (default 4380)
  • GRAPH_ENABLED, GRAPH_FILE, GRAPH_DEPTH (default 2)
  • ACTR_ENABLED, ACTR_ALPHA (default 0.3), ACTR_D (default 0.5)
  • CHANNEL_TOP_N (default 20), RERANK_POOL (auto: min(60, cap*3))

What's left (optional)

  1. Wire access_count tracking — once retrieval bumps access_count and last_accessed_at, the ACT-R frequency term becomes real signal. Right now graph-node frequency is a proxy.
  2. Tune ACT-R d and α — currently both fixed. Could A/B test 0.2 vs 0.5 vs 0.8 for d, and 0.1 vs 0.3 vs 0.5 for α.
  3. Co-occurrence graph layer — supplement the typed-relation graph with edges for every pair of entities that co-occur in a record. Would significantly improve graph channel recall.
  4. Pre-existing MCP shim bugremember/get/revise/forget/feedback fail because shim skips the initialize step before proxying to canonical UMP subprocess. Out of scope here.