**Phase 2 design — Linux serving leg on kitsubito, pre-registered; NEEDS-OPERATOR (by comment) for one shared-box posture write with its revert (doyle, 2026-09-12 03:40Z).**

**Why phase 2 was HELD (comment 5643115673):** kitsubito as postured has no failing state — ufw inactive, nft/iptables INPUT policy accept on ip and ip6, port 22 reachable from HFENDULEAM with no rule — so a BLOCKED cell cannot be measured and an ADMITTED cell would pass through an open door. The product's Linux backend (`crates/spt-daemon/src/bootstrap_firewall/linux.rs`, blob at `00c4dad9`) selects, in fixed order, active ufw → active firewalld → the `nft` binary. On kitsubito that is the nft backend, and the nft backend REFUSES this host: `nft_input()` at `:549-559` adopts exactly ONE input-hook chain across the inet/ip/ip6 families and errors on more than one ("multiple/family-specific/device-bound input chains are unsupported"); kitsubito carries two (ip and ip6 INPUT, hertz 03:21Z) plus tailscale's. Creating a new inet table for the leg would make three and refuse harder. Deleting the existing ones breaks tailscale. **The nft backend cannot run on kitsubito as it stands; phase 2 goes through the ufw backend.**

**Posture write (hertz, one hand, sudo, filed before running, every line's output posted verbatim):**
```
ufw default allow incoming
ufw default allow outgoing
ufw deny 29470/tcp
ufw --force enable
ufw status verbose
```
This is NOT default-deny: default policy stays ALLOW on both directions, so the allow set is "everything", ssh, tailscale (UDP 41641 + tailscale0), the CI runner's outbound, and every listener on the box are untouched; the ONLY packet the posture changes is inbound TCP 29470, which ufw DROPS (ufw's `deny` is a drop, not a reject). Drop, not reject, is deliberate: on a refusing host `reject` would give ADMISSION-BLOCKED the same face as STOPPED (curl 7 both), and the whole amended clause is about those two faces staying apart; with `deny`, BLOCKED reads curl 28 and STOPPED reads curl 7. `ufw enable` writes `ENABLED=yes` into `/etc/ufw/ufw.conf` (persists across reboot) and installs the ufw chains into nft; both are in the census and both are reverted. Product-side consequence: `ufw_active()` at `:88` reads `Status: active`, so the ufw backend is selected; reconcile runs ONE `ufw insert 1 allow in proto tcp from any to any port 29470 comment <identity>` (`:199-203`), which ufw expands into a v4 and a v6 rule, and `verify_ufw` (`:308`) certifies each family's owned rule above any rejecting user rule.

**Census (hertz, before and after every step, identical instrument each time):** `ufw status numbered` (or `Status: inactive`), `grep ^ENABLED /etc/ufw/ufw.conf`, `nft list ruleset | sha256sum` plus the count of `hook input` chains, `ss -ltn` rows for 29470, tailscale0 up + `tailscale status` one line, free space. D0 is the pre-write census; the leg ends only when the final census equals D0 on every field.

**Cells, in order, one hand per step (todlando on every fetch from HFENDULEAM and every product verb; hertz on every posture line and every kitsubito listener); every fetch is `curl --write-out` with exit code, time_connect, time_total, verbatim:**
1. **Posture probe (the amended clause's first step):** HFENDULEAM → kitsubito:29471 (verified closed) → expect curl 7 fast (REFUSING posture, so peer-side STOPPED is admissible on this host). Taken AFTER the posture write, since `ufw enable` is the thing that could change it.
2. **BLOCKED, measured, with the door proven closed on a LISTENING port:** hertz starts a throwaway listener on 29470 (python3 http.server, his, torn down after), todlando fetches → expect curl 28 at the client timeout. Then hertz stops the listener, todlando fetches again → expect 28 again. Two 28s with the listener up and down = the drop is real and is not the listener's absence. This is the negative control that licenses every later ADMITTED.
3. **ADMITTED by the product:** todlando runs the Linux head binary (same sha `00c4dad9`, built on kitsubito in hertz's `~/spt-core-hertz-linux` tree — bundle by ref, sha256 of the exe posted beside the anchor) with an isolated `SPT_HOME`, `spt serve lan` → expect `LAN_BOOTSTRAP_UP … (port 29470)`, `ufw status numbered` shows the owned pair inserted at [1] in each family with the ownership comment, todlando fetches → expect 200 with the head's sha256 in the body. This is the requirement's ADMITTED leg demonstrated BY THE PRODUCT on Linux, which Windows never got to (F-A1-3).
4. **STOPPED, host refusing (owned rule present, listener down):** hertz SIGKILLs the serving daemon (no cleanup runs, rule persists — the census shows it), todlando fetches → expect curl 7 (RST from a closed port, admitted through the owned rule). Distinct face from cell 2's 28 on the same peer, same port, same host: the clause's two refusals, both visible, because the host posture is REFUSING.
5. **Cleanup verb:** todlando runs the product's stop/cleanup path on the leftover state → expect `LAN_FIREWALL_CLEAN`, `ufw status numbered` shows the owned pair gone and the deny rule intact; fetch → 28 (BLOCKED again, cell 2's face).
6. **Repeat start/stop once** (cell 3 then the ordinary `--stop`), fetch 200 then 28, to cover the repeat-bootstrap reconcile shape on Linux.

**Revert (hertz, one hand, filed):**
```
ufw delete deny 29470/tcp
ufw disable
ufw status verbose ; grep ^ENABLED /etc/ufw/ufw.conf
```
then the final census, compared field by field to D0 (`ufw disable` flushes the ufw chains; the nft ruleset hash must return to D0's; `ENABLED=no`). Isolated `SPT_HOME` deleted; kitsubito process census by path shows none of the leg's exe.

**What this leg does NOT claim:** the firewalld backend (no host); the nft backend (refuses this host by design, and that refusal is itself a product behaviour worth one recorded run: cell 0, before the posture write, `spt serve lan` on kitsubito as postured must refuse with the `nft_input` message and write nothing — the census proves the nothing).

**Operator:** the write is a shared CI box's firewall state changing for the leg's duration (default-allow, one dropped port, ufw enabled then disabled). I am asking for the go on that write with the revert above, not for default-deny. Until then, cells 0 and 1 (read-only) may run on hertz's word.
