# Diag-arm intake criteria — releases#294 / v0.69.0

deployah's gate checklist for the `diag/294-sync-stages` arm. Written 2026-09-10 at ruling time, not
at run time, so none of it is rediscovered under pressure. Source: doyle's scope ruling ~14:42Z and
todlando's measurement contract, same minute.

## The distinction that must never blur

| | |
|---|---|
| **Candidate** | `a9e786b2` — the sha under gate, in both filed verdicts, and the sha that would tag. **Does not move.** |
| **Diagnostic tree** | `a9e786b2` **plus** the instrumentation patch. A different artifact. |

**A diag arm is NOT a gate arm.** It cannot discharge the gate, cannot produce a verdict, and its
numbers are never quotable as measurements of the candidate. Every report I write from one names the
ref and the tree explicitly, in the report itself, not just in a preserved file.

> Correction to my own earlier framing: I told doyle that instrumenting "costs one extra gate arm at
> the end." That was wrong under this ruling. The clean bare arm at the shipping sha was **always**
> owed to discharge the gate; the diag arm is not a gate arm and adds nothing to that count.

## Before the arm runs

- [ ] Ref is `diag/294-sync-stages`. **Never** `golden/**`, never an assembly branch.
- [ ] Confirm the diagnostic tree is `a9e786b2` + patch: record both the diagnostic sha and
      `a9e786b2`, and state the relationship. Verify by object, not by branch name — a hand-tracked
      branch is a snapshot of the last assembly it was moved to.
- [ ] `core#218` still unmerged; candidate sha unmoved.
- [ ] **No `traceable-reqs` tags in the hooks, no REQ activation.** Diagnostic code is not evidence
      for a requirement stage; tagging it mints coverage for something that never ships. Spot-check
      the patch for `[impl->`, `[unit->`, `[int->`, `[doc->` before running.
- [ ] Pool claimed for the diag lane (`pool-claim --pool <dir> --label diag-294`). Do not build the
      diagnostic tree into a pool a shipping lane will reuse without a claim in between. Sequential
      reuse is fine; silent sharing is not. Predict lane-identity refusals from the BUILD, never
      from `pool-claim`.
- [ ] Box census clean before arming; both boxes free.

## After the arm

- [ ] Preserve `instrumentation.patch` **beside the logs it produced**. A number whose instrument was
      thrown away is an anecdote.
- [ ] Preserve alongside it: diagnostic sha, platform, command/profile, raw output.
- [ ] Report names the ref and says DIAGNOSTIC TREE, not candidate — in the report body.
- [ ] Poll with `.spt/gate-poll.sh` (per-job transitions; selftested both directions).
- [ ] **When the diagnostic continuation SUCCEEDS, record its MARGIN as a number** — the elapsed
      against the budget, never bare "passed". (doyle's addition, and it is what this whole red
      teaches.) The 400x25 ms loop reports pass/fail and nothing else, so a 4.448 s success and a
      9.940 s success are *the same green*, while the failure is right-censored with no upper
      endpoint. **A green carrying no margin cannot be distinguished from a green that was one
      scheduling hiccup from red.** That is why r2 cost a full gate arm and taught almost nothing.
      Banked by doyle as KNOWN-HAZARDS 7.66 with a `REQ-HAZARD-*` id, registry-first with
      `required_stages = []`, activated by whichever lane delivers the test.

## What the numbers are supposed to answer

Stage boundaries, **both platforms**: Git store creation; each of the four `rev-parse` subprocesses;
`net_stream_send`; and the gap from first write to the responder's `accept_bi` becoming visible.
Plus the separately bounded **diagnostic continuation** on expiry — preserves the failure, reports
eventual visibility with id and first-observed elapsed. That is what turns a censored observation
into a real one.

todlando's contract adds: one process-wide monotonic epoch; identify test, pull ordinal,
requester/responder node, connection and stream (broker-local stream ids alone do not correlate
endpoints); timestamp requester-thread entry, store-init entry/exit, open and subscribe entry/exit,
each tip lookup entry/exit with ref and outcome, first-send entry/return, inbound accept and
registration, first eligible observation. **Distinguish send submission from actual transport
write** — if only submission is hooked, the downstream interval is labelled
*submission-to-registration*, never *wire latency*. Preserve the original 400-iteration acceptance:
the continuation never converts the original failure into a pass. Avoid per-poll added IPC.

## The fork these numbers decide (stated in advance so the result is not read backwards)

- **Process-spawn dominated** (git init + four subprocesses) → fix is **SEQUENCING**: move the git
  work before the subscribe/poll window opens. No budget change at all.
- **Post-write visibility-gap dominated** → transport question, different lane.
- **Neither dominates cleanly** → composite, and doyle says so rather than picking the prettier half.

todlando's caveat, carried: git-operation timings include process startup, Git work, filesystem
access and scheduling, so they **cannot alone establish spawn dominance**. Sequencing stays a
candidate intervention, not an automatic fix.

## Standing while this runs

Finding 1 **UNCLASSIFIED as to CAUSE** (all three cause phrasings withdrawn 2026-09-10: delayed
publication, measured tail, boundary defect). `34445961595` is the verdict of record; `34481993681`
a second red at the same cell. Release **HELD** — v0.69.0 not cleared, no tag, no publish, no board
close-out. **No new bare gate arm at `a9e786b2` until a measurement lands.**
