# RCA addendum — golden 35313912102 second red: twohost-b (kitsubito, job 105517287374) `two_host_ladder_role_b`
doyle, 2026-09-18 07:58Z. Sources: twohost-b-105517287374.log (this dir), crates/spt-daemon/tests/twohost.rs:533-545 (rig_wait) and :1137-1141 (the failing rung), .github/workflows/golden.yml job graph (test 88, n1-gate 849, twohost-b 1074, twohost-a 1252), golden #1 35299506382 job timeline via `gh run view --json jobs`.

## Verdict: CI JOB-GRAPH SHAPE red (rendezvous partner absent), NOT product. Route hertz. Rides the same successor head as todlando's fix; no same-sha rerun.

## What failed
Role B (kitsubito) ran 2 of 3 twohost tests green, then `two_host_ladder_role_b` panicked at rig_wait: "never converged on the rig: pairing: A rostered via the daemon-hosted responder" after the rig wait budget (test wall 900.48 s). B advertised `PAIR_MEET_UP:twohost` every 30 s from 07:24:26Z to 07:39:01Z with no A ever rostered. Role A's job (twohost-a, hfenduleam, job 105517287267) STARTED at 07:33:01Z — 10 min 39 s after B — and was still in its build/bring-up when B's window closed at 07:39:26Z. twohost-a will fail its mirrored rung once its own wait expires; that red is the same event, not a third.

## Why A was late — the job graph on a single-slot runner
- `twohost-a` and `twohost-b` both `needs: test`; `n1-gate` (matrix Windows + Linux) `needs: changes`. There is NO edge between `n1-gate (Windows)` and `twohost-a`, and both run on the single-slot hfenduleam runner.
- Golden #1 (35299506382): hfenduleam picked n1-gate FIRST (02:29:42-02:36:57), then test (02:36:58-03:44:16); twohost-a and twohost-b became eligible together at 03:44:19 and paired (a 17 min, b 31 min, both green).
- Golden #2: hfenduleam picked test FIRST (06:12:56-07:22:20); n1-gate Windows, queued since 06:12:55, took the runner next (07:22:22-07:32:59, 10.6 min); twohost-a queued behind it until 07:33:01. kitsubito was idle, so twohost-b started at 07:22:22 and burned its whole rendezvous budget before A's daemon existed.
- Which job the runner dequeues first is not controlled by the workflow → the pairing is a coin flip whose losing side costs one golden. The budget (900 s) is shorter than n1-gate Windows (~10.6 min) + twohost-a's fixture build/bring-up, so the loss is deterministic once the order goes the wrong way.

## Route and fix shape (hertz, thin PR on the successor head)
- Structural ordering, not a longer wait: make both twohost jobs eligible only when the runner they share is free — e.g. `needs: [test, n1-gate]` on BOTH twohost-a and twohost-b (both n1-gate legs finish before either twohost starts, so they become eligible in the same instant on idle runners, as golden #1 got by luck). Keep the 900 s budget; a longer budget would just move the cliff.
- Proof: the workflow change is exercised only by a golden run (a workflow-only PR's thin CI cannot pair hosts). Acceptance = the successor golden's twohost-a and twohost-b `startedAt` within seconds of each other AND both green; record the two timestamps in the PR/gate receipt. Negative control already exists: this run's 10 min 39 s skew.
- Register: file as an INFRA-REGISTER entry (IR-142 candidate: "golden job graph lets a single-slot runner interleave n1-gate ahead of twohost-a; the twohost rendezvous budget is shorter than that leg") — BUILT when the successor golden shows the paired start times.

## Standing for #307
Golden #2 has two reds, both closed with a mechanism: (1) product — reconcile offlines an UNBOUND perch mid-spawn (RCA-resume-unbound.md, todlando); (2) CI shape — twohost rendezvous lost to runner ordering (this file, hertz). Both land on the successor head; deployah reshapes once, one golden.
