# REQ-WEB-LAN-BOOTSTRAP-FIREWALL — INT-stage clause amendment (draft, doyle 2026-09-12)

## Sentence being replaced (traceable-reqs.toml:7670, tail of `title`)

> The negative controls are part of the requirement rather than the rig's taste: with the owned rule absent the same fetch must fail as ADMISSION-BLOCKED, and after the listener stops it must fail as STOPPED -- two refusals that MUST NOT SHARE A FACE, since a rig that cannot tell them apart reports a firewall as a clean shutdown.

## Replacement

> The negative controls are part of the requirement rather than the rig's taste. With the owned pair absent the same fetch from the second machine must fail as ADMISSION-BLOCKED. After the listener stops, the rig must be able to tell a stopped listener from a missing admission, and it MUST FIRST ESTABLISH WHETHER THE SERVING HOST'S POSTURE LETS A PEER SEE THE DIFFERENCE: before any STOPPED verdict, dial a known-closed port on the serving host from the second machine. A refused connect (RST) means a REFUSING posture: the peer-side STOPPED fetch is admissible and must not share a face with ADMISSION-BLOCKED. A silent timeout means a DROPPING posture (Windows with the firewall enabled and stealth mode at its default; Linux under a default-deny policy): the peer cannot see a refusal for ANY admission shape, so a peer-side STOPPED fetch is recorded and never interpreted, and STOPPED is witnessed on the serving host instead -- no listening socket on the port plus a host-local refusal -- with the owned-rule census carrying the admission state. The posture probe is keyed to the host as measured, never to the operating system (HFENDULEAM 2026-09-12: admitting hand rule present, listener down, 3x curl 28 at 6.0 s from kitsubito while loopback and own-LAN read 7; kitsubito as postured, ufw inactive and INPUT policy accept, refused a closed port to HFENDULEAM in one connect). A rig that skips the posture probe and reads a drop as a clean shutdown, or a refusal as a firewall, is the defect this clause exists to exclude.

## Consequences to carry with it

- `required_stages` comment (line 7671): int stays deactivated until hertz's lane lands the rig WITH the posture probe; the stopped cell (`bootstrap_stopped_from_second_machine`, blob 49102e39) is re-shaped after this text lands: posture probe first, then either the peer-side STOPPED (refusing host) or a host-side witness step (dropping host). No sub-second bound anywhere; the face (RST vs timeout) is the discriminator and elapsed is logged only.
- Phase 2 (Linux serving) needs an ENFORCING posture with a measured BLOCKED before the product's verb: kitsubito as postured has no failing state and the product's Linux backend refuses without active ufw/firewalld or an inet nft input chain (`linux.rs:153-162`, `:242-244`).
- doc stage: `docs-site/src/serving/overview.md` (tagged `[doc->REQ-WEB-LAN-BOOTSTRAP-FIREWALL]` at :255) gains one paragraph in end-user voice: on a Windows host with the firewall on, a remote machine cannot tell "spt stopped serving" from "the firewall is blocking"; check on the serving host (`spt serve lan` status / no listener) rather than by connecting from elsewhere. Docs-drift gate after.
- Operator: this is an acceptance-method change to a GREENLIT requirement, not a scope change; recorded on #304 and flagged for the operator's confirmation of the wording before the toml edit rides a lane.
