fix(plugin): the sweep missed the arm that fires most — two ledger directories (#4101)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Failing after 1m46s
CI & Build / Build & push image (push) Skipped

CI caught two things in c61f730, and the second is the one that mattered.

1. `scribe_autoinject.sh` keeps its note ledger in `${TMPDIR}/scribe-autoinject`,
   not `scribe-priorart`. Every ledger NAMED in the hooks was in the one
   directory the sweep visited, so it read as complete — and the arm that fires
   most (598 calls in five days) was the only one still carrying the bug. The
   clear ran, found nothing to remove, and exited 0. `SCRIBE_LEDGER_DIRS` in
   `scribe_defs.sh` is now the roster, and the guard reads that string rather
   than a copy of it, so a test can no longer agree with itself forever.

2. The convention guard over-reached: it flagged `<sid>.snap` and
   `<sid>.blocked`, which live in `scribe-afterwrite` and `scribe-reportcheck`
   and can never be touched by the sweep. It is now two tests keyed on the
   directory, because the two assumptions fail differently — one lets a ledger
   sit where nothing sweeps, the other lets it sit in the right place under a
   name the sweep does not match.

`test_only_the_rule_ledger_is_cleared_and_the_note_ledgers_are_left` also went
red, correctly: the note arms' exemption was a real decision, recorded in a
test, and my commit message said nothing about it had been decided. That was
wrong and the test was right to stop me. The decision is reversed rather than
ignored, and the reasoning is that #4101 removed its premise: it rested on a
note repeat being WITHHELD, so clearing the ledger meant re-injecting whole
menu lines the session already had. Now a repeat is rendered with a `seen`
marker, so the ledger only decides whether that marker is true — and across a
compaction it is false, telling a freshly-summarised session it has already
seen a record that is nowhere in its context. The test keeps its name and
records the reversal with the reason, rather than being deleted.

Verified by running the hook directly: all six ledgers across both directories
gone on `compact`, `<sid>.unreached` left standing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
2026-09-16 21:11:43 -04:00
co-authored by Claude Opus 5
parent 5c64ea0b4f
commit f1e63d207f
5 changed files with 156 additions and 59 deletions
+5 -3
View File
@@ -121,14 +121,16 @@ source=$(printf '%s' "$event" | jq -r '.source // empty' 2>/dev/null) || source=
# a ledger that cannot be removed costs a repeated exclusion, never a session.
#
# NOT swept: `<sid>.unreached`, which records that the instance was unreachable
# rather than what the session holds, and survives on purpose.
# rather than what the session holds, and survives on purpose. The directories
# swept are `scribe_defs.sh`'s `SCRIBE_LEDGER_DIRS` — plural, because the
# auto-inject arm keeps its ledger somewhere else and a single-directory sweep
# missed exactly the arm that fires most.
case "$source" in
compact|clear)
sid=$(printf '%s' "$event" | jq -r '.session_id // empty' 2>/dev/null) || sid=""
if [ -n "$sid" ]; then
safe_sid=$(printf '%s' "$sid" | tr -c 'A-Za-z0-9._-' '_')
scribe_clear_session_ledgers \
"${TMPDIR:-/tmp}/scribe-priorart" "$safe_sid"
scribe_clear_session_ledgers "$safe_sid"
fi
;;
esac