fix(build): compile on Rust 1.99 and isolate the restore route tests

Stable Rust 1.99.0 deprecates the atomic `fetch_update` (renamed `try_update`),
and release builds deny warnings, so every artifact build of the previous
head failed in codewhale-tui (workflow child counter, sub-agent pending
count). `try_update` is newer than the MSRV, so the three call sites (two
production, one app-server test fixture) are plain compare-exchange loops with
the same orderings and results.

The recurring shared-process failure of
`restore_routes_refuse_an_active_turn_in_the_workspace` was test isolation,
not restore admission. After the refusal assertions the route opens the
snapshot store under the resolved home. The test did not hold the test
environment lock, so the store could land under a sibling test's temporary
HOME and be deleted when that test ended, turning the expected 409 into
`500 Failed to list snapshots: git log failed`. That test and its sibling
`file_revert_route_validates_body_then_trust_then_ownership` now seal the
environment and own a CODEWHALE_HOME; the status assertion reports the body.
No production restore or admission code changes.

Local macOS evidence, family filter `runtime_api::tests::re` in one process:
before, 2 failures in 73 runs (first with status only, then with the body
above); after, 0 failures in 150 runs, each `21 passed; 0 failed`. Workflow
and sub-agent filter: `1135 passed; 0 failed`. App-server lib:
`126 passed; 0 failed`. cargo fmt --all --check passes. Local toolchain is
1.98.1, so the 1.99 build itself is proven only by hosted CI.

Signed-off-by: CodeWhale Bot <[email protected]>
This commit is contained in:
CodeWhale Bot committed 2026-10-01 06:19:03 -07:00
1 parent 9dd0d14476
commit 81d9ec8dc3
4 files changed
+54 -24

No files matched your search

+12 -9
View File
@@ -3424,15 +3424,18 @@ mod tests {
State(f): State<RecordingRuntime>,
AxumPath(thread_id): AxumPath<String>,
) -> StatusCode {
if f.lookup_failures
.fetch_update(
std::sync::atomic::Ordering::SeqCst,
std::sync::atomic::Ordering::SeqCst,
|remaining| remaining.checked_sub(1),
)
.is_ok()
{
return StatusCode::SERVICE_UNAVAILABLE;
use std::sync::atomic::Ordering::SeqCst;
let mut remaining = f.lookup_failures.load(SeqCst);
while remaining > 0 {
match f.lookup_failures.compare_exchange_weak(
remaining,
remaining - 1,
SeqCst,
SeqCst,
) {
Ok(_) => return StatusCode::SERVICE_UNAVAILABLE,
Err(current) => remaining = current,
}
}
if thread_id == "thr_minted" {
StatusCode::OK
+12 -1
View File
@@ -8103,7 +8103,12 @@ async fn file_revert_route_probes_as_available_and_404s_unknown_threads() -> Res
/// any case.
#[tokio::test]
async fn file_revert_route_validates_body_then_trust_then_ownership() -> Result<()> {
// The route opens the snapshot store under the resolved home. Seal the
// process environment and own that home, so a concurrent test's temporary
// HOME (deleted when it ends) can never host or remove this store mid-request.
let _env = lock_test_env();
let root = std::env::temp_dir().join(format!("deepseek-file-revert-gates-{}", Uuid::new_v4()));
let _home = EnvVarGuard::set("CODEWHALE_HOME", root.join("home"));
let sessions_dir = root.join("sessions");
let Some((addr, runtime_threads, handle)) =
spawn_test_server_with_root(root.clone(), sessions_dir).await?
@@ -8167,7 +8172,12 @@ async fn file_revert_route_validates_body_then_trust_then_ownership() -> Result<
/// workspace, and admit again once it settles. Nothing is changed on refusal.
#[tokio::test]
async fn restore_routes_refuse_an_active_turn_in_the_workspace() -> Result<()> {
// The route opens the snapshot store under the resolved home. Seal the
// process environment and own that home, so a concurrent test's temporary
// HOME (deleted when it ends) can never host or remove this store mid-request.
let _env = lock_test_env();
let root = std::env::temp_dir().join(format!("deepseek-restore-active-{}", Uuid::new_v4()));
let _home = EnvVarGuard::set("CODEWHALE_HOME", root.join("home"));
let sessions_dir = root.join("sessions");
let Some((addr, runtime_threads, handle)) =
spawn_test_server_with_root(root.clone(), sessions_dir).await?
@@ -8234,8 +8244,9 @@ async fn restore_routes_refuse_an_active_turn_in_the_workspace() -> Result<()> {
.json(&revert_body)
.send()
.await?;
assert_eq!(resp.status(), StatusCode::CONFLICT);
let status = resp.status();
let text = resp.text().await?;
assert_eq!(status, StatusCode::CONFLICT, "got: {text}");
assert!(text.contains("refresh the change record"), "got: {text}");
assert_eq!(fs::read_to_string(&file)?, "live");
+10 -5
View File
@@ -1972,11 +1972,16 @@ impl SubAgentInput {
/// Mark this input as consumed by the child loop.
fn mark_taken(&self) {
if let Some(pending) = self.pending.as_ref() {
let _ = pending.fetch_update(
std::sync::atomic::Ordering::AcqRel,
std::sync::atomic::Ordering::Acquire,
|value| Some(value.saturating_sub(1)),
);
// Saturating decrement as a compare-exchange loop: `fetch_update`
// is deprecated from Rust 1.99 and `try_update` is newer than the MSRV.
use std::sync::atomic::Ordering::{AcqRel, Acquire};
let mut value = pending.load(Acquire);
while value > 0 {
match pending.compare_exchange_weak(value, value - 1, AcqRel, Acquire) {
Ok(_) => break,
Err(current) => value = current,
}
}
}
}
}
+20 -9
View File
@@ -4799,15 +4799,26 @@ impl SubAgentWorkflowDriver {
}
};
self.ensure_admission_open()?;
let workflow_child_index = self
.child_counter
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |count| {
(count < self.max_children).then_some(count + 1)
})
.map_err(|_| DriverError::Rejected(format!(
"workflow.max_children limit ({}) reached; reduce remaining work or start a new reviewed plan",
self.max_children
)))?;
// A plain compare-exchange loop: `fetch_update` is deprecated from
// Rust 1.99 and its `try_update` replacement is newer than the MSRV.
let mut count = self.child_counter.load(Ordering::SeqCst);
let workflow_child_index = loop {
if count >= self.max_children {
return Err(DriverError::Rejected(format!(
"workflow.max_children limit ({}) reached; reduce remaining work or start a new reviewed plan",
self.max_children
)));
}
match self.child_counter.compare_exchange_weak(
count,
count + 1,
Ordering::SeqCst,
Ordering::SeqCst,
) {
Ok(reserved) => break reserved,
Err(current) => count = current,
}
};
let handoffs = WorkflowHandoffReservation {
board: self.gate_board.clone(),
artifacts: self.prepare_request_for_gates(&mut request)?,