diff --git a/docs/INFRA-REGISTER.md b/docs/INFRA-REGISTER.md index 39908031..273495f3 100644 --- a/docs/INFRA-REGISTER.md +++ b/docs/INFRA-REGISTER.md @@ -4961,6 +4961,65 @@ the wrapper's harness children orphaned + running") — so IR-80 ships callers, is the operator's box), [[IR-64]] (box-level facts only the operator can move), `twohost-web-helper-stall-shared-a-identity-stale-path` (memory; its CONFIRMED arm is re-read by this entry). +- **AMENDMENT 2026-09-09 — the WORKFLOW half is BUILT and FIELD-MEASURED; it is LANDED-pending-golden + (hertz).** The guard is two cells in `twohost_web.rs` plus a step per half in `golden.yml`, and it + grew four design corrections that are worth more than the guard itself, because each one is a way a + probe can certify the fault it exists to catch. + 1. **A FIXED SYMMETRIC WINDOW ADDS A THIRD CAUSE THAT LOOKS LIKE THE OTHER TWO.** The step boundary + orders the probe on ONE host; it does not align two, and after the ladder each half pays its own + wrapper and `cargo test` (on Windows a fingerprint scan plus Defender's first touch of a fresh + exe). MEASURED: the first hand-run in the A=kitsubito direction (13:14:13 → 13:14:51Z) redded + `INBOUND_BLOCKED` at 10.24 s with text asserting "a BOX rule, not a product or rig fault" — and + the cause was `cargo`'s start-up on the SENDER putting its first datagram after the receiver's + 10 s window closed. An innocent box, the guard's own words against it. What stopped it being + filed as a kitsubito block was that the box facts contradicted the text (`tailscale debug + netmap` on kitsubito lists `100.68.35.65/32` among its permitted inbound sources, and `ufw` is + inactive) — a failure text that contradicts a measured box is the text's defect. So the + rendezvous is DATA: A listens up to the rig budget and beacons once a second; B binds first, + waits for a beacon, and only then starts a ten-second clock, so B's red has already excluded + "A is not up". That is a FOURTH outcome with its own name, `PROBE_NO_BEACON`, never + `INBOUND_BLOCKED`. + 2. **THE LISTENING SOCKET MUST NEVER SEND.** Any outbound datagram from the measured port opens + stateful return state for it, so B's probe then arrives SOLICITED and crosses under both layers + — this entry's own "solicited return traffic works under either fault" applied to the guard + rather than to the ceremony. MEASURED: with the beacon sharing A's listening socket, the + out-of-grant control went **GREEN at 13:28Z** on a port a listen-only run had measured BLOCKED + at 13:20Z; a further green at 13:31Z with the beacon moved but the ack still leaving that socket + was residual state from 13:28. Beacon and ack both leave an ephemeral socket now, and B sends + from an ephemeral port too, so no run repeats a 4-tuple a previous run opened. + 3. **THE ACK IS ADDRESSED TO B'S RIG PORT, not to the probe's source port.** MEASURED: acking to + `from` produced a run that CONTRADICTED ITSELF — A said `INBOUND OK` and B said + `INBOUND_BLOCKED`, same run, 13:41:33 → 13:41:50Z — because A's ack leaves its ephemeral + socket, is therefore not return traffic of the flow B opened, and a receiver whose inbound rule + is a port RANGE drops it. The rig port is the only address either host is reachable on cold. + 4. **THE FALSIFIER, and it is the operator's own rule used as an instrument.** Forcing the probe + port to **7509** (`SPT_TWO_HOST_PORT_A=7480`), one port outside the granted udp 7460-7499, reds + the guard on demand with no elevation and no policy edit. Run TWICE BACK TO BACK at the final + code, 13:43:41 → 13:44:23Z and 13:44:25 → 13:45:07Z: **RED, RED** — A after 40 s having sent + 39 beacons, B in its ten seconds having sent 48 and 47 datagrams with no ack, both exit 101. + One red would only prove a state timeout expired; two consecutive reds prove the design writes + none. The grant boundary is therefore measured from inside the test binary: 7489 crosses, 7509 + does not, same hosts, same binary, one env var apart. + 5. **ONE ACK IS NOT ENOUGH — the same split verdict arrives by packet loss** (doyle, reviewing the + built lane). A acking ONCE and breaking leaves B's red resting on a single unrepeated UDP + datagram: lose it and A prints `INBOUND OK` while B reds `INBOUND_BLOCKED`, blaming a firewall + for ordinary loss — correction 3's defect reached by a different road. A now keeps draining for + a short window after its own verdict is already settled and acks EVERY probe in it, while B + stops on the first ack. The A-side assertion is unchanged: it was decided by the first datagram. + 6. **THE PROBE STEPS CARRY THEIR OWN BUDGET, 300 s, set EXPLICITLY** beside ceremony steps that say + 900. It bounds RENDEZVOUS skew, not pairing, so a blocked link costs 300 s ONCE instead of 900 + per cell per half. Left unset it would have been `from_env`'s invisible default sitting next to + a visible 900 on the step below — a number the next reader would have inferred wrongly, which is + this entry's whole failure mode in miniature. +- **FIELD PROOF, 2026-09-09, and it is the ONLY proof this guard has:** `dir 1` (A=hfenduleam, + B=kitsubito) 13:45:14 → 13:45:18Z and `dir 2` (A=kitsubito, B=hfenduleam) 13:45:41 → 13:45:58Z, + both GREEN with the ack after ONE datagram, both exits 0, both hosts running byte-identical source + (md5 `f31779339266f8034dcd72917c56a37e`, checked on both sides). Free space 174.38 GiB, flat across + all four arms. + ⚠ **THE `golden.yml` STEPS THEMSELVES ARE UNEXERCISED UNTIL THE NEXT GOLDEN RUN.** Thin CI + compiles the cells and SKIPS them — `Rig::from_env` returns `None` without `SPT_TWO_HOST`, so a + green thin run says the code builds and nothing about the steps. The wall times above are the field + proof; treat the workflow half as landed-pending-golden and not as verified by its own PR. - **Ripe when:** the WORKFLOW half, at `d882297f`'s PR. (The box half was ripe "now" against `25e60015` and is done; #272 golden acceptance is no longer blocked by it.) · **Size:** one workflow step remaining; the elevated command is spent.