What happened?
session-binding.ts implements branch-local binding checkpoints for restart-time resume:
latestBindingOnBranch() reads claude-sdk-oauth-binding custom entries back off the session
branch, and verifyBindingAgainstTranscript() turns one into a reattach. The extension's
AGENTS.md documents the file as "Branch-local binding checkpoint for restart-time resume
verification".
Nothing calls either function, and nothing ever writes a claude-sdk-oauth-binding entry. The
module's only commit, db8e8cfeb, added the module and its unit test — 2 files, 160 insertions,
no call sites. The unit test is the sole consumer.
The binding store that actually runs is const bindings = new Map() in session-reattach.ts.
Process memory. After a restart both the registry entry and the binding are gone, so
decideNativeContinuity returns { kind: "bootstrap" } and the lane flattens. session-stream.ts
synthesizes the reason as registry_miss because bootstrap carries none, and since firstTurn
is false session-observability.ts reports the kind as flatten.
The user-visible result on a 697-message session: resent the full conversation (registry_miss),
68.0KB, ~60K tokens re-billed, on the first turn after every restart.
Steps to reproduce
- Run a
claude-sdk-oauth session for several turns.
- Restart senpi.
- Send one more turn in the same session.
- The continuity notice reports a full re-send with reason
registry_miss.
grep -c claude-sdk-oauth-binding <session>.jsonl returns 0, confirming no checkpoint was ever
written.
Expected behavior
A restart should resume rather than re-send. The checkpoint is written as the turn commits and
consulted when the in-memory registry misses, so the first turn after a restart is a delta.
This is distinct from #691 (assistant_rewritten from thinking timing) and #790
(sent_stream_diverged from content-less user messages). Both of those fix divergence within a
live process; neither addresses a cold start, and unlike them this one has no workaround.
Version
@code-yeongyu/senpi 2026.8.11-2
@anthropic-ai/claude-agent-sdk 0.3.220
provider claude-sdk-oauth · model claude-opus-5
What happened?
session-binding.tsimplements branch-local binding checkpoints for restart-time resume:latestBindingOnBranch()readsclaude-sdk-oauth-bindingcustom entries back off the sessionbranch, and
verifyBindingAgainstTranscript()turns one into areattach. The extension'sAGENTS.mddocuments the file as "Branch-local binding checkpoint for restart-time resumeverification".
Nothing calls either function, and nothing ever writes a
claude-sdk-oauth-bindingentry. Themodule's only commit,
db8e8cfeb, added the module and its unit test — 2 files, 160 insertions,no call sites. The unit test is the sole consumer.
The binding store that actually runs is
const bindings = new Map()insession-reattach.ts.Process memory. After a restart both the registry entry and the binding are gone, so
decideNativeContinuityreturns{ kind: "bootstrap" }and the lane flattens.session-stream.tssynthesizes the reason as
registry_missbecausebootstrapcarries none, and sincefirstTurnis false
session-observability.tsreports the kind asflatten.The user-visible result on a 697-message session:
resent the full conversation (registry_miss),68.0KB, ~60K tokens re-billed, on the first turn after every restart.
Steps to reproduce
claude-sdk-oauthsession for several turns.registry_miss.grep -c claude-sdk-oauth-binding <session>.jsonlreturns 0, confirming no checkpoint was everwritten.
Expected behavior
A restart should resume rather than re-send. The checkpoint is written as the turn commits and
consulted when the in-memory registry misses, so the first turn after a restart is a delta.
This is distinct from #691 (
assistant_rewrittenfrom thinking timing) and #790(
sent_stream_divergedfrom content-less user messages). Both of those fix divergence within alive process; neither addresses a cold start, and unlike them this one has no workaround.
Version