Repository navigation
Conversation
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
… action pin comments Address the Codex security review and the zizmor code-scanning alerts (386-390) on #8613. repeatRust merged each package's cargo target flags through a Set of argv tokens, so two integration-test files in one package collapsed `--test codec --test connection` into `--test codec connection`. nextest reads the trailing `connection` as a test-name filter, lists nothing, and the lane took the "nothing to repeat" branch and reported success without running a test (verified against buzz-audio-client: the collapsed argv lists no tests and exits 0). rustTarget now returns one flag per entry and the new rustGroups keys each whole flag, so a `--test <name>` is emitted once per name while `--lib`/`--bins` stay single; the regression test asserts the exact argv for two integration files and for a src/ plus tests/ file in the same package, through the seam repeatRust uses. The `-p`, `-E` and filterset arguments were re-read for the same class of bug and pass single values. In _ci-flake.yml, actions/upload-artifact 043fb46d is v7.0.1 (the `v7` tag has since moved to v7.0.2), so its four comments now say so, as the other workflows do. rui314/setup-mold 7e4f20ad is a commit the `v1` tag no longer points at (339e96b4, mold 3.0.0), so the flake workflow pins the current `v1`; _ci-rust.yml, _ci-relay.yml and _ci-desktop.yml carry the same stale pin and are left for a separate change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent
Verdict: REQUEST CHANGES before merge. I’m submitting this as a comment review per this repo’s agent-review guidance; the blocker is still concrete and author-actionable.
This PR’s stated contract is to repeat changed-test selections on pull requests without silently skipping intended targets. At exact head 8a69757b6f648a5b937d79e6c2c81d8a8e2f263a, I found two false-green paths where changed Rust test surfaces produce an empty flake selection and the repeat lanes skip.
Findings
High — Desktop Tauri Rust tests are silently excluded from changed-test repetition
scripts/flake-check.mjs only classifies Rust files under crates/<crate>/(src|tests)/** (scripts/flake-check.mjs:70-82). Desktop Tauri Rust files under desktop/src-tauri/** fall through to undefined, even though the normal CI path filter treats desktop/src-tauri/** as a required desktop-rust surface (.github/workflows/ci.yml:89-90) and the repo’s local Tauri test command runs cd desktop/src-tauri && cargo test --workspace (Justfile:231-232). There are real Tauri integration tests, e.g. desktop/src-tauri/tests/rodio_mixer_diagnostic.rs:53.
I verified the selector behavior at the reviewed SHA:
desktop/src-tauri/tests/rodio_mixer_diagnostic.rs -> undefined
desktop/src-tauri/src/lib.rs -> undefined
crates/buzz-core/src/filter.rs -> rust
And with a synthetic tree that changed only desktop/src-tauri/tests/rodio_mixer_diagnostic.rs, node scripts/flake-check.mjs select HEAD <tree> reported:
## Flake check selection
No Rust, node:test, Playwright or Flutter test files changed.
rust=
Because _ci-flake.yml skips the Rust repeat job when needs.flake-select.outputs.rust == '' (.github/workflows/_ci-flake.yml:67-70), a PR that changes or adds a Desktop Tauri Rust test gets a successful selection job and skipped repeat lanes. That is a false “nothing selected” green on a required test surface.
Author action: include desktop/src-tauri Rust test/source files in flake-check.mjs selection and repeat execution, with the correct manifest/workspace command and sidecar-stub setup if needed; or explicitly declare this surface out of scope and make the skip visible in the selection summary. Add a regression proving a changed Tauri Rust test produces a non-empty Rust selection through the real select path.
High — Rust integration-test helper changes can select no tests and skip the repeat lane
classify() treats crates/<crate>/tests/**/*.rs as Rust (scripts/flake-check.mjs:70-73), but selectRust() returns undefined when the changed file itself has no Rust test functions (scripts/flake-check.mjs:354-360), and the caller records no test functions then continues without producing a Rust selection (scripts/flake-check.mjs:518-520).
That is unsafe for shared integration-test helper modules. crates/buzz-agent/tests/common/mod.rs states that every integration test file includes it with mod common; and compiles it once per binary (crates/buzz-agent/tests/common/mod.rs:1-5); current importers include fake_llm.rs, anthropic_continuation.rs, regressions.rs, and permission_boundary.rs.
I verified the reachable behavior at the reviewed SHA by creating a synthetic tree that only appended a comment to crates/buzz-agent/tests/common/mod.rs, then running node scripts/flake-check.mjs select HEAD <tree>:
| crates/buzz-agent/tests/common/mod.rs | rust | no test functions |
rust=
So a PR can change a shared Rust integration-test harness/helper and get all flake repeat lanes skipped, even though the dependent integration binaries compile and exercise that helper.
Author action: make no-test Rust files under crates/<crate>/tests/** select the dependent runnable integration tests instead of producing an empty selection. A conservative minimal behavior would repeat all non-ignored/non-infra integration tests in the package, or all integration-test targets that could include the helper. Add a regression using crates/buzz-agent/tests/common/mod.rs or an equivalent fixture that proves a helper-only change yields a non-empty Rust selection through the real select path.
Review basis
- Local HEAD and remote
refs/pull/8613/headboth verified as8a69757b6f648a5b937d79e6c2c81d8a8e2f263abefore posting. - Authenticated reviewer:
jedwards27; PR author:matt2e. - Commands used for the material findings included:
git rev-parse HEADgit ls-remote origin refs/pull/8613/headnode --input-type=module -eimport ofclassify()for the path probes above- synthetic-tree probes with
git read-tree,git update-index --cacheinfo,git write-tree, thennode scripts/flake-check.mjs select HEAD <tree>
- CI was not fully terminal when checked, but these blockers are selector-contract defects independent of the remaining in-progress jobs.
Address the two High findings of review 5659898932 on #8613: a changed Rust test under desktop/src-tauri, or a changed helper module under a crate's tests/, produced an empty flake selection and every repeat lane skipped, a false "nothing selected" green. Desktop Tauri Rust is now a runner of its own rather than an unclassified path. rustFile places a Rust file in its workspace (the root crates, or desktop/src-tauri and its crates/*), and classify, cratePackage, rustTarget, rustModulePath and rustGroups read that instead of assuming crates/<crate>/. The new flake-tauri lane mirrors the Desktop Tauri core lane's setup (its apt packages, sidecar stubs and desktop-core rust-cache, restored read-only) and runs the same script against desktop/src-tauri/Cargo.toml. nextest reads its configuration from the workspace root, so that workspace gets its own .config/nextest.toml with the flake profile, and the Postgres exclusion applies only in the root workspace: nextest rejects a binary(/^postgres_/) predicate where no such binary exists, which the Tauri workspace's first live run showed. Supporting the surface for real was straightforward, since the workspace is an ordinary cargo workspace that nextest lists and runs by manifest path, so no out-of-scope declaration was needed. A tests/** file without test functions is a helper that integration binaries compile in with `mod common;`. select now finds the package's integration targets that include it (rustIncludes reads `mod <first>;` declarations with comments and strings blanked, `#[path]` attributes, and a tests/<dir>/main.rs owning its directory; a helper no target names falls back to every target) and selects each of those binaries whole, so the ignored and infrastructure exclusions still apply, with a row naming the importers. A helper and its importer changed together select each test once. A src/** file without test functions still selects nothing; a comment beside the row records that this is deliberate, since the regular lanes run what depends on it. Regression tests go through the real select entry point over a synthetic head tree (HEAD with a comment appended, as the reviewer probed): a changed desktop/src-tauri/tests/rodio_mixer_diagnostic.rs yields its three tests under tauri=, and a comment-only change to crates/buzz-agent/tests/common/mod.rs yields rust= entries in exactly anthropic_continuation, fake_llm, permission_boundary and regressions, the four files declaring `mod common;`. Verified live: cargo nextest list with the produced -p/--test flags and filterset matches all 85 entries, and `flake-check.mjs tauri --iterations=2` on the Tauri selection ran green end to end with its JUnit report under desktop/src-tauri/target/nextest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent reviewed exact head f02a4235a9fd0e60406e218acaab1b6537ca6446 against base 8216db1c712cefdc0e2af7191d501adae03ba392.
Requesting changes because this head has a PR-caused required Desktop gate failure.
Finding
High — Required Desktop JS gate fails because the new selector regression test reads stdout while CI redirects the child selector output to GitHub files
scripts/flake-check.test.mjs runs the real selector as a child process, but it does not control the child environment (scripts/flake-check.test.mjs:62-65). In GitHub Actions, that child inherits GITHUB_STEP_SUMMARY and GITHUB_OUTPUT; the production selector intentionally writes summaries to $GITHUB_STEP_SUMMARY (scripts/flake-check.mjs:444-447) and outputs to $GITHUB_OUTPUT (scripts/flake-check.mjs:724-726) when those variables are present. The new regression test then asserts the Tauri selection summary is present in result.stdout (scripts/flake-check.test.mjs:495-497), so under the same environment CI uses, result.stdout is empty.
That is already happening in live required CI: Desktop Domain / Desktop JS failed on this head with actual: '' at scripts/flake-check.test.mjs:495, which also fails the top-level required Desktop check.
Failure mode: every PR run of the Desktop JS lane inherits the GitHub output environment, so this regression test fails in CI even when the selector behavior itself is correct. That blocks merge and turns the protective test into the dungeon trap. Excellent craftsmanship, wrong victim.
Author action: make selectAppending() isolate or explicitly control child output routing. Either unset GITHUB_STEP_SUMMARY / GITHUB_OUTPUT for the child and keep stdout parsing, or set them to temporary files and read those files. Please also add a GitHub-like-env regression so this CI-only failure cannot return.
Verification owner: author fixes the test and reruns the required Desktop Domain / Desktop JS / top-level Desktop gates; I can re-review the next exact head.
Verification performed
- Confirmed authenticated reviewer
jedwards27is not PR authormatt2ebefore submitting this review. - Confirmed live PR head and local review checkout both equal
f02a4235a9fd0e60406e218acaab1b6537ca6446immediately before review submission. - Confirmed required checks currently include failing
Desktopand failingDesktop Domain / Desktop JSfor this head. - Ran the focused selector regression test with GitHub output env unset:
node --test --test-name-pattern 'select, through its entry point' scripts/flake-check.test.mjs— pass. - Ran the same focused test with
GITHUB_OUTPUTandGITHUB_STEP_SUMMARYset to temp files — fail with the same empty-stdout assertion while the expected summary/output data is written to those files. - Reviewed the two independent lane reports: both found the prior false-empty selector paths materially fixed and found no additional systems/product blocker beyond the required-gate failure above.
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent — REQUEST CHANGES
Reviewed: 8216db1c712cefdc0e2af7191d501adae03ba392..f02a4235a9fd0e60406e218acaab1b6537ca6446 (exact head f02a4235a9fd0e60406e218acaab1b6537ca6446)
Risk: high — this changes CI/test-selection contracts. A selector false negative gives contributors a false green, and a required exact-head gate is already red.
Behavior/contracts traced: changed-file diff selection → flake-check summary/output → GitHub Actions step outputs → Rust/Tauri repeat lanes; Rust integration-target versus helper-module classification.
Findings
-
Required Desktop JS CI is red because the new regression test is not hermetic to GitHub Actions output env.
selectAppending()asserts the child selector’sstdout(scripts/flake-check.test.mjs:48-74,scripts/flake-check.test.mjs:489-507). In GitHub Actions, though,GITHUB_STEP_SUMMARYandGITHUB_OUTPUTare set, andscripts/flake-check.mjswrites the summary/output there instead of stdout (scripts/flake-check.mjs:444-448,scripts/flake-check.mjs:703-726). The exact-head required checks showDesktop Domain / Desktop JS,Desktop Domain / Desktop, andDesktopfailing. Locally, the same test passes with those env vars unset and fails in a CI-shaped env while writing the expected Tauri selection into the summary/output files. That is a PR-caused required-gate failure, not a reviewer tooling gap.Author action: make the test helper hermetic to GitHub Actions env — either clear
GITHUB_STEP_SUMMARY/GITHUB_OUTPUTin the spawned child when asserting stdout, or provide temp files and assert their contents. Then get the Desktop JS/Desktop required gate green at the new exact head.
Verification owner: author for fix + CI rerun; reviewer/CI for exact-head recheck. -
A runnable Rust integration-test target with no local test functions is still treated as a helper, so the changed target is skipped and unrelated binaries are repeated.
selectRust()returnsundefinedwhen the changed file has no locally parsed Rust test functions (scripts/flake-check.mjs:408-414), andselecttreats anytests/**file in that state as a helper/importer case (scripts/flake-check.mjs:640-654). Butcrates/buzz-acp/tests/pool_lifecycle_state.rs:1-4is itself a real integration-test binary; it includes../src/pool_lifecycle.rs, whose#[cfg(test)]module contains runnable tests (crates/buzz-acp/src/pool_lifecycle.rs:134-146,crates/buzz-acp/src/pool_lifecycle.rs:282-300).cargo test -p buzz-acp --test pool_lifecycle_state -- --listlists 9 tests for that target. A synthetic change topool_lifecycle_state.rs, however, produces flake output that selectsgit_bootstrap,run_task, andstdio_contractand omitspool_lifecycle_state. That preserves a false-green path for integration targets whose test bodies come through#[path]/included modules.Author action: distinguish true helper modules from runnable integration targets. For
tests/<stem>.rsandtests/<dir>/main.rs, select that target’s runnable tests — or introduce a whole-target repeat representation consumed by the runner — even when tests are discovered only through included modules. Keep importer fan-out for true helper modules. Add a regression aroundcrates/buzz-acp/tests/pool_lifecycle_state.rsproving the selected entries include thepool_lifecycle_statetarget’s 9 tests and do not substitute unrelated integration binaries.
Verification owner: author for selector/repeater fix and regression; reviewer/CI for the synthetic probe and flake lane rerun.
Validation
At clean local head f02a4235a9fd0e60406e218acaab1b6537ca6446, with refs/pull/8613/head also resolving to f02a4235a9fd0e60406e218acaab1b6537ca6446:
gh api user→ authenticated reviewerjedwards27; PR author ismatt2e.gh pr view 8613 --json author,baseRefOid,headRefOid,statusCheckRollup,title,url→ base8216db1c712cefdc0e2af7191d501adae03ba392, headf02a4235a9fd0e60406e218acaab1b6537ca6446; required Desktop checks above are failing.git ls-remote origin refs/pull/8613/head→f02a4235a9fd0e60406e218acaab1b6537ca6446.env -u GITHUB_STEP_SUMMARY -u GITHUB_OUTPUT node --test scripts/flake-check.test.mjs→ pass, 15/15.GITHUB_STEP_SUMMARY=$PWD/.scratch/.../summary.md GITHUB_OUTPUT=$PWD/.scratch/.../output.txt node --test scripts/flake-check.test.mjs→ fail withAssertionErrorbecausetauri.summaryis empty; the expected Tauri selection is written tosummary.md/output.txt.cargo test -p buzz-acp --test pool_lifecycle_state -- --list→ pass and lists 9pool_lifecycle::tests::*tests.- Synthetic selector run using
node scripts/flake-check.mjs select HEAD <tree-with-crates/buzz-acp/tests/pool_lifecycle_state.rs-appended>→ selectsgit_bootstrap,run_task, andstdio_contract; does not selectpool_lifecycle_state.
No full local just ci run. The blocking issues above are exact-head required-gate failure plus a directly reproduced selector false negative.
Manual/native evidence: not applicable; this PR changes CI/tooling behavior, verified through exact-head GitHub checks and local selector probes.
Residual risk: the product/dev-experience lane could not complete because of an internal tool failure, so this review is limited to exact-head CI/selector contracts. That does not weaken the two author-actionable blockers above.
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent
Verdict: REQUEST CHANGES before merge.
Reviewed exact head f02a4235a9fd0e60406e218acaab1b6537ca6446 against base 8216db1c712cefdc0e2af7191d501adae03ba392. Risk is high because this PR changes CI selection/repetition policy, and false-green behavior here is exactly what the PR is meant to eliminate.
Findings
High — Required Desktop JS gate fails in the GitHub Actions environment
The new Desktop JS gate runs node --test scripts/flake-check.test.mjs (.github/workflows/_ci-desktop.yml:55-56). That test spawns the production selector and reads result.stdout (scripts/flake-check.test.mjs:62-74), then asserts the selection summary is in stdout (scripts/flake-check.test.mjs:495-497).
In GitHub Actions, the child process inherits GITHUB_STEP_SUMMARY and GITHUB_OUTPUT. The production selector deliberately writes the summary to $GITHUB_STEP_SUMMARY (scripts/flake-check.mjs:444-447) and outputs to $GITHUB_OUTPUT (scripts/flake-check.mjs:724-726) when those are present. So the child’s stdout is empty under CI, and the new regression test fails even though it passes locally with those env vars unset.
Impact: this exact head already has failing required checks: Desktop Domain / Desktop JS, Desktop Domain / Desktop, and top-level Desktop.
Author action: isolate or explicitly control the child selector environment in selectAppending(): either unset GITHUB_STEP_SUMMARY / GITHUB_OUTPUT for the child when the test wants stdout, or set them to temp files and read/assert those files. Add a GitHub-like-env regression so this CI-only failure cannot return.
Verification owner: author reruns node --test scripts/flake-check.test.mjs both with and without GITHUB_STEP_SUMMARY/GITHUB_OUTPUT set, and CI proves the required Desktop JS/Desktop checks green on the new exact head.
High — Feature-gated Rust selections can still false-skip instead of being repeated
The selector can now produce real Rust/Tauri entries for previously missed surfaces, but the repeat path does not preserve the feature configuration used by the normal CI lanes. When a selected test is compiled only behind a feature, repeatRust() lists/runs cargo without that feature, finds no runnable candidates, then reports “nothing to repeat” as if every selected test were ignored or infrastructure-backed (scripts/flake-check.mjs:902-906). That is a false green on the PR’s core contract.
Root Rust example:
- Normal CI intentionally runs feature-flag tests with LaunchDarkly enabled:
cargo nextest run -p buzz-feature-flags --features launchdarkly(Justfile:479-482). - The LaunchDarkly module is behind
#[cfg(feature = "launchdarkly")](crates/buzz-feature-flags/src/lib.rs:13-15). - The flake repeat lane calls
node scripts/flake-check.mjs rust --iterations=10 $SELECTEDwith no feature args (.github/workflows/_ci-flake.yml:97-100). repeatRust()builds cargo args as-p <crate>plus target flags only (scripts/flake-check.mjs:846-851) and uses those same args for bothcargo nextest listandcargo nextest run(scripts/flake-check.mjs:869-880,scripts/flake-check.mjs:922-933). There is no per-package--features launchdarklypath.
I verified the failure shape at this exact head: a synthetic change to crates/buzz-feature-flags/src/launchdarkly.rs selects 25 Rust test entries, including tests::launchdarkly_test_config_uses_null_event_processor; cargo test -p buzz-feature-flags tests::launchdarkly_test_config_uses_null_event_processor -- --list lists 0 tests, while adding --features launchdarkly lists that selected test. Without feature preservation, the repeat lane has selected work that cannot become runnable candidates.
Desktop Tauri has the same source-level contract break:
- The normal mesh lane runs
cargo test --manifest-path desktop/src-tauri/Cargo.toml --features mesh-llm --lib(Justfile:234-236). - The mesh module is behind
#[cfg(feature = "mesh-llm")](desktop/src-tauri/src/lib.rs:25-28). - The flake Tauri lane invokes
node scripts/flake-check.mjs tauri --iterations=10 $SELECTEDwith onlyCMAKE_POLICY_VERSION_MINIMUMset and no--features mesh-llmroute (.github/workflows/_ci-flake.yml:161-165), whilerepeatRust()uses the same no-feature cargo path above.
Author action: preserve the normal CI feature configuration for selected Rust/Tauri tests when listing and running repetitions. At minimum, buzz-feature-flags selections need --features launchdarkly, and Tauri mesh selections need --features mesh-llm. Add regression coverage through the production repeat/listing seam proving a selected LaunchDarkly test and a selected Tauri mesh test become runnable candidates and cannot silently degrade to “ignored or infrastructure-backed.” Also make unmatched selected tests fail or explicitly classify why they are unmatched; do not summarize feature-missing selected tests as ignored/infra.
Verification owner: author adds the feature-gated repeat regressions and reruns the affected flake repeat lanes; reviewer rechecks focused selector/list probes plus CI on the new exact head.
Validation performed
- Confirmed authenticated reviewer
jedwards27differs from PR authormatt2e. - Confirmed local checkout,
gh pr view, andgit ls-remote origin refs/pull/8613/headall matched exact headf02a4235a9fd0e60406e218acaab1b6537ca6446immediately before this review. - Confirmed live required checks include failing
Desktop Domain / Desktop JS,Desktop Domain / Desktop, andDesktopfor this head. env -u GITHUB_STEP_SUMMARY -u GITHUB_OUTPUT node --test --test-name-pattern 'select, through its entry point' scripts/flake-check.test.mjs→ pass at the reviewed SHA.GITHUB_STEP_SUMMARY=/tmp/... GITHUB_OUTPUT=/tmp/... node --test --test-name-pattern 'select, through its entry point' scripts/flake-check.test.mjs→ fail at the reviewed SHA withactual: ''for thescripts/flake-check.test.mjs:495assertion.- Synthetic selector for
crates/buzz-feature-flags/src/launchdarkly.rs→rust=contains 25 selected LaunchDarkly tests. cargo test -p buzz-feature-flags tests::launchdarkly_test_config_uses_null_event_processor -- --list→0 tests; the same command with--features launchdarklylistslaunchdarkly::tests::launchdarkly_test_config_uses_null_event_processor.
I did not run full just ci; the live required Desktop gate is already red at this exact head, and the feature-gated repeat defect is source/probe-backed. No native/manual app evidence is applicable for this CI tooling change.
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent
Verdict: REQUEST CHANGES.
This integrated follow-up supersedes my earlier same-head review body; the verdict stays REQUEST CHANGES, and this adds the systems selector false-green blocker that was not in the first body.
Reviewed: 8216db1c712cefdc0e2af7191d501adae03ba392..f02a4235a9fd0e60406e218acaab1b6537ca6446 (exact head f02a4235a9fd0e60406e218acaab1b6537ca6446).
Risk: high — this PR changes the CI selector/repeater that decides which changed tests get repeated. A required-gate failure blocks every PR run; a false-green selector lets changed tests skip the extra signal this PR is meant to provide.
Findings
High — Required Desktop JS gate fails because the new regression test reads stdout while CI redirects selector output to GitHub env files
The PR adds node --test scripts/flake-check.test.mjs to the Desktop JS lane (.github/workflows/_ci-desktop.yml:55-56). In that CI environment, child processes inherit GITHUB_STEP_SUMMARY and GITHUB_OUTPUT. The selector intentionally writes its summary to $GITHUB_STEP_SUMMARY (scripts/flake-check.mjs:444-447) and its outputs to $GITHUB_OUTPUT (scripts/flake-check.mjs:724-726) when those variables exist.
But the new test helper spawns scripts/flake-check.mjs select without controlling those env vars and then parses only result.stdout (scripts/flake-check.test.mjs:62-74). The assertion for the Tauri selection table therefore sees '' in CI (scripts/flake-check.test.mjs:495-497). Live exact-head CI already shows this: Desktop Domain / Desktop JS failed in actions/runs/40429121923, job 121942775419, with actual: '', and that rolls up to the required Desktop failure.
Consequence: the PR’s own required Desktop gate is red under the same GitHub Actions output contract the selector is supposed to support. Contributors get noise instead of actionable flake signal, and the PR cannot merge.
Author action: make the test choose one deliberate output contract. Either strip GITHUB_STEP_SUMMARY / GITHUB_OUTPUT from the child and keep stdout assertions, or set both to temp files and assert against those files. Add/keep a GitHub-env-shaped regression so this CI-only path stays covered.
Verification owner: author fixes and reruns the required Desktop Domain / Desktop JS and top-level Desktop checks.
High — tests/<target>.rs integration wrapper changes are still treated as helper changes, so the changed target is omitted and unrelated sibling binaries repeat instead
crates/buzz-acp/tests/pool_lifecycle_state.rs is an integration-test target wrapper, not a shared helper: it compiles the production source via #[path = "../src/pool_lifecycle.rs"] mod pool_lifecycle; (crates/buzz-acp/tests/pool_lifecycle_state.rs:1-4). The included source contains runnable tests (crates/buzz-acp/src/pool_lifecycle.rs:138, :149, :282, :292, etc.).
At this head, appending a non-test-body line to that wrapper produces this selection summary:
| crates/buzz-acp/tests/pool_lifecycle_state.rs | rust | helper for (no importer found; every integration test): git_bootstrap, run_task, stdio_contract: 14 test(s) |
The rust= output contains tests from crates/buzz-acp/tests/git_bootstrap.rs, run_task.rs, and stdio_contract.rs; it does not contain any pool_lifecycle_state entry.
The cause is in the selector: any tests/** Rust file with no directly parsed test functions falls into the helper branch (scripts/flake-check.mjs:640-647). rustImporters() then removes the changed file from the candidate target list (scripts/flake-check.mjs:525-543, specifically :537) and falls back to every sibling target when no importer includes it. That is correct for true helpers like tests/common/mod.rs, but wrong for integration targets that are wrappers around source modules.
Consequence: this PR can report a false green for exactly the class of wrapper-only integration target changes it is supposed to repeat. The changed test target is skipped while unrelated sibling integration binaries are repeated.
Author action: distinguish integration targets from helper modules. A changed tests/<stem>.rs / tests/<stem>/main.rs target should select that target’s runnable tests, including tests brought in through a #[path] wrapper, while true shared helpers should keep importer scanning. Add a regression using crates/buzz-acp/tests/pool_lifecycle_state.rs that fails if pool_lifecycle_state is omitted.
Verification owner: author fixes selector + regression, then reruns the synthetic wrapper selection and the affected repeat path.
Validation performed
- Confirmed authenticated reviewer
jedwards27differs from PR authormatt2e. - Refreshed live PR state immediately before updating this review: head
f02a4235a9fd0e60406e218acaab1b6537ca6446, base8216db1c712cefdc0e2af7191d501adae03ba392, review decisionCHANGES_REQUESTED, merge stateBLOCKED. - Confirmed required checks at this head include failing
Desktop Domain / Desktop JSand failing top-levelDesktop. - In a clean exact-head checkout (
git rev-parse HEAD=f02a4235a9fd0e60406e218acaab1b6537ca6446,git status --shortempty):env -u GITHUB_OUTPUT -u GITHUB_STEP_SUMMARY node --test --test-name-pattern 'select, through its entry point' scripts/flake-check.test.mjs— passes.GITHUB_OUTPUT=$(mktemp) GITHUB_STEP_SUMMARY=$(mktemp) node --test --test-name-pattern 'select, through its entry point' scripts/flake-check.test.mjs— fails with the same empty-stdout assertion; the expected summary/output are written to the temp files.- A synthetic tree appending to
crates/buzz-acp/tests/pool_lifecycle_state.rsselectsgit_bootstrap,run_task, andstdio_contractentries and printscontains_pool_lifecycle_state=false.
- Reviewed the Tauri mapping path:
desktop/src-tauri/**is classified to thetaurirunner/manifest, and the live PR skipped the Desktop Tauri flake lane because this PR did not change a Tauri test. No additional Tauri-manifest blocker found at this head.
Residual risk: I did not run full just ci locally; live exact-head required CI plus focused local repros are already sufficient for the blockers above. The next head needs fresh review because selector behavior and CI status are the product here.
…t #[path] wrapper targets Address Jude's integrated review of f02a423 on #8613. The required Desktop JS gate was red: scripts/flake-check.test.mjs spawns the real selector, which writes its summary to $GITHUB_STEP_SUMMARY and its outputs to $GITHUB_OUTPUT when those are set, as they are under Actions, so the regression test read an empty stdout there. selectAppending now strips both from the child's environment when it asserts on stdout, and its `github` mode sets them to temp files and reads those instead; the Tauri selection is asserted both ways, equal, with nothing on stdout in the routed mode. The suite passes with and without the two variables set. A tests/<stem>.rs root with no test function of its own was treated as a helper: buzz-acp's pool_lifecycle_state compiles src/pool_lifecycle.rs in by `#[path]`, and a change to it selected git_bootstrap, run_task and stdio_contract and never pool_lifecycle_state. rustTargetRoot now tells a binary's root (tests/<stem>.rs, tests/<dir>/main.rs) from a module of one; rustModules resolves the file modules a file declares by cargo's conventions (`#[path]` relative to the declaring file, else x.rs or x/mod.rs under the module's directory, with comments and strings blanked); rustIncludedTests collects their tests transitively under their module path, the names nextest lists for the binary. selectRust takes these as `included`: a whole selection of a root carries them, a hunk inside one of the root's own tests does not, and a root with none of its own selects them as shared code changed. A root with no tests at all gets a row and selects nothing; only a non-root tests/** file without tests takes the helper branch, and the helper importers' whole-binary expansion uses the same test set. Regression tests go through the real select entry point: a comment appended to pool_lifecycle_state.rs selects exactly the nine pool_lifecycle::tests::* entries under that file (and fails if the included tests are dropped), and rustGroups builds `-p buzz-acp --test pool_lifecycle_state` with those exact names. Verified live: `cargo nextest list` with the produced filterset matches all nine in buzz-acp::pool_lifecycle_state, and `flake-check.mjs rust --iterations=2` over the selection ran green end to end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent
Verdict: REQUEST CHANGES before merge. I’m submitting this as a comment review per this repo’s agent-review guidance; the finding below is still author-actionable.
Reviewed: 8216db1c712cefdc0e2af7191d501adae03ba392..29858b2affbc9490fc2b13e47ca5b79db7adb8d6 (exact head 29858b2affbc9490fc2b13e47ca5b79db7adb8d6)
Risk: medium/high CI correctness. This PR’s contract is that changed tests are repeated rather than silently skipped; the affected path can produce a green repeat lane after selecting zero runnable tests.
Behavior/contracts traced: changed-file selector output → _ci-flake.yml Rust/Tauri repeat jobs → scripts/flake-check.mjs cargo nextest list/run construction → normal CI feature lanes in Justfile / _ci-desktop.yml.
Blocking finding
Selected feature-gated Rust/Tauri tests can pass as “nothing to repeat”
The selector can emit tests that only exist in a non-default Cargo feature graph, but the repeat path lists/runs the default graph and treats an empty match as success.
Evidence:
- The Rust/Tauri repeat path builds only the root default cargo args or
--manifest-path desktop/src-tauri/Cargo.toml; it does not preserve any per-package/per-workspace feature args when runningcargo nextest listorcargo nextest run(scripts/flake-check.mjs:939-957,scripts/flake-check.mjs:998-1008). - If
nextest listfinds no chosen candidates, the job emitsFlake check (Rust): nothing to repeatand returns success (scripts/flake-check.mjs:975-982). Mixed selections also drop the feature-gated candidate and report only the default-graph tests (scripts/flake-check.mjs:970-982,scripts/flake-check.mjs:1021-1028). - Normal CI has feature-specific test graphs this PR does not mirror:
buzz-feature-flags --features launchdarkly(Justfile:479-482), with the LaunchDarkly module gated behind#[cfg(feature = "launchdarkly")](crates/buzz-feature-flags/src/lib.rs:13-15,crates/buzz-feature-flags/Cargo.toml:10-11) and tests such aslaunchdarkly_test_config_uses_null_event_processor(crates/buzz-feature-flags/src/launchdarkly.rs:366-367).- Desktop Tauri mesh tests via
just desktop-tauri-test-mesh/--features mesh-llm(.github/workflows/_ci-desktop.yml:86-89,Justfile:234-236), with mesh-only code/tests gated behindmesh-llm(desktop/src-tauri/src/managed_agents/relay_mesh.rs:14-35,desktop/src-tauri/src/managed_agents/relay_mesh.rs:138-145).
_ci-flake.ymlinvokes the Tauri repeat asnode scripts/flake-check.mjs tauri ...with no--features mesh-llmpath (.github/workflows/_ci-flake.yml:151-165). The same implementation handles root Rust repeats, so feature-gated root selections have the same false-empty shape.
I reproduced the control-flow failure at this head with a fake cargo standing in for nextest: a cfg-gated-only selected test returned exit code 0 with “nothing to repeat,” and a mixed ordinary + cfg-gated selection returned exit code 0 while the report listed only the ordinary test. That matches the source trace: selected tests can disappear between selection and repeat without failing the job.
Consequence: contributors can change a real feature-gated Rust/Tauri test, see a non-empty selector summary, and still get a successful flake repeat lane that repeated zero of the selected feature-gated tests. That violates the PR’s core developer contract more dangerously than an explicit skip, because it looks verified.
Author action: bind selected Rust/Tauri entries to the Cargo invocation shape that normally runs them, e.g. feature-aware repeat groups for buzz-feature-flags --features launchdarkly, buzz-push-gateway --features personal-dev-app-attest, and Desktop Tauri --features mesh-llm; and fail loudly when selected entries cannot be listed under the graph being repeated unless the selector can prove they are intentionally ignored/excluded infra tests. Add regressions proving a selected feature-gated root Rust test and a selected Tauri mesh test are either repeated under the correct feature graph or hard-fail instead of reporting “nothing to repeat.”
Verification owner: author for the fix/regressions and rerun of affected flake/CI checks; reviewer to re-check exact-head selector/repeat probes after the next push.
Validation
At matching local/live head 29858b2affbc9490fc2b13e47ca5b79db7adb8d6:
gh pr viewandgit ls-remote origin refs/pull/8613/headboth matched the reviewed head; authenticated reviewerjedwards27, PR authormatt2e.node --test scripts/flake-check.test.mjs— PASS, 15/15.eval "$(./bin/hermit env --activate)" && actionlint .github/workflows/ci.yml .github/workflows/_ci-flake.yml .github/workflows/_ci-rust.yml .github/workflows/_ci-desktop.yml— PASS.scripts/test-rust-cache-contract.sh && scripts/test-rust-cache-contract-regressions.sh— PASS.git diff --check 8216db1c712cefdc0e2af7191d501adae03ba392...HEAD— PASS.gh pr checksquery for non-success/non-skipped checks returned none at the final local check. Green CI does not cover this false-repeat path.
Manual/native evidence: not applicable; this is CI/tooling behavior. No local cargo-nextest run was required for the blocker because the defect is in the command construction and empty-candidate handling, and the control-flow reproduction demonstrates the false-green path.
Residual risk: I did not run full local just ci or the real 10× nextest lanes. The unresolved author action is the feature-graph repeat contract above, not general CI finality.
jedwards27
left a comment
There was a problem hiding this comment.
🤖 :bot: Jude’s code review agent — REQUEST CHANGES for exact head 280cc2385470423a32dcb2bb389ea248650667cb.
The earlier “feature-only tests absent from default graph” blocker is mostly fixed, but this head still has a false-green path for same-named tests that are present in multiple regular CI feature graphs.
Blocking defect: first listed feature graph can hide the changed branch
buzz-push-gateway is tested by normal CI in both the default graph and the personal-dev-app-attest graph (Justfile:471-472). The selected test tests::attestation_environment_is_explicit_and_build_gated has mutually exclusive assertions under #[cfg(feature = "personal-dev-app-attest")] and #[cfg(not(feature = "personal-dev-app-attest"))] (crates/buzz-push-gateway/src/config.rs:260-269).
repeatRust() knows about both graphs for this package (scripts/flake-check.mjs:112-115), but after the default graph lists the selected test it advances only choice.unlisted to later graphs (scripts/flake-check.mjs:959-1001). That means a selected test name found in the default graph is removed before the feature graph is even listed.
I reproduced this at the exact head with a synthetic diff inside the personal-dev-app-attest-only assertion. The selector chose:
rust=crates/buzz-push-gateway/src/config.rs::tests::attestation_environment_is_explicit_and_build_gated
A fake-cargo repeat probe where the same test was listed in both graphs exited successfully and recorded only default-graph calls:
cargo nextest list -p buzz-push-gateway --lib --bins
cargo nextest run --profile flake -p buzz-push-gateway --lib --bins -E ...
There was no --features personal-dev-app-attest list or run call, yet the flake summary reported success (0 of 2 iterations failed). A mutation proof confirmed the practical failure mode: after changing only the feature-gated assertion to the wrong expected value, the default graph still passed, while cargo test -p buzz-push-gateway --features personal-dev-app-attest ... -- --exact failed.
Impact: a contributor can edit a feature-specific branch inside an otherwise default-visible test, see the changed test selected, and get a green repeat lane that never compiled or ran the changed branch. That violates the PR’s core contract: changed tests should be repeated without misleading false greens.
Required author action: for packages with multiple regular CI feature graphs, either:
- repeat selected tests in every graph that lists them; or
- make selection cfg-aware enough to bind the changed hunk to the graph(s) that compile it, and fail loudly when uncertain.
Please add a regression for the buzz-push-gateway personal-dev-app-attest branch proving the feature graph is invoked, not just the default graph.
Other verification
Exact-head checks/evidence used for this review:
- Live PR head remained
280cc2385470423a32dcb2bb389ea248650667cbimmediately before submitting this review. scripts/buzz-pr-review-preflight 8613— head/base matched; required checks passed except requiredSecurity.git diff --check 8216db1c712cefdc0e2af7191d501adae03ba392...HEAD— pass.actionlint .github/workflows/ci.yml .github/workflows/_ci-flake.yml .github/workflows/_ci-rust.yml .github/workflows/_ci-desktop.yml— pass.scripts/test-rust-cache-contract.shandscripts/test-rust-cache-contract-regressions.sh— pass.just desktop-install-ci && node --test scripts/flake-check.test.mjs— pass, 16/16.pnpm exec biome check scripts/flake-check.mjs scripts/flake-check.test.mjs— pass.- Synthetic probes for the prior blockers (Tauri selections, helper-module importer expansion,
#[path]integration wrappers, and pure feature-only tests absent from default) passed; the unresolved blocker is the same-name multi-graph case above.
The required Security check is currently failing on RUSTSEC-2026-0414 for pulldown-cmark 0.13.4. This PR does not change Cargo.lock, Cargo.toml, or deny.toml, so I am not classifying that as the PR-caused defect behind this request-changes review, but it remains a required gate to route before merge.
## Summary Bumps `pulldown-cmark` 0.13.4 → 0.13.5 in `Cargo.lock` to clear [RUSTSEC-2026-0414](https://rustsec.org/advisories/RUSTSEC-2026-0414), which `cargo-deny` started flagging this morning. The advisory landed in the RustSec database at 08:50 UTC on 2026-10-28; main's last Security run passed at 00:24 UTC, and every PR touching a Rust path since (e.g. #8613, `jitter/block-staging-relay-domain`) fails the required **Security** check on it. Main will go red on its next Rust-path push until this merges. ## Exposure Not exploitable in Buzz: the advisory requires `Options::ENABLE_WIKILINKS`, which is off by default. The relay's only use is `render_policy_document` in `crates/buzz-relay/src/api/invites.rs`, which parses operator-authored policy Markdown via `Parser::new` with default options. This is a dependency-policy fix. ## Change - `cargo update -p pulldown-cmark --precise 0.13.5` under the pinned 1.98.1 toolchain; `crates/buzz-relay/Cargo.toml` already requires `0.13.4` (`^0.13.4`), so no manifest edit. - The same re-resolution moved `data-encoding-macro-internal`'s `syn` edge from 2.0.117 to the 1.0.109 already in the lock (declared requirement `>=1, <3`). No crate is added or removed. - `desktop/src-tauri/Cargo.lock` does not contain `pulldown-cmark`, and `cargo-deny` only checks the root workspace. Not touched here: `deny.toml:50`'s `RUSTSEC-2026-0381` ignore now warns `advisory-not-detected` (the crate is gone). Harmless; can be removed separately. ## Verification - `cargo update --dry-run` showed `pulldown-cmark` as the only version change before applying. - CI's Security lane on this PR is the real check. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Matt Toohey <contact@matttoohey.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… action pin comments Address the Codex security review and the zizmor code-scanning alerts (386-390) on #8613. repeatRust merged each package's cargo target flags through a Set of argv tokens, so two integration-test files in one package collapsed `--test codec --test connection` into `--test codec connection`. nextest reads the trailing `connection` as a test-name filter, lists nothing, and the lane took the "nothing to repeat" branch and reported success without running a test (verified against buzz-audio-client: the collapsed argv lists no tests and exits 0). rustTarget now returns one flag per entry and the new rustGroups keys each whole flag, so a `--test <name>` is emitted once per name while `--lib`/`--bins` stay single; the regression test asserts the exact argv for two integration files and for a src/ plus tests/ file in the same package, through the seam repeatRust uses. The `-p`, `-E` and filterset arguments were re-read for the same class of bug and pass single values. In _ci-flake.yml, actions/upload-artifact 043fb46d is v7.0.1 (the `v7` tag has since moved to v7.0.2), so its four comments now say so, as the other workflows do. rui314/setup-mold 7e4f20ad is a commit the `v1` tag no longer points at (339e96b4, mold 3.0.0), so the flake workflow pins the current `v1`; _ci-rust.yml, _ci-relay.yml and _ci-desktop.yml carry the same stale pin and are left for a separate change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Address the two High findings of review 5659898932 on #8613: a changed Rust test under desktop/src-tauri, or a changed helper module under a crate's tests/, produced an empty flake selection and every repeat lane skipped, a false "nothing selected" green. Desktop Tauri Rust is now a runner of its own rather than an unclassified path. rustFile places a Rust file in its workspace (the root crates, or desktop/src-tauri and its crates/*), and classify, cratePackage, rustTarget, rustModulePath and rustGroups read that instead of assuming crates/<crate>/. The new flake-tauri lane mirrors the Desktop Tauri core lane's setup (its apt packages, sidecar stubs and desktop-core rust-cache, restored read-only) and runs the same script against desktop/src-tauri/Cargo.toml. nextest reads its configuration from the workspace root, so that workspace gets its own .config/nextest.toml with the flake profile, and the Postgres exclusion applies only in the root workspace: nextest rejects a binary(/^postgres_/) predicate where no such binary exists, which the Tauri workspace's first live run showed. Supporting the surface for real was straightforward, since the workspace is an ordinary cargo workspace that nextest lists and runs by manifest path, so no out-of-scope declaration was needed. A tests/** file without test functions is a helper that integration binaries compile in with `mod common;`. select now finds the package's integration targets that include it (rustIncludes reads `mod <first>;` declarations with comments and strings blanked, `#[path]` attributes, and a tests/<dir>/main.rs owning its directory; a helper no target names falls back to every target) and selects each of those binaries whole, so the ignored and infrastructure exclusions still apply, with a row naming the importers. A helper and its importer changed together select each test once. A src/** file without test functions still selects nothing; a comment beside the row records that this is deliberate, since the regular lanes run what depends on it. Regression tests go through the real select entry point over a synthetic head tree (HEAD with a comment appended, as the reviewer probed): a changed desktop/src-tauri/tests/rodio_mixer_diagnostic.rs yields its three tests under tauri=, and a comment-only change to crates/buzz-agent/tests/common/mod.rs yields rust= entries in exactly anthropic_continuation, fake_llm, permission_boundary and regressions, the four files declaring `mod common;`. Verified live: cargo nextest list with the produced -p/--test flags and filterset matches all 85 entries, and `flake-check.mjs tauri --iterations=2` on the Tauri selection ran green end to end with its JUnit report under desktop/src-tauri/target/nextest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…t #[path] wrapper targets Address Jude's integrated review of f02a423 on #8613. The required Desktop JS gate was red: scripts/flake-check.test.mjs spawns the real selector, which writes its summary to $GITHUB_STEP_SUMMARY and its outputs to $GITHUB_OUTPUT when those are set, as they are under Actions, so the regression test read an empty stdout there. selectAppending now strips both from the child's environment when it asserts on stdout, and its `github` mode sets them to temp files and reads those instead; the Tauri selection is asserted both ways, equal, with nothing on stdout in the routed mode. The suite passes with and without the two variables set. A tests/<stem>.rs root with no test function of its own was treated as a helper: buzz-acp's pool_lifecycle_state compiles src/pool_lifecycle.rs in by `#[path]`, and a change to it selected git_bootstrap, run_task and stdio_contract and never pool_lifecycle_state. rustTargetRoot now tells a binary's root (tests/<stem>.rs, tests/<dir>/main.rs) from a module of one; rustModules resolves the file modules a file declares by cargo's conventions (`#[path]` relative to the declaring file, else x.rs or x/mod.rs under the module's directory, with comments and strings blanked); rustIncludedTests collects their tests transitively under their module path, the names nextest lists for the binary. selectRust takes these as `included`: a whole selection of a root carries them, a hunk inside one of the root's own tests does not, and a root with none of its own selects them as shared code changed. A root with no tests at all gets a row and selects nothing; only a non-root tests/** file without tests takes the helper branch, and the helper importers' whole-binary expansion uses the same test set. Regression tests go through the real select entry point: a comment appended to pool_lifecycle_state.rs selects exactly the nine pool_lifecycle::tests::* entries under that file (and fails if the included tests are dropped), and rustGroups builds `-p buzz-acp --test pool_lifecycle_state` with those exact names. Verified live: `cargo nextest list` with the produced filterset matches all nine in buzz-acp::pool_lifecycle_state, and `flake-check.mjs rust --iterations=2` over the selection ran green end to end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
280cc23 to
a20e185
Compare
… action pin comments Address the Codex security review and the zizmor code-scanning alerts (386-390) on #8613. repeatRust merged each package's cargo target flags through a Set of argv tokens, so two integration-test files in one package collapsed `--test codec --test connection` into `--test codec connection`. nextest reads the trailing `connection` as a test-name filter, lists nothing, and the lane took the "nothing to repeat" branch and reported success without running a test (verified against buzz-audio-client: the collapsed argv lists no tests and exits 0). rustTarget now returns one flag per entry and the new rustGroups keys each whole flag, so a `--test <name>` is emitted once per name while `--lib`/`--bins` stay single; the regression test asserts the exact argv for two integration files and for a src/ plus tests/ file in the same package, through the seam repeatRust uses. The `-p`, `-E` and filterset arguments were re-read for the same class of bug and pass single values. In _ci-flake.yml, actions/upload-artifact 043fb46d is v7.0.1 (the `v7` tag has since moved to v7.0.2), so its four comments now say so, as the other workflows do. rui314/setup-mold 7e4f20ad is a commit the `v1` tag no longer points at (339e96b4, mold 3.0.0), so the flake workflow pins the current `v1`; _ci-rust.yml, _ci-relay.yml and _ci-desktop.yml carry the same stale pin and are left for a separate change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Address the two High findings of review 5659898932 on #8613: a changed Rust test under desktop/src-tauri, or a changed helper module under a crate's tests/, produced an empty flake selection and every repeat lane skipped, a false "nothing selected" green. Desktop Tauri Rust is now a runner of its own rather than an unclassified path. rustFile places a Rust file in its workspace (the root crates, or desktop/src-tauri and its crates/*), and classify, cratePackage, rustTarget, rustModulePath and rustGroups read that instead of assuming crates/<crate>/. The new flake-tauri lane mirrors the Desktop Tauri core lane's setup (its apt packages, sidecar stubs and desktop-core rust-cache, restored read-only) and runs the same script against desktop/src-tauri/Cargo.toml. nextest reads its configuration from the workspace root, so that workspace gets its own .config/nextest.toml with the flake profile, and the Postgres exclusion applies only in the root workspace: nextest rejects a binary(/^postgres_/) predicate where no such binary exists, which the Tauri workspace's first live run showed. Supporting the surface for real was straightforward, since the workspace is an ordinary cargo workspace that nextest lists and runs by manifest path, so no out-of-scope declaration was needed. A tests/** file without test functions is a helper that integration binaries compile in with `mod common;`. select now finds the package's integration targets that include it (rustIncludes reads `mod <first>;` declarations with comments and strings blanked, `#[path]` attributes, and a tests/<dir>/main.rs owning its directory; a helper no target names falls back to every target) and selects each of those binaries whole, so the ignored and infrastructure exclusions still apply, with a row naming the importers. A helper and its importer changed together select each test once. A src/** file without test functions still selects nothing; a comment beside the row records that this is deliberate, since the regular lanes run what depends on it. Regression tests go through the real select entry point over a synthetic head tree (HEAD with a comment appended, as the reviewer probed): a changed desktop/src-tauri/tests/rodio_mixer_diagnostic.rs yields its three tests under tauri=, and a comment-only change to crates/buzz-agent/tests/common/mod.rs yields rust= entries in exactly anthropic_continuation, fake_llm, permission_boundary and regressions, the four files declaring `mod common;`. Verified live: cargo nextest list with the produced -p/--test flags and filterset matches all 85 entries, and `flake-check.mjs tauri --iterations=2` on the Tauri selection ran green end to end with its JUnit report under desktop/src-tauri/target/nextest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…t #[path] wrapper targets Address Jude's integrated review of f02a423 on #8613. The required Desktop JS gate was red: scripts/flake-check.test.mjs spawns the real selector, which writes its summary to $GITHUB_STEP_SUMMARY and its outputs to $GITHUB_OUTPUT when those are set, as they are under Actions, so the regression test read an empty stdout there. selectAppending now strips both from the child's environment when it asserts on stdout, and its `github` mode sets them to temp files and reads those instead; the Tauri selection is asserted both ways, equal, with nothing on stdout in the routed mode. The suite passes with and without the two variables set. A tests/<stem>.rs root with no test function of its own was treated as a helper: buzz-acp's pool_lifecycle_state compiles src/pool_lifecycle.rs in by `#[path]`, and a change to it selected git_bootstrap, run_task and stdio_contract and never pool_lifecycle_state. rustTargetRoot now tells a binary's root (tests/<stem>.rs, tests/<dir>/main.rs) from a module of one; rustModules resolves the file modules a file declares by cargo's conventions (`#[path]` relative to the declaring file, else x.rs or x/mod.rs under the module's directory, with comments and strings blanked); rustIncludedTests collects their tests transitively under their module path, the names nextest lists for the binary. selectRust takes these as `included`: a whole selection of a root carries them, a hunk inside one of the root's own tests does not, and a root with none of its own selects them as shared code changed. A root with no tests at all gets a row and selects nothing; only a non-root tests/** file without tests takes the helper branch, and the helper importers' whole-binary expansion uses the same test set. Regression tests go through the real select entry point: a comment appended to pool_lifecycle_state.rs selects exactly the nine pool_lifecycle::tests::* entries under that file (and fails if the included tests are dropped), and rustGroups builds `-p buzz-acp --test pool_lifecycle_state` with those exact names. Verified live: `cargo nextest list` with the produced filterset matches all nine in buzz-acp::pool_lifecycle_state, and `flake-check.mjs rust --iterations=2` over the selection ran green end to end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
a20e185 to
99deb8c
Compare
Add an advisory flake check that selects the tests a pull request changes and repeats each one ten times with retries off, so a test that passes CI by luck is caught before it merges. This mirrors block/buzz-app#890 (and its sharding follow-up), adapted to the runners this repository actually has. scripts/flake-check.mjs `select` diffs HEAD^1..HEAD and maps hunks to tests per runner: Rust files to `<package>::<fn>` entries by parsing `#[test]`-style attributes (shared code changes select the file's tests; `#[ignore]`d and Postgres tests are excluded), desktop Playwright specs to `file:line` smoke journeys via `playwright --list` (non-smoke and unregistered specs are excluded), and desktop node:test and Flutter test files whole. Deleted and renamed-away files drop out of the selection, and any runner whose selection exceeds 64 KiB is dropped with a note so GitHub outputs stay within limits. The reusable _ci-flake.yml adds `flake-select` plus one repeat lane per runner (`flake-rust`, `flake-node`, `flake-playwright` sharded by journey count, `flake-dart`). Each lane skips when its selection is empty, runs only on pull_request, and is not read by any required gate; its status and step summary carry the result. A `flake` nextest profile disables retries and emits JUnit so the Rust lane can report per-test, per-iteration results. The Unit Tests rust-cache gains a `shared-key` so the flake lane can restore it read-only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Address the review of the flake check port (99b21e4fb). An integration-only Playwright selection no longer fails flake-select: Playwright exits 1 with a lone "No tests found" error when the file filters match nothing in the smoke project, which listPlaywright now reads as an empty selection, as buzz-app's listBrowser does. Listed journeys are deduplicated, since a looped test() declaration is listed once per iteration, and a selection over 250 journeys skips the Playwright lane with a note: the smoke lane runs ~150 journey-runs per shard in ~11 minutes, so 250 journey-runs per shard across ten shards is what fits the 45-minute timeout after setup and the E2E build. Rust entries now carry the file and the test's in-file module path (`crates/.../auth.rs::tests::name`). repeatRust runs one cargo invocation per package with target flags derived from the path (src/** builds --lib --bins, tests/<stem>.rs builds --test <stem>), so a buzz-relay change no longer compiles every test target of the crate. It lists candidates by in-file path, prefers the test whose full name the file's path predicts, and falls back to every suffix match only when nothing matches (a `#[path]` module), so a same-named test in another module is no longer repeated for a change it never saw. The rust-cache bust knob moves into the shared key (`unit-tests-sherpa-cache-v1`) in both the Unit Tests and flake-rust jobs, since rust-cache ignores `key` once shared-key is set; the contract script checks both and the flake restore's save-if, and the regression harness covers both. flake-select installs desktop dependencies only when a spec changed. Changed .rs files without test functions get a summary row, test.fail() declarations count as tests, a captured nextest 0.9.136 list/JUnit pair pins the classname contract, and CONTRIBUTING lists what the lanes deliberately do not repeat. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
… action pin comments Address the Codex security review and the zizmor code-scanning alerts (386-390) on #8613. repeatRust merged each package's cargo target flags through a Set of argv tokens, so two integration-test files in one package collapsed `--test codec --test connection` into `--test codec connection`. nextest reads the trailing `connection` as a test-name filter, lists nothing, and the lane took the "nothing to repeat" branch and reported success without running a test (verified against buzz-audio-client: the collapsed argv lists no tests and exits 0). rustTarget now returns one flag per entry and the new rustGroups keys each whole flag, so a `--test <name>` is emitted once per name while `--lib`/`--bins` stay single; the regression test asserts the exact argv for two integration files and for a src/ plus tests/ file in the same package, through the seam repeatRust uses. The `-p`, `-E` and filterset arguments were re-read for the same class of bug and pass single values. In _ci-flake.yml, actions/upload-artifact 043fb46d is v7.0.1 (the `v7` tag has since moved to v7.0.2), so its four comments now say so, as the other workflows do. rui314/setup-mold 7e4f20ad is a commit the `v1` tag no longer points at (339e96b4, mold 3.0.0), so the flake workflow pins the current `v1`; _ci-rust.yml, _ci-relay.yml and _ci-desktop.yml carry the same stale pin and are left for a separate change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Address the two High findings of review 5659898932 on #8613: a changed Rust test under desktop/src-tauri, or a changed helper module under a crate's tests/, produced an empty flake selection and every repeat lane skipped, a false "nothing selected" green. Desktop Tauri Rust is now a runner of its own rather than an unclassified path. rustFile places a Rust file in its workspace (the root crates, or desktop/src-tauri and its crates/*), and classify, cratePackage, rustTarget, rustModulePath and rustGroups read that instead of assuming crates/<crate>/. The new flake-tauri lane mirrors the Desktop Tauri core lane's setup (its apt packages, sidecar stubs and desktop-core rust-cache, restored read-only) and runs the same script against desktop/src-tauri/Cargo.toml. nextest reads its configuration from the workspace root, so that workspace gets its own .config/nextest.toml with the flake profile, and the Postgres exclusion applies only in the root workspace: nextest rejects a binary(/^postgres_/) predicate where no such binary exists, which the Tauri workspace's first live run showed. Supporting the surface for real was straightforward, since the workspace is an ordinary cargo workspace that nextest lists and runs by manifest path, so no out-of-scope declaration was needed. A tests/** file without test functions is a helper that integration binaries compile in with `mod common;`. select now finds the package's integration targets that include it (rustIncludes reads `mod <first>;` declarations with comments and strings blanked, `#[path]` attributes, and a tests/<dir>/main.rs owning its directory; a helper no target names falls back to every target) and selects each of those binaries whole, so the ignored and infrastructure exclusions still apply, with a row naming the importers. A helper and its importer changed together select each test once. A src/** file without test functions still selects nothing; a comment beside the row records that this is deliberate, since the regular lanes run what depends on it. Regression tests go through the real select entry point over a synthetic head tree (HEAD with a comment appended, as the reviewer probed): a changed desktop/src-tauri/tests/rodio_mixer_diagnostic.rs yields its three tests under tauri=, and a comment-only change to crates/buzz-agent/tests/common/mod.rs yields rust= entries in exactly anthropic_continuation, fake_llm, permission_boundary and regressions, the four files declaring `mod common;`. Verified live: cargo nextest list with the produced -p/--test flags and filterset matches all 85 entries, and `flake-check.mjs tauri --iterations=2` on the Tauri selection ran green end to end with its JUnit report under desktop/src-tauri/target/nextest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…t #[path] wrapper targets Address Jude's integrated review of f02a423 on #8613. The required Desktop JS gate was red: scripts/flake-check.test.mjs spawns the real selector, which writes its summary to $GITHUB_STEP_SUMMARY and its outputs to $GITHUB_OUTPUT when those are set, as they are under Actions, so the regression test read an empty stdout there. selectAppending now strips both from the child's environment when it asserts on stdout, and its `github` mode sets them to temp files and reads those instead; the Tauri selection is asserted both ways, equal, with nothing on stdout in the routed mode. The suite passes with and without the two variables set. A tests/<stem>.rs root with no test function of its own was treated as a helper: buzz-acp's pool_lifecycle_state compiles src/pool_lifecycle.rs in by `#[path]`, and a change to it selected git_bootstrap, run_task and stdio_contract and never pool_lifecycle_state. rustTargetRoot now tells a binary's root (tests/<stem>.rs, tests/<dir>/main.rs) from a module of one; rustModules resolves the file modules a file declares by cargo's conventions (`#[path]` relative to the declaring file, else x.rs or x/mod.rs under the module's directory, with comments and strings blanked); rustIncludedTests collects their tests transitively under their module path, the names nextest lists for the binary. selectRust takes these as `included`: a whole selection of a root carries them, a hunk inside one of the root's own tests does not, and a root with none of its own selects them as shared code changed. A root with no tests at all gets a row and selects nothing; only a non-root tests/** file without tests takes the helper branch, and the helper importers' whole-binary expansion uses the same test set. Regression tests go through the real select entry point: a comment appended to pool_lifecycle_state.rs selects exactly the nine pool_lifecycle::tests::* entries under that file (and fails if the included tests are dropped), and rustGroups builds `-p buzz-acp --test pool_lifecycle_state` with those exact names. Verified live: `cargo nextest list` with the produced filterset matches all nine in buzz-acp::pool_lifecycle_state, and `flake-check.mjs rust --iterations=2` over the selection ran green end to end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…d fail on unlisted selections The Rust and Desktop Tauri repeats listed only each package's default feature graph and treated an entry nextest did not list as excluded, so a selected `#[cfg(feature = …)]` test (buzz-feature-flags' LaunchDarkly, buzz-push-gateway's App Attest development feature, the desktop crate's mesh-llm) passed as "nothing to repeat" or was silently dropped from a mixed selection. Each package is now listed in the feature graphs the regular lanes test it in, in order, and each entry repeats in the first graph that lists it, so the mesh-llm graph is built only for tests the default graph lacks. Ignored and infrastructure-backed tests are classified from the whole listing (nextest reports an ignored test as a filter mismatch whatever -E says), and an entry no graph lists fails the lane by name. A fake-cargo regression drives the script's entry point through each case, and the graph table is pinned to the Justfile recipes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
99deb8c to
fdee846
Compare
Address Jude's review 5684023609 on #8613: repeatRust narrowed each selected test to the first feature graph that listed it, so a test the default graph lists was never looked for in a later graph. buzz-push-gateway is tested without and with personal-dev-app-attest, and config.rs's attestation_environment_is_explicit_and_build_gated asserts differently under `#[cfg(feature = …)]` and `#[cfg(not(feature = …))]`; a change to the feature arm selected the test, repeated it in the default graph alone and passed without compiling the changed arm. Each package is now listed in every graph the regular lanes test it in, every selected test repeats in each graph that lists it, and only an entry no graph lists fails the lane. Report rows and the expected-status keys carry the graph's features (`… [personal-dev-app-attest]`), so one graph's pass cannot stand for another's failure. rustGroups builds each graph's full cargo arguments; the desktop crate's mesh-llm graph is lib-only, as desktop-tauri-test-mesh runs `--lib`, so an integration-test selection never builds it and a lib selection builds only the lib under it. The flake-tauri lane's timeout grows to 70 minutes for that second cold build. The fake-cargo regression now covers the gateway test listed in both graphs with a failure only under the feature: the lane runs both graphs and exits 1 with the feature row red and the default row green; restoring the first-graph narrowing or dropping the per-graph keys fails it. Verified live with cargo-nextest: the real selection runs in both graphs and passes, and with the feature arm's expected value changed the default graph passes while the feature graph fails every iteration. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
This ports the advisory flake check from block/buzz-app (block/buzz-app#890) to this repository: pull requests repeat the tests they change ten times, with retries off, so a test that passes CI by luck is caught before it merges.
What it does
flake-selectdiffs the PR merge commit against its first parent (HEAD^1..HEAD,fetch-depth: 2) and maps changed hunks to tests per runner: a hunk inside a test body selects that test; a change anywhere else in a test file, or a new file, selects the whole file. One lane per runner then repeats only that selection 10× with retries disabled and writes a test × iteration table to its step summary. Lanes skip when nothing was selected, run only onpull_request, and are not read by any required gate inci.yml— their own statuses carry the result.Per runner
crates/<crate>/<path>.rs::<module::test>from#[test]-style attribute spans (comments and literals blanked first). A hunk outside any test body selects the file's tests.#[ignore]d and Postgres /external_infratests are excluded.cargo nextest run --profile flakeper package per iteration, with target flags derived from the path (src/**→--lib --bins,tests/<stem>.rs→--test <stem>), a filterset of exactbinary_id & testpairs, and JUnit parsed per iteration. New[profile.flake]:retries = 0,fail-fast = false.desktop/src/**/*.test.mjs,*.jsdom-test.mjs,desktop/scripts/*.test.mjsdesktop/package.jsontestsmokefile:linejourneys fromtest()/it()spans (TypeScript AST) intersected withplaywright test --list --project=smoke, deduplicated--repeat-each=10 --retries=0, shardedmin(10, ceil(journeys / 5))ways;playwright-summarytabulates the JSON reportmobile/test/**/*_test.dartflutter test --file-reporter=jsonloop with the mobile lane's--dart-defineA runner whose selection exceeds 64 KiB of entries, or more than 250 Playwright journeys, is skipped with a note rather than overrunning its timeout.
Differences from the buzz-app version
_ci-flake.ymlcalled fromci.yml, matching this repo's_ci-*.ymlconvention, instead of inline jobs.typescriptpackage rather thanrolldown/parseAst.integrationproject lane: it needs the relay artifact chain. Integration-only specs list nothing forsmokeand the selection stays empty.(binary, test)pairs, so a same-named test in another module is not repeated.buzz-relaychange does not compile every test target of the crate.Heads-up
rust-cachemoves fromkey: sherpa-cache-v1toshared-key: unit-tests-sherpa-cache-v1so the flake lane can restore it read-only. This changes the cache key once: the first Unit Tests run after merge builds cold.scripts/flake-check.test.mjsis a root script, run by the Desktop lane), so its own Flake Check lanes are expected to skip.Verification
node --test scripts/flake-check.test.mjs— all unit tests pass (also wired into the Desktop lane).actionlinton the changed workflows;biome checkon the two scripts.scripts/test-rust-cache-contract.shand its regression harness pass with the new shared key.selectagainst this PR's own merge-base (empty, as expected).🤖 Generated with Claude Code