Skip to content

test(windows): guard clean MCP stdio startup - #2217

Closed
lorenzozanee wants to merge 2 commits into
DeusData:mainfrom
lorenzozanee:restore/pr-2182
Closed

lorenzozanee wants to merge 2 commits into
DeusData:mainfrom
lorenzozanee:restore/pr-2182

Conversation

@lorenzozanee

@lorenzozanee lorenzozanee commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a native Windows MCP stdio regression guard for #654. The guard runs a successful initialize/tools/list exchange with an isolated cache and runtime directory, captures stderr deterministically, and rejects the reported English or Spanish path-not-found diagnostics. The guard is registered in scripts/test-windows.ps1, and the stdio helper now joins its stderr reader on close so the captured output is complete.

Checklist

  • Every commit is signed off (git commit -s) — required, CI rejects unsigned commits (DCO, see CONTRIBUTING.md)
  • Tests pass locally (make -f Makefile.cbm test)
  • Lint passes (make -f Makefile.cbm lint-ci)
  • New behavior is covered by a test (reproduce-first for bug fixes)

Refs #654

Supersedes #2182(原PR分支已删,按原提交重建)

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@DeusData DeusData added maintainer-notes Internal observations and improvement notes windows Windows-specific issues priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 19, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thank you for preserving the startup diagnostics. This overlaps #2213, but this version also carries sibling-runtime and stderr-join coverage. Could you identify one canonical PR retaining those cases and ensuring temporary runtimes are cleaned up on failures? We will keep both open until that handoff is clear; no duplicate closure or extra routine rebase is being requested.

@DeusData

Copy link
Copy Markdown
Owner

Thank you for this — a native Windows MCP stdio guard for #654 is valuable, and the details here are the ones that matter: an isolated cache and runtime directory, deterministic stderr capture, and rejecting the diagnostic in both English and Spanish rather than assuming an English-locale runner.

First, a housekeeping question. This and #2213 are the same guard, opened thirteen seconds apart. This one looks like the fuller version — +59 vs +57 in tests/windows/test_mcp_stdio.py, plus tests/windows/mcp_stdio.py, plus the Spanish diagnostic handling. I have asked on #2213 which you would like to keep; my guess is this one, but it is your work and your call, so I will not close either until you say.

One real blocker: the dco check. Your commits carry no Signed-off-by trailer — the message is a headline with an empty body, so there is nothing for the check to parse. (Not the blank-line trap, where a sign-off sits outside the trailer block and git's parser ignores it while grep still finds it; here there is genuinely no trailer.)

git commit --amend -s          # single commit
git rebase --signoff origin/main   # several
git push --force-with-lease

Two of the red checks are ours, not yours:

  • test / test-msan fails on its Docker image build whenever apt.llvm.org is flaky.
  • test / test-windows-guards is known to redden PRs it has nothing to do with — confirmed on three unrelated ones.

Please ignore both. I track them separately and neither will block this.

On the Spanish diagnostic specifically: matching localized runner output is the sort of thing that usually gets discovered the hard way, months later, on someone else's machine. Thank you for getting there first.

@DeusData

Copy link
Copy Markdown
Owner

Thanks again for the Windows startup coverage. The outstanding coordination question is still which of #2217 and #2213 should carry the final guard, retaining deterministic stderr capture and the localized diagnostic case. Please confirm your preferred PR; the recorded sign-off request applies to the chosen branch.

@Shinken009 Shinken009 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.

Hi Martin and @lorenzozanee,

I'm following up as the reporter of #654. Thank you for the Windows regression coverage and for keeping the stderr/localized cases in scope.

I checked this PR at 193c60d66db7eb36c58a7d0803d3936f5dae1d70. There is one small cleanup gap related to the September 19 follow-up: cache + "-runtime" is outside the directory owned by TemporaryDirectory, so it is not removed when that context exits. I reproduced leftover runtime lock files after an exception injected immediately after a successful native initialize.

The inline suggestion puts cache and runtime as siblings under one owned temporary root. It changes only this test file (4 added lines, 2 removed), preserving the existing shared stderr-reader join, English/Spanish diagnostic checks, MCP exchange and daemon-stop sequence.

Validation of this exact delta

  • 13 supplemental simulated-lifecycle checks: the candidate passed all 13, with no errors or skips. The unmodified PR passed 4 and failed 9 related cleanup/ownership assertions; those are not nine separate product defects.
  • Native Windows v0.12.1, controlled failure: the original guard left its runtime; the candidate removed both directories. The injected exception remained visible. Both runs completed real daemon stop with code 0 and frontend exit 0.
  • Two normal candidate runs with the official, unmodified v0.12.1 binary: valid initialize/tools/list responses, 17 tools, empty stderr, frontend and guard exit 0.
  • Historical diagnostic control: successful MCP responses and frontend exit 0, but guard exit 1 on the Spanish path-not-found message, as intended.
  • Patch application and reversal were checked byte-for-byte against this head.

Native runs used fresh private directories and the same external UI-disabled safety fixture for both variants; that fixture is not in the suggestion. No indexing was requested. Monitoring recorded no forced kills or remaining MCP processes; binary/client-profile hashes and ancestor ACLs were unchanged.

This is a test cleanup improvement, not a production runtime fix, and I have not run the full Windows suite, repository-wide lint or hosted CI. Simulated stop failures/timeouts are not evidence that a real locked or unresponsive daemon can always be cleaned up.

I'm offering this here as an incremental suggestion, not opening a competing PR or choosing which of #2213/#2217 you should retain. It can follow whichever branch you agree on. I have not changed either branch or its sign-off history.

I hope this helps close the remaining cleanup point. Thank you both for your work.

AI assistance was used for the investigation, proposed change and write-up.

Comment thread tests/windows/test_mcp_stdio.py Outdated
Comment on lines +21 to +22
with tempfile.TemporaryDirectory(prefix="cbm-mcp-stdio-") as cache:
runtime = cache + "-runtime"

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.

The runtime currently sits outside the directory owned by the temporary context. Native failure injection confirmed that its lock files remain after daemon stop. Sharing one owning root keeps cache/runtime as siblings while giving both the same cleanup lifetime; the existing os.makedirs(runtime) stays immediately below this replacement.

Suggested change
with tempfile.TemporaryDirectory(prefix="cbm-mcp-stdio-") as cache:
runtime = cache + "-runtime"
with tempfile.TemporaryDirectory(prefix="cbm-mcp-stdio-") as work:
cache = os.path.join(work, "cache")
runtime = os.path.join(work, "runtime")
os.makedirs(cache)

@DeusData

Copy link
Copy Markdown
Owner

Thank you @Shinken009 for the focused cleanup suggestion and the clear native-Windows evidence and limits, and @lorenzozanee for the startup guard. Keeping cache and runtime under one owned temporary root addresses the reported test-cleanup gap without widening scope. We still need to settle which of #2213/#2217 carries the final guard and review the suggestion there. Sorry for the delay on our follow-up—I’ll follow up soon.

…root

The runtime dir was a sibling of the TemporaryDirectory (cache + "-runtime"),
so it was never removed and its daemon lock files stayed in %TEMP%. Create
cache/ and runtime/ under one owned temp root so both share its cleanup
lifetime, including on failure. Refs DeusData#654.

Co-authored-by: Shinken009 <[email protected]>
Signed-off-by: Martin Vogel <[email protected]>
@DeusData

Copy link
Copy Markdown
Owner

Thank you @lorenzozanee for this guard. You got the parts that matter right: an isolated cache and runtime directory so the check never touches a real install, joining the stderr reader on close so the captured output is complete, and checking for the path-not-found message in both English and Spanish instead of assuming an English-locale runner.

We added one small commit on top of your branch (76adece) that applies @Shinken009's inline suggestion from Oct 22. Thank you, @Shinken009, for the careful native-Windows check and the precise fix. The runtime directory used to be created next to the TemporaryDirectory (cache + "-runtime"), so it was never removed when the context exited and its lock files stayed behind in %TEMP%. Cache and runtime now live as two subdirectories under one owned temporary root, so both are cleaned up together, including when the test fails. Nothing else changes: same MCP exchange, same daemon stop, same diagnostic checks. We are treating this PR as the canonical one of the two, since it carries the fuller version.

One step only you can do: dco stays red because your commit 193c60d has no Signed-off-by line, and we cannot add a sign-off on your behalf. Could you pull our commit and sign off both commits?

git pull --ff-only
git rebase --signoff HEAD~2
git push --force-with-lease

Once dco is green we can move this forward. Thanks again to you both.

@DeusData

Copy link
Copy Markdown
Owner

Thank you, @lorenzozanee, for the Windows startup guard, and thank you again, @Shinken009, for the cleanup fix and the native-Windows checks behind it.

The parts you got right are the parts that make this guard trustworthy: an isolated cache and runtime so it never touches a real install, joining the stderr reader before the output is inspected so a late message cannot slip past, and checking the Spanish message as well as the English one instead of assuming an English-locale machine.

It has now landed in #2952 (merge ff812bf), with both of you credited as co-authors on the commit. We took that route because the dco check needs a sign-off on the original commit that only its author can add. On top of your version and the one-temp-root cleanup, the guard now fails setup if the stderr reader never finishes, instead of passing on partial output, and it also rejects any raw, non-log line on stderr, so a message in the next language is caught too. It runs in the Windows guards job on every pull request.

Closing this one in favor of #2952. #654 itself stays open for a check against a released binary. Thanks to you both.

@DeusData DeusData closed this Nov 11, 2026
taggedzi pushed a commit to taggedzi/codebase-memory-mcp that referenced this pull request Nov 12, 2026
Adds a native Windows guard for DeusData#654: a successful MCP initialize +
tools/list exchange, run against an isolated cache and runtime directory,
must leave nothing on stderr but the server's own structured log lines.

- tests/windows/test_mcp_stdio.py: the guard. The English and Spanish
  path-not-found messages reported in DeusData#654 are named cases; any other
  non-empty stderr line that is not a structured "level=<name> msg=<event>"
  record fails as well, so the same leak on a machine in another language
  is caught without listing its translation. The log format is pinned to
  text so an inherited CBM_LOG_FORMAT=json cannot change the verdict. Cache
  and runtime live under one temp root, so both are removed with it, also
  on failure, after the daemon is stopped.
- tests/windows/mcp_stdio.py: close() joins the stderr reader, and the new
  stderr_complete() reports whether the reader reached EOF. The guard reads
  stderr only after it has; a reader still running after the server exited
  is a SETUP failure (exit 2), never a verdict on a partial capture.
- scripts/test-windows.ps1: registers the guard in the green guard list
  and documents it in the header.

DeusData#2213 was an earlier duplicate of the same check.

Refs DeusData#654.

Distilled from DeusData#2217.

Co-authored-by: lorenzozanee <[email protected]>
Co-authored-by: Shinken009 <[email protected]>
Signed-off-by: Martin Vogel <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer-notes Internal observations and improvement notes priority/normal Standard review queue; useful PR with ordinary maintainer urgency. windows Windows-specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants