Skip to content

fix(code-index): hold the head-open claim across the clone successor copy - #1863

Merged
ScriptedAlchemy merged 1 commit into
masterfrom
fix/clone-successor-state-race
Sep 19, 2026
Merged

ScriptedAlchemy merged 1 commit into
masterfrom
fix/clone-successor-state-race

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

The redundancy and similar tools still answered search_failed (retryable: false) on the first try after a generation bump, even with the discard and classifier fixes from #1848 (run 35455290631, graph_query_test.rs:1621).

Root cause: open_published_text_artifact parked the slot at CloneSuccessorPending before begin_clone_successor copied the prior lexical artifact, with the slot lock released. advance_artifact_text_serving leaves its park loop on that state, so a concurrent wake took a second HeadOpening on top of the running open and both drove the same clone staging database. The open that resolved second found the slot reset and failed with Contract("clone-successor retry requires an active head-open claim"), which the executor's catch-all maps to a non-retryable search_failed. That is also the no such table: clone_successor_state symptom seen earlier: one open dropped the table under the other.

Fix: the head-open claim spans the copy. The retry marker is parked only when the begin fails, since a successful begin resolves the claim to BuildingCloneSuccessor anyway. One production hunk plus a test that drives four concurrent wakes from CloneSuccessorPending.

Evidence: journey pinned to 2 CPUs under load failed 10 of 20 before, 0 of 20 after. The new test caught the defect 3 of 10 runs with the fix reverted and passes 10 of 10 with it. fmt, clippy -D warnings on the crate, and commit lint are clean.

🤖 Generated with Claude Code

`HeadOpening` is the exclusive claim on one generation's text projection:
`advance_artifact_text_serving` parks every other wake while a claim is
live. `open_published_text_artifact` broke that claim from the inside. It
called `retain_clone_successor_retry` before `begin_clone_successor`, so
the slot became `CloneSuccessorPending` for the whole copy of the prior
lexical artifact, with the slot lock released. `CloneSuccessorPending` is
one of the states the park loop breaks out of, so a concurrent wake took a
second `HeadOpening` on top of the running open. Two wakes then drove the
same clone staging database, and whichever open resolved second found the
slot already reset by the other's claim.

The losing wake reported `Contract("clone-successor retry requires an
active head-open claim")`, which the clone lanes map to `Internal`, so
`tracedecay_redundancy` answered `reason_code=search_failed
retryable=false`. The earlier fix mapped `AuthorityUnavailable` to
`generation_unverified` on the assumption that the remaining refusals were
transient authority failures; they were this contract violation, and a
retryable verdict would only have hidden it.

Keep the slot in `HeadOpening` for the copy. A successful begin resolves
the claim to `BuildingCloneSuccessor` anyway, so the marker only mattered
when the begin failed: the owners installed just above would otherwise let
the next wake short-circuit on a plain `Idle` and never owe the successor
again. Park it on that path only.

Evidence: with the redundancy journey pinned to two CPUs under busy-loop
load, `graph_query_test::redundancy_pull_request_scope_shares_one_budget_and_resumes_changed_families`
failed 10 of 20 iterations before this change and 20 of 20 pass after. The
new scheduler test drives four concurrent wakes from
`CloneSuccessorPending`; without the fix it reports `lane authority is
unavailable: no such table: clone_successor_state`, the second wake having
dropped the table the first was still writing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: cacf79a

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-19T17:59:05.707357Z cacf79a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cacf79a8d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// The claim still owns `HeadOpening`, so this only
// parks the marker; the begin failure is the one
// worth reporting.
let _ = self.text_projection_build.retain_clone_successor_retry();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Propagate the retry-state contract failure

If retain_clone_successor_retry() observes anything other than HeadOpening—the exact ownership invariant this patch is intended to protect—it returns a Contract error, but this let _ discards that evidence and reports the unrelated begin_clone_successor error instead. In the Idle case, the claim guard also leaves the slot idle, so later wakes see ready owners and can permanently skip the owed successor. Propagate or combine the parking failure rather than suppressing it.

AGENTS.md reference: AGENTS.md:L152-L154

Useful? React with 👍 / 👎.

Comment on lines +2786 to +2790
return match self.begin_clone_successor(
descriptor,
prior,
sealed_identity,
source,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve backfilling status while holding the clone claim

When opening a published artifact without clone fingerprints, the owners are already ready while this corpus-sized copy runs under HeadOpening. clone_successor_progress() classifies HeadOpening as Idle, so concurrent dashboard/MCP freshness reads report the missing successor as Partial rather than Backfilling for the duration of the copy; the existing status test confirms that an idle missing successor maps to Partial. Keep the state untakeable while still identifying this as clone backfill, or teach the progress reader to distinguish this clone-opening claim.

AGENTS.md reference: AGENTS.md:L9-L12

Useful? React with 👍 / 👎.

@ScriptedAlchemy
ScriptedAlchemy merged commit 83d9a3c into master Sep 19, 2026
25 checks passed
ScriptedAlchemy added a commit that referenced this pull request Sep 19, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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