Session close: REPORT-visitors-2026-10-01, STATUS (go/no-go: the family gate; SparkyFitness licence), CONTEXT, capability map rows, R-783..R-787 (register 422)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# REPORT — the box tells visitors apart; the permanent-gate spike; SparkyFitness; R-772/R-773; release + golden (2026-10-01 night)
|
||||
|
||||
## The Part table
|
||||
|
||||
| Part | Result | Notes |
|
||||
|---|---|---|
|
||||
| **A** — visitors apart (build) | **DONE, with one change to the brief's sketch and one leg unmeasured** | The sketch plus 2 costs paid in the same rollout: a header clean-up at traefik, and 19 catalog router resets for the apps that read the LEFTMOST address. The brief named neither. ep0's one request was refused by Cloudflare before the box (R-779). |
|
||||
| **B** — permanent family gate (spike) | **DONE — PASS** on exit items 1–5; costs measured | Exit test committed before the run. Build plan: 2 sessions. Waits for the operator (R-780). |
|
||||
| **C** — SparkyFitness record | **DONE, with 7 rows open** | Bench (9401 rebuilt and destroyed) and 9202 measured. **Its licence forbids commercial use** (R-784, operator). |
|
||||
| **D** — R-772, R-773 | **DONE** | Both red-proven and live on 9202. R-772 needed a second fix found live (0.286.0 → 0.286.1). |
|
||||
| **E** — release, floor, golden | **DONE** | Controller 0.286.1 floored (min_agent 0.131.0); both demo boxes took it and reconciled traefik/cloudflared by themselves. Golden 0.286.1 baked, round-tripped and vouched; the currency gate is OK, not waived. |
|
||||
|
||||
Baselines (re-verified): controller `c1b123c64955`, agent `d766666ff8cf`, felhom.eu `bc9c7b49346b`, catalog `94477cba435a`.
|
||||
Ends at: controller `a4a753b` (v0.286.1), catalog `de0a9bd`, felhom.eu (this commit). Agent untouched.
|
||||
Architecture read: `01-topology-and-trust.md` §5 and §7 (both corrected), `09` §3 decisions 45–49, 57–62; decision 63 added
|
||||
first (operator ruling).
|
||||
|
||||
## Claims in the brief that turned out wrong (or right), named
|
||||
|
||||
- *`clientIP` takes the leftmost hop.* **Right** (`claim.go:232`, pre-0.286).
|
||||
- *A stranger can lock the household out of the dashboard.* **Right, through the tunnel only.** Every tunnel visitor shared
|
||||
cloudflared's address as the key; a LAN visitor always had its own key.
|
||||
- *Cloudflare appends to a client-sent `X-Forwarded-For`.* **Right, measured:** `6.6.6.6,37.191.56.193` (M2). Also
|
||||
measured, not in the brief:
|
||||
- Cloudflare passes a client's `X-Forwarded-Host` and `X-Forwarded-Port` unchanged.
|
||||
- It strips a client's `X-Real-IP`.
|
||||
- It refuses a client-sent `CF-Connecting-IP` at the edge (403).
|
||||
- *cloudflared's address is docker-assigned.* **Right** (`172.18.0.5`, no `ipv4_address`).
|
||||
- *The setup gate's token is minted only from a dashboard session.* **Right** (`ServeGateStart`, one caller). But **"the
|
||||
setup gate uses [the visitor address]" was wrong:** the gate read no client address at all, so there was nothing to
|
||||
switch over. It now logs the visitor.
|
||||
- *"Any reader takes the address at a fixed distance from the RIGHT."* **Half wrong.** The distance differs by path:
|
||||
second from the right through the tunnel, first on the LAN. So a fixed count is wrong for one of the two paths, and
|
||||
readers must skip trusted proxies from the right. Count readers (calibre-web, tandoor, wger) were left alone for that
|
||||
reason.
|
||||
- *The sketch (traefik trusts cloudflared) is enough.* **Not on its own.** Trusting cloudflared makes the leftmost entry
|
||||
— written by a stranger — reach every app. 19 apps read exactly that one (several for rate limits: audiobookshelf and
|
||||
docmost by address only, papra skips its limit on a junk value). It also lets a stranger's `X-Forwarded-Host` through.
|
||||
Both were closed in the same rollout.
|
||||
- *calibre-web `TRUSTED_PROXY_COUNT`, wger `AXES_*` proxy count.* **Left as they are.** Both are count readers, and both
|
||||
lock per NAME (decisions 58, 61). A count of 2 would break the LAN path, and for calibre-web also its proto/host.
|
||||
- *Grimmory improves.* **Right as read in source; not measured in this session** (R-775 updated).
|
||||
|
||||
## Part A — the box tells visitors apart
|
||||
|
||||
- **Paths**: `audits/visitors-2026-10-01/A/` — M1–M4 before, M5 after, DESIGN.md (the path table, the options, the choice,
|
||||
the docs quoted).
|
||||
- **Built** (controller v0.286.0/.1):
|
||||
- A `felhom-tunnel` network `172.16.253.0/29` with docker's allocation confined to `.4/30`. The hand prototype found
|
||||
traefik grabbing `.2`, so cloudflared now sits at a fixed `.2` and traefik at a fixed `.3`.
|
||||
- traefik trusts `172.16.253.2/32` only, and runs `felhom-forwarded@file`.
|
||||
- `EnsureBaseStack` reconciles a running traefik or cloudflared.
|
||||
- `clientaddr.go`, plus IPv6 counted per /64.
|
||||
- The dashboard login messages are informal, in both languages.
|
||||
- **Red-proofs**: RP-A1, RP-A2 and RP-A3 each fail on their mutant.
|
||||
- **Live**:
|
||||
- **9202, simulated tunnel:** a stranger rotating a forged leftmost address was locked after 5 tries; the household
|
||||
from another address got in at once; LAN and impostor forgeries were counted as themselves (L1).
|
||||
- **demo-hp, real tunnel:** an app sees `6.6.6.6,37.191.56.193, 172.16.253.2`. The dashboard counter was keyed on
|
||||
`37.191.56.193` and locked after 5. Every app answered (L2, M5, E/).
|
||||
- **ep0's one request:** refused 403 by Cloudflare's edge, with no line in the box's log, so the second outside
|
||||
address is unmeasured on the real tunnel → **R-779**.
|
||||
- **Apps** (sweep of all 56 apps plus Grimmory and MeTube, read in source: `A/sweep/`):
|
||||
- **19 router resets**, one commit each, shipped before the release. docmost on the real tunnel still throttles a
|
||||
rotating forger.
|
||||
- **BookStack `APP_PROXIES`**, with 3.6 re-measured before and after: the household is no longer throttled by the
|
||||
stranger.
|
||||
- **Gains with no change:** Home Assistant (it treated every internet visitor as "local"), actualbudget, immich,
|
||||
dawarich, claper, termix, Grimmory.
|
||||
- **Open:** kimai, zipline, vikunja, nextcloud (R-776); Emby and Jellyfin LAN rights (R-777).
|
||||
- **Checklist 3.10** added.
|
||||
|
||||
## Part B — the permanent gate (spike)
|
||||
|
||||
`audits/permanent-gate-2026-10-01/VERDICT.md`. **PASS** on items 1–5.
|
||||
- 36 stranger requests, 0 reached an app.
|
||||
- Family members got their own 30-day logins, websockets worked, and logout worked.
|
||||
- A stranger's guesses locked only him.
|
||||
- OPDS, Kobo and KOReader worked through anchored exceptions, with the app's own login still in force.
|
||||
- The family login never opened the dashboard.
|
||||
|
||||
Costs: +0.4 ms per request; with the gate down, apps answer 500 (closed); the build is 2 sessions. One build
|
||||
requirement: anchor every exception (`/api/v1/opdsx` slipped past an unanchored prefix; Grimmory's own login still
|
||||
refused it). Fully torn down.
|
||||
|
||||
## Part C — SparkyFitness
|
||||
|
||||
`app-catalog-felhom.eu/onboarding/sparkyfitness.md`.
|
||||
- **Bench:** 5.1 server 33 %; 5.2 server 38 % and db 53 % under a heavy burst, 0 kills; 1.4 v0.17.2 → v0.17.3 proven;
|
||||
2.1 CLEAN; 9.1 green.
|
||||
- **9202:**
|
||||
- A stranger got nothing during install.
|
||||
- Sign-up was blocked in 3 spellings, and blocked again after remove + restore.
|
||||
- Sign-in limit (3.6): ~10 s for everyone (R-783).
|
||||
- 4.4: the state read degraded within 10 s.
|
||||
- Backup → remove → restore read the data back.
|
||||
- **Open:** 0.1 licence (**R-784 — non-commercial only**), 0.5, 0.7, 1.6, 1.7, 5.4, 8.3 (R-786). The pin is 11 releases
|
||||
and a major behind (R-785). A licence sweep of the whole catalog is owed (R-787).
|
||||
|
||||
## Part D — R-772, R-773
|
||||
|
||||
- **R-772:** not-run → `healthy:false, not_checked:true`, plus a line on the app page. 0.286.0 still waited for the
|
||||
last healthy record's 5-minute interval; 0.286.1 sees it on the next tick. **Live:** not_checked 14 s after the stop,
|
||||
healthy 42 s after the start. Red-proofs RP-D1 and RP-D1b. Readers of `health_probe`: the state override and the
|
||||
API/page only; the hub never sees it.
|
||||
- **R-773:** a restore of a removed app writes the lock record (`opened_by: restore`) and the block before the start.
|
||||
**Live** on Karakeep and SparkyFitness: a stranger got 403 after remove + restore. Red-proof RP-D2.
|
||||
|
||||
## Part E — release, floor, golden
|
||||
|
||||
- **Release:** controller 0.286.1. Full suite rc 0, gates green. 0.286.0 ran on 9202 only.
|
||||
- **Floor:** `0.286.1` + `min_agent 0.131.0` → demo-hp and demo-felhom on 0.286.1 within ~60 s. Each created the
|
||||
network, recreated traefik and moved cloudflared by itself (`E/rollout-*.txt`).
|
||||
- **Golden 0.286.1** (`documentation/tests/golden-0.286.1-2026-10-01/`):
|
||||
- sha `1dec051d…a89`; the round trip is equal; token leaks 0, with the positive control at 1.
|
||||
- Vouched: golden 0.286.1 / agent 0.138.0 / min_agent 0.131.0. The hub then refused golden 0.285.0.
|
||||
- `golden_currency_gate`: OK (not waived). The waiver was not renewed — the bake ran.
|
||||
|
||||
## Rows
|
||||
|
||||
- **Closed:** R-753, R-754, R-772, R-773.
|
||||
- **Narrowed:** R-775.
|
||||
- **Opened:** R-776..R-787 (12).
|
||||
- **Register:** 410 → 422.
|
||||
- **Capability map:** two rows added (PARTIAL: visitors apart; MISSING/spiked: the family gate).
|
||||
- **`unproven.py`:** unchanged — 35 of 55 not walked.
|
||||
|
||||
## Teardown (three layers)
|
||||
|
||||
- **Machine:**
|
||||
- 9202: karakeep, bookstack and sparkyfitness removed with their data and backups through the product; the echo
|
||||
containers, the spike (gate, Grimmory, MariaDB, MeTube, volumes, network, dynamic file), test images and helper
|
||||
files removed. 9202 keeps controller 0.286.1, its new traefik config and `felhom-tunnel` — the product's own.
|
||||
- demo-hp 9201: `a1-echo` and its image removed; its traefik config was restored after the M2 minute, and is now the
|
||||
release's.
|
||||
- **Host:** the bench 9401 was rebuilt and destroyed (`pvesm` before/after in `C/bench/C0`, `C9`). The drill VM is
|
||||
powered off and reverted to `virgin`; CT 9100 destroyed.
|
||||
- **Hub:** the floor and the artifact manifest changed on purpose (above); no customer or appliance records created.
|
||||
- **ep0:** one HTTP request, nothing else.
|
||||
Reference in New Issue
Block a user