Skip to content

fix: scope read stubs by session_id on hosts without conversation_id (#1004)#1006

Closed
andig wants to merge 2 commits into
yvgude:mainfrom
andig:fix/session-scope-stub-1004
Closed

fix: scope read stubs by session_id on hosts without conversation_id (#1004)#1006
andig wants to merge 2 commits into
yvgude:mainfrom
andig:fix/session-scope-stub-1004

Conversation

@andig

@andig andig commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Problem

Fixes #1004. ctx_read(mode=full) could serve an [unchanged] stub on the first read of a file in a new session, pointing the model at content that session never received.

Root cause

The conversation-scope gate (core/conversation.rs) already re-delivers full content when a different conversation reads a file — but only Cursor supplied a scope id (conversation_id). Claude Code / Codex / CodeBuddy send session_id and no conversation_id, so current_conversation_id() resolved to None and the gate fell through to the legacy "allow stub" path. A new session therefore inherited the prior session's stubs.

Fix

Establish session awareness for those hosts: persist session_id into active_transcript.json and use it as the scope-id fallback (conversation_id.or(session_id)). This reuses the existing warm/cold/concurrency/subagent gate unchanged, so every tool that funnels through the shared read cache is covered.

Session semantics fall out naturally:

  • new session → new id → mismatch → full re-read
  • resume → same id → stub valid
  • /clear → new id → re-read

Changes

  • hook_handlers/observe.rs: extract session_id, persist it, and return conversation_id.or(session_id) from load_active_transcript
  • core/conversation.rs: module doc updated

Tests

2 new round-trip tests; existing conversation / cache / stub-index / compaction-sync suites (26 tests) pass.

🤖 Generated with Claude Code

andig and others added 2 commits July 18, 2026 10:24
…vgude#1004)

ctx_read(mode=full) could serve an [unchanged] stub on the first read of a
file in a new session, pointing the model at content that session never
received. The conversation-scope gate already re-delivers full content to a
different conversation, but only Cursor supplied a scope id (conversation_id).
Claude Code / Codex / CodeBuddy send session_id and no conversation_id, so
current_conversation_id() resolved None and the gate fell through to the
legacy "allow stub" path — a new session inherited the prior one's stubs.

Persist session_id into active_transcript.json and use it as the scope-id
fallback (conversation_id.or(session_id)). This reuses the existing
warm/cold/concurrency/subagent gate, so every tool that funnels through the
shared read cache is covered. New session -> new id -> full re-read; resume
-> same id -> stub valid; /clear -> new id -> re-read.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yvgude

yvgude commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Superseded by and integrated into #1013, including the session-scoped read-stub fix plus end-to-end hardening and full cross-platform CI. The original commit/authorship remains preserved in the integrated history. Thank you for the careful fix.

@yvgude yvgude closed this Jul 18, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx_read(mode=full) returns dedup stub on first read in a new session (cross-session ledger vs per-session context)

2 participants