Skip to content

fix(lcm): preserve retry backoff across dirty invalidation - #4808

Open
ScriptedAlchemy wants to merge 1 commit into
masterfrom
fix/4481-lcm-dirty-failure-backoff
Open

ScriptedAlchemy wants to merge 1 commit into
masterfrom
fix/4481-lcm-dirty-failure-backoff

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Root cause and scope

Refs #4481 — partial retry-loop repair; not issue acceptance. This PR fixes a distinct LCM convergence redrive path on the session store. It does not assert the original macOS idle CPU target or 24-hour store growth is resolved.

A failed retained-summary invalidation can leave a row in lcm_summary_convergence_dirty_raw (the raw revision remains genuinely dirty). In record_outcome, any such row overrode a retryable, unavailable, or permanent outcome with pending, reset failure_count, and discarded next_attempt_at_ms. The next daemon convergence page therefore immediately retried the same deterministic failure rather than honoring the session's durable retry/parking outcome.

The raw-revision CAS already refuses settlement when a new revision arrives. Keep an old dirty row as pending only for successful/in-progress (current/pending) outcomes. For failed outcomes, preserve the retry deadline or terminal parking until an actual new raw revision increments the generation and rearms the queue through the existing trigger.

Behavioral regression coverage

  • Dirty invalidation with a retryable storage failure retains its deadline; a second failure lengthens the deadline rather than hot-looping.
  • Reopening the same SQLite store preserves the deadline and failure count.
  • A fresh raw revision requeues promptly and rejects settlement from the stale generation.
  • unavailable and permanent outcomes park despite outstanding older dirty rows, but a new raw revision unblocks them.
  • Successful/in-progress settlement still cannot falsely report complete while dirty invalidation is owed.

Two files only: crates/tracedecay-lcm/src/summary_convergence.rs and its existing crate behavioral tests. No changes to schema, dependencies, policy thresholds, or generated surfaces.

Verification and limits

  • Independently reviewed the exact two-file Git object diff before publishing.
  • A SQLite predicate reproduction of the old vs fixed settlement shows pending/0/0 before and retryable/1/100000 after for identical dirty input, but this is not a Rust test or macOS daemon benchmark.
  • Bazel and macOS daemon are unavailable in the authoring runtime. New Rust tests have not executed here; hosted Bazel CI on the exact PR head must be checked. No cargo command was used.

Separate owners / acceptance

No overlap with #4793 projection batching, #4798 retention GC, or #4799 doctor reporting. No work moved through held draft #4776, Kev/decision-model branches, or release #4763.

#4481 stays open until the full idle-daemon CPU, retry-convergence and 24-hour bounded-growth acceptance is reproduced on master.

Keep retryable and terminal outcomes durable when an earlier raw revision
still has invalidation work; only new revisions can rearm those failures.
Cover retry deadlines across restart, terminal parking, recovery on new
raw input, and stale-generation refusal.

Refs #4481
@changeset-bot

changeset-bot Bot commented Nov 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ef7d7bf

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

This branch has not been deployed

No deployments
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.

1 participant