Skip to content

Enforce MCP readiness caller deadlines - #711

Open
baron wants to merge 2 commits into
mainfrom
wt/tip-ci-stability-post-headless
Open

Enforce MCP readiness caller deadlines#711
baron wants to merge 2 commits into
mainfrom
wt/tip-ci-stability-post-headless

Conversation

@baron

@baron baron commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Root cause

MCPToolCatalogReadiness.awaitReady(timeout:) computed a caller deadline, but both creators and joiners awaited the shared CheckAttempt.task.value directly. If scopePresenceOperation or windowStateOperation stalled, control never returned to the deadline checks, so callers could wait forever beyond their requested timeout.

Fix

  • add a per-attempt completion broadcaster with caller-local deadline and cancellation waiters
  • let an expired or cancelled caller remove only its own waiter without cancelling or unregistering the shared readiness task
  • keep one coalesced scope query for all callers
  • resolve remaining waiters and remove activeChecks only when the shared task settles, guarded by the attempt UUID
  • add a deterministic sticky-gate regression test proving a short waiter returns false while the shared query remains held, query count stays at 1, a late waiter joins the same check, and surviving waiters drain successfully after release

Validation

  • make dev-test FILTER='RepoPromptTests.ToolCatalogSnapshotTests/testReadinessCallerDeadlineDoesNotCancelSharedCheck'
  • make dev-test FILTER='RepoPromptTests.ToolCatalogSnapshotTests/testReadinessCoalescesLightweightScopeQueriesForOneTenAndOneHundredWaiters'
  • make dev-format (0/1449 files formatted on final pass)
  • make dev-lint
  • make dev-swift-build PRODUCT=RepoPrompt
  • .agents/skills/rpce-contribution-check/scripts/preflight.sh commit
  • .agents/skills/rpce-contribution-check/scripts/preflight.sh push

@baron

baron commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

Triage: the caller-local readiness deadline/shared-check ownership design is coherent and the current-main textual merge is clean. The historical failure was outside the two-file diff. As author I cannot self-approve; please obtain non-author exact-head review and refresh current-base checks.

@baron

baron commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Current-main recheck on exact head 68bfc3bdde1572270f862a41dabb0e1527b1f7c1: the caller-local deadline/shared-readiness implementation remains coherent and the synthetic integration is clean. The branch still needs fresh current-base hosted CI and a non-author exact-head approval before merge. The authenticated maintainer is also the PR author, so I am recording this as a comment rather than self-approving.

morluto commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Audit disposition — residual liveness blocker (2026-08-14)

Caller-local deadlines now return correctly, but a permanently stalled shared readiness task remains in activeChecks until it settles. Every future caller for that key joins the same poisoned attempt, waits to its own deadline, and returns false; the service never initiates a fresh readiness check.

Please give the shared attempt an owner deadline or retirement rule. A caller timing out should not cancel healthy shared work, but a check that never settles must eventually be fenced, removed, and replaced. Add a deterministic regression with a permanently held first operation and repeated late callers proving that a later generation can recover.

morluto commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Deep-review assessment — 2026-08-14

Disposition: block on shared-attempt retirement. Caller-local deadline/cancellation waiters correctly prevent one caller from awaiting task.value forever, and timing out one waiter should not cancel useful shared work. However, if the underlying readiness operation is permanently hung, the CheckAttempt remains in activeChecks forever. Every future caller joins the same poisoned attempt and only experiences its own timeout; the system never retries readiness.

Give the shared attempt an owner/hard deadline or a retirement generation. After that boundary, detach/ignore any late result, remove the attempt by UUID, and allow a subsequent caller to create a fresh check. Add a test where the first operation never releases and a later generation succeeds.

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