feat: "Make It Actually Useful" sprint — observability + Phase 10
Pipeline observability: - Retrieval harness runs nightly (Step E in batch-extract.sh) - Pipeline summary persisted to project state after each run (pipeline_last_run, pipeline_summary, retrieval_harness_result) - Dashboard enhanced: interaction total + by_client, pipeline health (last_run, hours_since, harness results, triage stats), dynamic project list from registry Phase 10 — reinforcement-based auto-promotion: - auto_promote_reinforced(): candidates with reference_count >= 3 and confidence >= 0.7 auto-graduate to active - expire_stale_candidates(): candidates unreinforced for 14+ days auto-rejected to prevent unbounded queue growth - Both wired into nightly cron (Step B2) - Batch script: scripts/auto_promote_reinforced.py (--dry-run support) Knowledge seeding: - scripts/seed_project_state.py: 26 curated Trusted Project State entries across p04-gigabit, p05-interferometer, p06-polisher, atomizer-v2, abb-space, atocore (decisions, requirements, facts, contacts, milestones) Tests: 299 → 303 (4 new Phase 10 tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -186,3 +186,98 @@ def test_memories_for_context_empty(isolated_db):
|
||||
text, chars = get_memories_for_context()
|
||||
assert text == ""
|
||||
assert chars == 0
|
||||
|
||||
|
||||
# --- Phase 10: auto-promotion + candidate expiry ---
|
||||
|
||||
|
||||
def _get_memory_by_id(memory_id):
|
||||
"""Helper: fetch a single memory by ID."""
|
||||
from atocore.models.database import get_connection
|
||||
with get_connection() as conn:
|
||||
row = conn.execute("SELECT * FROM memories WHERE id = ?", (memory_id,)).fetchone()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def test_auto_promote_reinforced_basic(isolated_db):
|
||||
from atocore.memory.service import (
|
||||
auto_promote_reinforced,
|
||||
create_memory,
|
||||
reinforce_memory,
|
||||
)
|
||||
|
||||
mem_obj = create_memory("knowledge", "Zerodur has near-zero CTE", status="candidate", confidence=0.7)
|
||||
mid = mem_obj.id
|
||||
# reinforce_memory only touches active memories, so we need to
|
||||
# promote first to reinforce, then demote back to candidate —
|
||||
# OR just bump reference_count + last_referenced_at directly
|
||||
from atocore.models.database import get_connection
|
||||
from datetime import datetime, timezone
|
||||
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
"UPDATE memories SET reference_count = 3, last_referenced_at = ? WHERE id = ?",
|
||||
(now, mid),
|
||||
)
|
||||
|
||||
promoted = auto_promote_reinforced(min_reference_count=3, min_confidence=0.7)
|
||||
assert mid in promoted
|
||||
mem = _get_memory_by_id(mid)
|
||||
assert mem["status"] == "active"
|
||||
|
||||
|
||||
def test_auto_promote_reinforced_ignores_low_refs(isolated_db):
|
||||
from atocore.memory.service import auto_promote_reinforced, create_memory
|
||||
from atocore.models.database import get_connection
|
||||
from datetime import datetime, timezone
|
||||
|
||||
mem_obj = create_memory("knowledge", "Some knowledge", status="candidate", confidence=0.7)
|
||||
mid = mem_obj.id
|
||||
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
"UPDATE memories SET reference_count = 1, last_referenced_at = ? WHERE id = ?",
|
||||
(now, mid),
|
||||
)
|
||||
|
||||
promoted = auto_promote_reinforced(min_reference_count=3, min_confidence=0.7)
|
||||
assert mid not in promoted
|
||||
mem = _get_memory_by_id(mid)
|
||||
assert mem["status"] == "candidate"
|
||||
|
||||
|
||||
def test_expire_stale_candidates(isolated_db):
|
||||
from atocore.memory.service import create_memory, expire_stale_candidates
|
||||
from atocore.models.database import get_connection
|
||||
|
||||
mem_obj = create_memory("knowledge", "Old unreferenced fact", status="candidate")
|
||||
mid = mem_obj.id
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
"UPDATE memories SET created_at = datetime('now', '-30 days') WHERE id = ?",
|
||||
(mid,),
|
||||
)
|
||||
|
||||
expired = expire_stale_candidates(max_age_days=14)
|
||||
assert mid in expired
|
||||
mem = _get_memory_by_id(mid)
|
||||
assert mem["status"] == "invalid"
|
||||
|
||||
|
||||
def test_expire_stale_candidates_keeps_reinforced(isolated_db):
|
||||
from atocore.memory.service import create_memory, expire_stale_candidates
|
||||
from atocore.models.database import get_connection
|
||||
|
||||
mem_obj = create_memory("knowledge", "Referenced fact", status="candidate")
|
||||
mid = mem_obj.id
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
"UPDATE memories SET reference_count = 1, "
|
||||
"created_at = datetime('now', '-30 days') WHERE id = ?",
|
||||
(mid,),
|
||||
)
|
||||
|
||||
expired = expire_stale_candidates(max_age_days=14)
|
||||
assert mid not in expired
|
||||
mem = _get_memory_by_id(mid)
|
||||
assert mem["status"] == "candidate"
|
||||
|
||||
Reference in New Issue
Block a user