fix(plugin): a compaction clears every session ledger, not the two on the list (#4101)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 49s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Failing after 1m4s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 49s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / Python tests (push) Failing after 1m4s
CI & Build / Build & push image (push) Skipped
`scribe_session_context.sh` cleared `.rules.ids` and `.opened.ids` by name and left `.ids`, `.sync.ids` and `.derive.ids` standing, under a comment asserting that was a decision. Reading the note arms says it was not: their exclusions go straight into `semantic_search_notes`, so a surfaced note leaves the result set rather than being rendered as a reference the way #3750 gave a repeated rule, and unlike the rules ledger they never age. Hard, permanent, never cleared — a note surfaced in a session's first minute is unreachable for the rest of it, which is milestone 386's own defect alive on the arms that fire most often. The list was the bug, so the fix is not a longer list. `scribe_clear_session_ ledgers` matches the naming convention instead — a per-session ledger is `<sid>[.<kind>].ids` — which covers all five and covers the sixth on the day it is written. `<sid>.unreached` is deliberately outside it: that records an outage, not held context, and #2932 needs it to survive. tests/test_session_ledger_clear.py runs the hook rather than grepping it for `rm -f`, since grepping for the names is the pattern being removed. It pins both directions — `compact`/`clear` take all five, `startup`/`resume` take none — plus the convention the glob rests on, checked against the hooks themselves so a ledger named outside it fails loudly instead of silently never clearing. Also drops a stale comment pointing at a rules-etag marker that milestone 394 retired. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
@@ -77,9 +77,11 @@ source=$(printf '%s' "$event" | jq -r '.source // empty' 2>/dev/null) || source=
|
||||
# this state are the ones that fire most often, which is to say the ones that
|
||||
# apply most.
|
||||
#
|
||||
# The session id survives a compaction — the etag marker further down is
|
||||
# rewritten on `compact` and keyed by session_id, which is only meaningful if
|
||||
# the id is stable — so the stale ledger is genuinely found again, not orphaned.
|
||||
# The session id survives a compaction — the ledgers are keyed by it and are
|
||||
# still found under the same name afterwards, so a stale ledger is genuinely
|
||||
# reached again rather than orphaned. (This used to point at an etag marker as
|
||||
# the evidence for that; milestone 394 removed the preload the etag described,
|
||||
# and `plugin_context.py` records its retirement.)
|
||||
#
|
||||
# CLEARED ON THE SOURCES THAT DESTROY CONTEXT, AND ONLY THOSE:
|
||||
#
|
||||
@@ -93,25 +95,40 @@ source=$(printf '%s' "$event" | jq -r '.source // empty' 2>/dev/null) || source=
|
||||
# fork carries the conversation, so if it inherits the id the ledger
|
||||
# is accurate, and if it gets a new one the file is empty anyway.
|
||||
#
|
||||
# ONLY the rules ledger. The same directory holds .ids / .sync.ids /
|
||||
# .derive.ids for the note arms. Whether a surfaced NOTE should return after a
|
||||
# compaction is a different question with a different answer, and leaving those
|
||||
# alone is a decision rather than an oversight.
|
||||
# EVERY LEDGER, AND THE NOTE ARMS NEEDED IT MOST (#4101).
|
||||
#
|
||||
# This used to clear the two rule ledgers by name and say, in a comment, that
|
||||
# leaving `.ids` / `.sync.ids` / `.derive.ids` alone was "a decision rather than
|
||||
# an oversight". Reading the note arms says otherwise, on two counts:
|
||||
#
|
||||
# - They are HARD exclusions. `exclude_ids` goes into `semantic_search_notes`
|
||||
# itself, so a surfaced note is removed from the result set — it is not
|
||||
# rendered as a reference the way #3750 made a repeated rule. There is no
|
||||
# weaker form for it to fall back to.
|
||||
# - They never AGE. #3751 gave the rules ledger a TTL precisely because
|
||||
# salience decays without a context event; the note channels were left on a
|
||||
# flat read.
|
||||
#
|
||||
# Hard plus permanent plus never cleared means a note surfaced in the first
|
||||
# minute of a session is unreachable for the rest of it, through any number of
|
||||
# compactions. That is milestone 386's original defect, alive on the arms that
|
||||
# fire most often, and nothing about it was decided.
|
||||
#
|
||||
# THE LIST WAS THE BUG, so the fix is not a longer list. `scribe_clear_session_
|
||||
# ledgers` matches on the naming convention — a per-session ledger is
|
||||
# `<sid>[.<kind>].ids` — which covers all five and covers the sixth on the day
|
||||
# it is written. Best-effort, like every other filesystem touch in these hooks:
|
||||
# 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.
|
||||
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._-' '_')
|
||||
# Best-effort, like every other filesystem touch in these hooks: a ledger
|
||||
# that cannot be removed costs a repeated exclusion, never a session.
|
||||
rm -f "${TMPDIR:-/tmp}/scribe-priorart/${safe_sid}.rules.ids" 2>/dev/null || true
|
||||
# BOTH ledgers, for one reason (#4100). `.opened.ids` records what the
|
||||
# session read; a compaction is exactly the event that takes it away
|
||||
# again. Clearing the naming ledger while keeping this one would leave
|
||||
# the surfacing arms telling a freshly-summarised session "you opened
|
||||
# it earlier" about a rule that is no longer anywhere in its context —
|
||||
# a more confident version of the claim this milestone removed.
|
||||
rm -f "${TMPDIR:-/tmp}/scribe-priorart/${safe_sid}.opened.ids" 2>/dev/null || true
|
||||
scribe_clear_session_ledgers \
|
||||
"${TMPDIR:-/tmp}/scribe-priorart" "$safe_sid"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user