harness(memory): ask the brain, not the DB — they do not share a lifetime
deploy / test (push) Successful in 5m1s
deploy / build (push) Successful in 1m2s

assert_project_memory compared carried memory against
mission_phase_evaluations, which is the wrong source: memory lives in the
per-repo .brain, and wiping missions cascades the verdict rows while
leaving the brain untouched. Measured after the full prod wipe — the
scratch repo had 0 earlier verdicts and an 18,982-byte brain still
holding them — so the assertion failed on correct behaviour.

It now asks whether a repo brain exists, and only fails when memory
appeared with neither a verdict nor a brain to have come from.

Worth stating plainly because it changes what "clean slate" means: a
mission wipe does NOT clear what agents remember about a repository.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
Omar Sobh
2026-09-22 13:58:50 -05:00
co-authored by Claude Opus 5
parent 620d1bfc5f
commit 162506cd53
+14 -2
View File
@@ -930,7 +930,7 @@ assert_verifier_read_only() { # <mission> <label>
# the first mission on a repo has nothing to recall and must not fail for it: # the first mission on a repo has nothing to recall and must not fail for it:
# the earlier-verdict count is what decides which branch is the truth. # the earlier-verdict count is what decides which branch is the truth.
assert_project_memory() { # <mission> <label> assert_project_memory() { # <mission> <label>
local counts earlier carried local counts earlier carried brain
counts=$(ssh "$HOST" "docker exec clawmates_postgres_1 psql -U postgres -d clawmates -tAc \ counts=$(ssh "$HOST" "docker exec clawmates_postgres_1 psql -U postgres -d clawmates -tAc \
\"select (select count(*) from mission_phase_evaluations e \"select (select count(*) from mission_phase_evaluations e
join missions m on m.id = e.mission_id join missions m on m.id = e.mission_id
@@ -943,9 +943,21 @@ assert_project_memory() { # <mission> <label>
and detail->>'text' like '%What past missions on this repository learned%')::text;\"" \ and detail->>'text' like '%What past missions on this repository learned%')::text;\"" \
| head -1 | tr -d '\r') | head -1 | tr -d '\r')
earlier=${counts%% *}; carried=${counts##* } earlier=${counts%% *}; carried=${counts##* }
# Memory lives in the per-repo `.brain`, NOT in mission_phase_evaluations,
# and the two do not share a lifetime: wiping missions cascades the verdict
# rows and leaves the brain file untouched. Measured — after a full prod
# wipe the scratch repo had 0 earlier verdicts and an 18 KB brain still
# holding them, so "carried memory with no DB verdict" is correct
# behaviour, not a defect. Ask the brain whether it has anything.
local brain
brain=$(ssh "$HOST" "docker exec clawmates_server_1 sh -c 'ls /data/brains/repo_*.h5 2>/dev/null | wc -l'" | tr -d '[:space:]')
case "$earlier:$carried" in case "$earlier:$carried" in
0:0) pass "$2-memory: first judged mission on this repo — nothing to recall, nothing carried" ;; 0:0) pass "$2-memory: first judged mission on this repo — nothing to recall, nothing carried" ;;
0:*) fail "$2-memory: the brief carried project memory but no earlier verdict exists for this repo" ;; 0:*)
case "${brain:-0}" in
0) fail "$2-memory: the brief carried memory with no earlier verdict AND no repo brain — where did it come from?" ;;
*) pass "$2-memory: the brief carried memory from the repo brain, which outlives the verdict rows ($brain brain file(s))" ;;
esac ;;
*:0) fail "$2-memory: $earlier earlier verdict(s) on this repo and the brief carried NONE — recall is not reaching the prompt" ;; *:0) fail "$2-memory: $earlier earlier verdict(s) on this repo and the brief carried NONE — recall is not reaching the prompt" ;;
*) pass "$2-memory: $earlier earlier verdict(s) on this repo; the brief carried the recalled section" ;; *) pass "$2-memory: $earlier earlier verdict(s) on this repo; the brief carried the recalled section" ;;
esac esac