Repository navigation
fix: every write tool reports durability; resolve_thread stops claiming success (GIT-101) - #40
Merged
2 commits merged intoSep 22, 2026
Merged
2 commits merged into
2 commits merged into
Conversation
…hread stops claiming success (GIT-101)
resolve_thread computed supabaseSynced, logged it to metrics and returned
success: true regardless, so a resolve the durable store never saw looked
done while other sessions still saw the thread open.
- WriteResult { success, durable, stored_in } (types + services/write-result.ts)
is create_thread's contract, now shared: success = durable || !hasSupabase(),
and false whenever nothing was stored.
- Applied to create_learning, create_decision, create_thread, resolve_thread,
archive_learning, record_scar_usage, record_scar_usage_batch, session_close,
promote_suggestion (passes create_thread's outcome through) and
save_transcript. Result types extend WriteResult, so every return states it.
- resolve_thread on pro without a durable write: success false,
stored_in local_only, and a display that says RESOLVED LOCALLY ONLY.
- session_close reports whether the session row reached the store on every
exit, including a failure after the row landed.
One parameterized test, Supabase failing at the network, pro tier: each of the
10 tools reports success false, durable false, the right stored_in, and a
display that says so. 10 of 12 fail on origin/main (resolve_thread: success
true). +12 tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eads (GIT-101) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 22, 2026
neoneye
pushed a commit
to agent-memory-atlas-archive/gitmem-dev--gitmem
that referenced
this pull request
Sep 22, 2026
Conflicts: - session-close.ts: gitmem-dev#39's payloadReadError and gitmem-dev#40's sessionRowStored are separate declarations; both kept. - blank-supabase.mjs: gitmem-dev#40's resolve step before gitmem-dev#39's no-payload close (both before the real close); both result fields; all three checks. Semantic (tsc): gitmem-dev#39's "closing-payload.json not found" return predates WriteResult; it is a pre-write exit, so it gets ...notStored().
neoneye
pushed a commit
to agent-memory-atlas-archive/gitmem-dev--gitmem
that referenced
this pull request
Sep 22, 2026
Conflicts: - session-close.ts: gitmem-dev#40 and gitmem-dev#41 add the same sessionRowStored flag; one declaration kept (one assignment after the upsert), comment covers both uses. - blank-supabase.mjs: all result fields and all checks kept. tsc clean; no new returns to type.
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.
What
Every write tool now says whether its write is durable, and
resolve_threadstops claiming success it doesn't have (GIT-101).WriteResult { success, durable, stored_in }(src/types/index.ts, helpers insrc/services/write-result.ts) iscreate_thread's contract, now shared by every write tool:durable: the record is in Supabase. Never true on free.stored_in:"supabase","local"(free),"local_only"(pro, durable write failed, local copy kept) ornull(stored nowhere).success = durable || !hasSupabase(), and false whenever nothing was stored.create_learning,create_decision,create_thread,resolve_thread,archive_learning,record_scar_usage,record_scar_usage_batch,session_close,promote_suggestion(passescreate_thread's outcome through) andsave_transcript. Their result typesextend WriteResult, so the compiler made every return state its outcome.resolve_threadon pro without a durable write returnssuccess: false, durable: false, stored_in: "local_only", and its display saysRESOLVED LOCALLY ONLY — not durable … other sessions still see t-… as open.session_closereports on every exit whether the session row reached the store, including a failure that happens after the row landed. A partial close (a thread didn't sync) isdurable: true, success: false: the row is saved, the close isn't complete.Why
resolve-thread.tscomputedsupabaseSynced, logged it to metrics and then returnedsuccess: trueregardless. A resolve the durable store never saw looked done, while every other session still saw the thread open.How to test
One parameterized test (
write-result-contract.test.ts): pro tier, Supabase configured, and every request to it fails atfetch. For each of the 10 tools it asserts:success: false,durable: false;stored_in(local_onlyforcreate_thread,resolve_threadandpromote_suggestion;nullfor the rest);fail|not stored|not durable|locally only). Over MCP,server.tssends onlydisplaywhen one exists, so the fields alone never reach the agent.origin/mainresolve_thread:success: truewith the store unreachable; display "Thread resolved".Venue (v1.8.0
setup.sql,vujndhcumgroztfkkdus; production not touched):flownow creates a second thread, resolves it, and readsgitmem_threadsback:status: resolved, display "Thread resolved", no "LOCALLY ONLY". The success side lands on a customer-shaped store;resolution_noteandresolved_by_sessionexist in v1.8.0. Exit 0; close persisted; thread counts match; only GIT-73 and GIT-105 seen (the GIT-105 400 is the resolve's triple write, which item 7 addresses).Unit tests: 1286/1286 pass (+12). No existing test encoded the old behaviour.
Left out on purpose (flagging)
absorb_observations,dismiss_suggestion,contribute_feedback: they write session state or local files by design, not the durable store. Observations reach the store withsession_close.cleanup_threads: a report with an optional archive.archiveDormantThreadsswallows errors and returns 0, so "nothing dormant" and "archive failed" look identical. Giving it a WriteResult means changing that service first. That would be a separate ticket.record_scar_usage_batchstores nothing (it defers to the single-record tool) and has always returned success. It now saysstored_in: nullalongsidesuccess: true(no durable store to miss). That's the one placesuccessandstored_in: nullcoexist.record_scar_usage_batch, partial: if some inserts land and one throws, it still reportsnotStored. The per-row outcome isn't tracked yet.Checklist
npm run test:unitpasses (1286)Breaking changes
resolve_thread(and the others, whose failure paths already said so) now returnsuccess: falsewhen the durable write didn't land on pro. That's the fix. New fieldsdurableandstored_inare additive.🤖 Generated with Claude Code