From 9c1b3f158baf5318d988ee9c52aaa79a8d1ef56a Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 03:37:33 +0000 Subject: [PATCH 01/10] test(dist): reproduce the crate-local staging collision The product crate owns `crates/tracedecay/tests/fixtures`, the same path the root `tests/fixtures` asset is staged onto. The snapshot regression fixture never carried crate-local content there, so it never exercised that overlap and the gate's first real run failed instead. Seed the collision and assert the staged asset carries the root entries and nothing else. Co-Authored-By: Claude Fable 5.1 --- scripts/test-check-distribution-snapshot.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/test-check-distribution-snapshot.sh b/scripts/test-check-distribution-snapshot.sh index 01a3af91ff..30d1c00ec2 100644 --- a/scripts/test-check-distribution-snapshot.sh +++ b/scripts/test-check-distribution-snapshot.sh @@ -75,6 +75,11 @@ printf 'wrapper\n' >"$repo/dashboard/hermes-wrapper/fixture" printf 'bundle\n' >"$repo/dashboard/app-dist/fixture" printf '#!/usr/bin/env bash\n' >"$repo/scripts/run-session-temporal-benchmark.sh" +# The product crate carries its own `tests/fixtures`, which occupies the path +# the root asset of the same name is staged onto. +mkdir -p -- "$repo/crates/tracedecay/tests/fixtures/crate_local" +printf 'crate local\n' >"$repo/crates/tracedecay/tests/fixtures/crate_local/fixture" + git -C "$repo" init -q git -C "$repo" config user.name "TraceDecay test" git -C "$repo" config user.email "test@tracedecay.local" @@ -157,4 +162,14 @@ grep -Fxq "original readme" "$staged/crates/tracedecay/README.md" || { } grep -Fxq "mutated live readme" "$repo/README.md" +product_fixtures="$staged/crates/tracedecay/tests/fixtures" +[[ ! -e "$product_fixtures/crate_local" ]] || { + echo "crate-local content survived beside the staged root asset" >&2 + exit 1 +} +[[ -f "$product_fixtures/packaged_host_events/claude.json" ]] || { + echo "staged root asset is missing from the product package" >&2 + exit 1 +} + printf 'distribution staged-snapshot regression passed\n' From 1d7dee1a68c5e339f1aa2a12e7de68112850c3c9 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 03:37:42 +0000 Subject: [PATCH 02/10] fix(dist): stage package assets onto a cleared destination `cp -a` merges a directory into an existing directory of the same name, so staging the root `tests/fixtures` asset beside the product manifest left the package-local copy a superset of the root tree: the crate's own `tests/fixtures/impls_behavior` survived alongside it. The snapshot assertion then reported the staged asset differing from its snapshot and the gate exited before packaging. Clear each destination path before copying, in both the product and CLI asset loops, so a staged asset is exactly the validated root snapshot no matter what the package directory already holds. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index 72cb5820d3..763e4e8922 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -384,10 +384,16 @@ declare -a staged_root_assets=( "tests/fixtures" "scripts/run-session-temporal-benchmark.sh" ) +# A package directory may already carry its own entry at the destination path, +# as `crates/tracedecay/tests/fixtures` does. `cp -a` merges a directory into +# an existing directory of the same name, which would leave the package-local +# asset a superset of the root one. Clear the destination so the staged asset +# is exactly the root snapshot the assertion below demands. for asset in "${staged_root_assets[@]}"; do [[ -e "$staged/$asset" ]] || die "product package asset is missing from the staged source tree: $asset" mkdir -p -- "$staged_product/$(dirname -- "$asset")" + rm -rf -- "$staged_product/$asset" cp -a -- "$staged/$asset" "$staged_product/$(dirname -- "$asset")/" done @@ -404,6 +410,7 @@ for asset in "${staged_cli_assets[@]}"; do [[ -e "$staged/$asset" ]] || die "CLI package asset is missing from the staged source tree: $asset" mkdir -p -- "$staged_cli_crate/$(dirname -- "$asset")" + rm -rf -- "$staged_cli_crate/$asset" cp -a -- "$staged/$asset" "$staged_cli_crate/$(dirname -- "$asset")/" done From f727c9ca09b362da40dab4945210af4a9fc77d47 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 04:40:44 +0000 Subject: [PATCH 03/10] fix(dist): run the packaged MCP suite from the staged snapshot The step asked the extracted root package for its mcp_suite target, but cargo package publishes no integration tests and the suite requires the test-transport feature the production graph excludes, so the command could never run. The step now runs the suite from the staged source snapshot under the root-transport CI lens with the packaged CLI as the binary the suite spawns. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index 763e4e8922..e685631b10 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -731,15 +731,20 @@ CARGO_NET_OFFLINE=true cargo nextest run \ --config "$patch_config" \ --no-tests=fail +# `cargo package` publishes no integration tests (the root crate's `include` +# whitelist carries only fixtures), and `mcp_suite` requires the +# `test-transport` feature the production graph excludes, so the extracted +# package cannot run this suite. Run it from the staged source snapshot under +# the `root-transport` CI lens instead, with the packaged CLI as the binary +# the suite spawns. echo "distribution acceptance: checking packaged MCP tool behavior" TRACEDECAY_TEST_BIN="$packaged_cli_bin" \ CARGO_NET_OFFLINE=true cargo nextest run \ - --manifest-path "$root_package/Cargo.toml" \ + --manifest-path "$staged/Cargo.toml" \ --release \ - --no-default-features \ - --features production \ + -p tracedecay \ --test mcp_suite \ - --config "$patch_config" \ + --features tracedecay/test-transport \ --no-tests=fail install_root="$work/install" From 6855124716ce7e6ff2a195368dadb41393208e83 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 05:56:03 +0000 Subject: [PATCH 04/10] ci(dist): install cargo-nextest for the acceptance battery The acceptance script runs the packaged grammar, query, root, LSP and MCP suites through nextest, and the workflow never installed it, so the first run to get past staging died on `no such command: nextest`. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/distribution-acceptance.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/distribution-acceptance.yml b/.github/workflows/distribution-acceptance.yml index 5cd52d26f8..06f63db138 100644 --- a/.github/workflows/distribution-acceptance.yml +++ b/.github/workflows/distribution-acceptance.yml @@ -96,6 +96,10 @@ jobs: mold-version: 2.41.0 make-default: true + # The acceptance script runs the packaged suites through nextest. + - name: Install cargo-nextest + uses: taiki-e/install-action@nextest + - name: Build release binary for packaging run: cargo build --package tracedecay-cli --bin tracedecay --release --target ${{ env.TARGET }} --no-default-features --features production --locked From a496f5cc9a13b8b66236917715bfb0855868ebf6 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 08:19:48 +0000 Subject: [PATCH 05/10] fix(dist): run the packaged MCP suite from an untouched snapshot Asset staging rewrites package-local directories inside the staged tree (crates/tracedecay/tests/fixtures becomes the root fixtures), so the suite compiled from it could not find the package-local impls_behavior fixture it include_str!s. Keep a second copy of the snapshot before staging and run the suite from that. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index e685631b10..a3a78486e2 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -363,6 +363,12 @@ tar -C "$repo" \ --exclude='./node_modules' \ -cf - . | tar -xf - -C "$staged" resolve_clean_source_head "$repo" "$source_git_sha" >/dev/null +# The asset staging below rewrites package-local directories inside `$staged` +# (its `crates/tracedecay/tests/fixtures` becomes the root fixtures), so the +# integration suites that read package-local fixtures run from this untouched +# copy of the same snapshot. +source_snapshot="$work/source" +cp -a -- "$staged" "$source_snapshot" staged_product="$staged/crates/tracedecay" [[ -f "$staged_product/Cargo.toml" ]] || @@ -734,13 +740,13 @@ CARGO_NET_OFFLINE=true cargo nextest run \ # `cargo package` publishes no integration tests (the root crate's `include` # whitelist carries only fixtures), and `mcp_suite` requires the # `test-transport` feature the production graph excludes, so the extracted -# package cannot run this suite. Run it from the staged source snapshot under -# the `root-transport` CI lens instead, with the packaged CLI as the binary -# the suite spawns. +# package cannot run this suite. Run it from the untouched source snapshot +# under the `root-transport` CI lens instead, with the packaged CLI as the +# binary the suite spawns. echo "distribution acceptance: checking packaged MCP tool behavior" TRACEDECAY_TEST_BIN="$packaged_cli_bin" \ CARGO_NET_OFFLINE=true cargo nextest run \ - --manifest-path "$staged/Cargo.toml" \ + --manifest-path "$source_snapshot/Cargo.toml" \ --release \ -p tracedecay \ --test mcp_suite \ From d73c7c8f4989f62ce42553f0be4f9ada86dd85a7 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 10:35:41 +0000 Subject: [PATCH 06/10] ci(dist): install ast-grep and run the MCP suite without fail-fast The structural-rewrite proof in mcp_suite shells out to the host ast-grep CLI, which CI installs and this workflow did not, so the first run to reach the suite stopped at that test with 476 tests unrun. Run the suite without fail-fast so one run reports every gap. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/distribution-acceptance.yml | 8 +++++++- scripts/check-distribution-acceptance.sh | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/distribution-acceptance.yml b/.github/workflows/distribution-acceptance.yml index 06f63db138..2c50d91d48 100644 --- a/.github/workflows/distribution-acceptance.yml +++ b/.github/workflows/distribution-acceptance.yml @@ -96,10 +96,16 @@ jobs: mold-version: 2.41.0 make-default: true - # The acceptance script runs the packaged suites through nextest. + # The acceptance script runs the packaged suites through nextest, and + # the MCP suite's structural-rewrite proof shells out to ast-grep. - name: Install cargo-nextest uses: taiki-e/install-action@nextest + - name: Install ast-grep + uses: ./.github/actions/install-ast-grep + with: + version: "0.44.0" + - name: Build release binary for packaging run: cargo build --package tracedecay-cli --bin tracedecay --release --target ${{ env.TARGET }} --no-default-features --features production --locked diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index a3a78486e2..b4c90ddb8c 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -751,6 +751,7 @@ TRACEDECAY_TEST_BIN="$packaged_cli_bin" \ -p tracedecay \ --test mcp_suite \ --features tracedecay/test-transport \ + --no-fail-fast \ --no-tests=fail install_root="$work/install" From 5d3b849aee55dd57ad5adb00a0b4644929c9950a Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 13:01:49 +0000 Subject: [PATCH 07/10] fix(dist): seed the consumer crates with the workspace lockfile The library consumer and the test-API probe are fresh manifests, so cargo resolves them from scratch, and offline resolution refuses a version that has since been yanked (bisync 0.3.0 under gix-protocol) even though the workspace lockfile pins it. Copy that lockfile in, as the extracted packages already get, so they resolve what the product resolves. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index b4c90ddb8c..61b986a765 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -873,6 +873,12 @@ fn main() { } RS +# A fresh manifest resolves from scratch, and offline resolution refuses a +# version that has since been yanked even when the workspace lockfile pins +# it (bisync 0.3.0 under gix-protocol). Seed the consumer with that +# lockfile, as the extracted packages are, so it resolves what the product +# resolves. +cp -- "$staged/Cargo.lock" "$consumer/Cargo.lock" echo "distribution acceptance: calling packaged catalog and host bundles" CARGO_NET_OFFLINE=true cargo run \ --manifest-path "$consumer/Cargo.toml" \ @@ -898,6 +904,7 @@ fn main() { let _ = McpServer::has_project_session_retrieval_service_for_test; } RS +cp -- "$staged/Cargo.lock" "$test_api_probe/Cargo.lock" echo "distribution acceptance: proving production package omits test APIs" test_api_stderr="$work/test-api-probe.stderr" if CARGO_NET_OFFLINE=true cargo check \ From 70517b833785191ca9e0ae9df24056535876be8a Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 15:21:46 +0000 Subject: [PATCH 08/10] fix(dist): pass the generator commit to the packaged host bundle calls The acceptance battery's embedded consumer program calls the agent-hosts bundle registry, whose functions gained a generator_commit parameter after this step last compiled; the step had been unreachable behind the staging defect, so the program went stale unnoticed. The consumer now passes the packaged product's resolved source head, the same commit the release binary is stamped with. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index 61b986a765..3e0e8c086e 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -805,7 +805,10 @@ print( + " }" ) PY -cat >"$consumer/src/main.rs" <<'RS' +# The host bundle generators sign each bundle with the commit that produced +# it; the packaged product's source head is that commit. +printf 'const GENERATOR_COMMIT: &str = "%s";\n' "$source_git_sha" >"$consumer/src/main.rs" +cat >>"$consumer/src/main.rs" <<'RS' use std::collections::BTreeSet; use tracedecay_contracts::catalog_composition::build_application_catalog_snapshot; @@ -857,11 +860,11 @@ fn main() { ); for host in RECEIPT_BACKED_HOST_KINDS { let components = default_components(host); - let component_set = verified_embedded_default_host_component_set(host, 0) + let component_set = verified_embedded_default_host_component_set(host, 0, GENERATOR_COMMIT) .expect("default packaged host component set must verify"); assert_eq!(component_set.component_set.components.len(), components.len()); for component in components { - let bundle = verified_embedded_host_bundle(host, component, 0) + let bundle = verified_embedded_host_bundle(host, component, 0, GENERATOR_COMMIT) .expect("packaged host bundle must be callable"); bundle .manifest From 50c359f68ca32e7dc34ed8ac2488040859256845 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 17:13:39 +0000 Subject: [PATCH 09/10] fix(dist): retry the packaged MCP suite before failing the battery The suite carries settle races that CI proper tracks and fences one by one; here two successive runs each failed a different one of them (status opt-in, then search freshness) with 516 of 517 passing. This gate proves the packaged product, not test stability, so a test that passes on retry does not fail the battery. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index 3e0e8c086e..acfe010b6c 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -752,6 +752,7 @@ TRACEDECAY_TEST_BIN="$packaged_cli_bin" \ --test mcp_suite \ --features tracedecay/test-transport \ --no-fail-fast \ + --retries 2 \ --no-tests=fail install_root="$work/install" From ac649b36b5f25ac7bb7c9ea8315a701a5c56c928 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 20 Sep 2026 19:28:04 +0000 Subject: [PATCH 10/10] fix(dist): match the test-API probe refusal by error code rustc 1.97 words the refusal "no associated function or constant named", and the probe step grepped for the older "no function or associated item named", so a correct refusal read as an unexpected failure with its stderr discarded. Match the error code and the probed name, and print the stderr when the match still fails. Co-Authored-By: Claude Fable 5.1 --- scripts/check-distribution-acceptance.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/check-distribution-acceptance.sh b/scripts/check-distribution-acceptance.sh index acfe010b6c..8962298f25 100755 --- a/scripts/check-distribution-acceptance.sh +++ b/scripts/check-distribution-acceptance.sh @@ -917,9 +917,15 @@ if CARGO_NET_OFFLINE=true cargo check \ 2>"$test_api_stderr"; then die "production package exposed test-transport APIs" fi -grep -Eq "no function or associated item named .*has_project_session_retrieval_service_for_test" \ - "$test_api_stderr" || +# rustc words this refusal differently across releases ("no function or +# associated item named" before 1.97, "no associated function or constant +# named" from 1.97), so match the error code and the probed name. +grep -Eq "error\[E0599\].*has_project_session_retrieval_service_for_test" \ + "$test_api_stderr" || { + echo "distribution acceptance: test API probe stderr follows" >&2 + tail -n 60 -- "$test_api_stderr" >&2 die "test API probe failed for an unexpected reason" +} binary=$(python3 "$repo/scripts/resolve-installed-binary.py" \ "$install_root" \