diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a03a4d8..de220016 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.2.3] - 2026-07-02 + +### Fixed + +- Fixed a flaky unit test: `ai_assess_writes_llm_invocation_audit_row_via_runner` intermittently failed under heavy parallel `cargo test --lib` load with `failed to write Gemini stdin: Broken pipe (os error 32)`. The test's fake-`gemini` script never read stdin before exiting, racing against `run_gemini_assessment`'s concurrent stdin-writer task under scheduler pressure. The script now drains stdin to EOF before responding, removing the race deterministically. Test-only change; no production code affected. + ## [3.2.2] - 2026-07-01 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 00632483..95e1d25c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -507,7 +507,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cortex" -version = "3.2.2" +version = "3.2.3" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index 35878f8a..69a43cee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [package] name = "cortex" -version = "3.2.2" +version = "3.2.3" edition = "2024" rust-version = "1.86" license = "MIT" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 8278c17a..bd25dd25 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -23,7 +23,7 @@ services: # Default tag is kept in sync by `cargo xtask bump-version` (version canon); # previously this was frozen at 1.0.0 while migrations moved forward — # a stale binary against a newer schema (full-review OH1). - image: ghcr.io/jmagar/cortex:${CORTEX_VERSION:-3.2.2} + image: ghcr.io/jmagar/cortex:${CORTEX_VERSION:-3.2.3} container_name: cortex user: "${CORTEX_UID:-1000}:${CORTEX_GID:-1000}" env_file: diff --git a/mcpb/manifest.json b/mcpb/manifest.json index 520ada89..3ee75de3 100644 --- a/mcpb/manifest.json +++ b/mcpb/manifest.json @@ -3,7 +3,7 @@ "manifest_version": "0.4", "name": "cortex", "display_name": "Cortex", - "version": "3.2.2", + "version": "3.2.3", "description": "Query local cortex SQLite logs through a bundled stdio MCP server.", "long_description": "cortex packages the existing cortex stdio entrypoint as a local MCP Bundle. It is query-only: it reads the configured SQLite database and does not start syslog listeners, HTTP servers, Docker Compose, REST, or deploy flows.", "author": { diff --git a/server.json b/server.json index e1ecfad7..bf0e9a97 100644 --- a/server.json +++ b/server.json @@ -7,11 +7,11 @@ "url": "https://github.com/jmagar/cortex", "source": "github" }, - "version": "3.2.2", + "version": "3.2.3", "packages": [ { "registryType": "oci", - "identifier": "ghcr.io/jmagar/cortex:v3.2.2", + "identifier": "ghcr.io/jmagar/cortex:v3.2.3", "transport": { "type": "stdio" }, diff --git a/src/app/service_tests.rs b/src/app/service_tests.rs index cafb6f28..1f53c3fe 100644 --- a/src/app/service_tests.rs +++ b/src/app/service_tests.rs @@ -1660,13 +1660,21 @@ async fn ai_assess_writes_llm_invocation_audit_row_via_runner() { // run_gemini_assessment succeeds without needing a real Gemini CLI — // same fake-script-on-PATH pattern used by // src/assessment_tests.rs::gemini_assessment_timeout_kills_and_reaps_child. + // + // `cat >/dev/null` drains stdin before the script prints anything: the + // parent's stdin_task is writing the prompt concurrently, and under + // heavy parallel-test-suite scheduling pressure this script could + // otherwise exit (closing its stdin read end) before that write + // completed, surfacing a spurious "Broken pipe" from run_gemini_assessment. + // Reading stdin to EOF first makes the child block until the parent's + // write+shutdown finishes, removing the race deterministically. let source = tempfile::tempdir().unwrap(); std::fs::create_dir_all(source.path().join(".gemini")).unwrap(); std::fs::write(source.path().join(".gemini").join("settings.json"), "{}").unwrap(); let script = source.path().join("fake-gemini.sh"); std::fs::write( &script, - "#!/usr/bin/env bash\necho '{\"type\":\"message\",\"role\":\"assistant\",\"content\":\"ok\"}'\necho '{\"type\":\"result\",\"status\":\"success\"}'\n", + "#!/usr/bin/env bash\ncat >/dev/null\necho '{\"type\":\"message\",\"role\":\"assistant\",\"content\":\"ok\"}'\necho '{\"type\":\"result\",\"status\":\"success\"}'\n", ) .unwrap(); #[cfg(unix)]