fix(protocol): ignore late progress for recently completed tokens - #2586
fix(protocol): ignore late progress for recently completed tokens#2586qiushui7 wants to merge 2 commits into
Conversation
🦋 Changeset detectedLatest commit: 1e7b8b6 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
|
Validated — and the core fix does what it should, but there's a second door onto the same race that this doesn't close yet. I built from the PR head ( The gap:
|
|
Thanks — great catch. I’ve pushed a follow-up in The update:
The focused protocol suite now passes 140/140 tests, the broader non-Windows-stdio suite passes 2,748/2,748 tests, and the full upstream CI matrix is green on the new commit. If you’re able to rerun your deterministic control/abort/timeout harness against |
|
Confirmed on Same harness as before, unchanged, rebuilt from the new PR head (verified I also reproduced your focused-suite number independently rather than taking it on trust: On the implementationExtracting private _cleanupProgressHandler(progressToken: number): void {
if (this._progressHandlers.delete(progressToken)) {
this._rememberCompletedProgressToken(progressToken);
}
}Worth noting for future readers: after this commit there is exactly one raw You also got the task nuance right, which was the part I was least sure about when I raised it. Coverage nowBetween the two commits the original issue is closed for: normal completion, caller abort, request timeout, The 64-entry bound still looks comfortable. Adding the abort/timeout paths does raise the fill rate — every cancelled request now consumes a slot where before only completions did — but for a stdio client the in-flight window is nowhere near that. Nothing outstanding from my side; happy to see it marked ready for review. The |
|
Correction to my own comments, before it settles into the record: I misattributed the original repro to I introduced the name in my first comment here; it isn't in #2580, which describes a generic server ("Server emits N progress notifications then the result", tool named Two consequences:
If a real-server confirmation is still wanted before this goes ready-for-review, the honest version is a purpose-built stdio server that emits N progress notifications immediately followed by the result — essentially the repro from #2580 — rather than any existing server of mine. Happy to build that if it's useful, though I'd still argue the deterministic harness is the stronger evidence for exactly the reason raised earlier in this thread: it removes the timing dependence instead of relying on losing a race on a loaded machine. |
|
Thanks for the thorough validation and for correcting the server attribution. Agreed that the deterministic in-memory coverage is the stronger validation here, so I won’t treat a real-server reproduction as a blocker. With the request lifecycle paths covered and CI green, this is ready for maintainer review from my side. |
Summary
Context
Several request lifecycle paths remove a registered progress handler before an already-written progress notification can be dispatched.
_onprogressthen treats the previously valid token as unknown and callsonerror.This change remembers a bounded set of recently finished progress tokens whenever a registered handler is retired. It covers normal responses, caller aborts, request timeouts,
maxTotalTimeout, and terminal task cleanup without delivering stale progress. Tokens that were never registered still take the existing error path.Addresses #2580.
Validation
npm run checknpx vitest run test/shared/protocol.test.ts— 140 tests passednpx vitest run --exclude test/client/stdio.test.ts --exclude test/e2e/scenarios/stdio.test.ts— 2,748 tests passednpx tsc -p tsconfig.prod.jsonnpx tsc -p tsconfig.cjs.jsonThe two excluded stdio suites depend on Unix process and signal behavior that is not available in the local Windows environment. The upstream Linux CI matrix runs them on every pushed commit.