---
name: gate-clean-target-not-incremental
description: Local compile gate on stale incremental cache gives FALSE GREEN; gate in a fresh CARGO_TARGET_DIR
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 251884f6-2913-4536-9288-15eed2974564
  modified: 2026-07-29T13:56:56.554Z
---

Gating a build on the main `target\` dir trusts STALE INCREMENTAL CACHE and can pass a build that FAILS a clean compile.

**Why:** Gating W2 @a93ddba, a fresh `CARGO_TARGET_DIR` build hit `error[E0063] missing field subnets` in 3 `#[cfg(test)]` initializers (crates/spt/src/picker/{data.rs:427,model.rs:1084,view.rs:499}). TWO things were true: (a) incremental main-`target\` reused pre-field objects so `clippy --workspace --all-targets` + `nextest -p spt` + targeted units all passed = false green; (b) the field `EndpointRow.subnets` was todlando's UNCOMMITTED W3 (picker-pair) WIP sitting in the SHARED main checkout — NOT part of committed a93ddba (which never touched EndpointRow). My scratch build compiled the DIRTY WORKING TREE and I wrongly attributed the break to the pushed commit. `git status` was clean at gate-start but his WIP landed mid-gate. a93ddba itself is clean/green.

**How to apply:** TWO lessons.
1. Compile/E2E gate in a throwaway `CARGO_TARGET_DIR` (scratchpad): `export CARGO_TARGET_DIR=<scratch>; cargo nextest run ...`. Fresh target = CI truth; never trust incremental main-target green for a struct/enum/signature change. Bonus on HFENDULEAM: dodges the live-daemon lock on `target\debug\spt.exe` (os-error-5 on rebuild) + E2E `fs::copy(spt.exe)` collisions with live infra.
2. On a SHARED main checkout with a live executor (todlando), the working tree is a MOVING TARGET — a fresh build compiles whatever's dirty NOW, which may be another agent's uncommitted WIP. Gate the SPECIFIC committed sha (git stash / `git worktree add` of the ref), or re-check `git status` at build time, before attributing a break to a commit. See [[seedmap-test-collides-live-daemon]] [[no-machinewide-killon-shared-runner]].
3. SECOND INSTANCE (2026-07-02, F-026 SI-1 gate @a18d4e2): same trap, FALSE RED flavor — background nextest on the shared checkout compiled todlando's uncommitted stamp-convergence broker.rs mid-run → `driven_by_selfheal::gap_a` failed deterministically; I fingered the wrong commit (ad609d5) off a range-bisect of COMMITTED history while the failure came from UNCOMMITTED WIP. Resolution pattern that settled it: pure-sha legs — `git worktree add --detach <scratch> <sha>` + throwaway target, run the failing test at each suspect sha; both passed → attribution moved to the WIP. RULE HARDENED: gates on this box run in an ISOLATED WORKTREE of the sha by default (clean target alone is NOT enough); coordinate quiet windows with the executor before long builds in the shared tree.
4. THIRD FLAVOR (2026-07-03, F-028 W1 gate @1de11cb): fresh-target + TARGETED suite = FALSE RED on fixture-dependent e2e — `cargo nextest run -p spt` on a fresh CARGO_TARGET_DIR never builds `mock-session.exe` (the dummy-harness fixture other crates provide), so `live_adapt_translation_swap_e2e` + `gateway_e2e` fail INSTANTLY (~0.05s, "must be built"). Full `--workspace` runs build it implicitly. RULE: in a fresh gate target, run nextest `--workspace` (or pre-build fixture bins) — never a bare `-p` slice; an instant sub-100ms e2e fail on a fresh target = missing fixture binary, not code.
5. FOURTH FLAVOR (2026-07-03 late, F-029 C-1 gate @15d48bf): FALSE GREEN from the gate SCRIPT itself — `cargo nextest run 2>&1 | tail -3; echo "exit=$?"` captures TAIL's exit (always 0), not nextest's. The suite actually DIED (disk-full 112 → cargo 101, nextest never ran) yet printed exit=0. TWO rules: (a) exit capture through a pipe = `${PIPESTATUS[0]}`, never `$?` (same class as the piped-send rule); (b) verdict requires the `Summary [ ...s] N tests run: N passed` line PRESENT — exit codes alone never certify a gate. Chunks with a full Summary line stay trustworthy even when the exit capture was wrong.
6. DISK DISCIPLINE (same incident): `git worktree remove --force` does NOT delete a `_target` held by leaked test daemons — my chunk-3 worktree left 23GB and the NEXT gate hit disk-100%. RULE: after every gate, kill holders by exe-path scope THEN `rm -rf` the gate dir THEN verify with `du`/`df`; one gate target (~23GB) at a time on this box.
7. **DISPOSAL LEG (BINDING, doyle-adopted 2026-07-29, todlando's W2b lesson): throwaway-target deletion is the LAST LEG of every gate battery on any box hosting a CI runner — a rig step, not memory.** W2b's battery left a 47.08GB throwaway target; C: fell 92→10GB and the NEXT PR's Windows CI (#123) died on the n1-gate 32GB free-space floor — "a 47GB gate artifact on a CI box is a CI outage with a delay fuse." Sequence: verify zero processes using it (exe-path scope, rule 6) → rm → report before/after free bytes. **Amendments same day: (a) flynn — sweep covers named non-Temp throwaways too (e.g. spt-alchemy target/verify build-around-locked-exe); primaries (target/debug) EXEMPT. (b) deployah — a battery crossing a context reset leaves a target on BOTH sides; disposal-as-last-leg misses the pre-clear half BY CONSTRUCTION, so any across-commune written while a throwaway exists MUST carry a DISPOSAL DEBT line (path+size) the reborn session inherits as a first-class next-step (proof: both W2 targets — todlando's build 14.78GB @3e92c075 AND doyle's gate 13.03GB @f438335b — survived their sessions' resets). (c) No multi-GB deletion while a timing-sensitive CI job runs on the box.** Related: **Phase B leaks ~6 spt.exe daemon children that outlive the suite ~2min — CI's job cleanup reaps them, LOCAL RIGS NEVER DO** (they hold target\debug\spt.exe → os error 5 on next build); sweep by exe-path before disposal. See [[e2e-leaked-daemons-shared-box]], [[hfenduleam-disk-full-ci]].
