Skip to content

fix: close out #1025 step 2 — the 2026-07-28 era on the packaged artifacts, a 2025-era backend on request, three leftover fixes - #1126

Merged
debugmcpdev merged 7 commits into
mainfrom
fix/1025-closeout
Nov 11, 2026
Merged

debugmcpdev merged 7 commits into
mainfrom
fix/1025-closeout

Conversation

@debugmcpdev

@debugmcpdev debugmcpdev commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Closes out #1025 step 2 after the five-PR stack merged (#1114–#1118). Nothing here changes how a debug session behaves; it finishes what the issue's own "done when" still asked for, fixes three siblings of the bugs fixed during the merge, and corrects what the docs and one tool description said.

Why

  1. Move to the v2 TypeScript SDK, then to protocol 2026-07-28 — two steps, v0.27 or later #1025 is not done on the packaged artifacts. Its "done when" names the Docker image and the npx bundle passing their smokes. They did, in the 2025 era only: nothing under tests/e2e/docker, tests/e2e/npx or the canary spoke 2026-07-28 to a packaged server.
  2. The proxies made the 2025 era invisible to sweeps. The dev proxy now negotiates with its backend, so against a current backend it always lands on 2026-07-28. Every /testdebugger and /testpublished pass would exercise only the new era, while most clients will still speak 2025-11-25 to 0.27.
  3. Siblings of the merge-time fixes. f1338709 stopped the idle-policy parser from logging a rejected environment value; the three MCP_HTTP_* parsers still did. 91a7e7f8 made the idle-expiry outcome per session; the outcome was still wrong for a session with nothing running.

What changes

The 2026-07-28 era on the packaged artifacts

  • createDockerMcpClient and createNpxMcpClient take protocol: 'legacy' | 'modern'. modern pins the SDK client to 2026-07-28 over a transport subclass: for its exact base stdio transport the SDK probes on a sibling process spawned from the same parameters, which here would be a second docker run --name <same>.
  • One new case each in docker-smoke-python and npx-smoke-python: the artifact answers server/discover, lists all 29 tools, and runs a Python breakpoint cycle with no MCP session behind it. The existing cases are untouched and stay on the 2025 era.
  • Canary. scripts/canary-smoke.mjs is a raw JSON-RPC client that opens with initialize; that stays. --era 2026-07-28 runs the same cycle opened with server/discover, each request carrying its envelope. canary.yml adds one such Python cycle per channel (npm, Docker), gated by the artifact's own version through scripts/canary-era-gate.mjs: skipped with a notice before 0.27.0, strict from 0.27.0, prereleases included — so the beta rehearsal runs the leg the final is waiting on. A version the gate cannot read is a usage error, never a skip. The Docker leg reads the synchronized shared-package version inside the pulled image, so npm and Docker dist-tags moving at different times cannot misclassify it.

DEV_PROXY_BACKEND_ERA

auto (default) negotiates as today; legacy opens with initialize, so a sweep through the proxy can exercise the 2025 era against a server that serves both. Any other value refuses to start, naming the variable. dev_server_status already shows the era in force.

Fixes

  • MCP_HTTP_* warnings name the rejected setting and the default in force, not the value (the rule of f1338709).
  • Idle-expiry outcome closed. A session the policy removes that had no running program — never launched, or already over — used to be recorded as "its program was ended", or as "released … keeps running" under an attach root. It now answers "It had no running program by then." The set is read when the policy decides, so a child that ends during the cascade is still ended, as 91a7e7f8 pinned. A child an earlier detach released stays released. The sentence also states the idle time in the window's unit.
  • restart_debugging description said "Not available for attach sessions". A Flutter session hot-restarts in place, attached or not; the description now says so (24 tool-list snapshots move by that one sentence).

Provenance and docs

Evidence

Check Result
tests/e2e/npx/npx-smoke-python.test.ts 4/4, the 2026 case included (packed tarball, installed globally)
tests/e2e/docker/docker-smoke-python.test.ts 4/4, the 2026 case included (image built from this tree)
Canary driver, local build PASS in both eras (Python, raw JSON-RPC)
Canary driver, image built from this tree PASS in both eras
Canary driver, published 0.26.0, --era 2026-07-28 FAIL -32601 Method not found — the leg can fail
…the same with --artifact-version 0.26.0 skipped with the notice, exit 0
…the same with --artifact-version 0.27.0-beta.1 FAIL — a prerelease is held to it
…with --artifact-version latest usage error, exit 2
Canary driver, published 0.26.0, default era PASS — the 2025 leg is unchanged

Every behaviour change was written test-first; the red runs failed at the assertion they were written for.

Calls I made

  • The closed outcome is decided when the policy decides, not at each session's own close. The plan said per-close. Per-close would have turned 91a7e7f8's "a child that ends while an earlier close waits is ended" into closed; that child was running when the policy came for the tree.
  • The new DEV_PROXY_BACKEND_ERA error does not quote the value, unlike its two neighbours in backend-env.mjs, which do and are pinned to. I followed the newer rule for new code and left the neighbours alone.
  • One Python cycle per channel is the canary's 2026 leg, not one per language: the era is a property of the server's front door, and Python is the leg with a real adapter on every platform.
  • changelog.d/1025-idle-policy.added.md was amended rather than a fixed fragment added: the policy is unreleased, so no reader ever saw the old wording.

Review

One independent review of the whole diff before the push: no critical or important findings, five minor.

  • Applied (8d21f7a2): a test for the mixed tree (a launch root that had already ended, its child still running: closed and ended); a comment that a detached attach root reads closed beside its released children.
  • Follow-up fixes (e5e39e7): the Docker canary reads the version from the pulled image rather than the npm registry, removing the publication race; the modern artifact smoke accepts a successful pending:true launch and uses a bounded wait_for_stop before reading locals. Regression cases cover immediate and delayed stops, timeout, and early exit.
  • Not applied: rounding the idle time to the nearest minute (the sentence rounds down, so it never claims more idle time than there was, and never less than the window); making the smoke's tool-list comparison order-independent (server-tool-list-snapshot.test.ts already pins that tools/list is in TOOL_NAMES order).

The reviewer had no shell, so it read the tests and did not run them; the runs in the table above are mine.

Not in this PR

  • The mirror table in docs/tool-reference.md lacks C/C++, COBOL and Dart rows; filling it needs a VS Code measurement.
  • trackAll() in the proxy's subscription relay still mutates state outside the queue. It is reachable only as the front client leaves, when the proxy exits.

🤖 Generated with Claude Code

cynarlab and others added 6 commits November 11, 2026 14:11
…ue (#1025)

The three HTTP reaper parsers quoted the rejected environment value in
their warning, so a secret pasted into the wrong variable, or a value
with a line break, reached the server log. They now name the variable
and the default in force, the rule the idle-policy parser already
follows.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
#1025)

A session the idle policy removed with nothing running in it (never
launched, or its program already over) was recorded as "its program was
ended", or as "released ... keeps running" under an attach root. The
record gains a third outcome, closed, and the answer says "It had no
running program by then."

Which sessions those are is read when the policy decides to close the
tree: a child that ends while the cascade is running was alive at the
decision and stays "ended". A child an earlier detach released stays
"released". The sentence also states the idle time in the unit of the
window.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…the backend (#1025)

The proxy negotiates the era with its backend, so against a current
backend it always lands on 2026-07-28 and nothing driven through it
exercises the 2025 era most clients still speak. DEV_PROXY_BACKEND_ERA
is auto (default, negotiate) or legacy (open with initialize); any other
value refuses to start, naming the variable and not the value.

Also cites modelcontextprotocol/typescript-sdk#3133 beside the
BackendStdioTransport workaround it explains.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…rotocol 2026-07-28 (#1025)

The packaged-artifact smokes only ever spoke the 2025 era. The Docker
and npx helpers take protocol: 'modern', which pins the SDK client to
2026-07-28 over a transport subclass (the base class probes on a sibling
process, a second docker run with the same name); one new Python case in
each proves discover, the full tool list and a breakpoint cycle. The
existing cases stay on the 2025 era.

canary-smoke.mjs gains --era 2026-07-28 (server/discover, then the same
cycle with the per-request envelope) and canary.yml one such Python
cycle per channel, gated on the artifact's own version by
canary-era-gate.mjs: skipped with a notice before 0.27.0, strict from
it, prereleases included; an unreadable version is a usage error.

Measured: the 2026 cycle fails on the published 0.26.0 (-32601) and
passes on this tree's build and image; the 2025 cycle passes on both.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…ee survey corrections (#1025)

The restart_debugging description said "Not available for attach
sessions"; a Flutter session hot-restarts in place, attached or not
(24 tool-list snapshots move by that sentence).

session-tree.md: M2 PR 2 merged as #1096; the Ruby and CodeLLDB survey
rows say where a re-read of the engine's source disagrees with them
(the debug gem's accept serves the inherited socket first; CodeLLDB
1.12 has codelldb.start_debugging). Both unmeasured.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
… image leg can false-fail (#1025)

Review follow-ups, no behaviour change: a launch root that had already
ended while its child still runs records the root as closed and the
child as ended; a comment says a detached attach root reads closed
beside its released children; the canary's image step notes the one
window in which a scheduled run can read the new version for the old
image.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Read the Docker artifact version from its synchronized shared package,
not npm's independently moving dist-tag. Allow successful pending launches
to reach their breakpoint through wait_for_stop before inspecting locals.
Add regression cases for immediate, delayed, timed-out and exited launches.

@debugmcpdev debugmcpdev left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed the full diff and the surrounding idle-session close cascade. Fixed two test reliability findings in e5e39e7:

  • The Docker canary queried npm's mutable dist-tag to classify an already-pulled Docker image. During publication those versions can differ. It now reads the synchronized shared-package version from that image, with the workflow assertion updated.
  • The modern artifact smoke required start_debugging to return paused immediately, although a successful launch may return running with pending:true. It now uses a bounded wait_for_stop before reading locals. Regression tests cover immediate and delayed stops, timeout, and early exit, including cleanup on failure.

A dependency-free harness reproduced the delayed-stop failure before the fix and verified the corrected success/failure paths. Local cloning was unavailable due to a network error, so full repository validation is being performed by CI on this exact commit. Lint/typechecks, both MCP conformance lanes, CodeQL, and Go/Dart/Flutter/COBOL jobs have passed; the main Windows/Linux and container suites are still running. No other actionable findings from the review.

@debugmcpdev
debugmcpdev merged commit 785f199 into main Nov 11, 2026
16 checks passed
@debugmcpdev
debugmcpdev deleted the fix/1025-closeout branch November 11, 2026 22:10
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