# Gate record — W2 `feat/335-adapter-leg`, PR #252 @`6c95d691` (doyle, 2026-09-24)

Milestone releases#331 SEAMLESS-UPDATES. Base `d3582138` (= origin/main at gate time; merge-base
== main, so the PR is a fast-forward and the merge result is the head content). One commit.
Members: releases#335 + #278 + #62, with #329 (no code) and #2 arm 1 answered in the PR body.

## Conditions

1. **CI green on the tested sha.** HOLDS — run `35988370797` **5/5**: changes, traceability,
   lint, `unit (Linux, kitsubito)` 3269/3269, `unit (Windows, hfenduleam)` 3306/3306 in 260.7 s
   (job `107596627449`, 10:39:19→10:55:48Z, 16m29s wall against the 60-min cap). The ~1 min of
   cargo contention at its start (box note below) did NOT damage it. On Windows only 2 of the 3
   `entry_exec::tests` arms exist — the `#[cfg(unix)]` one is compiled out, which is the whole
   reason conditions 3 and 4 are argued on box 2.

**VERDICT: all five conditions hold. ff-landed 2026-09-24 10:56Z — `d3582138..6c95d691` → main,
tested sha == merged sha, no rewrite.** Post-merge run `35990141244`: `unit` **skipped** via the
IR-144 exact-PR-proof reuse, so the merge cost the box only a `lint` job on kitsubito.
2. **Merged-tree traceability.** HOLDS, doyle measurement: `traceable-reqs 0.4.1` (= CI pin)
   `check` exit 0 in an isolated worktree at `6c95d691`; `[[requirements]]` headers **949 == 949**
   ids (toml tail-union hazard: the header count is asserted separately from the id count).
   Registry moved 946 → 949, the three ids this lane mints.
3. **The evidence EXECUTES, per layer.** Split deliberately — a PR green can prove COMPILE and
   nothing about EXECUTION.
   - **unit: HOLDS as a doyle measurement.** Read out of the Linux unit job log
     (`107596627551`, "3269 tests across 28 binaries", Summary 3269 passed): all three
     `spt-runtime entry_exec::tests::*` arms ran — including the `#[cfg(unix)]`
     `force_heals_only_declared_entries_once`, which is the arm Windows can never reach —
     plus `spt-daemon crc_swap::tests::{plan_prunes_only_stale_strings_never_binaries_or_litter,
     a_rolled_back_commit_prunes_nothing}`, the three `cli::tests::adapter_fan_out_*`, and the
     `spt-proto emit::tests::*` capture arms. Named, not inferred from a total.
   - **int: DOES NOT execute in CI.** Same blind spot as H3: the thin lane filters
     `kind(lib) + kind(bin)` and both new int binaries (`adapter_fanout_e2e`, `adapter_swap_e2e`)
     are `tests/` binaries — the log's own "210 binaries skipped". `golden.yml` runs ints
     workspace-wide, so the skip is ADR-0050 by design, not an infra item; the consequence is
     that these ints' first CI execution anywhere is the #331 golden run.
     → **doyle closed that gap by hand on box 2 (kitsubito, 2026-09-24 ~10:50Z):**
     `cargo nextest run -p spt -E 'binary(adapter_swap_e2e) + binary(adapter_fanout_e2e)'
     --success-output immediate` in the lane tree at `ecd19186` (see the subject check below)
     → **"Starting 3 tests across 2 binaries", 3/3 PASS**, named:
     `adapter_swap_e2e::an_update_prunes_retired_strings_and_keeps_dropped_binaries`,
     `adapter_swap_e2e::a_declared_entry_arriving_without_its_exec_bit_is_forced_loud_then_runs`
     (the `#[cfg(unix)]` arm), `adapter_fanout_e2e::three_adapters_update_at_once_and_report_like_the_serial_sweep`.
     Evidence read out of the success output, not inferred from the green:
     `ADAPTER_ENTRY_EXEC_FORCED:xx: …/srcs/xx/entry-bin extracted 0644 — packaging defect
     upstream` appears TWICE — once on the applied update, once on the following
     `ADAPTER_UPDATE_UPTODATE` run (the mode-only heal a content swap can never see) — and the
     third run is silent, so idempotence is observed rather than asserted.
     `PARALLEL_WALL: 6.379934781s for 3 adapters (not asserted)` against todlando's serial
     mutation of 62.9 s. Log: `todlando-w2/doyle-kitsubito-int.log`.
   - **Subject check (why the box-2 run counts for this sha).** The kitsubito lane tree is at
     `ecd19186`, not the PR head. `git patch-id --stable` over each commit's own diff:
     `ecd19186` → `04595e80d57b350aa2db9ee130c3a2c64549fe81`, `6c95d691` → the SAME id. Identical
     change, so the box-2 runs (mine, and todlando's 156/156 + mutation) measure the gated
     content. Tree was clean (`git status --porcelain` empty) and unmodified by me — the run
     references nothing I edited, so it needs no baseline arm.
4. **#62 is cfg-gated, so the REACHING mutation must be proved on box 2.** todlando's raw
   `kitsubito-mut62.raw` inspected by doyle: with `force_entry_exec` neutered, the real update
   reaches `ADAPTER_UPDATE_POST_FAIL:xx: post-step did not run: failed to spawn session:
   Permission denied (os error 13)` and the int reds — the field brick reproduced on Linux.
   That is a PEER measurement whose raw log I read, not a doyle measurement; the positive arm is
   doyle's own kitsubito run under condition 3.
5. **#2 arm 1 measured, scope stated.** Record `todlando-w2/ARM1-RESULT.md` + `arm1.out` read:
   control (plain overwrite of the running exe) REFUSED with a sharing violation; `spt adapter
   update` rc=0, v2 bytes on disk, live pid surviving on the renamed `svc.exe.old`, registry
   1.1.0 — the shipped crc_swap C1 displace (ruled shape 2), so no step-aside build. Scope
   limit stated in the PR body and honoured here: **CLI-direct route only; the
   daemon-coordinated route (live endpoint / declared `[service]`) was NOT measured.**

## Findings (non-gating, recorded)

- **F1 — `entry_exec` containment check is lexical, so a `..` token escapes it (code read, not
  measured).** `declared_entry_binaries` keeps a resolved program when
  `resolved.starts_with(install_dir)`. `Path::starts_with` compares whole components without
  normalising, and `resolve_program_in_dir` returns `install_dir.join(program)` (an absolute
  filled token passes through as-is), so a declared command of the shape
  `{adapter_dir}/../victim` yields `<install>/../victim`, which passes the check and gets
  `chmod +x`. The module's own doc states the opposite contract ("one resolving outside the
  install dir is not ours to touch"), so this is a claim-vs-code mismatch rather than a
  surprise. Blast radius is small — the same manifest already gets that program SPAWNED, and
  the install dir is itself named by the adapter — so the new capability is only "force +x on a
  file outside the install". Cheap fix: canonicalise before the containment check, or refuse a
  filled token containing a `..` component. Route: todlando, next W2-adjacent lane.
- **F2 — the `REQ-ADAPTER-UPDATE-PARALLEL` title still specifies a gate the code deliberately
  does NOT implement.** The title says the int is "three mock adapters with sleeps finish in
  about max not sum". The delivered int gates on STATE (a three-way rendezvous inside the
  post-steps) and prints `PARALLEL_WALL` unasserted — which is STRONGER and is the project's own
  rule (never race a product budget on a shared box). The title should be amended to the
  evidence, or a later reader re-derives a stopwatch gate from the registry. Route: todlando,
  same lane as F1.
- **F3 — `xtask check` (docs-drift) is not in the thin lane.** The `lint` job runs
  `clippy --workspace --all-targets` + `xtask brain-read-check`; the full `xtask check` is a
  golden-only step. The three doc edits (`docs-site/.../manifest.md`, `self-update/overview.md`,
  `docs/MANIFEST.md`) rest on todlando's `xtask check OK` until golden. Known, unchanged from
  prior lanes.
- **F4 — both new int binaries mutate the process env (`SPT_HOME`) around registration.** Safe
  under nextest (process per test) and under golden, which runs ints via nextest; a bare
  `cargo test -p spt` would race the two `adapter_swap_e2e` tests against each other. Noted so a
  future reader does not "fix" it by reaching for bare `cargo test`.
- **F5 (mine, corrected).** At the H3 gate I routed two traceability Quality-audit `[must]`
  findings to hertz as lane carry-forward. Measured after: `traceable-reqs lint` reports **1496
  `[must]` findings over 825 of 949 requirements (87 %)** — length 819, contains-and 674,
  tbd-todo 3 — and W2's three new ids carry the identical pair each. A class that fires on 87 %
  of the corpus is a calibration object, not a lane defect. Withdrawn to hertz by replacement;
  filed as **IR-146** in `docs/INFRA-REGISTER.md`.

## Box note (affects how a Windows red must be read)

hertz's queued H2 compile gated on post-merge run `35988140031` COMPLETING (10:38:56Z) and
started immediately — one minute before #252's Windows unit leg started at 10:39:19Z. He
TaskStopped it at ~10:40:08Z; his first leg had already died on `0xc0000142`
STATUS_DLL_INIT_FAILED under link contention. So **~1 minute of #252's Windows unit leg ran
against a competing cargo.** If that leg reds with a DLL/link/timing signature it is a VOID leg
to be rerun, not a W2 red. Lesson recorded: *"the previous run completed" is not a box-free
signal when a new push can land in the same minute* — the box empties after the POST-MERGE run,
and a new PR push re-occupies it immediately.
