Skip to content

fix: a thread counts as synced only when the store confirms its row (GIT-117) - #52

Merged
2 commits merged into
mainfrom
bugfix/GIT-117-thread-sync-truth
Sep 23, 2026
Merged

2 commits merged into
mainfrom
bugfix/GIT-117-thread-sync-truth

Conversation

@nTEG-dev

Copy link
Copy Markdown
Member

What

A thread counts as synced only when the store confirms its row (GIT-117).

  • Confirmed writes only: the sync loop uses throwing variants of the helpers.
    • A create counts when directUpsert returns the row.
    • A resolve or touch counts only when the PATCH returns a row; 0 rows is a failure.
    • A thread the store doesn't have is a failure, not a no-op.
    • touchThreadsInSupabase now reports per-thread outcomes.
    • The boolean/null wrappers used by create_thread and resolve_thread are unchanged.
  • Partial sync: the close header says PARTIAL (the session saved, some threads didn't) and the message names each failed id with its error. threads.json keeps them marked sync_pending. Session files are retained, as before.
  • Carry-forward: session_start keeps sync_pending threads whatever their age (they were dropped as "stale" after 24 h). Their local state wins over the store's copy, so an unwritten resolution survives, until a later close writes them. A full sync clears the flag.

Why

The helpers caught their own failures and returned null / false / void, and the loop never read the result. So a thread the store rejected was counted as synced. session_close reported COMPLETE, pruned threads.json and deleted the session files. A local-only thread was then discarded as stale 24 h later, and a failed resolution was overwritten by the store's still-open copy. The GIT-70 test didn't catch it because it failed only the lookup, the one call whose error propagated.

How to test

Venue (vujndhcumgroztfkkdus, v1.8.0 setup.sql; production not touched). A new flow probe makes the store really reject a thread: its source_session names a session the store has never seen, so FK 23503 fires. After the close, it restarts on the same home.

origin/main 1.11.0 This branch
Store rejected the thread yes yes
Close header COMPLETE PARTIAL, names t-fk…
threads.json no pending marker sync_pending: true
Next session_start not carried Carrying forward 1 thread(s) … t-fk…
Exit 1 0

The probe's own intentional 409 is excluded from the failure gate; every other request still counts.

Unit tests: 1363/1363. thread-sync-result.test.ts gains 6 tests that fail the writes (create rejected; resolve 0 rows; resolve rejected; touch rejected; one failure among three; an all-confirmed control). 5 fail on main; the control passes on both.

Existing tests

None changed. The 13 existing sync tests still pass. Their supabase-client mock lacked directPatch, so the resolve and touch paths had never been exercised (the audit's mock-blindness shape); the mock now provides it.

Checklist

  • Fails on main, passes on the branch (unit + venue v1.8.0)
  • No schema change

🤖 Generated with Claude Code

Claude and others added 2 commits September 22, 2026 20:28
…GIT-117)

syncThreadsToSupabase called create/resolve/touch helpers that caught their
own failures and returned null/false/void, which the loop never read. So a
thread whose write the store rejected was counted as synced: session_close
reported COMPLETE, pruned threads.json and deleted the session files, and
a local-only thread was dropped as stale 24 h later.

- The loop uses throwing variants: a create counts when directUpsert
  returns the row; a resolve or touch counts only when the PATCH returns a
  row (0 rows = failed); a thread the store doesn't have is a failure, not
  a no-op. touchThreadsInSupabase reports per-thread outcomes.
- Partial sync: the close says PARTIAL (session saved, threads not) and
  names the failed ids; threads.json keeps them marked sync_pending.
- session_start keeps sync_pending threads whatever their age and prefers
  their local state over the store's (so an unwritten resolution survives)
  until a later close writes them; a full sync clears the flag.

thread-sync-result.test.ts: the GIT-70 tests only failed the lookup, the
one call that propagated. +6 tests fail the writes; 5 fail on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ks PARTIAL + carry-forward (GIT-117)

On 1.11.0 the store rejects the thread and the close says COMPLETE with
no pending marker: exit 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nTEG-dev nTEG-dev closed this pull request by merging all changes into main in 60a990e Sep 23, 2026
@nTEG-dev
nTEG-dev deleted the bugfix/GIT-117-thread-sync-truth branch September 23, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant