Merge verified CI probe repairs from main into PR #6985

Carry main 51c00f231a without changing the original PR-specific
source. Pin the no-host-tools metric fixture through its existing test-only
capability seam and remove echo/grep pipe races from mobile smoke.

Main repair verification: 2 focused existing Rust tests passed; full tool
catalog JSON unchanged; default CLI build and all 9 mobile HTTP assertions
passed; npm 1312 passed, 0 failed, 7 skipped; check:web, scoped rustfmt,
ShellCheck, Bash syntax and diff checks passed. Original isolated mobile
launch failed socket-path length before assertions; corrected only the
launcher and reran the same binary. Fresh resulting-head hosted native
qualification remains required; no old-source CI result is relabeled.

Only the three inherited probe paths differ from the previous PR head.
Both histories are retained. No new test, publication or branch cleanup.

Refs CW-6439

Signed-off-by: Hunter Bown <[email protected]>
This commit is contained in:
CodeWhale Bot committed 2026-10-15 14:15:57 -07:00
commit 9f5ed8ebb6
3 files changed
+18 -17

No files matched your search

@@ -451,17 +451,18 @@ async fn measure_production_mode_tool_catalogs() -> serde_json::Value {
let _userprofile = EnvVarGuard::set("USERPROFILE", &home);
let _codewhale_home = EnvVarGuard::set("CODEWHALE_HOME", home.join(".codewhale"));
// Interpreter-backed advanced tools are intentionally excluded from this
// cross-platform built-in profile. The production planner still owns that
// decision; a deliberately nonexistent PATH root makes its real dependency
// probes return absent without inheriting the developer or CI host.
// cross-platform built-in profile. Pin host capabilities because Windows
// system-directory lookup can find interpreters outside PATH. Keep the
// nonexistent PATH root for the canonical shell spelling below.
let _host_tools = crate::dependencies::pin_recorded_host_tools(Vec::new());
let _path = EnvVarGuard::set("PATH", tmp.path().join("no-host-interpreters"));
// Shell syntax is part of the tool schema. A bare name plus the empty
// PATH resolves to the same `bash` spelling on Unix and Windows without
// executing or requiring that interpreter. Do not inherit the host shell.
let _shell = EnvVarGuard::set("SHELL", "bash");
// The macOS Vision OCR probe is a framework check that ignores PATH, so
// the profile neutralizes it explicitly: every host presents no local OCR
// capability here, matching the no-host-interpreters PATH pin above.
// Keep the explicit OCR-unavailable environment for framework probes that
// ignore PATH; the host capability pin above also excludes local OCR from
// this profile.
let _ocr = EnvVarGuard::set("CODEWHALE_LOCAL_OCR_UNAVAILABLE", "1");
let api_config = Config {
+8 -8
View File
@@ -350,10 +350,10 @@ pub fn resolve_pandoc() -> Option<String> {
/// Whether an optional tool whose backend lives on this host (an interpreter,
/// a converter, an OCR engine) is available: `probe` decides, except that a
/// conformance replay answers with the recorded host's set so goldens do not
/// test fixture answers with the recorded host's set so results do not
/// depend on what the machine running them has installed (test builds only).
pub(crate) fn host_tool_available(tool: &str, probe: impl FnOnce() -> bool) -> bool {
#[cfg(all(test, unix))]
#[cfg(test)]
if let Some(available) = RECORDED_HOST_TOOLS.with(|cell| {
cell.borrow()
.as_ref()
@@ -361,13 +361,13 @@ pub(crate) fn host_tool_available(tool: &str, probe: impl FnOnce() -> bool) -> b
}) {
return available;
}
// Only a conformance replay reads the name.
#[cfg(not(all(test, unix)))]
// Only test fixtures read the name.
#[cfg(not(test))]
let _ = tool;
probe()
}
#[cfg(all(test, unix))]
#[cfg(test)]
thread_local! {
static RECORDED_HOST_TOOLS: std::cell::RefCell<Option<Vec<String>>> =
const { std::cell::RefCell::new(None) };
@@ -375,16 +375,16 @@ thread_local! {
/// Pin [`host_tool_available`] on this thread to a recorded host's tools until
/// the guard drops.
#[cfg(all(test, unix))]
#[cfg(test)]
pub(crate) fn pin_recorded_host_tools(tools: Vec<String>) -> RecordedHostToolsGuard {
RECORDED_HOST_TOOLS.with(|cell| *cell.borrow_mut() = Some(tools));
RecordedHostToolsGuard
}
#[cfg(all(test, unix))]
#[cfg(test)]
pub(crate) struct RecordedHostToolsGuard;
#[cfg(all(test, unix))]
#[cfg(test)]
impl Drop for RecordedHostToolsGuard {
fn drop(&mut self) {
RECORDED_HOST_TOOLS.with(|cell| *cell.borrow_mut() = None);
+3 -3
View File
@@ -103,7 +103,7 @@ assert_body_contains() {
local body
body=$(curl "${curl_args[@]}" "$url" 2>/dev/null || true)
if echo "$body" | grep -q "$substring"; then
if grep -q -- "$substring" <<< "$body"; then
pass "$method $path body contains '$substring'"
else
fail "$method $path body missing '$substring'"
@@ -121,7 +121,7 @@ assert_body_not_contains() {
local body
body=$(curl "${curl_args[@]}" "$url" 2>/dev/null || true)
if echo "$body" | grep -q "$substring"; then
if grep -q -- "$substring" <<< "$body"; then
fail "$method $path body unexpectedly contains '$substring'"
else
pass "$method $path body does not contain '$substring'"
@@ -209,7 +209,7 @@ else
fail "mobile unexpectedly accepted a 0.0.0.0 binding"
fi
if echo "$BIND_OUTPUT" | grep -qi "loopback-only"; then
if grep -qi -- "loopback-only" <<< "$BIND_OUTPUT"; then
pass "rejection explains the loopback-only boundary"
else
fail "rejection missing loopback-only guidance"