Skip to content

Let the store connection release the streams its scope outlives - #3694

Merged
trissim merged 1 commit into
mainfrom
claude-code/cursor-scope
Oct 30, 2026
Merged

trissim merged 1 commit into
mainfrom
claude-code/cursor-scope

Conversation

@trissim

@trissim trissim commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Tracebacks per heartbeat pass: 1+ -> 0. The installed connector logs Exception ignored while closing generator TypedRow.iterate ... typed_table.py:610 cursor.close() ... Cannot operate on a closed database every 2-3 min.

Why it existed

TypedRow.iterate (typed_table.py:603) closes its cursor in finally. A caller that drops a half-read stream (e.g. next(FailedTurnEvidence.stream(...)) at goal_attempts.py:149) leaves that finally to the collector, which runs after the store scope has already closed the connection. #3670 patched two callers with closing(). That is a several-places fix: every new streaming caller would need it again. The fact "a query lives no longer than its connection" belongs to the connection.

Change

  • store_files.py: StoreContention.reader/writer, the one place store connections are opened, pass factory=LendingConnection.
  • LendingConnection(sqlite3.Connection) lends LentCursors (through cursor/execute/executemany/executescript) and retires them in close() before closing itself.
  • RetiredCursor(LentCursor): a retire swaps the class, and its close() has nothing left to release. No flag, no branch.
  • 1 family test, test_store_connection_releases_streams_its_scope_outlives: a half-read stream outlives its closing() scope; gc.collect(); sys.unraisablehook receives nothing.

Proof

  • Repro on installed core-790988ef9: unraisable: [ProgrammingError('Cannot operate on a closed database.')]. On this head: unraisable: [].
  • tests/round2/test_typed_table.py + test_commander_forks.py::test_two_commanders_cannot_assign_the_same_unit_concurrently: 22 passed.

Follow-on: #3670's closing() commit (todos.py:6036, goal_attempts.py:149) becomes redundant and should be dropped from its carrier.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu

Every heartbeat pass logged "Exception ignored while closing generator
TypedRow.iterate ... Cannot operate on a closed database": a caller dropped a
half-read typed stream, the store scope closed its connection, and the
collector later ran the stream's finally, closing a cursor on a dead database.

StoreContention, the one place store connections are opened, now opens a
LendingConnection. It owns every cursor it lends and retires them before it
closes, so a stream released afterwards has nothing left to release. Callers
no longer need closing() around each stream to cover for the scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbFMSoWgC3ZwKzjT4SwMDu
Copilot AI balanced review requested due to automatic review settings October 30, 2026 12:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@github-actions

Copy link
Copy Markdown

debt-src at 10b5bf1, every finding:

grew TypeErrors:src/agent_comms/store_files.py +5
grew UnannotatedParameter:src/agent_comms/store_files.py +4
found TypeErrors:src/agent_comms/store_files.py at src/agent_comms/store_files.py:475 (Function is missing a type annotation for one or more parameters  [no-untyped-def]) src/agent_comms/store_files.py:479 (Signature of "cursor" incompatible with supertype "sqlite3.Connection"  [override]) src/agent_comms/store_files.py:484 (Function is missing a type annotation for one or more parameters  [no-untyped-def]) src/agent_comms/store_files.py:487 (Function is missing a type annotation for one or more parameters  [no-untyped-def]) src/agent_comms/store_files.py:491 (Incompatible return value type (got "Cursor", expected "LentCursor")  [return-value])
found UnannotatedParameter:src/agent_comms/store_files.py at src/agent_comms/store_files.py:134 src/agent_comms/store_files.py:134 src/agent_comms/store_files.py:134 src/agent_comms/store_files.py:475 src/agent_comms/store_files.py:475 src/agent_comms/store_files.py:484 src/agent_comms/store_files.py:487

@trissim
trissim enabled auto-merge October 30, 2026 12:40
@trissim
trissim merged commit d39dfb1 into main Oct 30, 2026
8 of 9 checks passed
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.

2 participants