docs(offsite): resolve §4.3 MTU open decision → client MTU 1280 (S3.1)

The CGNAT smoke test's OPEN DECISION is made: fleet-wide, permanent,
family-agnostic client MTU 1280 (RFC 8200 IPv6-minimum floor), implemented in
felhom-agent v0.65.0.

- §4.3: OPEN DECISION → made decision + rationale + rejected alternatives
  (auto-probe/per-type = fragility for a non-metric; MSS-clamp = unneeded).
  "ships MTU 1420" → 1280; corrected "fixed-line unaffected" (DS-Lite ~1452,
  PPPoE would also black-hole at 1420 — one floor covers all).
- §4.2: 1280 is family-agnostic so MTU correctness is decoupled from v4/v6
  resolution; v4-pin noted as a separate optional determinism item.
- §3.2 wire-field note + §8 S6 row: MTU 1420 → 1280; S6 residual now only the
  true-CGNAT-SIM retest.
- REPORT.md overwritten.

Docs-only; the constant change is in felhom-agent v0.65.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-04 14:02:48 +02:00
parent 2028785f5e
commit a7f954dde7
2 changed files with 55 additions and 46 deletions
+20 -29
View File
@@ -4,36 +4,27 @@
---
# REPORT — S3 appendix: CGNAT smoke test (operational validation, docs-only in this repo) (2026-07-04)
# REPORT — S3.1 doc close-out: offsite-tunnel MTU decision resolved (docs-only) (2026-07-04)
Ran the deferred S3 appendix: the one open transport caveat in `06-offsite-connectivity.md` §7 —
does plain-WireGuard (box dials out + `PersistentKeepalive=25`) establish and **hold** a mapping
through a mobile-carrier NAT? Executed live on **felhom-pve** (`demo-felhom`, agent v0.64.0) with a
USB-tethered Xiaomi Mi 11i. No code touched; the only host changes were runtime `ip`/`dhclient`
one-shots, all reverted to the Phase-0 baseline at the end.
Docs-only companion to the S3.1 implementation (the constant change lives in **felhom-agent
v0.65.0** — see that repo's REPORT). Resolves the OPEN DECISION the 2026-07-04 CGNAT smoke test
left in `documentation/architecture/06-offsite-connectivity.md` §4.3.
**Method (surgical, SSH-safe):** kept the box on its wired default; steered **only** ep0's `/32`
out the phone so just the tunnel's outer UDP traversed the carrier NAT. Neutralized the phone's
RA-provided IPv6 + pinned ep0→v4 so the tunnel took the **v4/NAT** path (not un-NATed v6). 32-min
idle soak sampling handshake age every 30 s. Full restore verified against the captured baseline.
**Decision recorded:** fleet-wide client **MTU 1280** (RFC 8200 IPv6-minimum floor; outer 1340 v4 /
1360 v6 fits every realistic path), permanent + family-agnostic, client-only (endpoint `wg0`
untouched — interface MTU caps box→PBS, advertised MSS caps PBS→box).
**Findings:**
- **Uplink:** phone got a **public mobile IPv4** (`84.225.188.131`, Magyar Telekom) — a real
single-NAT traversal (phone tether NAT), **not** true CGNAT `100.64/10`. Recorded as such.
- **Handshake/PBS:** established over the mobile NAT path (endpoint v4 `167.233.158.164:443`);
in-tunnel ping 4/4 ~57 ms; PBS login page reachable **after** the MTU fix.
- **MTU (actionable):** outer path MTU ~**1400 B** → shipped `wg-felhom` MTU 1420 **black-holed
bulk data** (ping/handshake healthy, PBS page empty). MTU **1340** (= 1400 60) restored it;
1360 failed. Recorded in §4.3 with an **OPEN DECISION**: permanent fleet-wide lower MTU vs
connection-type-dependent (1420 fixed-line / ≤1340 mobile, or MSS clamp).
- **Soak:** 64 samples, max handshake age 125 s (normal rekey), **zero stalls**, final ping after
32 min idle with no bounce → **mapping held on keepalive alone.**
- **v6 trap:** a dual-stack mobile uplink made `wg-quick` prefer the endpoint AAAA and ride
un-NATed IPv6 until v4 was forced (recorded in §4.2).
**Edits to `06-offsite-connectivity.md`:**
- **§4.3** — replaced "OPEN DECISION (not yet made)" with the made decision + rationale + the
rejected alternatives (auto-probe/per-connection-type = fragility for a non-metric; MSS-clamp =
unneeded without forwarding). Updated "the unit ships explicit MTU 1420" → 1280.
- **§4.3** — corrected the over-general "fixed-line customers are unaffected": sub-1500 fixed-line
paths (DS-Lite ~1452, some PPPoE) would also have black-holed at 1420; one 1280 floor covers all.
- **§4.2** — noted the 1280 floor is chosen family-agnostic *specifically so* MTU correctness does
not depend on the v4/v6 resolution outcome; the deterministic v4-pin stays a separate, optional
future determinism note (not built here).
- **§3.2 / §8 S6 row** — stale "MTU 1420" wire-field note → 1280; S6 residual list drops the
now-resolved MTU decision, keeping only the low-risk true-CGNAT-SIM retest.
**Doc edits (this commit):** `06-offsite-connectivity.md` — §7 open-validation **CLOSED**;
§4.3 MTU mobile finding + open decision; §4.4 keepalive 32-min mobile hold; §4.2 dual-stack v6
trap; §8 S6 row updated. Runbook: `RUNBOOK-s3-cgnat-smoke`.
**Still open:** true-CGNAT-SIM retest (deferred, low risk — "when able"); the §4.3 MTU
permanent-vs-per-connection decision; S4 PBS-over-tunnel; S5 DR consume; S6 tunnel-health alerting.
**Not changed:** no code, no endpoint, no hub/controller, no JSON golden (MTU is never on the wire).
One docs-only commit.