Skip to content

ci: restore green master (gates, clippy, bench, all Linux partitions) - #1789

Merged
ScriptedAlchemy merged 19 commits into
masterfrom
fix/master-ci-green
Sep 18, 2026
Merged

ScriptedAlchemy merged 19 commits into
masterfrom
fix/master-ci-green

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Master CI has been red since the last green tip 61ca3b0 (2026-09-15); ~950 commits landed since, including #707. This branch repairs every failing job on master run 35360666279 (77c5504): Repository gates, Clippy, Benchmark harness self-tests, and the Linux partitions root-lib, root-sessions, root-journeys, root-transport, runtime, core-storage, core-contracts.

Each commit names the failure it fixes and the merged commit that caused it. Production changes are limited to four root-cause fixes; everything else is a stale expectation updated with the commit that made the new behavior intentional.

Production fixes

  • fix(global-db): refuse a vanished projection output rowfix(global-db): repair stale projection rows under current provenance #1775 + fix(global-db): restore a missing uniquely owned projection session #1781 together let a deleted projected message be recorded as a "repaired" session row that wrote nothing (converge_released_output_rendering only supersedes). Guard both repair arms on the output row still existing.
  • fix(code-index): retry a contended code-generation store lock — a publication refused with "code-generation store has an active owner" was never classified transient, so the worktree stalled until an unrelated wake (CI: 121 s timeout). Reproduced under taskset -c 0,1, 25/25 after.
  • fix(work): clamp TaskSession page size to the mounted budget — legal Work evidence requests above the profile's hydration budget (16) were refused permanently instead of served with a continuation.
  • ci: fix rustfmt drift, clippy doc lint, bench readiness slack — fmt drift in two files, doc_lazy_continuation from the prose pass in tracedecay-privacy, and a 0.2 s readiness window in the benchmark harness that a loaded runner can't meet.

Stale expectations (test-side only, each cites the intentional change)

  • search-eval query-fallback digests re-pinned after the extractor revision bumps in fix(code-index): move every extractor revision for the clone-body bound #1741/fix(clones): bound body bytes before tokenizing large literals #1784 (bisected; per-query ranking output byte-identical, only the sealed-generation identity moved).
  • partitioned codec digest/segments re-pinned onto extractor.rust.v10 (each file segment +1 byte for the revision string).
  • legacy-generation restore RSS proof now measures against a paged control instead of relying on a warm allocator; the guard still fires at 1.37x when evidence pages are retained.
  • Codex prepare probe pins a codex binary on the host search path (result was a property of the machine since 7bdc33d).
  • dashboard credential-gate assertion made case-insensitive after the prose rewrite in d73b315.
  • code-index-runtime scheduler tests: expect the typed AuthorityUnavailable text-budget refusal (fix(code-index): shrink text builds to available memory headroom #1782), select the trait declaration by exact owner after <Type as Trait> owners (878ae3e), seat crafted clone-backfill owners, poll for settled clone-index coverage (d86fd22), attribute probe receipts by arrival.
  • session_suite: update-side audit test now asserts the fix(global-db): repair stale projection rows under current provenance #1775 repair contract instead of the pre-fix(global-db): repair stale projection rows under current provenance #1775 refusal.
  • transport refresh journey: reassemble the over-budget search page through its retrieve handle, 96-file batch instead of 768, 25 ms polling instead of yield_now.
  • mcp work journey fixture gets 4 worker threads: sync exact-SQL reads on tokio workers self-deadlocked for the full 30 s idle-lease reclaim on 2 threads (CI lost that race every time; a real architectural follow-up, noted in the commit body).
  • fan-out journey: 8e7952f retired the only production federated query authority, so the TaskSession tail can never hydrate; the test again gates that tail on the authority being mounted and asserts the typed task_session/unavailable omission the conformance suite already pins.

Verification

  • Every previously failing test re-run locally at least twice; CI dispatches on this branch: 35378766990 (gates/bench), 35390928038 (all partitions green except root-journeys and runtime), 35396311891 (this tip).
  • cargo fmt --all -- --check clean; clippy --all-features --all-targets -- -D warnings clean on every touched crate.

Not fixed

  • advisory_runtime_acceptance::packaged_host_ingest_delivers_a_registered_advisory_cycle failed on the master run but not on later runs and could not be reproduced (5/5 local, 8/8 under 4-CPU contention). Two accounting defects that turn an already-projected cursor pass into accepted_for_replay (dropped projected count in projection_drain.rs, dropped exact_duplicates in cursor projection.rs) are documented for a follow-up with a reproducing test.

🤖 Generated with Claude Code

ScriptedAlchemy and others added 18 commits September 18, 2026 18:07
- cargo fmt drift in code_index_generations/locking.rs and lifecycle_lease.rs
- clippy::doc_lazy_continuation in tracedecay-privacy rules.rs (a prose pass
  had split a sentence across a lazy continuation and left a ////// line)
- benchmark harness: the dashboard HTTP-variant self-test gave the stub 0.2s
  to bind, which on a loaded runner timed out in dashboard_connect

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The pinned partitioned manifest bytes were measured at extractor.rust.v8.
Two revision bumps have landed since: fe58bba ("move every extractor
revision for the clone-body bound") took Rust to v9, and 941d908
("bound body bytes before tokenizing large literals") took it to v10.

The revision string is part of every sealed file segment, so the state
digest and all four segment digests move. v8 and v9 are the same length
but v10 is one character longer, which is the whole size change: each of
the three file segments grows by exactly one byte (11_070 -> 11_071,
5_170 -> 5_171, 6_278 -> 6_279) and the evidence segment, which carries
no per-file extractor revision, stays at 6_837. Each file segment was
confirmed to hold `extractor.rust.v10` exactly once.

format_revision is unchanged at 12 (set by e358627, before the last
pin), so this is an intentional extractor identity change, not container
drift or recording noise.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The guard compared the legacy restore's absolute peak-RSS growth against
half the on-disk generation, treating the paged restore that runs first
as a warm-up that leaves the allocator holding the arena a restored
generation needs. That only holds when the allocator keeps the freed
arena. On the CI runner it returns the pages, so the legacy probe faults
them in again and its "extra" cost is the whole restored generation:
paged grew 4276 KiB and legacy 4768 KiB, and the 4882432-byte legacy
figure failed a bound of half the 8641409-byte generation. The 492 KiB
that actually separated the two forms was far below the 1736866-byte
evidence segment, so nothing was being materialized.

Both forms issue the identical reads (300 whole file reads and 7 ranged
evidence reads): load_next_legacy_chunk streams an unpaged descriptor in
GENERATION_EVIDENCE_PAGE_MAX_BYTES_V1 chunks, so the production path is
correct and only the measurement was wrong.

Measure the difference instead. One discarded probe pays the process's
cold-start cost, then the paged restore of the same generation is the
control and the legacy restore's growth beyond it is the pre-paging
path's own cost. That cost must stay below the evidence segment, which a
materializing restore would hold whole. Verified by injecting a retained
copy of every evidence page: the guard fires at 1.37x the segment, while
the streaming restore measures 0.12x to 0.38x. The bound is tighter than
the one it replaces, which permitted 2.5x this segment.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7bdc33d ("clear LCM, proxy, codex, partial, rebuild reds") made
prepare_non_interactive_install return a typed DeferredUserAction when
Codex's own plugin CLI is absent, because Core apply can only drive
`codex plugin add` when the host binary is there. The outcome therefore
became a property of the machine: the test passed on a developer box
with `codex` on PATH and failed on CI runners, which carry none.

Install an executable `codex` on the host-program search path for the
duration of the test, the same seam the Gemini and Kiro lifecycle tests
use. Only host program resolution sees the fixture directory; the
process PATH is untouched, and the guard's own lock keeps a second
override from being installed while this one is held. The stub is never
executed, preparation only asks whether the binary resolves.

Verified hermetic by running the built test binary with a PATH that has
no `codex` on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
d73b315 ("drop em dashes and stock phrasing from prose") rewrote the
GitHubCredentialNotConfigured reason from "... for this profile and
repository - configure a token (or register ...)" to two sentences, so
the clause now starts with a capital: "Configure a token (or register
...)". The guidance the gate contracts to carry is intact; only the
sentence break moved, and the case-sensitive substring check broke on it.

Compare case-insensitively. The contract is that the gate names the step
the reader has to take, not where a sentence happens to break around it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The packaged query-fallback receipts drifted once every extractor revision
moved for the clone-body bound: c7eb62e (PR #1741) took Rust v8 to v9,
TypeScript/protobuf/SQL v4 to v5 and the rest v3 to v4, and 542d28c
(PR #1784) took Rust to v10. The extractor revision is part of the
extraction batch identity, so the sealed generation every candidate
binding names moves with it, and the fallback subpayload digest hashes
those bindings. Bisecting the packaged comparison over the range since the
last re-pin (3320ad4) lands on c7eb62e, whose only production change
is those three revision integers.

The ranking did not change. Comparing the packaged report at 3320ad4
against the current tip, every per-query row is byte identical: same first
useful rank, returned candidates, wrong-scope and forbidden hits, and
quality. Both partitions keep their exact conceptual-miss sets (10 train,
7 validation) and their mean reciprocal rank (476881 ppm train, 587222 ppm
validation). Only the provenance identity inside the receipt moved.

Re-pin both partition receipts, packaged::WORKLOAD_SHA256, and the
byte-pinned workload digest both search-eval bins assert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CI clippy runs `--all-targets --all-features -- -D warnings` and the crate
denies `clippy::all`, so `await_holding_lock` fails the gate on
`dashboard_freshness_does_not_join_a_clone_backfill_slice`. Holding the
clone-successor slot across the dashboard read is the scenario that test
exists to pin: the read must answer without joining the backfill that owns
the slot. Carry the same allow and rationale the two scheduler-guard tests
in this file already use.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
0ae9fad made the text-artifact reservation gate keep its typed detail
instead of collapsing every refusal into BudgetExceeded, and added a
pre-admission check that refuses with AuthorityUnavailable when the headroom
below the resident-memory watermark is under the requested minimum. It
updated three sibling expectations but not this one, so the clone-successor
refusal asserted a variant the production path no longer returns:

  left: Err(AuthorityUnavailable("text-artifact build needs at least
  134217728 bytes; 67108864 bytes are available below the resident-memory
  watermark"))
  right: Err(BudgetExceeded)

The test still requires a refusal, and still requires the V14 owners to stay
queryable and the successor to stay pending; only the variant moves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
878ae3e gave Rust trait-impl methods the owner `<Type as Trait>` so two
impls of one trait no longer collide. The unresolved-dispatch assertion
picked its expected trait method with `qualified_name.contains("Processor")`,
which now also matches `<Tripler as Processor>::process` and
`<Doubler as Processor>::process`. The first match by occurrence order was
an impl method, so the test demanded that a `resolve_trait_dispatch: false`
callee page contain an impl it also asserts must be absent.

Select the declaration by its exact owner. The graph already returned the
right edge: `src/lib.rs::Processor::process`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both clone-backfill tests build the "V14 ready, successor pending" owner on
a standalone scheduler and inject it into the mounted registry as
`text_generation`, leaving the registry seated on its own generation. The
worker only drives a retained text projection when the seated generation is
that text owner (`drive_retained = !owners_ready || (serving_matches_text &&
source_current)` in registry/mount.rs), so an unseated crafted owner is never
advanced and the pair asserted states the daemon cannot reach:

- expired_source_proof_reschedules_pending_clone_backfill waited out its
  10 s ceiling with pending_wake=Some(0) and the successor untouched.
- query_admission_serves_v14_while_clone_successor_is_pending compared the
  seat id to the crafted id, which cannot match: `captured_at` is part of
  the intake digest, so two captures of one checkout never mint one id.

Seat the crafted owner as well. The expired-proof test now settles in 0.8 s
instead of timing out, which is the successor pass the test exists to prove.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
d86fd22 made `clone_index_status` read the clone-successor slot with
`try_lock` so a freshness read never joins a running backfill; a busy slot
answers `Unavailable { "clone-index status is being updated" }`. That is the
right production answer, but the coverage test sampled the dashboard once
after the edit and demanded ready:

  the changed V16 artifact must return to ready: Some(Unavailable { reason:
  "clone-index status is being updated" })

`wait_for_dashboard_ready` gates on staleness and coverage, neither of which
tracks the successor slot, so the read raced the backfill of the republished
generation. Poll for the settled status instead. Every coverage and update
assertion is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The suppressed-probe assertion compared a receipt count taken just before
the probe with one taken 50 ms after, which charges the probe for any wake
that was already in flight. Since the seat stopped waiting for the clone
successor the mount leaves pending backfill, and each drain wake posts its
own Noop receipt, so the count grew inside the window (left: 3, right: 2)
with the extra receipt carrying a wake_micros from before the probe.

Settle the mount-era chain first, and attribute receipts by the arrival the
pass claimed rather than by list position. The assertion is stricter: a
probe-era receipt now fails wherever it lands in the list. Add
`pending_wake_micros_for_root` so a test holding only the checkout path can
see the pending-wake slot, as the scope variant already allows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A publication refused because another holder owns the code-generation store
lock left the worktree stale until an unrelated wake. The refusal is exactly
the class `is_transient_capacity_failure` documents: bounded shared capacity
already held, released by its holder without notifying this worktree. It was
not classified there, so the worker skipped its self-scheduled retry, and the
restored arrival sat in the pending-wake slot with no permit behind it.

distinct_stores_reconcile_in_parallel_under_bounded_admission caught it on a
loaded runner: the first worktree, released from its held scheduler lock, ran
one pass that failed with "the publication authority is unavailable:
code-generation store has an active owner", posted no receipt, and never ran
again, so the wait timed out at its 2 minute ceiling (observed in CI job
105663734109 at 121.07s). Under `taskset -c 0,1` it reproduced in about one
run in five, and passes 25/25 with the classification in place.

Both the refusal and the classifier now read one shared detail token so they
cannot drift apart.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`converge_released_output_rendering` supersedes an existing `session_messages`
row; it never inserts one. #1775 (c55058a) began recording every
`OutputCollision` for convergence and #1781 (b7c9b0d) added the
`row_missing` session arm, but `ProjectionRowsBatch` derives its session keys
from the message rows it found, so a deleted message row is reported as a
missing *session* row. The audit therefore recorded a repair that wrote
nothing, went green, and left the output permanently gone.

Record for convergence only when the output row is still there. A stale row is
still repaired (#1775) and a missing session row beside a present message row
is still inserted (#1781); a vanished output row is the hard failure both
commits promised.

The update-side test asserted the pre-#1775 refusal, so it now asserts the
intended contract: reopen succeeds and re-projects the tampered body.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`work_attempt_consumers_read_the_public_start_attempt_effect` leaves the second
attempt in flight and then reads it. The Work read handlers are synchronous:
`load_effect_dispatch` holds its tokio worker thread while waiting for the
exact-SQL transaction slot the in-flight attempt worker owns. On the fixture's
two worker threads the reader and that worker deadlock until the 30s
transaction-idle reclaim releases the slot.

Measured per tool call: `tracedecay_work_execution_history` took 30.0047s with
two worker threads and 12ms with eight, against its own 30s Work deadline
contract, so the journey resolved by a millisecond-wide race. CI lost it and
reported tool_dispatch_deadline_exceeded; a local 96-core run won it by 4ms.

Four worker threads carry the reader and the attempt worker, and the run drops
from 33.5s to 3.5s. The underlying blocking-read starvation is unchanged and
reported separately.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`background_refresh_and_reopen_report_only_servable_generations` could not
finish on a four-core runner for two independent reasons, neither of which was
the 90s budget.

The search page still crossed the MCP response budget after #1783 shrank it to
three results: 18,084 characters, of which the cursor and candidate provenance
are most. The answer is then a preview plus a `tracedecay_retrieve` handle, so
`wait_for_current_generation` never saw `code_generation` and spun until the
budget expired even though status already read current. Reassemble a truncated
response through its handle, the way an agent does and the way mcp_suite's own
helper already does; the page stays small for the common answer.

The 768-file batch indexed 98,304 symbols into 455 million lexical units and
645 MB on disk. On four cores that took ~61s to commit and then pushed the
reopen past the composition harness's own 20s publish gate, so a 400s budget
still failed: the journey could not complete at that size. 96 files keep the
refresh observable across many polls and every open inside its gate.

The wait loops also yielded rather than slept, issuing ~290 status calls a
second against the worker they were waiting for.

Verified on four cores (taskset -c 0-3, perf profile): 92s FAIL before, 31s
PASS after, 3/3 there and 3/3 unconstrained.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`WorkEvidenceRetrieveRequestV1::page_size` bounds evidence sources in the
Work page and validates up to MAX_WORK_ROOTED_EVIDENCE_SOURCES_V1 (100).
The TaskSession adapter passed it through as the per-attempt session
hydration page size and refused, permanently and unretryably, whenever it
exceeded the mounted authority's retrieval budget. The checked-in core
query policy caps max_hydrated_results at 16, so every legal request above
16 hydrated TaskSession as `Unavailable` with no way for a client to learn
the ceiling.

Clamp the per-attempt page size to the mounted budget instead. The budget
is still never exceeded, and a short page already reports partial coverage
plus a continuation, so the caller can page the rest. Zero stays a refusal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Until 8e7952f ("retire dense FastEmbed path for lexical/graph") this
journey returned early unless TRACEDECAY_DISTRIBUTION_FASTEMBED_FIXTURE
named an installed distribution package, because only the evaluated
federated profile that fixture activated could rank and hydrate
TaskSession anchors. That commit deleted the accepted-profile federated
authority, left project open mounting the checked-in core
exact/lexical/graph policy (a Fallback-mode QueryAuthorityV1), and removed
the fixture gate in the same change. QueryAuthorityV1::task_session_score_domain
serves only a Federated authority, and the only remaining federated
constructor in the tree is a test helper, so the tail this commit added
(wait_for_task_session_available) waited out its full 180s deadline on
every run and the journey has been unconditionally red on master since.

Restore the gate at the same boundary instead of asserting a lane no
mounted authority can serve: probe once, assert the typed `task_session`
`unavailable` omission that work_route_exposure_conformance already pins
in assert_task_session_unavailable, and skip the evidence tail. Everything
before it (fan-out, recovery, synthesis, physical restart, byte-exact
receipt preservation) keeps running, and the tail runs unchanged as soon
as a federated authority is mounted again.

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

changeset-bot Bot commented Sep 18, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1828d6e

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 18, 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-18T21:27:18.147388Z 7855fba 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: 7855fbacce

ℹ️ 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".

/// within milliseconds of this operation's own 30s deadline, so the journey
/// passed or failed by a race rather than by its contract. Provision the
/// threads the journey's own concurrency needs.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]

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 Fix the blocking Work read instead of adding workers

On a valid two-worker Tokio runtime, this test demonstrates that load_effect_dispatch blocks an executor thread while waiting for the transaction slot, causing the in-flight attempt and its reader to deadlock until the 30-second reclaim. Raising worker_threads only hides that production starvation; it can recur on two-core deployments or whenever concurrent blocking reads occupy all workers. Move the blocking wait off the async executor or remove the transaction-slot dependency rather than increasing the test's concurrency budget.

AGENTS.md reference: AGENTS.md:L114-L119

Useful? React with 👍 / 👎.

Comment on lines +1420 to +1422
) else {
return;
};

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 Keep independent handoff checks outside the TaskSession gate

With the production fallback authority described immediately above, this branch is always taken, so the remainder of mounted_fan_out_recovers_then_synthesizes_and_hands_off no longer tests the proximity route, handoff issue/redeem/replay behavior, or workflow retirement. None of those assertions consumes _task_session, so only the TaskSession-specific section should be capability-gated; returning here silently masks failures in the independent integrated tail.

AGENTS.md reference: AGENTS.md:L177-L178

Useful? React with 👍 / 👎.

Comment on lines +163 to +165
# The stub takes a moment to bind on a loaded runner;
# 0.2s left the probe stuck in dashboard_connect.
readiness_timeout=2.0,

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 Restore the bounded readiness timeout

Each malformed/empty/404 probe intentionally remains not ready, so OwnedDaemon::start waits for the entire deadline before raising; this change expands the three-case test from roughly 0.6 seconds to 6 seconds and masks slow stub startup instead of making startup deterministic. Synchronize on the stub binding its port before running the short typed-failure window rather than raising the timeout, as the repository explicitly forbids using larger timeouts to cover gate failures.

AGENTS.md reference: AGENTS.md:L177-L178

Useful? React with 👍 / 👎.

unchanged_reconcile_does_not_reactivate_the_serving_generation sampled a
receipt count right after the initial-generation wait and then asserted that
the receipt at that index was the overflow's Noop. The seat is published
mid-pass, so the mount's own receipt lands after the pass releases its
in-progress guard: on a loaded runner the baseline was taken at 0 and index 0
was the mount's Published receipt, not the overflow's (dumped receipts under
`taskset -c 0,1`: [Mount/Published, Overflow/Noop, BusyFollowUp/Noop]). Both
nextest tries failed that way in CI run 35390928038, and it reproduced 6 times
in 25 runs locally.

The list-position assumption is the stale part, exactly as in 6318c18. The
mount also leaves clone backfill behind now, and each drain wake posts its own
receipt, so settle the whole mount-era chain first, then attribute the receipt
by the arrival the pass claimed. Settling also matters for correctness of the
attribution: `note_wake` keeps the earliest pending instant, so a mount-era
wake still pending when the overflow arrives would hand the overflow pass a
pre-overflow arrival. Read the serving generation after that settle, since it
is the generation the reconcile must retain. `wait_for_settled_owner` moves to
the shared test module so both tests use one helper.

Passes 30/30 under `taskset -c 0,1`; the probe and parallel-admission siblings
pass 10/10 and 6/6.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ScriptedAlchemy
ScriptedAlchemy merged commit 556062d into master Sep 18, 2026
23 of 25 checks passed
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