fix(memory): Wave 1 — SQL-aggregate dashboard counts + memory write-path fixes
Closes three live-affecting bugs surfaced by the 2026-04-29 Codex review,
all in the memory write/read path. Pre-deploy on Dalidou the live
discrepancy was dashboard.memories.active=315 vs integrity active=1091.
1. /admin/dashboard counts now SQL-aggregate (no sampling).
New get_memory_count_summary() helper. Dashboard memories.{active,
candidates,by_type,by_project,reinforced,by_status,total} all derive
from full-table SQL, not a confidence-sorted limit=500 sample. Post
deploy the dashboard active count must match the integrity panel.
2. PUT /memory/{id} accepts project; auto-triage now applies it.
Added project to MemoryUpdateRequest and update_memory() with
resolve_project_name canonicalization, before/after audit, and
duplicate-active check scoped to the new project. scripts/auto_triage.py
suggested-project correction now PUTs {"project": suggested} so
misattribution flags actually retarget the memory.
3. POST /memory/{id}/invalidate uses direct id lookup.
New get_memory(id) helper. Replaces the old
_get_memories(status="active", limit=1) lookup, which only saw the
highest-confidence active row. Active memories outside slot 0 no
longer 404. Same status-guard structure applied to
POST /memory/{id}/supersede so candidates can't silently flip to
superseded.
14 regression tests added (572 -> 586 locally). Reviewed by Codex twice:
verdict GO on tip 9604c3e.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -404,19 +404,23 @@ def process_candidate(cand, base_url, active_cache, state_cache, known_projects,
|
||||
known_projects, TIER1_MODEL, DEFAULT_TIMEOUT_S,
|
||||
)
|
||||
|
||||
# Project misattribution fix: suggested_project surfaces from tier 1
|
||||
# Project misattribution fix: suggested_project surfaces from tier 1.
|
||||
# Earlier code POSTed only {"content": cand["content"]}, which left
|
||||
# the project field unchanged because MemoryUpdateRequest had no
|
||||
# project key and the service signature didn't accept one. Wave 1
|
||||
# added project to MemoryUpdateRequest and update_memory(); this
|
||||
# caller now actually applies the suggested project.
|
||||
suggested = (v1.get("suggested_project") or "").strip()
|
||||
if suggested and suggested != project and suggested in known_projects:
|
||||
# Try to re-canonicalize the memory's project
|
||||
if not dry_run:
|
||||
try:
|
||||
import urllib.request as _ur
|
||||
req = _ur.Request(
|
||||
f"{base_url}/memory/{mid}", method="PUT",
|
||||
headers={"Content-Type": "application/json"},
|
||||
data=json.dumps({"content": cand["content"]}).encode("utf-8"),
|
||||
data=json.dumps({"project": suggested}).encode("utf-8"),
|
||||
)
|
||||
_ur.urlopen(req, timeout=10).read() # triggers canonicalization via update
|
||||
_ur.urlopen(req, timeout=10).read()
|
||||
except Exception:
|
||||
pass
|
||||
print(f" ↺ misattribution flagged: {project!r} → {suggested!r}")
|
||||
|
||||
Reference in New Issue
Block a user