Files
Dicklesworthstone 4cd1c37ffe test(fleet-resilience): budget-envelope contracts, robot parseability under pressure & doctor/parity gates
Test side of the fleet-resilience increment. Locks in the wire contracts
and resilience behavior introduced on the src side.

- Budget-envelope gates (cli_status_budget, cli_view_budget,
  cli_doctor_budget, cli_status, cli_view_archive, cli_trace_file):
  assert every robot/status/view/trace JSON carries a well-formed budget
  block (object with elapsed_ms present, timed_out=false on healthy runs),
  so downstream agents can always reason about partial vs complete output.

- Robot parseability under pressure (robot_parseability_under_pressure):
  exercises noisy RUST_LOG filter permutations (slow-query-warn,
  drop-close-warn, database-busy, …) to prove robot JSON stays parseable
  even when stderr is flooded with subsystem warnings.

- Swarm status & coordination contracts (swarm_status_contract,
  coordination_intelligence_gate): registry must expose >= 6 macros and
  macro text must not embed bare `cass ` invocation examples (keeps the
  macro catalog tool-agnostic).

- Doctor / parity E2E (doctor_e2e_runner): end-to-end doctor runner
  coverage aligned with the new host-probe classification.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-16 17:12:20 -04:00

1192 lines
42 KiB
Rust

use assert_cmd::Command;
use coding_agent_search::search::tantivy::{SCHEMA_HASH, expected_index_dir};
use coding_agent_search::sources::config::{SourceDefinition, SourcesConfig, SyncSchedule};
use coding_agent_search::storage::sqlite::CURRENT_SCHEMA_VERSION;
use fs2::FileExt;
use serde_json::json;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::time::Duration;
fn write_quarantined_manifest(generation_dir: &Path) {
fs::create_dir_all(generation_dir).expect("create generation dir");
fs::write(
generation_dir.join("lexical-generation-manifest.json"),
serde_json::to_vec_pretty(&json!({
"manifest_version": 1,
"generation_id": "gen-quarantined",
"attempt_id": "attempt-1",
"created_at_ms": 1_733_000_000_000_i64,
"updated_at_ms": 1_733_000_000_321_i64,
"source_db_fingerprint": "fp-test",
"conversation_count": 3,
"message_count": 9,
"indexed_doc_count": 9,
"equivalence_manifest_fingerprint": null,
"shard_plan": null,
"build_budget": null,
"shards": [{
"shard_id": "shard-a",
"shard_ordinal": 0,
"state": "quarantined",
"updated_at_ms": 1_733_000_000_222_i64,
"indexed_doc_count": 9,
"message_count": 9,
"artifact_bytes": 512,
"stable_hash": "stable-hash-a",
"reclaimable": false,
"pinned": false,
"recovery_reason": null,
"quarantine_reason": "validation_failed"
}],
"merge_debt": {
"state": "none",
"updated_at_ms": null,
"pending_shard_count": 0,
"pending_artifact_bytes": 0,
"reason": null,
"controller_reason": null
},
"build_state": "failed",
"publish_state": "quarantined",
"failure_history": []
}))
.expect("serialize manifest"),
)
.expect("write manifest");
}
fn write_generation_manifest(
generation_dir: &Path,
generation_id: &str,
build_state: &str,
publish_state: &str,
shard_state: &str,
pinned: bool,
reclaimable: bool,
) {
fs::create_dir_all(generation_dir).expect("create generation dir");
fs::write(
generation_dir.join("lexical-generation-manifest.json"),
serde_json::to_vec_pretty(&json!({
"manifest_version": 3,
"generation_id": generation_id,
"attempt_id": format!("{generation_id}-attempt"),
"created_at_ms": 1_733_000_010_000_i64,
"updated_at_ms": 1_733_000_010_321_i64,
"source_db_fingerprint": "fp-lifecycle-test",
"conversation_count": 4,
"message_count": 12,
"indexed_doc_count": 12,
"equivalence_manifest_fingerprint": "eq-lifecycle-test",
"shard_plan": null,
"build_budget": null,
"shards": [{
"shard_id": format!("{generation_id}-shard"),
"shard_ordinal": 0,
"state": shard_state,
"updated_at_ms": 1_733_000_010_222_i64,
"indexed_doc_count": 12,
"message_count": 12,
"artifact_bytes": 256,
"stable_hash": format!("{generation_id}-stable"),
"reclaimable": reclaimable,
"pinned": pinned,
"recovery_reason": null,
"quarantine_reason": if shard_state == "quarantined" { Some("validation_failed") } else { None::<&str> }
}],
"merge_debt": {
"state": "none",
"updated_at_ms": null,
"pending_shard_count": 0,
"pending_artifact_bytes": 0,
"reason": null,
"controller_reason": null
},
"build_state": build_state,
"publish_state": publish_state,
"failure_history": []
}))
.expect("serialize manifest"),
)
.expect("write manifest");
fs::write(
generation_dir.join("segment"),
format!("{generation_id}-artifact-bytes"),
)
.expect("write generation artifact");
}
fn write_remote_source_config(config_home: &Path) {
let mut source = SourceDefinition::ssh("status-remote", "user@status-remote");
source.paths = vec!["~/.codex/sessions".to_string()];
source.sync_schedule = SyncSchedule::Hourly;
SourcesConfig {
sources: vec![source],
disabled_agents: Vec::new(),
}
.save_to(&config_home.join("cass/sources.toml"))
.expect("write sources config");
}
fn isolated_cass_cmd(temp_home: &Path) -> Command {
let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("cass"));
cmd.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1");
cmd.env("CASS_IGNORE_SOURCES_CONFIG", "1");
cmd.env("HOME", temp_home);
cmd.env("XDG_DATA_HOME", temp_home.join(".local/share"));
cmd.env("XDG_CONFIG_HOME", temp_home.join(".config"));
cmd.env("CODEX_HOME", temp_home.join(".codex"));
cmd
}
fn write_ingest_quarantine_record(data_dir: &Path) {
write_ingest_quarantine_records(data_dir, 1);
}
fn write_ingest_quarantine_records(data_dir: &Path, count: usize) {
let quarantine_dir = data_dir.join("quarantine");
fs::create_dir_all(&quarantine_dir).expect("create ingest quarantine dir");
let now_ms = chrono::Utc::now().timestamp_millis();
let mut lines = String::new();
for idx in 0..count {
let started_at = i64::try_from(idx).expect("idx fits i64") + 1;
let ended_at = started_at + 1;
let record = json!({
"schema_version": 1,
"conversation_id": format!("tester|/logs/demo-{idx}.jsonl|/workspace/demo|poison-{idx}|{started_at}|{ended_at}|1"),
"schema_version_at_quarantine": CURRENT_SCHEMA_VERSION,
"first_quarantined_at_ms": now_ms,
"last_attempt_at_ms": now_ms,
"attempt_count": 1,
"reason": "index-ingest-out-of-memory",
"error_kind": "out-of-memory",
"last_error": "out of memory",
"agent_slug": "tester",
"external_id": format!("poison-{idx}"),
"source_path": format!("/logs/demo-{idx}.jsonl"),
"workspace": "/workspace/demo",
"started_at": started_at,
"ended_at": ended_at,
"message_count": 1
});
lines.push_str(&format!("{record}\n"));
}
fs::write(quarantine_dir.join("index_ingest_poison.jsonl"), lines)
.expect("write ingest quarantine record");
}
fn seed_active_rebuild_runtime(data_dir: &Path) -> std::fs::File {
let db_path = data_dir.join("agent_search.db");
let index_path = expected_index_dir(data_dir);
fs::create_dir_all(&index_path).expect("create index dir");
fs::write(
index_path.join(".lexical-rebuild-state.json"),
serde_json::to_vec_pretty(&json!({
"version": 2,
"schema_hash": SCHEMA_HASH,
"db": {
"db_path": db_path.display().to_string(),
"total_conversations": 10,
"total_messages": 20,
"storage_fingerprint": "seed:10"
},
"page_size": 1024,
"committed_offset": 4,
"committed_conversation_id": 4,
"processed_conversations": 4,
"indexed_docs": 20,
"committed_meta_fingerprint": null,
"pending": null,
"completed": false,
"updated_at_ms": 1_733_000_123_000_i64,
"runtime": {
"queue_depth": 3,
"inflight_message_bytes": 65_536,
"max_message_bytes_in_flight": 131_072,
"pending_batch_conversations": 9,
"pending_batch_message_bytes": 131_072,
"page_prep_workers": 6,
"active_page_prep_jobs": 2,
"ordered_buffered_pages": 4,
"budget_generation": 1,
"producer_budget_wait_count": 2,
"producer_budget_wait_ms": 17,
"producer_handoff_wait_count": 1,
"producer_handoff_wait_ms": 9,
"host_loadavg_1m_milli": 7_250,
"controller_mode": "pressure_limited",
"controller_reason": "queue_depth_3_reached_pipeline_capacity_3",
"staged_merge_workers_max": 3,
"staged_merge_allowed_jobs": 1,
"staged_merge_active_jobs": 1,
"staged_merge_ready_artifacts": 5,
"staged_merge_ready_groups": 1,
"staged_merge_controller_reason": "page_prep_workers_saturated_6_of_6",
"staged_shard_build_workers_max": 6,
"staged_shard_build_allowed_jobs": 5,
"staged_shard_build_active_jobs": 4,
"staged_shard_build_pending_jobs": 2,
"staged_shard_build_controller_reason": "reserving_1_slots_for_staged_merge_active_jobs_1_ready_groups_1",
"updated_at_ms": 1_733_000_124_000_i64
}
}))
.expect("serialize rebuild state"),
)
.expect("write rebuild state");
let lock_path = data_dir.join("index-run.lock");
let mut lock_file = OpenOptions::new()
.create(true)
.truncate(true)
.read(true)
.write(true)
.open(&lock_path)
.expect("open lock file");
lock_file.lock_exclusive().expect("hold index lock");
writeln!(
lock_file,
"pid={}\nstarted_at_ms={}\ndb_path={}\nmode=index",
std::process::id(),
1_733_000_111_000_i64,
db_path.display()
)
.expect("write lock metadata");
lock_file.flush().expect("flush lock metadata");
lock_file
}
#[test]
fn status_and_health_json_surface_ingest_quarantine_as_nonfatal_degraded() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let index_out = isolated_cass_cmd(test_home.path())
.args([
"index",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
"--no-progress-events",
])
.output()
.expect("run cass index --json");
assert!(
index_out.status.success(),
"cass index --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&index_out.stdout),
String::from_utf8_lossy(&index_out.stderr)
);
write_ingest_quarantine_record(&data_dir);
let status_out = isolated_cass_cmd(test_home.path())
.args([
"status",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass status --json");
assert!(
status_out.status.success(),
"cass status --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&status_out.stdout),
String::from_utf8_lossy(&status_out.stderr)
);
let status_payload: serde_json::Value =
serde_json::from_slice(&status_out.stdout).expect("status JSON");
assert_eq!(status_payload["status"].as_str(), Some("healthy"));
assert_eq!(status_payload["healthy"].as_bool(), Some(true));
assert_eq!(status_payload["health_level"].as_str(), Some("degraded"));
assert_eq!(
status_payload["index"]["quarantined_conversations"].as_u64(),
Some(1)
);
assert_eq!(
status_payload["ingest_quarantine"]["quarantined_conversations"].as_u64(),
Some(1)
);
assert!(
status_payload["warnings"]
.as_array()
.is_some_and(|warnings| !warnings.is_empty()),
"status should expose a nonfatal ingest-quarantine warning: {status_payload}"
);
assert!(
status_payload["recommended_action"]
.as_str()
.is_some_and(|action| action.contains("quarantine")),
"status should recommend inspecting quarantine state: {status_payload}"
);
let health_out = isolated_cass_cmd(test_home.path())
.args([
"health",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass health --json");
assert!(
health_out.status.success(),
"cass health --json should remain exit 0 for nonfatal ingest quarantine: stdout={} stderr={}",
String::from_utf8_lossy(&health_out.stdout),
String::from_utf8_lossy(&health_out.stderr)
);
let health_payload: serde_json::Value =
serde_json::from_slice(&health_out.stdout).expect("health JSON");
assert_eq!(health_payload["status"].as_str(), Some("healthy"));
assert_eq!(health_payload["healthy"].as_bool(), Some(true));
assert_eq!(health_payload["health_level"].as_str(), Some("degraded"));
assert_eq!(
health_payload["ingest_quarantine"]["quarantined_conversations"].as_u64(),
Some(1)
);
assert!(
health_payload["warnings"]
.as_array()
.is_some_and(|warnings| !warnings.is_empty()),
"health should expose a nonfatal ingest-quarantine warning: {health_payload}"
);
}
/// uojcg.3.3: health/status/triage and search --robot-meta must carry a
/// structured `search_completeness` verdict so agents can tell a *stale* index
/// (still complete) from one that *excludes known conversations* (quarantined).
#[test]
fn readiness_surfaces_report_degraded_search_completeness_when_quarantined() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let index_out = isolated_cass_cmd(test_home.path())
.args([
"index",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
"--no-progress-events",
])
.output()
.expect("run cass index --json");
assert!(
index_out.status.success(),
"cass index --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&index_out.stdout),
String::from_utf8_lossy(&index_out.stderr)
);
write_ingest_quarantine_record(&data_dir);
// The degraded (but searchable) verdict every readiness surface must agree on.
let assert_degraded = |payload: &serde_json::Value, surface: &str| {
let sc = &payload["search_completeness"];
assert_eq!(
sc["quarantine_status"].as_str(),
Some("degraded"),
"{surface} search_completeness should be degraded: {payload}"
);
assert_eq!(
sc["quarantined_conversations"].as_u64(),
Some(1),
"{surface} should count the quarantined conversation: {payload}"
);
assert_eq!(
sc["complete"].as_bool(),
Some(false),
"{surface} coverage is incomplete: {payload}"
);
assert_eq!(
sc["can_search"].as_bool(),
Some(true),
"{surface} ordinary search still runs: {payload}"
);
assert_eq!(
sc["coverage_suspect"].as_bool(),
Some(false),
"{surface} a single non-burst quarantine is not suspect: {payload}"
);
assert!(
sc["next_command"]
.as_str()
.is_some_and(|cmd| cmd.contains("quarantine")),
"{surface} should point at the quarantine inspect command: {payload}"
);
};
for surface in ["status", "triage"] {
let out = isolated_cass_cmd(test_home.path())
.args([
surface,
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass readiness surface --json");
assert!(
out.status.success(),
"cass {surface} --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
let payload: serde_json::Value =
serde_json::from_slice(&out.stdout).expect("parse readiness surface JSON");
assert_degraded(&payload, surface);
}
// triage must also surface the quarantine facts inside its readiness block.
let triage_out = isolated_cass_cmd(test_home.path())
.args([
"triage",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass triage --json");
let triage_payload: serde_json::Value =
serde_json::from_slice(&triage_out.stdout).expect("triage JSON");
assert_eq!(
triage_payload["readiness"]["ingest_quarantine"]["quarantined_conversations"].as_u64(),
Some(1),
"triage readiness should now include ingest_quarantine: {triage_payload}"
);
// health (exit 0 for a single nonfatal quarantine) carries the same verdict.
let health_out = isolated_cass_cmd(test_home.path())
.args([
"health",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass health --json");
assert!(
health_out.status.success(),
"cass health --json should stay exit 0 for a single nonfatal quarantine: stdout={} stderr={}",
String::from_utf8_lossy(&health_out.stdout),
String::from_utf8_lossy(&health_out.stderr)
);
let health_payload: serde_json::Value =
serde_json::from_slice(&health_out.stdout).expect("health JSON");
assert_degraded(&health_payload, "health");
// search --robot-meta carries the compact verdict in its _meta header.
let search_out = isolated_cass_cmd(test_home.path())
.args([
"search",
"anything",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--robot",
"--robot-meta",
])
.output()
.expect("run cass search --robot --robot-meta");
let search_payload: serde_json::Value =
serde_json::from_slice(&search_out.stdout).expect("search JSON");
let search_meta = &search_payload["_meta"]["search_completeness"];
assert_eq!(
search_meta["quarantine_status"].as_str(),
Some("degraded"),
"search --robot-meta should carry the degraded completeness verdict: {search_payload}"
);
assert_eq!(search_meta["quarantined_conversations"].as_u64(), Some(1));
}
/// uojcg.3.3: with no quarantine, every readiness surface reports complete
/// coverage (`ok`), and search --robot-meta omits the verdict entirely so the
/// common payload is unchanged.
#[test]
fn readiness_surfaces_report_complete_search_coverage_without_quarantine() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let index_out = isolated_cass_cmd(test_home.path())
.args([
"index",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
"--no-progress-events",
])
.output()
.expect("run cass index --json");
assert!(index_out.status.success());
for surface in ["status", "health", "triage"] {
let out = isolated_cass_cmd(test_home.path())
.args([
surface,
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass readiness surface --json");
let payload: serde_json::Value =
serde_json::from_slice(&out.stdout).expect("parse readiness surface JSON");
let sc = &payload["search_completeness"];
assert_eq!(
sc["quarantine_status"].as_str(),
Some("ok"),
"{surface} should report complete coverage: {payload}"
);
assert_eq!(sc["complete"].as_bool(), Some(true), "{surface}: {payload}");
assert_eq!(
sc["quarantined_conversations"].as_u64(),
Some(0),
"{surface}: {payload}"
);
}
// No quarantine => search --robot-meta omits the verdict (no new bytes).
let search_out = isolated_cass_cmd(test_home.path())
.args([
"search",
"anything",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--robot",
"--robot-meta",
])
.output()
.expect("run cass search --robot --robot-meta");
let search_payload: serde_json::Value =
serde_json::from_slice(&search_out.stdout).expect("search JSON");
assert!(
search_payload["_meta"].get("search_completeness").is_none(),
"search --robot-meta should omit search_completeness when nothing is quarantined: {search_payload}"
);
}
/// uojcg.9.2/9.5: status/triage/doctor --json carry a root_cause attribution
/// (family/locus/confidence/evidence_refs/summary). On a clean, freshly-indexed
/// dir no signal implicates a family, so the attribution is the explicit
/// unknown/unknown record — the field is always present and well-shaped.
#[test]
fn status_triage_doctor_emit_root_cause_attribution() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let index_out = isolated_cass_cmd(test_home.path())
.args([
"index",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
"--no-progress-events",
])
.output()
.expect("run cass index --json");
assert!(index_out.status.success());
let assert_root_cause = |rc: &serde_json::Value, surface: &str| {
assert!(
rc.get("schema_version")
.and_then(serde_json::Value::as_u64)
.is_some(),
"{surface} root_cause needs schema_version: {rc}"
);
assert_eq!(
rc["family"].as_str(),
Some("unknown"),
"{surface} clean dir => unknown family: {rc}"
);
assert_eq!(
rc["confidence"].as_str(),
Some("unknown"),
"{surface} clean dir => unknown confidence: {rc}"
);
assert!(
rc.get("locus")
.and_then(serde_json::Value::as_str)
.is_some()
);
assert!(
rc.get("evidence_refs")
.map(serde_json::Value::is_array)
.unwrap_or(false)
);
assert!(
rc.get("summary")
.and_then(serde_json::Value::as_str)
.is_some()
);
};
for surface in ["status", "triage"] {
let out = isolated_cass_cmd(test_home.path())
.args([
surface,
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass readiness surface --json");
let payload: serde_json::Value =
serde_json::from_slice(&out.stdout).expect("parse readiness surface JSON");
assert_root_cause(&payload["root_cause"], surface);
}
let doctor_out = isolated_cass_cmd(test_home.path())
.args([
"doctor",
"check",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.output()
.expect("run cass doctor check --json");
let doctor_payload: serde_json::Value =
serde_json::from_slice(&doctor_out.stdout).expect("parse doctor JSON");
assert_root_cause(&doctor_payload["root_cause"], "doctor");
}
#[test]
fn status_and_health_json_escalate_recent_ingest_quarantine_bursts() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let index_out = isolated_cass_cmd(test_home.path())
.args([
"index",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
"--no-progress-events",
])
.output()
.expect("run cass index --json");
assert!(
index_out.status.success(),
"cass index --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&index_out.stdout),
String::from_utf8_lossy(&index_out.stderr)
);
write_ingest_quarantine_records(&data_dir, 3);
let status_out = isolated_cass_cmd(test_home.path())
.args([
"status",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.env("CASS_INGEST_QUARANTINE_CIRCUIT_LIMIT", "3")
.output()
.expect("run cass status --json");
assert!(
status_out.status.success(),
"cass status --json failed: stdout={} stderr={}",
String::from_utf8_lossy(&status_out.stdout),
String::from_utf8_lossy(&status_out.stderr)
);
let status_payload: serde_json::Value =
serde_json::from_slice(&status_out.stdout).expect("status JSON");
assert_eq!(status_payload["status"].as_str(), Some("unhealthy"));
assert_eq!(status_payload["healthy"].as_bool(), Some(false));
assert_eq!(status_payload["health_level"].as_str(), Some("critical"));
assert_eq!(
status_payload["ingest_quarantine"]["circuit_breaker_active"].as_bool(),
Some(true)
);
let health_out = isolated_cass_cmd(test_home.path())
.args([
"health",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.env("CASS_INGEST_QUARANTINE_CIRCUIT_LIMIT", "3")
.output()
.expect("run cass health --json");
assert!(
!health_out.status.success(),
"cass health --json should exit nonzero for critical ingest quarantine readiness: stdout={} stderr={}",
String::from_utf8_lossy(&health_out.stdout),
String::from_utf8_lossy(&health_out.stderr)
);
let health_payload: serde_json::Value =
serde_json::from_slice(&health_out.stdout).expect("health JSON");
assert_eq!(health_payload["status"].as_str(), Some("unhealthy"));
assert_eq!(health_payload["healthy"].as_bool(), Some(false));
assert_eq!(health_payload["health_level"].as_str(), Some("critical"));
assert!(
health_payload["errors"]
.as_array()
.is_some_and(|errors| errors.iter().any(|err| err
.as_str()
.is_some_and(|msg| msg.contains("quarantine circuit breaker")))),
"health should expose the circuit breaker as an error: {health_payload}"
);
}
#[test]
fn status_and_health_json_surface_remote_source_sync_summary_without_live_probe() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
write_remote_source_config(test_home.path());
let status_out = Command::new(assert_cmd::cargo::cargo_bin!("cass"))
.args([
"status",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1")
.env("XDG_DATA_HOME", test_home.path())
.env("XDG_CONFIG_HOME", test_home.path())
.env("HOME", test_home.path())
.output()
.expect("run cass status --json");
assert!(
status_out.status.success(),
"cass status --json failed: {}",
String::from_utf8_lossy(&status_out.stderr)
);
let status_payload: serde_json::Value =
serde_json::from_slice(&status_out.stdout).expect("status JSON");
let status_remote = &status_payload["remote_source_sync"];
assert_eq!(status_remote["checked"].as_bool(), Some(true));
assert_eq!(status_remote["archive_checked"].as_bool(), Some(false));
assert_eq!(
status_remote["live_remote_probe_attempted"].as_bool(),
Some(false)
);
assert_eq!(
status_remote["remote_source_state"].as_str(),
Some("local_mirror_gap")
);
assert_eq!(
status_remote["sync_staleness"].as_str(),
Some("never_synced")
);
assert_eq!(
status_remote["local_mirror_state"].as_str(),
Some("missing")
);
assert_eq!(
status_remote["configured_remote_source_count"].as_u64(),
Some(1)
);
assert_eq!(
status_remote["recommended_action"].as_str(),
Some("cass sources sync --all --json")
);
assert_eq!(
status_payload["doctor_summary"]["remote_source_sync"]["remote_source_state"].as_str(),
Some("local_mirror_gap")
);
let health_out = Command::new(assert_cmd::cargo::cargo_bin!("cass"))
.args([
"health",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1")
.env("XDG_DATA_HOME", test_home.path())
.env("XDG_CONFIG_HOME", test_home.path())
.env("HOME", test_home.path())
.output()
.expect("run cass health --json");
let health_payload: serde_json::Value =
serde_json::from_slice(&health_out.stdout).expect("health JSON");
assert_eq!(
health_payload["remote_source_sync"]["remote_source_state"].as_str(),
Some("local_mirror_gap")
);
assert_eq!(
health_payload["remote_source_sync"]["source"].as_str(),
Some("health-fast-local-config")
);
assert_eq!(
health_payload["remote_source_sync"]["live_remote_probe_attempted"].as_bool(),
Some(false)
);
assert_eq!(
health_payload["doctor_summary"]["remote_source_sync"]["recommended_action"].as_str(),
Some("cass sources sync --all --json")
);
}
#[test]
fn status_json_surfaces_runtime_queue_and_byte_budget_headroom() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
fs::create_dir_all(&data_dir).expect("create data dir");
let _lock = seed_active_rebuild_runtime(&data_dir);
let out = Command::new(assert_cmd::cargo::cargo_bin!("cass"))
.args([
"status",
"--data-dir",
data_dir.to_str().expect("utf8"),
"--json",
])
.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1")
.env("CASS_IGNORE_SOURCES_CONFIG", "1")
.env("CASS_TANTIVY_REBUILD_PIPELINE_CHANNEL_SIZE", "5")
.env("XDG_DATA_HOME", test_home.path())
.env("HOME", test_home.path())
.output()
.expect("run cass status --json");
assert!(
out.status.success(),
"cass status --json failed: {:?}",
out.status
);
let stdout = String::from_utf8(out.stdout).expect("utf8");
let payload: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
let runtime = &payload["rebuild"]["pipeline"]["runtime"];
let rebuild_progress = &payload["rebuild_progress"];
assert_eq!(runtime["queue_depth"].as_u64(), Some(3));
assert_eq!(runtime["queue_capacity"].as_u64(), Some(5));
assert_eq!(runtime["queue_headroom"].as_u64(), Some(2));
assert_eq!(runtime["inflight_message_bytes"].as_u64(), Some(65_536));
assert_eq!(
runtime["max_message_bytes_in_flight"].as_u64(),
Some(131_072)
);
assert_eq!(
runtime["inflight_message_bytes_headroom"].as_u64(),
Some(65_536)
);
assert_eq!(rebuild_progress["active"].as_bool(), Some(true));
assert_eq!(
rebuild_progress["processed_conversations"].as_u64(),
Some(4)
);
assert_eq!(rebuild_progress["total_conversations"].as_u64(), Some(10));
assert_eq!(
rebuild_progress["remaining_conversations"].as_u64(),
Some(6)
);
assert_eq!(rebuild_progress["completion_ratio"].as_f64(), Some(0.4));
assert_eq!(rebuild_progress["queue_depth"].as_u64(), Some(3));
assert_eq!(rebuild_progress["queue_capacity"].as_u64(), Some(5));
assert_eq!(rebuild_progress["queue_headroom"].as_u64(), Some(2));
assert_eq!(
rebuild_progress["inflight_message_bytes"].as_u64(),
Some(65_536)
);
assert_eq!(
rebuild_progress["inflight_message_bytes_headroom"].as_u64(),
Some(65_536)
);
assert_eq!(
rebuild_progress["controller_mode"].as_str(),
Some("pressure_limited")
);
assert_eq!(
rebuild_progress["controller_reason"].as_str(),
Some("queue_depth_3_reached_pipeline_capacity_3")
);
}
#[test]
fn status_json_surfaces_quarantine_gc_summary() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
let backups_dir = data_dir.join("backups");
fs::create_dir_all(&backups_dir).expect("create backups dir");
let failed_seed_root =
backups_dir.join("agent_search.db.20260423T120000.12345.deadbeef.failed-baseline-seed.bak");
fs::write(&failed_seed_root, b"seed-backup").expect("write failed seed bundle");
fs::write(
failed_seed_root.with_file_name(format!(
"{}-wal",
failed_seed_root
.file_name()
.and_then(|name| name.to_str())
.expect("file name")
)),
b"seed-wal",
)
.expect("write failed seed wal");
let index_path = expected_index_dir(&data_dir);
fs::create_dir_all(&index_path).expect("create expected index dir");
let retained_publish_dir = index_path
.parent()
.expect("index parent")
.join(".lexical-publish-backups");
fs::create_dir_all(&retained_publish_dir).expect("create retained publish dir");
let older_backup = retained_publish_dir.join("prior-live-older");
fs::create_dir_all(&older_backup).expect("create older retained backup");
fs::write(older_backup.join("segment-a"), b"retained-live-segment-old")
.expect("write older retained publish backup");
std::thread::sleep(Duration::from_millis(20));
let newer_backup = retained_publish_dir.join("prior-live-newer");
fs::create_dir_all(&newer_backup).expect("create newer retained backup");
fs::write(newer_backup.join("segment-b"), b"retained-live-segment-new")
.expect("write newer retained publish backup");
let generation_dir = index_path
.parent()
.expect("index parent")
.join("generation-quarantined");
write_quarantined_manifest(&generation_dir);
fs::write(
generation_dir.join("segment-a"),
b"quarantined-generation-bytes",
)
.expect("write quarantined generation artifact");
let out = Command::new(assert_cmd::cargo::cargo_bin!("cass"))
.args([
"status",
"--json",
"--data-dir",
data_dir.to_str().expect("utf8"),
])
.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1")
.env("CASS_IGNORE_SOURCES_CONFIG", "1")
.env("CASS_LEXICAL_PUBLISH_BACKUP_RETENTION", "1")
.env("XDG_DATA_HOME", test_home.path())
.env("XDG_CONFIG_HOME", test_home.path())
.env("HOME", test_home.path())
.output()
.expect("run cass status --json");
assert!(
out.status.success(),
"cass status --json failed: {}",
String::from_utf8_lossy(&out.stderr)
);
let payload: serde_json::Value = serde_json::from_slice(&out.stdout).expect("valid JSON");
let quarantine = &payload["quarantine"];
let summary = &quarantine["summary"];
assert_eq!(summary["gc_eligible_asset_count"].as_u64(), Some(1));
assert!(
summary["gc_eligible_bytes"].as_u64().unwrap_or(0) > 0,
"one retained publish backup should fall outside the retention cap"
);
assert_eq!(summary["inspection_required_asset_count"].as_u64(), Some(3));
assert!(
summary["inspection_required_bytes"].as_u64().unwrap_or(0) > 0,
"failed seed bundles and quarantined lexical generation should remain inspection-only"
);
assert_eq!(
summary["retained_publish_backup_retention_limit"].as_u64(),
Some(1)
);
let failed_seed_entries = quarantine["failed_seed_bundle_files"]
.as_array()
.expect("status.quarantine must expose failed seed bundle entries");
assert_eq!(
failed_seed_entries.len(),
2,
"status.quarantine must preserve full failed seed bundle inventory, not only summary"
);
assert!(failed_seed_entries.iter().all(|entry| {
entry["path"]
.as_str()
.is_some_and(|path| path.contains(".failed-baseline-seed.bak"))
|| entry["path"].as_str().is_some_and(|path| {
path.contains(".failed-baseline-seed.bak-wal")
|| path.ends_with(".failed-baseline-seed.bak-wal")
})
}));
let retained_backups = quarantine["retained_publish_backups"]
.as_array()
.expect("status.quarantine must expose retained publish backups");
assert_eq!(
retained_backups.len(),
2,
"status.quarantine must preserve retained publish backup details"
);
assert!(
retained_backups
.iter()
.any(|entry| entry["safe_to_gc"].as_bool() == Some(true)),
"one retained publish backup should be GC-eligible outside the cap"
);
assert!(
retained_backups
.iter()
.any(|entry| entry["safe_to_gc"].as_bool() == Some(false)),
"one retained publish backup should remain protected by the cap"
);
let lexical_generations = quarantine["lexical_generations"]
.as_array()
.expect("status.quarantine must expose lexical generation inventory");
assert_eq!(lexical_generations.len(), 1);
assert_eq!(
lexical_generations[0]["generation_id"].as_str(),
Some("gen-quarantined")
);
assert_eq!(
lexical_generations[0]["publish_state"].as_str(),
Some("quarantined")
);
let inspection_artifacts = quarantine["quarantined_artifacts"]
.as_array()
.expect("status.quarantine must expose flattened quarantined artifacts");
assert!(
inspection_artifacts.iter().any(|entry| {
entry["artifact_kind"].as_str() == Some("lexical_generation")
&& entry["generation_id"].as_str() == Some("gen-quarantined")
}),
"status.quarantine must include the quarantined lexical generation artifact"
);
assert!(
inspection_artifacts.iter().any(|entry| {
entry["artifact_kind"].as_str() == Some("lexical_shard")
&& entry["generation_id"].as_str() == Some("gen-quarantined")
&& entry["shard_id"].as_str() == Some("shard-a")
}),
"status.quarantine must include the quarantined shard artifact"
);
}
#[test]
fn status_json_surfaces_lexical_generation_lifecycle_inventory() {
let test_home = tempfile::tempdir().expect("tempdir");
let data_dir = test_home.path().join("cass-data");
let index_path = expected_index_dir(&data_dir);
fs::create_dir_all(&index_path).expect("create expected index dir");
let generation_root = index_path.parent().expect("index parent");
write_generation_manifest(
&generation_root.join("generation-current"),
"gen-current",
"validated",
"published",
"published",
true,
false,
);
write_generation_manifest(
&generation_root.join("generation-staged"),
"gen-staged",
"built",
"staged",
"staged",
false,
true,
);
write_generation_manifest(
&generation_root.join("generation-failed"),
"gen-failed",
"failed",
"staged",
"abandoned",
false,
true,
);
write_generation_manifest(
&generation_root.join("generation-superseded"),
"gen-superseded",
"validated",
"superseded",
"published",
false,
true,
);
write_generation_manifest(
&generation_root.join("generation-quarantined"),
"gen-quarantined",
"failed",
"quarantined",
"quarantined",
false,
false,
);
write_generation_manifest(
&data_dir
.join("synced-sessions")
.join("remote-a")
.join("generation-decoy-outside-index"),
"gen-decoy-outside-index",
"validated",
"published",
"published",
false,
false,
);
let out = Command::new(assert_cmd::cargo::cargo_bin!("cass"))
.args([
"status",
"--json",
"--data-dir",
data_dir.to_str().expect("utf8"),
])
.env("CODING_AGENT_SEARCH_NO_UPDATE_PROMPT", "1")
.env("CASS_IGNORE_SOURCES_CONFIG", "1")
.env("XDG_DATA_HOME", test_home.path())
.env("XDG_CONFIG_HOME", test_home.path())
.env("HOME", test_home.path())
.output()
.expect("run cass status --json");
assert!(
out.status.success(),
"cass status --json failed: {}",
String::from_utf8_lossy(&out.stderr)
);
let payload: serde_json::Value = serde_json::from_slice(&out.stdout).expect("valid JSON");
let summary = &payload["quarantine"]["summary"];
assert_eq!(summary["lexical_generation_count"].as_u64(), Some(5));
assert_eq!(
summary["lexical_generation_publish_state_counts"]["published"].as_u64(),
Some(1)
);
assert_eq!(
summary["lexical_generation_publish_state_counts"]["staged"].as_u64(),
Some(2)
);
assert_eq!(
summary["lexical_generation_publish_state_counts"]["superseded"].as_u64(),
Some(1)
);
assert_eq!(
summary["lexical_generation_publish_state_counts"]["quarantined"].as_u64(),
Some(1)
);
assert_eq!(
summary["lexical_generation_build_state_counts"]["validated"].as_u64(),
Some(2)
);
assert_eq!(
summary["lexical_generation_build_state_counts"]["built"].as_u64(),
Some(1)
);
assert_eq!(
summary["lexical_generation_build_state_counts"]["failed"].as_u64(),
Some(2)
);
assert_eq!(
summary["lexical_quarantined_generation_count"].as_u64(),
Some(1)
);
}