Day 2 2026-10-19: ep0 keep-weekly 2 (D18), passphrase measured (R-1159 READY, D19), hub 0.160.0 deployed, controller 0.333.0 floor, gofmt gates; register 167 -> 163 (closed 6, opened R-1165, R-1166)
gates / gates (push) Successful in 7m15s
gates / gates (push) Successful in 7m15s
This commit is contained in:
@@ -26,6 +26,17 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-10-19 (second day brief) — ep0 one copy per week, the passphrase measured, hub 0.160.0, controller 0.333.0, gofmt gates (full text of each row: `git show 73f38992:documentation/backlog/OPEN-ITEMS.md`)
|
||||
|
||||
| Row | What | Closed | Evidence |
|
||||
|---|---|---|---|
|
||||
| **R-1155** | **FileBrowser's own 2-hour token for the one-sign-in user can outlive the dashboard session.** (P4) | CLOSED 2026-10-19 — **controller 0.333.0, the floor for every box.** Measured first on demo-hp: the household user's FileBrowser token (HS256; claims `belongsTo`, `Permissions`, `iat`, `exp` 2 h, `iss`) still opened FileBrowser (200) after the dashboard sign-out, as a cookie and as Bearer. Now the forwardAuth answer refuses a request with no valid files cookie that carries a non-admin FileBrowser token, in every place FileBrowser 1.5.6 reads one (cookie, `?auth=`, Bearer, Basic password); `admin`'s token passes. The commit's security review found Basic missing from the first version — fixed before release, red-proved. Live (rc.2 on demo-hp, 0.333.0 on Tester 1): the token alone 401 in all four forms before and after the sign-out; with the files cookie 200. | `audits/day-2026-10-19b/P3/r1155-live-rc2.txt`, `P6/05-files-one-sign-in.txt` |
|
||||
| **R-1161** | **The escrow wizard still says „Ez mostantól az élő helyreállítási kód" („this is now the live recovery code") the moment the code is shown;** (P4) | CLOSED 2026-10-19 — **controller 0.333.0**: the reveal says the code becomes live after the two words come back and that closing the page keeps the old code; the old sentence shows only for an agent before 0.160.0 (no confirm). Fixtures `escrow_first`, `escrow_receremony` re-captured (R-1151 made the old text untrue); the rest byte-identical. Live on demo-hp: new text shown, old hidden, the switch present, negative control absent. | `audits/day-2026-10-19b/P6/06-escrow-page-text.txt` |
|
||||
| **R-1156** | **A reinstall done within the stale threshold (45 min) of the old box's last report reads as „live":** (P4) | CLOSED 2026-10-19 — **hub 0.160.0 deployed** (the operator's yes, 11:2x local): `host_reenroll_while_live` is a WARNING mailed to the operator with the same instruction as the stale case (delete the old host, run the installer again); a `--resume` or repair re-run mails too and the text says it needs nothing. Red-proved (info severity → the test fails). Deploy: only Deployment/hub synced, Synced/Healthy, running digest = built digest, 0 ERROR lines, floor read back, host + controller reports from all three boxes after the restart. | `audits/day-2026-10-19b/P4/`, `05` §8 |
|
||||
| **R-1157** | **While the cadence-cap flag stays degraded (the agent's 24 h hold), further refused backups raise no new alarm:** (P4) | CLOSED 2026-10-19 — **hub 0.160.0 deployed**: a changed agent reason while the cadence cap stays degraded is a further refusal — counted (`refusals_in_episode`, `first_refusal` in the details), the alarm repeats at most once a day, the cleared record carries the total. No agent change. Red-proved (without the branch a day-later refusal raises nothing). | `hub/internal/monitor/host_capability.go`, `07` §6.1 |
|
||||
| **R-1158** | **The off-site re-issue on a clean-slate re-enroll may be obsolete:** (P4) | CLOSED 2026-10-19 — **measured from the code, kept, and its words corrected (hub 0.160.0).** The only reader of the Storage Box sub-account password is the hub's own key registrar (`offsitekeys.TargetFor`); `ConsumeOneTimeSecret` has no production caller and `consume-password` answers 410 since v0.127.0, so the leg changes nothing a box uses. Not proven useless: it hands the hub a fresh, working login at every clean reinstall (it repairs a broken stored one). Comments and the `offsite_reissued` record no longer say the controller takes the password (red-proved test). CC's memory note on reinstalls updated. | `05` §8 [FACT R-1158] |
|
||||
| **R-1160** | **The hub and the agent have no gofmt gate, and both drift:** (P4) | CLOSED 2026-10-19 — **one formatting-only commit per repo** (hub `d5e3c8b0`, 22 files; agent `1edfd8e`, 14 files; tests green before each), then the controller's gofmt gate shape in both runners: `hub-gofmt` in `repo_gates.py`, `gofmt` in `agent_gates.py`, fast set, each with decoys (an unformatted file convicted by name, its formatted twin passes, CI without Go passes out loud, a dev machine without Go is INCONCLUSIVE); red-proved with the conviction switched off. No agent release (the next one carries it). | `scripts/hub_gofmt_gate.py`, felhom-agent `scripts/gofmt_gate.py` |
|
||||
|
||||
## 2026-10-19 — the website keeps syncing during an internet outage (`fd75003e`)
|
||||
|
||||
| Row | What | Closed | Evidence |
|
||||
|
||||
@@ -112,7 +112,7 @@ match what the reader sees is how an instrument stops being believed (R-421). It
|
||||
**nothing was proven on the day this line was drawn** and a stopping line that moves a status is a
|
||||
stopping line that lies.
|
||||
|
||||
## Install & onboarding — 9 rows (P3 5, P4 4)
|
||||
## Install & onboarding — 7 rows (P3 5, P4 2)
|
||||
|
||||
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -123,8 +123,6 @@ stopping line that lies.
|
||||
| **R-993** | Install & onboarding | P3 | **Operator: approve the minimum machine in `documentation/audits/sizing-2026-10-13/SIZING.md` §5** (the input R-991's hardware page needs). MEASURED 2026-10-13 on the N100 demo box (61 apps deployed and removed through the product, 15 min at rest each; heavy apps with one real action). Proposal: **minimum** x86-64, 4 cores (N100 class), **8 GB**, 256 GB SSD; **recommended 16 GB**, 512 GB SSD; out: ARM / Raspberry Pi, Synology-QNAP, routers, cloud VPS. Worked from the floor (2.5 GB for the whole box with no apps) + Immich, Jellyfin, Nextcloud, Home Assistant, Vaultwarden, Paperless-ngx at their peaks (5.0 GB) + 50 % headroom ≈ 12.3 GB. 8 GB runs that set without Immich; 16 GB runs all of it twice over. Data for the estimator: `sizing.json`. **2026-10-13 (estimator session) — the installer accepts a host BELOW this minimum:** `autosize_guest_caps` has no floor on the host, only on the guest; on a 4 GB box (MemTotal ≈ 3.5 GiB) the guest gets host − 1 GB ≈ 2.4 GB and Proxmox keeps ≈ 1 GB, where it used ≈ 2.0 GB on the N100 (SIZING.md §1). Whatever minimum is approved, nothing enforces it at install today. The three-verdict wording of §5 now matches the estimator page (`/gepigeny`, R-997). | **WAITING-ON-OPERATOR** — filed 2026-10-13 | the operator's decision | Operator: approve or change §5. If nothing is done: no hardware page; a buyer with a Raspberry Pi can still download the installer (R-991 stays open) | operator |
|
||||
| **R-494** | Install & onboarding | P4 | **NARROWED 2026-09-14 by operator ruling → [P3-LOW] the hub COULD create the tunnel at customer creation, for a domain already on Cloudflare. Not blocking: every customer has their own domain and the operator creates the tunnel per day-0 A.1 (`architecture/01-topology-and-trust.md`).** *Original finding, kept:* **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **READY — rank P3-LOW; owner: CC** **Re-ranked 2026-10-03: P3→P4: operator-side automation; the operator creates the tunnel by hand per the day-0 runbook.** | — | — | CC |
|
||||
| **R-504** | Install & onboarding | P4 | **[P3-LOW] `iso.felhom.eu` cannot show an index page on its own — its root returns 404, and the download page lives on the website instead.** MEASURED 2026-09-14: `https://iso.felhom.eu/` and `/index.html` → 404; only named objects answer. The host is an R2 bucket behind a custom domain; whether R2 would serve an uploaded `index.html` at `/` was **not measured** (uploading anything to the public bucket is a publication). The ISO v1.27.0 task puts the Hungarian download page at `felhom.eu/letoltes` (published with the ISO, after the operator's yes). **Remaining:** a redirect from `iso.felhom.eu/` to that page needs a Cloudflare rule the session has no credential for. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (Cloudflare rule)** **Re-ranked 2026-10-03: P3→P4: households are sent to the website's download page; the bare address is cosmetic.** | — | — | operator |
|
||||
| **R-1156** | Install & onboarding | P4 | **A reinstall done within the stale threshold (45 min) of the old box's last report reads as „live":** the hub writes only the info record `host_reenroll_while_live`, no warning mail, so the operator is not told to delete the old host and re-issue. The residual of R-1154's loud-only rule. Found 2026-10-19. | OPEN — filed 2026-10-19 | — | Decide: mail the live case too, or a shorter window for this check | CC |
|
||||
| **R-1158** | Install & onboarding | P4 | **The off-site re-issue on a clean-slate re-enroll may be obsolete:** since hub v0.127.0 no box receives the provider password (a fresh box registers its key with the controller API key), so `reissueOnReenroll`'s off-site leg may now only reset a password nobody uses — and CC's memory note on reinstalls (2026-08-21) may be stale on this point. Read from code, not measured. Found 2026-10-19. | OPEN — filed 2026-10-19 | — | Measure on the next Tester4 install (after deleting its old host) | CC |
|
||||
|
||||
## Apps & catalog — 13 rows (P3 5, P4 8)
|
||||
|
||||
@@ -154,7 +152,7 @@ stopping line that lies.
|
||||
| **R-683** | App updates | P3 | **[P3-LOW] Watch: after a power cut during an update's health check, the hold named an HOUR-OLD second-drive copy, not the one the update's own backup should have just made.** 2026-09-24 chaos round 3 (nextcloud, `backup_max_age: 1m`): no `backing-up` phase was seen and the hold named Tier 2 at 13:04 for an update pressed at 14:04; the pre-cut controller log was lost with the container (the runner now saves it at arm time — R-320). Round 11, the same action without a power cut, named a fresh 14:34 copy and logged the Tier-2 copy. The sentence was TRUE (it named the copy it offered); the question is why the update did not back up first. Not reproduced; watch the next power-cut drill. `audits/night-2026-09-24/E/round-03*.json`, `E/round-11-controller-pre.log` | **OPEN — P3; owner: CC (watch)** | — | — | CC |
|
||||
| **R-785** | App updates | P3 | **[P3-LOW] SparkyFitness is pinned 11 releases and a major behind upstream (v0.17.3; upstream v1.7.3, v1.6.0 dated 2026-07-24).** READ 2026-10-01 (`audits/visitors-2026-10-01/C/bench/C1-previous-tag.txt`). **Needs:** an update walk 0.17 → 1.x through the ladder (bench + box), after R-784 is decided. | **OPEN — rank P3-LOW; owner: CC (after R-784)** | — | — | CC |
|
||||
|
||||
## Backup & restore — 28 rows (P2 3, P3 13, P4 12)
|
||||
## Backup & restore — 28 rows (P2 3, P3 14, P4 11)
|
||||
|
||||
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -184,8 +182,8 @@ stopping line that lies.
|
||||
| **R-878** | Backup & restore | P4 | **A catch-up (R-871) runs the database-dump leg in the DAY, and that leg stops an app with a volume for its copy — the household may notice the stop, and a large volume makes it longer.** MEASURED 2026-10-05 on demo-felhom: the catch-up at 08:25:02 stopped opengist, copied 182.5 KB, started it again — about 1 s, then a few seconds of `health: starting`; the night does exactly the same, unseen. Nothing measured for a large volume. Fix direction (if it matters): skip the volume copy of a running app in a DAYTIME catch-up and leave it to the next night, or warn. `audits/catchup-2026-10-05/partA/live-demo-felhom.txt` | **READY — owner: CC** **2026-10-05 (burn-down night): NEEDS A LIVE MEASUREMENT** — a timed catch-up on 9202 for an app with a multi-GB volume, then the skip-or-warn choice. | — | measure a large volume first | CC |
|
||||
| **R-32** | Backup & restore | P4 | **[P2-HIGH] RESET must purge the customer base dir; the orphan card must stay honest; unattributed bytes must be visible.** The rehearsal's S7 said in advance that an orphan card would BE a finding — and one appeared (16:58:14). Cause: RESET's `"hetzner":"ok"` leg destroys the sub-account, but **a Hetzner sub-account is an access-control object, not a data object** — its directory survives, so re-enabling offsite recreated an account over the previous lifecycle's ciphertext, encrypted under a key that same RESET had destroyed. **MIGRATED FROM `ROADMAP.md` 2026-08-22 (R-369) — originally filed 2026-07-21, size M, roadmap state `idea`.** Moved verbatim; nothing added or reinterpreted. The roadmap keeps its copy as history, marked moved. | **OPEN — migrated from ROADMAP 2026-08-22, rank unchanged** **2026-10-06 night: design written** (`audits/night-burndown-2026-10-06/design-R-32.md`) — pick A: purge the repo + set-aside copies through the sub-account's own password login BEFORE deleting it (no main-account credential); the „repo data destroyed" comment at `hub/internal/offsite/offsite.go:276-280` is false for the shared tier; part (3) waits on a read-only measurement (`du` on port 23). Operator: agree to route A. **2026-10-07 07:58: `09` §3 decision 167 — option A yes, and delete the old RESET leftovers once.** **2026-10-07 (Part D step 2, read only):** the hub shows bx11 holding 3.3 GB of data while the four live customers account for ~0.6 GB → **~2.7 GB belongs to no live customer**; no live customer shows a set-aside folder, so the leftovers are in homes whose sub-account is gone, reachable only by the pool box's MAIN account. **The one-time clean-up is STOPPED:** no main-account login for bx11 is held on DooPlex (the API token in the credentials file sees no box). Needs: the main-account login, or the operator lists and deletes in the Hetzner console (`audits/day-2026-10-07/D/D2-listing-readonly.txt`). **2026-10-07: option A DELIVERED (hub 0.142.0):** RESET purges the repo and every `.orphaned-*` through the sub-account's own login before deleting it, and keeps the sub-account if the purge fails (red-proved, `audits/day-2026-10-07/D/`). Not yet seen live (no scratch RESET today). **The one-time clean-up of the ~2.7 GB of leftovers is STOPPED:** it needs the pool box's main-account login (see above). **2026-10-07 14:43 — `09` §3 decision 173: leave the ~2.7 GB of old leftovers for now; re-ranked P2 → P4.** Option A itself is delivered (hub 0.142.0). What stays open is ONLY the leftovers: they were computed (box total minus live customers), never listed, and deleting them needs the pool box's MAIN login, which reaches every customer's data. **Blocker: a safe main-account path.** | — | **Ruling from the run (three parts, deliberately separate):** (1) because RESET destroys custody, the ciphertext it leaves behind is unrecoverable **BY DESIGN** → RESET gains a **main-account purge of the customer base dir** (the existing operator ack already covers it); (2) the **move-aside guard STAYS** for reinstall-*without*-RESET — there custody survives and the card's "history recoverable" promise is true (R-26 depends on exactly that); (3) the operator **Restic tab shows per-customer directory bytes vs attributed snapshot bytes**, so dead data cannot hide. Measured on the pool box that night: **49 M attributed** (2 snapshots, 48.717 MiB) against **1.4 G + 3.0 M unattributed** across TWO `.orphaned-*` dirs. Evidence `restic-and-pool.txt` | CC |
|
||||
| **R-1087** | Backup & restore | P4 | **Whole-box copies left on the OLD local target are never pruned after the target moves.** MEASURED 2026-10-15 (storage-identity build B space check): the N100's host root (`local`) holds three copies from 2026-07-28 (5.5–5.7 GB each, ≈ 16.8 GB); its agent's `local_backup_target` is now `felhom-backup` (the USB disk, retention 3), and retention prunes only the current target. On a small-root box such leftovers would starve the local copies (R-548). Evidence: `audits/storage-identity-buildB-2026-10-15/space/felhom-pve-9201.txt`. | OPEN | — | Decide whether the agent prunes its own `vzdump-lxc-<vmid>-*` files on a former target (after a newer copy exists on the new one), or the target move asks; until then, the N100's three July files can be removed by hand with the operator's word. | CC |
|
||||
| **R-1161** | Backup & restore | P4 | **The escrow wizard still says „Ez mostantól az élő helyreállítási kód" („this is now the live recovery code") the moment the code is shown;** since R-1151 (agent 0.160.0, controller 0.332.0) the code becomes live only after the two words are typed back, and closing the page keeps the old one. The safe direction (it overstates), but it is now untrue until the confirm. A Hungarian + English copy change; not done in-session (the controller's one release of the session was out). Found 2026-10-19. | OPEN — filed 2026-10-19 | — | Next controller release: say the code becomes live after the check | CC |
|
||||
| **R-1162** | Backup & restore | P3 | **The whole-guest off-site tier (ep0) prunes by count (keep-last 2), so a compromised controller can still push out the pre-compromise copy, slowly:** with R-973's cap one run per 6 days gets through, so a copy older than the compromise survives about 6 days and every extra attempt alarms. Time buckets on ep0's prune job (e.g. keep-weekly 2) would make it unfloodable; check that DooPlex's pull copy of ep0 is keep-weekly, not keep-last. The off-site half of R-973, carried over when R-973 closed. An ep0/hub prune-job change. | OPEN — carried from R-973 2026-10-19 | — | Operator decides the ep0 prune shape | operator + CC |
|
||||
| **R-1162** | Backup & restore | P3 | **ep0's whole-guest off-site prune was a count (keep-last 2), so a compromised controller could push out the pre-compromise copy, slowly.** Operator decision (STATUS D18, the brief's D1 = A, 2026-10-19 08:24): one copy per ISO week, 2 weeks. Before: PBS's own dry run and an offline model of its selection both showed `keep-weekly 2` removing nothing on demo-hp (2026-10-08, 10-15 kept) or demo-felhom (10-06, 10-13 kept); nothing deleted by the dry runs (8 snapshots before and after). On the operator's „yes": `prune-demo-hp` and `prune-demo-felhom` changed to `keep-weekly 2` (schedule 03:30 unchanged), read back 07:49 UTC. DooPlex's copy of ep0 already keeps `keep-weekly 8` (decision 71) — unchanged. Households without a job: R-1165. | NARROWED 2026-10-19 — changed and read back; the first scheduled run is 2026-10-20 03:30 UTC | `audits/day-2026-10-19b/P1/` | Read the 2026-10-20 03:30 UTC prune task on ep0 (`proxmox-backup-manager task list`, `prunejob` for both namespaces: OK, `keep-weekly 2`, two snapshots each), then close | CC |
|
||||
| **R-1165** | Backup & restore | P3 | **A household namespace on ep0 gets no prune job by itself, so its whole-guest off-site copies are never pruned.** Read 2026-10-19: ep0 has prune jobs only for `demo-hp`, `demo-felhom` (made by hand in July, R-82) and `operator`; `tester-1` (3 weekly copies, growing one a week) and `Tester-2` (1) have none; `felhom-tenantsync.sh` creates no job and the hub's provisioner neither. The install script's own comment warns that a missing job is unbounded growth. Close to R-89 (per-customer retention on the hub), but this is the gap today, at every new household. The operator chose not to add a tester-1 job by hand today (2026-10-19). | OPEN — filed 2026-10-19 | `audits/day-2026-10-19b/P1/ep0-settings-before.txt` | The hub (or tenantsync) creates `prune-<ns>` with `keep-weekly 2` when it provisions a household's namespace; meanwhile one job per existing household | CC + operator |
|
||||
|
||||
## Storage & devices — 9 rows (P3 3, P4 6)
|
||||
|
||||
@@ -201,7 +199,7 @@ stopping line that lies.
|
||||
| **R-1077** | Storage & devices | P4 | **No USB enclosure that hides or fakes a disk's serial has been measured.** The storage-identity spike (2026-10-15) had none at hand and found none in earlier evidence; the design's `usb_bridge` unknown rule (`architecture/16-storage-physical-identity.md` §3) is therefore an assumption. Cheap single- and dual-bay bridges are known to report one bridge serial for any disk. Evidence: `audits/storage-identity-2026-10-15/README.md` case 4b. | OPEN | — | Buy or borrow one cheap USB enclosure (single and dual bay), run `tools/physdisk_probe.py` against it, and set the rule from what it reports. | Operator (a device) then CC |
|
||||
| **R-1094** | Storage & devices | P4 | **The whole-disk format refusal tells the household to format the free part — which is refused while the other part is in use.** SEEN 2026-10-16 (controller 0.318.0): 409 „Ezen a lemezen egy használatban lévő meghajtó van, ezért a teljes lemez nem formázható. Csak a szabad részét formázhatod." — since agent 0.158.1 a part next to a mounted part can only be USED (the root wrapper trusts no „Felhom's own" claim). Evidence: `audits/storage-identity-buildB-2026-10-15/live/14-samedisk-refusal-offer.txt`. | READY | — | Reword `err.web.meghajto_hasznalatban_formazas` (hu + en): „… nem formázható. A szabad részét használatba veheted." Next controller release; the copy gates run. | CC |
|
||||
|
||||
## Security & access — 22 rows (P1 1, P2 2, P3 12, P4 7)
|
||||
## Security & access — 21 rows (P1 1, P2 2, P3 12, P4 6)
|
||||
|
||||
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -225,8 +223,7 @@ stopping line that lies.
|
||||
| **R-1054** | Security & access | P3 | **The hub's operator/global API key is still one bearer that can do everything on `/api/v1`, including reading every box's break-glass root password (`GET /admin/hosts/{id}/recovery-credential`).** Hub v0.152.0 gave the web surface scoped tokens (`05` §17) but tokens are refused on `/api/v1` by design. Who uses the global key today is not listed in one place. Fix: list its consumers; move each operator use to a scoped token on the web side (or a token class on the API), and keep the global key only where a box path needs it — or retire it. | OPEN — filed 2026-10-15 by the token build | — | List the global key's consumers (pod env, scripts, runbooks) | CC |
|
||||
| **R-1118** | Security & access | P3 | **CC's secrets moved off the plain `~/.config/credentials` into an encrypted store with a broker and guards; what is left is retiring the old file.** BUILT 2026-10-17 (store B, operator ruling 11:28): private repo `admin/cc-secrets` (`ARCHITECTURE.md`, the design verbatim in `docs/`), `sec` (no get), PreToolUse refusals + PostToolUse masking for Bash and Read in `~/.claude/settings.json` (every CC session on DooPlex), nightly transcript sweep with mail. 55 tests, 18 red-proofs, 36-row child-session proof in both launch modes, fresh-session proof (`audits/cc-creds-build-2026-10-17/`). 25 names in the store (23 imported, `RESEND_API` from CC's environment, a self-test value). `12-agent-tooling.md` §5 points at it. | NARROWED — built; the old file's retirement is R-1134 | the week with no reader (R-1134) | `sec doctor` stays all OK; R-1134 | CC |
|
||||
| **R-1121** | Security & access | P3 | **`~/rotated-secrets-2026-10-09.txt` still exists on DooPlex** — 632 bytes, modified 2026-10-09 13:08 +0200, mode 600 (SPIKE Q6: `test -e` + `stat` only, not opened). Left by the R-925 rotation work. If any value in it is still valid, it is one more plaintext secrets file in the home folder, readable by every CC session. | WAITING-ON-OPERATOR | what the file holds — only the operator knows | Operator: confirm every value in it is revoked, then `shred -u` it; or move the live ones into the R-1118 store | operator |
|
||||
| **R-1155** | Security & access | P4 | **FileBrowser's own 2-hour token for the one-sign-in user can outlive the dashboard session.** The controller clears it together with the files cookie whenever a stale files cookie arrives (sign-out, password change), but a browser that lost only the files cookie (or a token copied out of it) keeps FileBrowser's token until it expires, and with no files cookie the forwardAuth answer passes the request through. Closing it would need the box to read FileBrowser's token (a box-held `auth.key`) or a shorter FileBrowser token life. Found 2026-10-19 (R-1100 build, security review). | OPEN — filed 2026-10-19 | — | Decide whether a box-held FileBrowser key is worth it | CC |
|
||||
| **R-1159** | Security & access | P3 | **The household's retrieval passphrase already yields the controller's hub API key, and that key alone registers and confirms off-site keys.** `GET /config/{id}` (passphrase-gated) returns `controller.yaml` with `hub.api_key`; `/offsite/register-key` and `/offsite/confirm-key` accept that key (`offsiteKeyAuth`). Pre-existing, and wider than R-1154 (whose fix keeps the passphrase away from the operator's re-issues). Read from code by the hub helper 2026-10-19, not measured. | OPEN — filed 2026-10-19 | — | Measure what a passphrase holder can do to the off-site tier; decide a second factor or a scope | CC + operator |
|
||||
| **R-1159** | Security & access | P3 | **The household's retrieval passphrase alone reaches the box's keys and through them the whole off-site key surface — MEASURED 2026-10-19** (the real hub router, a made-up customer, a fake off-site service; status codes and field names only — Tester4's passphrase is not in CC's store and reading it from the hub DB was refused by CC's own safety check). `GET /config/{id}` with the passphrase → 200, `hub` fields `api_key`, `enabled`, `url`, the key the box's controller uses; wrong passphrase 401. `POST /host-enroll` with it → 200 and the EXISTING host's key. With the controller key (wrong key → 401 each): `register-key` (pins the holder's own key append-only), `confirm-key` (removes every other line — the box's own key too), `move-aside` (renames the repository), `window-open` (a 20-min deleting line for the CONFIRMED key, weekly), `abandon-request` (the hub DELETES a set-aside copy after 7 days unless cancelled), `abandon-cancel`, `abandon-status` — all reach the service. With the host key: `GET /hosts/<id>/escrow` (sealed blob, loud), `PUT /hosts/<id>/escrow` and `PUT …/recovery-credential` (past auth: 400 on an empty body), `wg`, `desired-state`, `jobs`, `host-report`. A config download is a log line only. The passphrase is used only at install time (the installer, the controller's setup wizard). **Option A (CC's pick): the passphrase serves keys only while the customer has no host record** — `GET /config` leaves out `hub.api_key` and `/host-enroll` refuses (409, „delete the old host first") once a host exists; a reinstall needs the operator's delete first, which is already the rule (R-1154). Cost: a hub change; a guest rebuilt on a live host needs the operator. Closes the whole chain at its source. **Option B: a second factor on the destructive off-site routes** (`confirm-key` that removes a line, `move-aside`, `abandon-request`, `window-open`) — the operator's approval or the host key. Cost: every reinstall's key rotation waits for the operator, and the host key is itself reachable by the passphrase today, so B alone does not close it. | READY — measured 2026-10-19, options in STATUS D19 | `audits/day-2026-10-19b/P2/passphrase-reach.txt` | Operator picks A or B | operator + CC |
|
||||
|
||||
## Box system & updates — 12 rows (P2 1, P3 7, P4 4)
|
||||
|
||||
@@ -246,7 +243,7 @@ stopping line that lies.
|
||||
| **R-1061** | Box system & updates | P4 | **A per-customer floor reached Tester 1 only at its next 15-minute report, not in seconds.** Set 2026-10-15 12:55:51 UTC for tester-1, demo-hp and demo-felhom together (hub 0.153.0, CC's token): demo-hp and demo-felhom ran 0.314.0 within 13 s (the hub's wake); Tester 1 moved at 13:09:35, its regular report (`audits/gate-restore-2026-10-15/release/03-boxes-move.txt`). It had restarted at 12:54:29 onto rc.1 and logged „hub wait channel active". Why the wake did not reach it is not read (the wake line is DEBUG). No harm: the floor arrived. | **OPEN** — filed 2026-10-15 | — | Read Tester 1's DEBUG ring at the next floor change; compare with the hub's bump log | CC |
|
||||
|
||||
|
||||
## Monitoring & notifications — 12 rows (P2 1, P3 7, P4 4)
|
||||
## Monitoring & notifications — 11 rows (P2 1, P3 7, P4 3)
|
||||
|
||||
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -261,7 +258,6 @@ stopping line that lies.
|
||||
| **R-285** | Monitoring & notifications | P4 | **A planned, supervised reinstall pages the operator as if the machine had died — there is no notion of expected downtime anywhere.** During the 2026-08-09 rehearsal the hub sent, all `status: sent` to the operator channel: `host_stale` 08:58 UTC, `node_stale` 09:00, **`host_down` 09:28 (error)**, **`node_down` 09:30 (error)**, `host_leaf_changed` 09:31, `host_recovered` 09:31, `node_recovered` 09:34, `offsite_delivery_stuck` 09:34 — eight operator mails for work that was deliberate, attended and announced. **This is the OPPOSITE gap from the one R-281 filed:** the alarms are not missing, they are indiscriminate. `host_stale` at 30 min and `host_down` at 60 min (`monitor/host_staleness.go:22-23`, `downAfter = 2 * threshold`) cannot distinguish a wiped-on-purpose box from a dead one, and `host_leaf_changed` firing on a reinstall is correct-but-expected. **Note the interaction with the mute used on 2026-08-09 evening:** blocking a customer silences everything, so today the only two settings are *page me for planned work* and *tell me nothing at all*. **What is owed is a middle:** a maintenance window, or an operator-set expected-downtime flag, that suppresses staleness and leaf-change while leaving genuine faults audible | **READY (M) — NEW 2026-08-09** | — | The evidence is the operator's mailbox plus `events`/`notification_log` for 2026-08-09 | CC |
|
||||
| **R-1005** | Monitoring & notifications | P4 | **A recovery mail says how long the box was „stale", not how long it was gone: after a 51-minute power cut demo-hp's `host_recovered` read „was stale for 8m" and `node_recovered` „23m".** An operator reading only the recovery mail under-reads the outage (`audits/night-power-2026-10-13/` R6). Same kind, the other way: the off-site mail of 2026-10-14 02:18 was titled „3 of 3 apps failed to back up (offsite run)" while 11 other apps were backed up in that run — only the 3 flagged apps were counted. | **READY** — filed 2026-10-14 | — | CC: add the time since the last report before the gap to both recovery messages, and count every app of the run in the off-site subject, with a test that asserts each text; next hub release | CC |
|
||||
| **R-1049** | Monitoring & notifications | P3 | **A pulled drive mails the operator „unexpectedly disconnected” (error), and nothing ever mails that it came back.** MEASURED 2026-10-14 night (`audits/media-drive-events-2026-10-14/K8-hub-mails.txt`, the hub DB with its WAL from the running pod, and the mailbox as the second channel): two pulls → two `storage_disconnected` mails; the hub RECEIVED both `storage_reconnected` and both `health_recovered` (severity info) and logged no notification for any of them — they are not in `recoveredPairedDownTypes` (`hub/internal/notify/dispatcher.go`), so the severity gate drops them. The R-97a shape: told it broke, never told it healed — the operator cannot tell a returned drive from one still gone without opening the hub. **BUILT 2026-10-15 — hub v0.151.0 (`12552aca`): both pairs in `recoveredPairedDownTypes`, cooldowns ended by the next loss (`TestR1049_DriveBackMailsBothEdges`, red-proved). Not deployed: the operator's „yes” first (decision 162); the image build waits for it too.** | **WAITING-ON-OPERATOR** — hub v0.151.0 code pushed, not built, not deployed | the operator's „yes” to the hub deploy | On the „yes”: build + deploy hub v0.151.0; read a „came back” mail on the next pull | CC |
|
||||
| **R-1157** | Monitoring & notifications | P4 | **While the cadence-cap flag stays degraded (the agent's 24 h hold), further refused backups raise no new alarm:** a guest refused every day reads as one long episode, one mail. The same before hub 0.159.0. Found by the hub helper 2026-10-19. | OPEN — filed 2026-10-19 | — | Decide whether a refusal count in the event detail or a daily repeat is wanted | CC |
|
||||
|
||||
|
||||
## Hub & operator — 13 rows (P3 6, P4 7)
|
||||
@@ -302,7 +298,7 @@ stopping line that lies.
|
||||
| **R-990** | Business & legal | P4 | **Operator: read `documentation/audits/forum-research-2026-10-12/FELHOM.md` §5 and rule on each recommendation.** READ-ONLY research 2026-10-12: three years (#7943–#11092, 2,908 posts, 195 people, 82 beginner threads) of the public PROHARDVER! topic „Home server / házi szerver építése”, tagged and counted by person (`FINDINGS.md`, method and spot-check in `METHOD.md`; no username or post text in git). Ten ranked recommendations, none acted on; the top three: a „which machine works” page (8 of 33 beginners who name their hardware own only a Synology, a router disk or a Raspberry Pi — the installer cannot run there; the same gap is R-989's first recommendation from a different source, and the shipped-page half is R-991), „you do not choose an operating system — we do” (the biggest beginner question, 20 of 82 threads), and „bring your old office PC” as the cheap entry. Catalog gap (≥ 3 people): a DLNA server (7), an ad/DNS blocker (5), a camera recorder (5). | **WAITING-ON-OPERATOR** — filed 2026-10-12 | the operator's reading | Operator: rule on each of the ten (yes / no / later). If nothing is done: nothing changes; the research ages | operator |
|
||||
| **R-1035** | Business & legal | P4 | **Did the „felhő tárhely” page earn anything? Two dated checks.** **Baseline (reported by the operator from Search Console, 2026-10-14, last 3 months):** 1 click, 48 impressions, CTR 2.1 %, average position **73.6**; „felhő tárhely” 19 impressions, „felhőtárhely” 5, „felhő alapú tárhely” 3. CC measured separately that the phrase „felhő tárhely” appeared **0 times** on the home, FAQ and backup pages — Google was showing the home page for those queries by accident. `/sajat-felho-tarhely` + `/en/own-cloud-storage` published **2026-10-14**; full baseline, price sources and the power provenance in `audits/seo-2026-10-14/BASELINE.md`. **What to measure, both times:** impressions and average position for „felhő tárhely” and „saját felhő tárhely”, plus the new page's own impressions, clicks and position. **A null result at +4 weeks means nothing on its own** — a new page on a site at position 73.6 takes weeks to months to move, and „felhő tárhely” alone is held by Microsoft, Google and the big list sites; the page aims at the two longer phrases. That is why there are two checks and not one, and why neither should be read as a verdict on the copy. **There is no Search Console connector in this project, so CC cannot read these numbers** — the operator reads them, CC records and compares. **Blocked until the operator asks for indexing** (Search Console → URL-ellenőrzés → the URL → „Indexelés kérése”): until that happens, or Google finds the page itself, both checks read zero for a reason that is not the page. **This is a slow channel and does not replace talking to people.** | **WATCHING** | operator: request indexing, then supply the Search Console read | 2026-11-11: first read (+4 weeks); 2026-12-09: second (+8 weeks), compared with the first | operator + CC |
|
||||
|
||||
## Process & tooling — 31 rows (P3 8, P4 23)
|
||||
## Process & tooling — 31 rows (P3 9, P4 22)
|
||||
|
||||
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -336,7 +332,7 @@ stopping line that lies.
|
||||
| **R-1128** | Process & tooling | P4 | **The controller's decoy suite edits real tracked files (`handler_debug.go`, `update.go`, the locale bundles, templates) and plants `.go` files, with no lock** — a full run while another session edits the controller tree can overwrite that session's edits. felhom.eu's suite took an `flock` after the 2026-10-08 clobber. Found by the R-1116 helper 2026-10-17. | OPEN — filed 2026-10-17 | — | Run the suite in a scratch copy of the tree, or take the felhom.eu-style lock | CC |
|
||||
| **R-1123** | Process & tooling | P4 | **`reuse_refs_check.py` treats every git directory beside the repo as a sibling repo**, including stray clones in the workspace (`felhom.eu-media`, `felhom.eu-sizing-push`, `felhom.eu-wt-sizing`), so a citation can resolve against a stale clone and pass. Found by the R-1116 helper 2026-10-17 (it also makes the agent suite 20 s here vs 5 s in CI). | OPEN — filed 2026-10-17 | — | Search only the four known repo names (or the main clones), with a decoy | CC |
|
||||
| **R-1152** | Process & tooling | P4 | **felhom CI's 5-minute job timeout is inert** (act_runner 0.6.1 does not enforce a job-level `timeout-minutes`, R-1136), so a hung step runs up to the runner's 3 h. Move it to a step-level `timeout-minutes` on each workflow's gate step (e.g. 20 min for felhom.eu, which runs ~7 min), measured first: a step timeout fails the job AND the `if: failure()` alarm still runs. Needs a scratch repo (the admin token cannot create one — the operator, or a token with `write:user`). Found 2026-10-18. | OPEN — filed 2026-10-18 | — | Measure on a scratch repo, then the four workflows | CC |
|
||||
| **R-1160** | Process & tooling | P4 | **The hub and the agent have no gofmt gate, and both drift:** about 20 hub files and 14 agent files are not gofmt-clean (`gofmt -l`, 2026-10-19); the controller has `gofmt_gate.py`. Not fixed in-session: a mechanical rewrite of files other sessions own. | OPEN — filed 2026-10-19 | — | One gofmt commit per repo in a quiet window, then the controller's gate in both runners | CC |
|
||||
| **R-1166** | Process & tooling | P3 | **Another device takes demo-hp's address (192.168.0.104) every few minutes.** Measured 2026-10-19 from DooPlex: the LAN's ARP entry for .104 flipped between demo-hp's `7c:d3:0a:77:d9:76` and `b8:06:0d:60:45:58` eight times in 19 minutes (10:02–10:17 UTC); while the other MAC holds it, SSH and the Proxmox UI answer „connection refused" and ping still answers. 09:46–09:54 UTC demo-hp also lost its link to ep0 (`Can't connect to 10.77.0.1:8007`, 52 lines). demo-hp's address is static (`nodes.md`), so the other device most likely got .104 from the router's DHCP. | OPEN — filed 2026-10-19 | `audits/day-2026-10-19b/P3/demo-hp-arp-watch.txt` | Operator: find `b8:06:0d:60:45:58` in the router's DHCP list and reserve .104 for demo-hp (or move demo-hp out of the DHCP range) | operator |
|
||||
|
||||
<!-- DUE-CHECKS-BEGIN — machine-readable. Parsed by scripts/due_checks_gate.py.
|
||||
One row per dated check. The R-number must have a row above. Dates are UTC.
|
||||
|
||||
Reference in New Issue
Block a user