Skip to content

fix: session_close honours or refuses an explicit session_id; gitmem_session_id alias (GIT-122) - #69

Merged
nTEG-dev merged 4 commits into
mainfrom
fix/git-122-session-close-id-invariant
Oct 5, 2026
Merged

nTEG-dev merged 4 commits into
mainfrom
fix/git-122-session-close-id-invariant

Conversation

@nTEG-dev

@nTEG-dev nTEG-dev commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

What

Fixes GIT-122: session_close must honour or refuse an explicit session id. Root cause (GIT-122, 19:07Z comment): on 2026-10-04 the Claude remote-devices bridge strips a parameter named session_id, so gitmem received no id, silently fell back to its registry-bound session, and overwrote an already-closed session (ed6b400e). Server log at 13:39Z: Recovered session_id from registry: ed6b400e, a path that only runs when no id arrives.

Stacked on #68 (GIT-123, the e2e sandbox fix; that commit is included here). Once #68 merges I rebase and this diff is the two GIT-122 commits only.

Changes (src/tools/session-close.ts, schema/types/tool definition)

  1. gitmem_session_id alias: same meaning as session_id, under a name a proxy won't claim. Both given and different → refused. The tool definition now requires only close_type.
  2. Invariant: the requested id is captured at entry; a resolved id that differs is refused before thread sync or any write, and again just before the upsert (asserting on the row id, not a resolved promise). Retroactive closes (new row by design) are exempt.
  3. Re-close: refused unless reclose: true. A close that only partly persisted (threads not synced) is flagged partial_persist and stays retryable. Free-tier path gets the same rule.
  4. No id + several live sessions: refused, candidates named (GIT-103 rule 3). Deliberate behaviour change: a no-id close fails while another agent's session is open on the machine.
  5. Payload: sessions/<id>/closing-payload.json wins when present and is refused if it names another session. The shared root closing-payload.json (still what the Stop hook and gitmem init point at) is read for one release when its session_id names the closing session, whatever the number of live sessions; refused if it names another; with no session_id it is used only while a single session is live, otherwise ignored with the "not found at " message. The Stop hook text, gitmem init templates, the agent templates and session_start's payload schema now tell agents to include "session_id", so hook and server agree under concurrent sessions.
  6. Result/display show the full id actually written; the raw incoming id is logged to stderr on entry.

Tests (+24 unit in session-close-id-invariant.test.ts; 1 updated; +1 hook test)

Written first and failing on main (13 of the 20 fail there; the others are regression guards, e.g. reclose: true accepted, partial-persist retry, explicit A while bound to B). Covers (incl. root payload with a matching id consumed with two live sessions, mismatched refused, ownerless ignored, and a test that runs the real Stop hook, follows its instruction literally and closes through the server's reader): A + payload carrying B refused; closed session refused / reclose allowed; no id with two live sessions refused; payload mismatch refused; per-session payload read and B's payload untouched; legacy fallback only when one session is live; full id in result and display; stderr log; alias alone, both equal, both different, malformed, logged.

  • Unit: 1474/1474. hooks/tests/test-hooks.sh: the new assertion passes; 2 "not detected" tests fail only on a machine that has a gitmem binary on PATH and pass in CI (stock PATH).
  • CI: build 18/20/22, hooks-macos, hooks-without-jq green; venue gate (manual dispatch, disposable venue, v1.8.0 schema then current) green.

Known, unrelated

7 e2e tests (user-journey 6, organic-discovery 1) start real claude sessions via the Agent SDK and time out (90s/180s). Not caused by this change; undiagnosed. Full e2e summary lines are in the PR comments.

Not merged, tagged or published; Chris decides. The full rollout of gitmem_session_id to other tools is GIT-103.

🤖 Generated with Claude Code

@nTEG-dev

nTEG-dev commented Oct 4, 2026

Copy link
Copy Markdown
Member Author

Full npm run test:e2e on this branch (GIT-123 sandbox + GIT-122 changes):

 Test Files  2 failed | 8 passed | 2 skipped (12)
      Tests  7 failed | 123 passed | 17 skipped (147)

Same counts as the GIT-123 branch alone (#68). cursor-cross-tool 34/34 passes. The 7 failures are the known, unrelated real-claude timeouts: user-journey (6) and organic-discovery (1). The 2 skipped files are pro-* (no Docker). Sentinel file in the real ~/.gitmem byte-identical after the run.

Claude and others added 4 commits October 4, 2026 19:06
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ip session_id (GIT-122)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ion; hook and templates say to include session_id (GIT-122)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@nTEG-dev
nTEG-dev force-pushed the fix/git-122-session-close-id-invariant branch from 9c1b604 to e17888b Compare October 5, 2026 00:06
@nTEG-dev
nTEG-dev merged commit af02896 into main Oct 5, 2026
7 checks passed
nTEG-dev added a commit that referenced this pull request Oct 5, 2026
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