Conversation
…ct (#339) SessionStart fires again at every auto-compaction. The hook read session_id out of that payload and discarded `source`, so a compaction got the same full recap a cold start does. A compaction is not a new session: the store has not changed and the bytes were already delivered once, in this session. So at source=compact the bodies are not repeated -- except identity.md, which works by presence rather than by pointer and which nothing else in the output even names. The rest are named with their sizes (#124's "kept but not injected"), because a recap that shrinks in silence is indistinguishable from a store that emptied. Read in one direction only. No `source`, an empty value, an unknown spelling or no stdin at all leaves it unrecognised and takes today's path unchanged. startup/resume/clear/fork, the handoff blocks, the history hint, the consolidation trigger and the hooks.d dispatches are untouched at every source; neither the recovery block nor the capture-gap check branches on it. Co-Authored-By: Max <noreply>
…339) The fixture wrote five of the six MEMORY_FILES entries; today-<date>.md was never created, so nothing exercised the largest deferred file. The #206 comment above the stdin read still said only session_id is taken out of the payload. True for the job that comment is about, and no longer true of the block as a whole. Co-Authored-By: Max <noreply>
This was referenced Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #339
The reported problem, and the part of it that was asserted
session-start-hook.shreadsHOOK_STDINforsession_idand discardssource, so the full memory recap is printed identically atstartup,resume,clear,compactandfork. The reporter measured it across 50 sessions:compactfired 82 times againststartup's 180, at comparable per-fire cost.That measurement is of cost, not of overlap. The issue's stated rationale — that at
compactthe conversation already holds a summary covering the same ground — was asserted rather than measured, and this repo's own README says close to the opposite: auto-compact discards conversation history before the save pipeline can capture it, which is why the README recommends turning it off. A compaction summary is task-focused and lossy. So "skip the recap atcompact" would trade a measured ~459 chars for an unmeasured, silent loss of identity and long-term memory for the rest of every long session — an absence read as a presence, which is the defect class this repo files most often.What this does instead
The
.remember/pointer is not at stake.=== REMEMBER ===is emitted unconditionally further up and already namesnow.md,today-*.md,recent.md,archive.mdandcore-memories.md. The one file it does not name isidentity.md, and that asymmetry is what the fix is built on:source=compactidentity.mdcore-memories.md,today-*.md,now.md,recent.md,archive.mdNamed rather than dropped, for #124's reason: a recap that shrinks in silence is indistinguishable from a store that emptied.
startup,resumeandclearare unchanged.forkis unchanged deliberately — what a fork inherits from its parent context could not be established, and an unverified belief is not grounds for withholding memory.Absence must not read as
compactsourceis extracted by the same narrow shell heuristic assession_id(_stdin_session_idis now a thin wrapper over a shared_stdin_json_string KEY RAW), then whitelisted againststartup|resume|clear|compact|fork. Anything else — missing field, empty value, unknown spelling, no stdin at all — becomes""and takes the unchanged full-recap path. A payload shape we do not recognise must never silently disable memory injection.post-tool-hook.shkeeps its own copy of the heuristic. It reads one field, and sourcing a library from a hook that has to survive a broken install is the worse trade.The memory file list existed twice and now needs a third read, so it is hoisted into a
MEMORY_FILESarray — a seventh file cannot be added to one loop and missed by the others.Tests
Written first. The first RED run produced only one failure, because a full recap already prints
--- core-memories.md ---as a body header, so the basename assertion passed against unchanged code — a test that would pass if the code did nothing. Rewritten to assert the resolved path plus the byte size:After the fix:
18 passed in 10.40s. Full suite:1569 passed, 43 skipped in 879.20s. Windows unverified locally; CI is the authority there.Review
One independent Sonnet agent against the committed diff, with no sight of the author's reasoning — it re-derived the RED behaviour by running the test file against
HEAD~1in a scratch clone. Two findings, both fixed: #206's comment still claimed onlysession_idwas needed from stdin, and the fixture covered five of sixMEMORY_FILES(today-<date>.mdwas never written). Nothing refused.Found in passing, not fixed here
=== LAST HANDOFF ===increments its delivery counter on every compaction, because the fingerprint is unchanged and the "already delivered" branch fires. Four compactions render as "already delivered 5 times" for a note delivered once.compactwhen past-day staging files exist.Both are pre-existing and unrelated to
source. Narrowing either one here would be exactly the silent scope change this change is trying not to make.