mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-09 09:59:45 -10:00
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:
1 parent
9dd0d14476
commit
81d9ec8dc3
4 files changed
+54
-24
No files matched your search
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?,
|
||||
|
||||
Reference in new issue
Block a user