From 0860f36a91853b1583c1c7c20ef21d1b4990fff4 Mon Sep 17 00:00:00 2001 From: HasNoBeef Date: Thu, 30 Apr 2026 20:34:39 -0700 Subject: [PATCH] fix: treat missing native setup as doctor info --- CHANGELOG.md | 1 + crates/mimir-harness/src/lib.rs | 18 ++++++++++--- crates/mimir-harness/tests/binary.rs | 39 ++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32addbe..6149abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Mim ### Fixed — harness isolation +- **Project-native setup doctor policy** — `mimir doctor` now treats completely missing project-local Claude/Codex setup as informational instead of action-required, so public repositories can forbid agent artifacts while still reaching a green readiness state. Partial native setup remains actionable. - **Wrapped-session environment isolation** — `mimir status`, `mimir health`, `mimir drafts`, and `mimir remote` now ignore inherited wrapper `MIMIR_CONFIG_PATH` / `MIMIR_DRAFTS_DIR` when an explicit `--project-root` is supplied without `--config`, so inspecting sibling repositories cannot accidentally read the current wrapped session's Mimir state. Project-local config also wins over inherited `MIMIR_DRAFTS_DIR` for status, health, launch, drafts, and remote planning. - **Binary smoke-test isolation** — the real `mimir rustc --version` subprocess smoke test now scrubs inherited `MIMIR_*` variables before launch, preventing local test runs from staging operator-live draft envelopes. - **Quorum adapter spawn stability** — adapter and synthesis execution now retry transient Unix `ETXTBSY` spawn failures, closing a local parallel-test flake where freshly written executable shims could briefly report "text file busy". diff --git a/crates/mimir-harness/src/lib.rs b/crates/mimir-harness/src/lib.rs index 5eea318..933f8c1 100644 --- a/crates/mimir-harness/src/lib.rs +++ b/crates/mimir-harness/src/lib.rs @@ -1869,8 +1869,20 @@ fn append_librarian_doctor_checks(checks: &mut Vec, config: &Harnes fn append_native_setup_doctor_checks(checks: &mut Vec, start_dir: &Path) { for agent in [NativeSetupAgent::Claude, NativeSetupAgent::Codex] { let status = project_native_setup_status(agent, start_dir); - if status != "installed" { - checks.push(DoctorCheck::action( + match status { + "installed" => {} + "missing" => checks.push(DoctorCheck::info( + "P2", + match agent { + NativeSetupAgent::Claude => "native_setup_claude_project_missing", + NativeSetupAgent::Codex => "native_setup_codex_project_missing", + }, + format!( + "{} project setup is missing; install it only when repo policy permits project-local agent artifacts.", + agent.as_str() + ), + )), + _ => checks.push(DoctorCheck::action( "P1", match agent { NativeSetupAgent::Claude => "native_setup_claude_project", @@ -1885,7 +1897,7 @@ fn append_native_setup_doctor_checks(checks: &mut Vec, start_dir: & "{} project setup is {status}; inspect the exact install/remove actions.", agent.as_str() ), - )); + )), } } } diff --git a/crates/mimir-harness/tests/binary.rs b/crates/mimir-harness/tests/binary.rs index 692113a..c63ff0f 100644 --- a/crates/mimir-harness/tests/binary.rs +++ b/crates/mimir-harness/tests/binary.rs @@ -1162,12 +1162,47 @@ fn doctor_reports_public_readiness_actions_without_raw_draft_text( assert!(stdout.contains("doctor_check index=0")); assert!(stdout.contains("id=pending_drafts")); assert!(stdout.contains("mimir drafts list --state pending")); - assert!(stdout.contains("id=native_setup_claude_project")); - assert!(stdout.contains("mimir setup-agent doctor --agent claude")); + assert!(stdout.contains("id=native_setup_claude_project_missing")); + assert!(!stdout.contains("mimir setup-agent doctor --agent claude")); assert!(!stdout.contains("Do not leak this raw doctor draft")); Ok(()) } +#[test] +fn doctor_treats_missing_native_project_setup_as_info() -> Result<(), Box> { + let tmp = tempfile::tempdir()?; + let project = tmp.path().join("project"); + fs::create_dir_all(&project)?; + write_git_origin(&project, "https://github.com/buildepicshit/Mimir.git")?; + let data_root = tmp.path().join("mimir-data"); + let drafts_dir = tmp.path().join("mimir-drafts"); + let remote_url = tmp.path().join("memory.git"); + write_remote_config( + &project.join(".mimir/config.toml"), + &data_root, + &drafts_dir, + &remote_url, + )?; + + let output = Command::new(env!("CARGO_BIN_EXE_mimir")) + .arg("doctor") + .arg("--project-root") + .arg(&project) + .env_remove("MIMIR_CONFIG_PATH") + .env_remove("MIMIR_DRAFTS_DIR") + .output()?; + + assert!(output.status.success(), "status: {:?}", output.status); + let stdout = String::from_utf8(output.stdout)?; + assert!(stdout.contains("doctor_readiness=ready")); + assert!(stdout.contains("doctor_action_count=0")); + assert!(stdout.contains("id=native_setup_claude_project_missing")); + assert!(stdout.contains("id=native_setup_codex_project_missing")); + assert!(!stdout.contains("mimir setup-agent doctor --agent claude")); + assert!(!stdout.contains("mimir setup-agent doctor --agent codex")); + Ok(()) +} + #[test] fn doctor_guides_missing_config_to_config_init() -> Result<(), Box> { let tmp = tempfile::tempdir()?;