Skip to content

fix(mcp): join auto-watch before closing its GraphStore - #1127

Merged
1 commit merged into
tirth8205:stagingfrom
azizur100389:codex/fix-mcp-watch-shutdown
Nov 6, 2026
Merged

1 commit merged into
tirth8205:stagingfrom
azizur100389:codex/fix-mcp-watch-shutdown

Conversation

@azizur100389

@azizur100389 azizur100389 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

MCP auto-watch currently closes its GraphStore as soon as the transport ends, even while startup reconciliation or a debounced event batch is using it. Retain the watcher thread, signal its existing stop event, and join it before closing the store. Shutdown waits for in-flight work without a timeout that could reintroduce use-after-close; the stdio flag is restored even if cleanup raises.

Closes #1121.

Validation follows a reproduce/fix/regression approach:

  • The reporter's deterministic event-gated reproduction failed on unchanged staging (2 failed, 2 post-processing cases skipped). The new suite passes normal and exceptional transport shutdown plus unavailable/failed watcher startup: 6 passed, 4 skipped.
  • Applied the lifecycle changes in an isolated checkout of fix(mcp): run post-processing during auto-watch updates #1108's 09dca915: 10 passed, including startup and batch post-processing with both returning and raising transports. This PR does not include fix(mcp): run post-processing during auto-watch updates #1108's independent FTS changes.
  • Existing main/incremental/watch/stdio suites: 258 passed, 2 skipped, with two Windows symlink-privilege failures. Those failures also occur on unchanged staging. An initial native run crashed on both the branch and unchanged staging; the diagnostic rerun completed with only those two privilege failures.
  • Ruff, mypy (--platform linux, matching CI), and Bandit pass.

The regression retains the real watcher, handler and debouncer and replaces only external boundaries. It checks that close occurs once after all workers exit and holds operations past the watcher's short join timeout. No real SQLite connection is opened by that reproduction.

GitHub CI on 68ffef3: 17 successful checks, including Python 3.10–3.13 (5,051 passed per version, 86.65–86.69% coverage), browser tests, MCP end-to-end tests on Linux/macOS/Windows, and native Windows resource/daemon tests. The manual upgrade-path check is skipped as configured. No merge conflicts with staging.

@github-actions

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.65 (MEDIUM) — 37 changed function(s)/class(es), 45 affected flow(s), 1 test gap(s)

Risk-scored changes

Risk Level Symbol Location Tested
0.65 medium code_review_graph/incremental.py::start_watch_thread code_review_graph/incremental.py:3337 yes
0.55 medium code_review_graph/main.py::main code_review_graph/main.py:1454 yes
0.50 medium tests/test_mcp_watch_store_shutdown.py::Harness.refuse_sqlite tests/test_mcp_watch_store_shutdown.py:137 (test)
0.40 medium tests/test_mcp_watch_store_shutdown.py::_Trace.record tests/test_mcp_watch_store_shutdown.py:42 (test)
0.40 medium tests/test_mcp_watch_store_shutdown.py::Harness._use tests/test_mcp_watch_store_shutdown.py:173 (test)
0.35 low tests/test_mcp_watch_store_shutdown.py::_Trace tests/test_mcp_watch_store_shutdown.py:37 (test)
0.35 low tests/test_mcp_watch_store_shutdown.py::InstrumentedStore tests/test_mcp_watch_store_shutdown.py:52 (test)
0.35 low tests/test_mcp_watch_store_shutdown.py::InstrumentedStore.enter tests/test_mcp_watch_store_shutdown.py:64 (test)
0.35 low tests/test_mcp_watch_store_shutdown.py::InstrumentedStore.leave tests/test_mcp_watch_store_shutdown.py:68 (test)
0.35 low tests/test_mcp_watch_store_shutdown.py::FakeObserver tests/test_mcp_watch_store_shutdown.py:82 (test)

Affected execution flows

  • process — criticality 0.74, 538 node(s) across 14 file(s)
  • _run — criticality 0.74, 565 node(s) across 16 file(s)
  • build_or_update_graph_tool — criticality 0.73, 619 node(s) across 24 file(s)
  • refactor_tool — criticality 0.72, 159 node(s) across 12 file(s)
  • main — criticality 0.72, 925 node(s) across 40 file(s)
  • ...and 40 more affected flow(s)

Test gaps

  • code_review_graph/incremental.py::_run (code_review_graph/incremental.py:3355)

Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are reported for the watcher shutdown-ordering change.

No open issues 🎉

What changed in this PR

Fixes #1121 by ensuring MCP auto-watch finishes in-flight work before its GraphStore is closed, preventing use-after-close during shutdown.

Changes:

  • Retains the watcher thread, signals it to stop, and joins it without a timeout before closing the store.
  • Adds an optional stop event to start_watch_thread() while preserving positional argument compatibility.
  • Adds shutdown-ordering regressions for returning and raising transports, plus unavailable or failed watcher startup.
File Description
tests/​test_mcp_watch_store_shutdown.py Adds event-gated lifecycle tests, with conditional post-processing coverage.
code_review_graph/​main.py Orders shutdown as stop → join → close and restores the stdio flag even if cleanup raises.
code_review_graph/​incremental.py Accepts and forwards an optional watcher stop event.

Review effort: Balanced

@tirth8205 tirth8205 closed this pull request by merging all changes into tirth8205:staging in 0160eb0 Nov 6, 2026
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
… post-processing

Both PRs change start_watch_thread and main(). Keep the callback and the stop
event. Tests that ended the watcher with a patched time.sleep now use the stop
event, because the loop no longer sleeps when one is given.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 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.

[Bug]: MCP auto-watch can close GraphStore while its watcher is still active

3 participants