Skip to content

fix(lcm): retry timed-out summarizers without a binding change - #4526

Merged
ScriptedAlchemy merged 7 commits into
renovate/modelcontextprotocol-client-2.x-lockfilefrom
fix/lcm-retry-transient-summarizer-failures
Oct 25, 2026
Merged

ScriptedAlchemy merged 7 commits into
renovate/modelcontextprotocol-client-2.x-lockfilefrom
fix/lcm-retry-transient-summarizer-failures

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Merge #4478 first, followed by #4526, #4510, #4524, #4489, #4485, #4527, #4528, #4530, #4531, #4529, #4534, and #4541.

This PR is number 2 of 13, based on #4478. Merge #4510 next.

#4515 has already merged into this branch.

Use merge commits. After merging a parent PR, change its child's base to master before merging the child. Auto-merge is disabled.

Cursor and Codex summarizer timeouts were reported as unavailable providers. LCM then parked the session without counting a failure or setting a retry deadline. A slow run could stop summary generation until the binding changed.

Timeouts now return the existing LcmError::DeadlineExceeded. Convergence counts the failure and retries through its durable queue and capped backoff. The persisted delay starts after the failed run finishes, and the scheduler calculates the remaining delay at the end of the page. Provider runtime no longer consumes the retry delay.

Missing or unconfigured providers still park. Other failure classifications, cancellation, and conditional queue updates keep their existing behavior.

The four new regressions use executable adapters and a registered session store. They cover Cursor and Codex timeouts, missing executables, persisted failure counts, retry eligibility, status, and successful summary publication without a binding change.

Fixes #4522.

Validation

Local Rust builds and tests used Cargo with the pinned nightly toolchain.

  • Before the fix, the two timeout regressions failed with unavailable or pending outcomes. Both missing-executable controls passed.
  • After the fix, all 4 new regressions passed. The timeout test covers both providers. Its baseline run stopped at the first Cursor assertion.
  • The affected LCM selection passed 63 tests, with none failed or ignored.
  • The first session-runtime run passed 165 tests. Four profile fixtures failed because the store authority rejects the cloud machine's overlay filesystem. Those four passed with the same executable and TMPDIR on supported local tmpfs. All 169 selected tests therefore passed, with none ignored.
  • One existing test was excluded from both selections: lcm_effects::tests::refresh_begins_at_the_committed_frontier_after_background_summaries_publish. test flake: refresh_begins_at_the_committed_frontier_after_background_summaries_publish times out under load #4518 and PR test(session-runtime): keep fake summarizer under default budget #4521 track that flake.
  • Rustfmt, whitespace checks, and commit-message lint passed.

The recorded build command was:

cargo --config profile.test.package.asupersync.codegen-units=256 test \
  --locked --offline \
  -p tracedecay-session-runtime \
  -p tracedecay-rusqlite-runtime \
  --features tracedecay-rusqlite-runtime/test-runtime \
  --lib --no-run --message-format=json

The second package enables the existing native test-runtime bootstrap without manifest changes. The session-runtime executable from Cargo's artifact records ran with --test-threads=1, an isolated profile, and the global database disabled.

Compilation used one job, no incremental compilation, no test optimization or debug information, and 256 codegen units for asupersync. The fixture rerun changed no source or filesystem policy. Production timeout and retry limits remain unchanged.

Preserve provider timeouts as DeadlineExceeded instead of unavailable so
convergence counts the failure and retries through its existing backoff.
Keep genuinely missing and unconfigured providers parked.

Schedule retry deadlines from failure settlement and calculate wake delays
at the end of the page so slow attempts cannot consume their own backoff.

Cover configured Cursor and Codex timeouts, durable retry timing,
same-binding recovery, and missing-executable behavior.

Fixes #4522
@changeset-bot

changeset-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1733323

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

ScriptedAlchemy and others added 3 commits October 24, 2026 23:23
The fake cursor-agent in the LCM effects tests ran under a 5 s provider
timeout, the smallest admitted value. On a loaded runner the /bin/sh child
is starved past 5 s, the provider kills it, and the session is parked as
cursor_agent_unavailable until the summarizer binding changes. The test then
waits out its 30 s poll for summaries that can never publish.

Use the provider default budget so the stand-in is not killed by scheduling
delay. The polling waits are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* test(privacy): expect high-entropy object keys redacted in place

JSON and TOML documents whose keys read as high-entropy tokens are
withheld whole today. Pin the target behavior: the key becomes a
placeholder unique within its object, the values under it are redacted,
and passphrase-shaped secrets stay redacted in every position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(privacy): redact flagged object keys in place

A JSON or TOML object key that trips a credential or entropy detector
withheld the whole document, because the sanitizer had no way to rewrite
a key. Long identifiers used as keys (schema $defs type names, benchmark
target names, path keys) score above the entropy floor, so files such as
dashboard-contracts.schema.json were never indexed.

The span-reporting JSON and TOML parsers already give each key's byte
range. Replace a flagged key with a placeholder unique within its object
(TraceDecay-redacted-key-N), redact every scalar under it, and keep the
rest of the document byte-exact. Detection is unchanged: no token is
exempted. A document is still withheld when the key has no span (YAML)
or the rewritten text no longer parses as its format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(privacy): verify descendant and repeated key redaction

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@ScriptedAlchemy
ScriptedAlchemy changed the base branch from fix/lcm-summary-frontier-test-flake to renovate/modelcontextprotocol-client-2.x-lockfile October 25, 2026 01:32
@ScriptedAlchemy
ScriptedAlchemy merged commit 59243c2 into renovate/modelcontextprotocol-client-2.x-lockfile Oct 25, 2026
16 checks passed
ScriptedAlchemy added a commit that referenced this pull request Oct 25, 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.

lcm: one summarizer timeout parks a session until the summarizer binding changes

1 participant