---
name: cargo-builds-package-bins-for-integration-tests
description: Cargo builds EVERY bin target of a package whenever it builds ANY integration test of that package — so same-package fixture bins are already guaranteed and env!(CARGO_BIN_EXE_*) adds no build edge; the real gap is cross-package consumers and UNIT tests.
metadata: 
  node_type: memory
  type: project
  originSessionId: 7a3c43bb-f0d9-471d-88ad-ac02f7759292
  modified: 2026-08-03T22:50:48.166Z
---

Measured on spt-core 2026-08-03, cargo 1.93.0, and it falsified a claim I had put in
the infra register:

**Cargo builds every `[[bin]]` target of a package whenever it builds ANY integration
test (`tests/*.rs`) of that package.** That is what makes `CARGO_BIN_EXE_<name>`
resolvable in the first place. Probe: deleted all four `translate_proof_fixture`
artifacts, then built `--test attach_wedge_e2e` — an unmodified test that never names
the fixture. The plain exe returned at a fresh mtime; the hash-suffixed harness exes
stayed absent (so it came back as a *bin dependency of the integration-test build*,
not as a `--bins` harness compile). doyle replicated on `gh_fixture` / `--test
json_emit` / a different pool, same result.

**Consequence — split the population by "is the BUILD guaranteed", NOT by "could the
dependency be expressed":**

| consumer | build guaranteed? |
|---|---|
| integration test, SAME package | YES, automatically. No hazard. |
| **unit** test, same package | NO — unit tests get no `CARGO_BIN_EXE_*` at all |
| any test, CROSS package | NO |

So converting same-package sites to `env!("CARGO_BIN_EXE_<fixture>")` is a **clarity
and robustness** change (the path cargo actually emitted, instead of string-joining
`EXE_SUFFIX` onto a `CARGO_BIN_EXE_spt` directory anchor) — **not a build fix**. In
spt-core the genuine hazard population is 33 cross-package sites plus one unit-test
member (`crates/spt/src/cli.rs`), which is why `.github/workflows/ci.yml:105-106`
hand-prebuilds `translate_proof_fixture`.

Remedy options for the cross-package half, measured the same day:
- **Artifact deps** (`artifact = "bin"` in dev-dependencies) is the only shape that
  expresses the edge to cargo, but `artifact = …` **requires `-Z bindeps`** — refused
  on stable 1.93.0 (exit 101), works on nightly. Under **nextest the CLI flag is not
  enough** (nextest's inner `cargo metadata` dies, exit 102); it needs
  `[unstable] bindeps = true` in `.cargo/config.toml`. Artifacts land in
  `target/debug/build/<pkg>/<hash>/out/` via `CARGO_BIN_FILE_*`, not `target/<profile>/`.
- **In-test `cargo build`** guarantees the file at run time but expresses nothing to
  cargo, and **serialises**: 4 of 4 concurrent invocations hit "Blocking waiting for
  file lock" on the build directory. Warm cost ~0.4s; cold cost unmeasured.

**Why:** the register's own CI-member paragraph already stated the general rule (bins
are built for integration tests and benches, not unit tests) and both doyle and I drew
the opposite consequence one section later. A general rule you wrote does not protect
you from contradicting it nearby — see [[audit-the-boring-claims]].

⚠ **THE CONSUMER POPULATION IS BIGGER THAN A `sibling_bin` GREP FINDS — there are
THREE resolution syntaxes, and counts built on two of them undercount.** Measured
2026-08-03 after a checker returned a clean green over a gap known to be real:
1. `sibling_bin("<name>")` — 29→24 local resolver copies.
2. `env!("CARGO_BIN_EXE_<name>")`.
3. **A bare bin-name string joined onto a resolved directory** — `crates/spt/src/cli.rs`
   (`current_exe()` → `deps/` → parent, then `format!("translate_proof_fixture{EXE_SUFFIX}")`),
   and the SHARED resolver `crates/spt-term/tests/support/fixture_bin.rs`, whose
   cross-package consumers (`capture-player` ×3, `console-mode-probe` ×1 in
   spt-term/ and spt-daemon/ tests) appear in NO `sibling_bin` count.
   That resolver takes the required build command as its second argument
   (`"cargo build -p mock-adapter --bin capture-player"`), so at those sites the
   needed prebuild is already declared machine-readably in the source.
A raw string-literal scan returns ~133 hits, but `mock-shell` (121) and `mock-session`
(6) double as adapter/kind names — that number is an over-matching upper bound, not a
site count, and the triage is unfinished.

**How to apply:** before claiming an `env!` reference creates a build edge, ask which
of the three rows above the consumer is in — and before trusting any COUNT of consumers,
check it covers all three syntaxes ([[verdict-from-probe-competence]]). Probe design that settled it:
[[probe-an-unmodified-subject-needs-no-baseline]]. Related: [[spt-bin-lane-fixture-bins]],
[[workspace-bin-name-collision]], [[gate-int-tests-with-nextest-not-bare-cargo-test]].
