diff --git a/.claude/rules/docs.md b/.claude/rules/docs.md index 22fc4419..fa516000 100644 --- a/.claude/rules/docs.md +++ b/.claude/rules/docs.md @@ -17,6 +17,7 @@ repo. Sibling repos point here; this is where the pointed-at thing must actually | host addresses, routes, node names, break-glass, what is provisioned | `operations/nodes.md` | | Tailscale topology, accept-dns/accept-routes | `operations/tailscale.md` | | which box may be broken, and what may be done to it | `runbooks/target-selection.md` | +| what happened on the lived-in N100 (dated, each line with its register row) | `lived-in/n100.md` | | an operational procedure | `runbooks/RUNBOOK-*.md` | | logging levels and phrasing | `runbooks/logging-conventions.md` | | a spike or campaign result | `audits/` | diff --git a/CLAUDE.md b/CLAUDE.md index 153dec04..63af2aa8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,7 @@ Four surfaces in one repo, plus the design home for the whole system: | UI, tokens, badges, Hungarian copy | the **`felhom-ui-design`** skill | | host addresses, break-glass, node facts | `documentation/operations/nodes.md` — never restate them | | which box may I break | `documentation/runbooks/target-selection.md` | +| a problem seen on the N100 (the lived-in box, `09` §3 decision 254) | goes into `documentation/lived-in/n100.md` AND the register | | what version is live anywhere | ask the hub (`/hosts`, `/configs`) or the box — **never a doc** | | the authoritative design | `documentation/architecture/01..11-*.md` (00 = the capability map) | diff --git a/CONTEXT.md b/CONTEXT.md index 137332d8..aa65e4b2 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -25,6 +25,13 @@ > while a release is ahead. CC has no scoped route to the global floor (R-1051) — only the operator page with the > operator's password. A box on an `-rc` tag is never moved by the floor (R-1053). +> **2026-10-15 (evening, last) — the N100 is the lived-in box (`09` §3 decision 254).** Product paths only; no +> deliberate failure without the operator's word; diary `documentation/lived-in/n100.md`; Tier 0 is demo-hp alone. Media +> apps installed through the dashboard and wired by the box; films proven never off-site (the controller's classifier; +> vzdump excludes mp8). The USB split was NOT done: `hdd_1` is the whole-guest backup target (R-1062, operator decides); +> the decommission flow's half-state on an agent refusal is R-1063; a claimed Plex gets no libraries until a wiring run +> (R-1065). The box-walk library has no N100 row: `audits/n100-lived-in-2026-10-15/tools/n100.py` overrides it. + > **2026-10-15 (evening, later) — controller v0.314.0, the first release under decision 250.** The floor 0.314.0 (MinAgent > 0.155.0) was raised at 13:11 UTC by CC's token (`HUB_TOKEN` in `~/.config/credentials`, not `~/.felhom-hub/cc-token`) > after Tester 1, demo-hp and demo-felhom ran it through per-customer floors and the box walk's checks were green; the diff --git a/REPORT-n100-lived-in-2026-10-15.md b/REPORT-n100-lived-in-2026-10-15.md new file mode 100644 index 00000000..e629f0e4 --- /dev/null +++ b/REPORT-n100-lived-in-2026-10-15.md @@ -0,0 +1,92 @@ +# REPORT — the N100 becomes the lived-in box (2026-10-15) + +Written in ASD-STE100 Simplified Technical English. Read first: `runbooks/target-selection.md`, `operations/nodes.md`, +`07-backup-architecture.md`, `15-media-library.md`, `09` §3 decisions 240, 243, 250. Evidence: +`documentation/audits/n100-lived-in-2026-10-15/`. + +## What waits on you + +1. **The sheet** (about 30 minutes): `documentation/audits/n100-lived-in-2026-10-15/SHEET.md`. Install and claim Plex; + make the admins in Prowlarr, Sonarr and Radarr; add download sources in Prowlarr; add one show and one film. Then say + „done". If you do nothing, the apps wait, safe behind their gate. +2. **Decide (R-1062):** the USB drive is also the box's whole-box backup drive. Split it anyway? My pick: **no, keep one + drive**. If you do nothing, it stays one drive. + +## 1. The lived-in rule, and the files + +`09` §3 **decision 254**: +- The N100 changes only through the product: the dashboard, the hub, the release train, the OS update rings. +- No deliberate failure without your word for that one act. +- Reads and observation are free. A problem goes into the diary and the register. +- It is not Tier 2. It is no longer „reach here first". + +Decisions 240 and 243 point at it now. + +Files changed: +- `architecture/09-update-architecture.md`; +- `runbooks/target-selection.md` (a new „lived-in" row; Tier 0 is demo-hp alone; the N100 section rewritten); +- `operations/nodes.md` (role and drive lines); +- `architecture/11-os-updates.md` (ring 0 no longer calls the N100 disposable); +- `CLAUDE.md` and `.claude/rules/docs.md` (one line each: the diary); +- `documentation/lived-in/n100.md` (new); +- `STATUS.md`, `CONTEXT.md`, the register. +- My own memory index: it called both demo boxes disposable. + +## 2. What the N100 had, and what the 6 GB is + +- Controller 0.314.0, agent 0.156.1. Guest: 12 GB of memory, 0.2 GB used. One app (opengist). +- The five media apps need about 2 GB by the estimator's rule. They fit. +- `/dev/dri`: the host has it, the guest does not. So Plex cannot use hardware transcoding today. +- **The USB drive is not only app test data.** It holds: + - 2.7 GB: the box's nightly whole-box backups (`dump/`). The host storage `felhom-backup` points at this drive. + - 3.1 GB: app backups and an off-site restore copy. + - 422 MB: leftovers of removed apps. + - Empty media folders. + + There are no family files on it. +- **So I did not split it.** It is the box's whole-box backup target. The product refuses to retire such a drive, and the + box has no other drive to take that role. I also did not press the retire button. Reading the code showed that a + refused retire leaves the dashboard showing the drive as retired (R-1063). + +## 3. Films and off-site — proven before any download + +I ran the controller's own classifier on the deployed apps: +- off-site takes no media folder; +- the cross-drive tier would take only qBittorrent's downloads, and only if someone switches it on. It is off. With one + data drive it falls back to the internal SSD, and takes state only, not downloads; +- the whole-box backup's own log says: „excluding bind mount point mp8 ('/mnt/felhom-drives')". + +## 4. What the box linked by itself + +- I installed qBittorrent, Prowlarr, Sonarr and Radarr through the dashboard's own call, and sent no drive. Each was + healthy in under 35 s. The box picked `hdd_1` by itself. +- From the apps' own answers: + - Sonarr: `…/media/tv`. Radarr: `…/media/movies`. Both have the tag `hdd-1`, and qBittorrent as their client. + - qBittorrent: the categories `tv-hdd-1` and `movies-hdd-1`, saving under `…/media/torrents/` on the same drive. + - Prowlarr: linked to Sonarr and Radarr. +- A stranger meets the gate on Prowlarr, Sonarr and Radarr, and qBittorrent's own login. +- **Not done by itself:** a freshly claimed Plex gets no libraries until the next linking run (R-1065, from the code). + The sheet tells you what to press if it happens. + +## 5. demo-hp's warning + +Gone. I removed `/mnt/sizing-bench` through the dashboard, and the hub showed demo-hp **OK** at 14:56 UTC. The path held +two apps' cross-drive copies, and the dashboard said nothing about them (R-1064). + +## 6. Wrong claims in the prompt; commits; register; STATUS + +**Claims in the prompt that turned out wrong:** +1. „the 6.1 GB … app test data": it is mostly the box's own backups. The drive is the whole-box backup target, so the + split cannot go through the product. +2. „The box wires … Plex by itself": not right after the claim (R-1065). +3. „HD710 PRO": that is the USB enclosure. The disk inside is a TOSHIBA MQ04ABF100 (931.5 GB). True, but incomplete. + +**Commits:** felhom.eu (this commit). No product code. + +**Register:** before **152** · opened **4** (R-1062, R-1063, R-1064, R-1065) · closed **0** · after **156**. + +**STATUS.md:** 61 lines. + +**Teardown:** I installed four apps on the N100 on purpose (they stay). I deleted a temporary test file in the +controller tree; it was never committed. On demo-hp I removed one storage path. The hub was read only, through my token. +ep0, DooPlex and Tester 1 were not touched. diff --git a/STATUS.md b/STATUS.md index 85c8c7ad..6f8372d9 100644 --- a/STATUS.md +++ b/STATUS.md @@ -6,6 +6,7 @@ `documentation/backlog/STATUS-HISTORY.md`. Reports: `REPORT-night-2026-10-14.md`, `REPORT-immich-rollout-2026-10-14.md`, `REPORT-seo-felho-tarhely-2026-10-14.md`, `REPORT-immich-repair-2026-10-14.md`, `REPORT-power-cut-fixes-2026-10-14.md`, `REPORT-night-power-2026-10-13.md`, `REPORT-poweroff.md`. ## What works +- **The N100 is the lived-in box** (since 2026-10-15): used like a household's box, changed only through the product. qBittorrent, Prowlarr, Sonarr and Radarr are installed and linked by the box; films never go off-site (checked before any download). Its diary: `documentation/lived-in/n100.md`. - A restored app comes back exactly as safe as it was at the backup: closed to strangers until its first account is made (0.314.0, proven on the scratch box). A box on a test build now moves with the floor (Tester 1 did, by itself). The box claims Plex again (demo-hp's Plex claimed through the dashboard, 2026-10-15). A brand-new box from the public installer updated itself to the floor 3 minutes after it was linked (test box, since removed). - Scripts use the hub with a scoped token, not your password (hub 0.153.0): CC sets the floor with its own token; no token can see a secret, delete anything, or send, make or show a household's password or link. Your new hub password is yours alone (changed 2026-10-15). - Every public name of the three test boxes answers only over https: plain http gets a 301 to the same https address, and browsers are told to remember it for one day (29 names checked, 2026-10-14 night). @@ -41,8 +42,10 @@ | D6 | R-992 | The scratch box cannot read the private drill catalog: give it a read-only login, or make that copy readable? | **A read-only login** | Readable copy: the drill catalog becomes public | every new-app test needs hand-staging | new-app tests | | D7 | R-990, R-989 | Rule yes / no / later on the forum ideas (`audits/forum-research-2026-10-12/FELHOM.md` §5) and the selfh.st ideas (`audits/selfhst-survey-2026-10-12/FELHOM.md` §6) | — | — | nothing changes; the research ages | — | | D8 | R-206 | Install DooPlex's Docker settings from git (restarts Docker), and prune the build cache weekly: yes or no? | **Yes, in a quiet window** | — | a rebuild of DooPlex still has the settings in git | — | +| D9 | R-1062 | The N100's USB drive is also its whole-box backup drive. Split it in two anyway? | **No — keep one drive**; the lived-in box keeps its nightly whole-box backup | Split: the box loses its local whole-box backup (or add a second drive first) | it stays one drive; multi-drive tests stay on Tester 1 | — | ## Waiting on you — do +- **The N100 sheet (about 30 minutes):** `documentation/audits/n100-lived-in-2026-10-15/SHEET.md` — install Plex and claim it, make the admins in Prowlarr/Sonarr/Radarr, add your download sources in Prowlarr, add one show and one film. Then say „done". If not: the media apps wait, safe behind their gate. - **Delete the test customer „Tester3” in the hub (browser only).** Its test box is already gone and switched off on purpose, so no alarm is coming. If not: a dead test customer stays in your list. - **Hub 0.153.0 (your rulings 13:20 + R-1059 „A"): no token can resend a claim code, create or edit a customer, make a passphrase or a link, or re-issue an off-site password.** Live since 13:39 (checked with CC's token: all six refused). - **Remove the test server „plex-k6” from your Plex account** (plex.tv → Settings → Authorized Devices). The claim test passed and the server is gone from Tester 1. If not: a dead server stays listed in your Plex apps. diff --git a/documentation/architecture/09-update-architecture.md b/documentation/architecture/09-update-architecture.md index 2113d96a..b4a3f6be 100644 --- a/documentation/architecture/09-update-architecture.md +++ b/documentation/architecture/09-update-architecture.md @@ -948,6 +948,26 @@ its length, and both fixes cost something the household would notice — operato **Extended the same day (operator, R-1059 = A):** the off-site and PBS-DR re-issues (they mint a household credential for the box) are session only too; „Off-site: write" keeps the windows and freeze. +### 2026-10-15 (evening) — the N100 is the lived-in box (recorded by the n100-lived-in task; decisions 240 and 243) + +254. **The N100 (`demo-felhom`) is the lived-in box.** *Operator ruling 2026-10-14 (decision 240), its timing + decision 243 (after the Tester 1 all-drives test — done 2026-10-15), written down 2026-10-15 at the operator's + request.* Decision 240 said the rule „is recorded by the second task of 2026-10-14" — it never was; this is it. + 1. **It changes only through the product's own paths:** the dashboard, the hub, the normal release train (the floor + under decision 250, the weekly golden), the OS update rings. No drill catalog, no hand edits inside the guest, no + `docker` command that changes state, no reinstall. + 2. **No deliberate failure** — power cut, drive pull, drill, restore test — **without the operator's word for that + one act.** A failure that happens by itself is observed and recorded, and repaired by hand only where the + household could do the same. + 3. **Reads, logs, metering and observation are free.** A problem found goes into the diary + (`documentation/lived-in/n100.md`) and the register. + 4. **It stays a demo box:** no paying customer's data; it is not Tier 2. It is no longer „reach here first" — Tier 0 + is demo-hp (and its guests and VMs) alone (`runbooks/target-selection.md`). + 5. **The one hand change granted before the rule (operator, 2026-10-15 16:31): split the USB drive in two.** NOT + done: the drive is the box's whole-guest backup target (`felhom-backup`) and holds its nightly backups, so the + product refuses to decommission it and the N100 has no other drive to move that role to (R-1062, + `audits/n100-lived-in-2026-10-15/B/`). The grant is not used; a split needs a new word. + ### 2026-10-15 (afternoon) — a restore puts the setup gate back as it was (operator brief, R-1057 raised to P2) 253. **A restore puts the setup gate back exactly as it was when the backup was taken.** *Operator brief 2026-10-15 @@ -1008,6 +1028,8 @@ its length, and both fixes cost something the household would notice — operato (`15-media-library.md` §2; R-1014) 243. **The N100 lived-in setup waits until the all-drives build has been tested on the Tester 1 rig.** Until then the N100 stays Tier 0 and is not fenced (it may host a second test rig). This replaces decision 240's timing. + **Fulfilled 2026-10-15** (the Tester 1 rig was tested; release 0.313.0): the rule is decision 254 — the N100 is no + longer Tier 0. *Operator ruling 2026-10-14.* ### 2026-10-14 (afternoon) — media apps on every drive (recorded before the work; the media-all-drives brief) @@ -1020,7 +1042,8 @@ its length, and both fixes cost something the household would notice — operato 239. **Each drive shows whether its apps have restarted since it was added.** If they have not, a manual restart button is there. *Operator ruling 2026-10-14.* (R-1023) 240. **The N100 becomes a lived-in box.** Its rule is recorded by the second task of 2026-10-14 - (`TASK-media-folder-fix-and-n100-2026-10-14.md`). *Operator ruling 2026-10-14.* + (`TASK-media-folder-fix-and-n100-2026-10-14.md`). *Operator ruling 2026-10-14.* **That task did not record it** (its N100 part was removed the + same evening, decision 243); the rule is decision 254 (2026-10-15). 241. **Tester 1 may follow the drill catalog for the media test, until the operator says „tear it down".** It is the one exception to §6.5's fence; the teardown is R-1022. *Operator ruling 2026-10-14.* diff --git a/documentation/architecture/11-os-updates.md b/documentation/architecture/11-os-updates.md index a02f18a8..46befbb3 100644 --- a/documentation/architecture/11-os-updates.md +++ b/documentation/architecture/11-os-updates.md @@ -148,8 +148,9 @@ has not ruled on it as such. ### 5.1 Two rings -- **Ring 0:** demo-felhom (N100) and demo-hp. They are disposable (`runbooks/target-selection.md`), and - they have different hardware. They take every update first. +- **Ring 0:** demo-felhom (N100) and demo-hp, on different hardware. They take every update first. demo-hp is + disposable; the N100 is the lived-in box (`09` §3 decision 254) — it takes ring 0 through the product like any box, + which is the point: a lived-in box meets an update before a customer does (`runbooks/target-selection.md`). - **Ring 1:** every other box. It takes only what ring 0 approved. ### 5.2 Two lanes diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/01-state.txt b/documentation/audits/n100-lived-in-2026-10-15/B/01-state.txt new file mode 100644 index 00000000..998d2593 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/01-state.txt @@ -0,0 +1,46 @@ +== host +demo-felhom +felhom-agent 0.156.1 + total used free shared buff/cache available +Mem: 15772 2408 8108 66 5664 13363 +NAME SIZE TYPE FSTYPE MOUNTPOINT MODEL SERIAL +sda 476.9G disk AirDisk 512GB SSD QDF922W009654S30EX +|-sda1 1007K part +|-sda2 1G part vfat /boot/efi +`-sda3 475.9G part LVM2_member + |-pve-swap 8G lvm swap [SWAP] + |-pve-root 96G lvm ext4 / + |-pve-data_tmeta 3.6G lvm + | `-pve-data-tpool 348.8G lvm + | |-pve-data 348.8G lvm + | |-pve-vm--9201--disk--2 32G lvm ext4 + | `-pve-vm--9201--disk--3 250G lvm ext4 + `-pve-data_tdata 348.8G lvm + `-pve-data-tpool 348.8G lvm + |-pve-data 348.8G lvm + |-pve-vm--9201--disk--2 32G lvm ext4 + `-pve-vm--9201--disk--3 250G lvm ext4 +sdb 931.5G disk ext4 /mnt/hdd_1 TOSHIBA MQ04ABF100 65NOP3HDT +VMID Status Lock Name +9201 running demo-felhom +== guest +cores: 3 +memory: 12288 +mp0: local-lvm:vm-9201-disk-3,mp=/var/lib/felhom,backup=1,size=250G +mp8: /mnt/felhom-drives,mp=/mnt/felhom-drives +mp9: /var/lib/felhom-agent/guests/9201/bootstrap,mp=/etc/felhom-bootstrap,ro=1 +rootfs: local-lvm:vm-9201-disk-2,size=32G +swap: 512 +gitea.dooplex.hu/admin/felhom-controller:0.314.0 +192.168.0.149 169.254.253.2 172.16.253.1 172.17.0.1 172.18.0.1 + total used free shared buff/cache available +Mem: 12288 222 10945 8 1128 12065 +Filesystem Size Used Avail Use% Mounted on +/dev/mapper/pve-vm--9201--disk--2 32G 1.2G 29G 4% / +/dev/sdb 916G 6.2G 864G 1% /mnt/felhom-drives/hdd_1 +ls: cannot access '/dev/dri': No such file or directory +cloudflared Up 41 hours (healthy) +felhom-controller Up 2 hours (healthy) +filebrowser Up 21 hours (healthy) +opengist Up 12 hours (healthy) +traefik Up 12 hours diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/02-drive.txt b/documentation/audits/n100-lived-in-2026-10-15/B/02-drive.txt new file mode 100644 index 00000000..adec941c --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/02-drive.txt @@ -0,0 +1,26 @@ +NAME TRAN VENDOR MODEL SERIAL SIZE +sdb usb ADATA TOSHIBA MQ04ABF100 65NOP3HDT 931.5G +ID_BUS=ata +ID_MODEL=TOSHIBA_MQ04ABF100 +ID_SERIAL=TOSHIBA_MQ04ABF100_65NOP3HDT +ID_USB_MODEL=HD710_PRO +ID_USB_VENDOR=ADATA +by-path +card0 +renderD128 +== top +total 32 +drwxr-xr-x 5 root root 4096 Jul 28 21:25 . +drwxr-xr-x 5 root root 4096 Aug 3 09:15 .. +drwxr-xr-x 2 root root 4096 Oct 15 04:59 dump +drwxr-xr-x 6 100000 100000 4096 Jul 18 22:11 felhom-data +drwx------ 2 root root 16384 Jul 18 18:41 lost+found +== du +2.7G /mnt/hdd_1/dump +3.5G /mnt/hdd_1/felhom-data +16K /mnt/hdd_1/lost+found +== felhom-data +32K /mnt/hdd_1/felhom-data/shares +528K /mnt/hdd_1/felhom-data/userdata +422M /mnt/hdd_1/felhom-data/appdata +3.1G /mnt/hdd_1/felhom-data/backups diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/03-drive-detail.txt b/documentation/audits/n100-lived-in-2026-10-15/B/03-drive-detail.txt new file mode 100644 index 00000000..37883029 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/03-drive-detail.txt @@ -0,0 +1,47 @@ +Name Type Status Total (KiB) Used (KiB) Available (KiB) % +felhom-backup dir active 960303848 6435888 905013448 0.67% +felhom-pbs pbs active 0 0 0 0.00% +local dir active 98497780 32496832 60951400 32.99% +local-lvm lvmthin active 365760512 9290317 356470194 2.54% +dir: felhom-backup + +== dump +-rw-r--r-- 1 root root 950588793 Oct 13 04:53 vzdump-lxc-9201-2026_10_13-04_52_51.tar.zst +-rw-r--r-- 1 root root 16 Oct 13 04:53 vzdump-lxc-9201-2026_10_13-04_52_51.tar.zst.notes +-rw-r--r-- 1 root root 1505 Oct 14 04:54 vzdump-lxc-9201-2026_10_14-04_54_24.log +-rw-r--r-- 1 root root 951109351 Oct 14 04:54 vzdump-lxc-9201-2026_10_14-04_54_24.tar.zst +-rw-r--r-- 1 root root 16 Oct 14 04:54 vzdump-lxc-9201-2026_10_14-04_54_24.tar.zst.notes +-rw-r--r-- 1 root root 1504 Oct 15 04:59 vzdump-lxc-9201-2026_10_15-04_59_17.log +-rw-r--r-- 1 root root 951089306 Oct 15 04:59 vzdump-lxc-9201-2026_10_15-04_59_17.tar.zst +-rw-r--r-- 1 root root 16 Oct 15 04:59 vzdump-lxc-9201-2026_10_15-04_59_17.tar.zst.notes +== backups +4.0K /mnt/hdd_1/felhom-data/backups/offsite-proof +1.6G /mnt/hdd_1/felhom-data/backups/offsite-restore +1.3G /mnt/hdd_1/felhom-data/backups/primary +274M /mnt/hdd_1/felhom-data/backups/secondary +== appdata +12K /mnt/hdd_1/felhom-data/appdata/romm +24K /mnt/hdd_1/felhom-data/appdata/paperless +63M /mnt/hdd_1/felhom-data/appdata/nextcloud +360M /mnt/hdd_1/felhom-data/appdata/immich +== userdata +/mnt/hdd_1/felhom-data/userdata +/mnt/hdd_1/felhom-data/userdata/media +/mnt/hdd_1/felhom-data/userdata/media/nzbget +/mnt/hdd_1/felhom-data/userdata/media/usenet +/mnt/hdd_1/felhom-data/userdata/media/movies +/mnt/hdd_1/felhom-data/userdata/media/music +/mnt/hdd_1/felhom-data/userdata/media/comics +/mnt/hdd_1/felhom-data/userdata/media/podcasts +/mnt/hdd_1/felhom-data/userdata/media/audiobooks +/mnt/hdd_1/felhom-data/userdata/media/transmission +/mnt/hdd_1/felhom-data/userdata/media/transmission/watch +/mnt/hdd_1/felhom-data/userdata/media/grimmory +/mnt/hdd_1/felhom-data/userdata/media/torrents +/mnt/hdd_1/felhom-data/userdata/media/tv +/mnt/hdd_1/felhom-data/userdata/media/photos +/mnt/hdd_1/felhom-data/userdata/media/metube +/mnt/hdd_1/felhom-data/userdata/media/books +/mnt/hdd_1/felhom-data/userdata/media/books/metadata.db +/mnt/hdd_1/felhom-data/userdata/media/books/metadata.db-shm +/mnt/hdd_1/felhom-data/userdata/media/books/metadata.db-wal diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/04-sizing.txt b/documentation/audits/n100-lived-in-2026-10-15/B/04-sizing.txt new file mode 100644 index 00000000..ff72daef --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/04-sizing.txt @@ -0,0 +1,7 @@ +standing now: typical 27 MB, peak 68 MB; rule (platform 470 + peak) x 1.5 = 807 MB vs guest 12288 MB -> fits +standing + the five: typical 636 MB, peak 841 MB; rule (platform 470 + peak) x 1.5 = 1966 MB vs guest 12288 MB -> fits + plex: typical 232 MB, peak 234 MB (measured) + qbittorrent: typical 163 MB, peak 318 MB (onboarding) + prowlarr: typical 41 MB, peak 44 MB (onboarding) + sonarr: typical 77 MB, peak 77 MB (onboarding) + radarr: typical 96 MB, peak 100 MB (measured) diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/05-dashboard-view.txt b/documentation/audits/n100-lived-in-2026-10-15/B/05-dashboard-view.txt new file mode 100644 index 00000000..cc0fc141 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/05-dashboard-view.txt @@ -0,0 +1,16 @@ +/api/storage/paths -> 404 {"_raw": "404 page not found\n"} +/api/disks -> 200 {"data": {"vmid": 9201, "disks": [{"name": "felhom-backup", "type": "local-dir", "state": "attached", "backing_device": "/dev/sdb", "mount_path": "/mnt/hdd_1", "class": "slow", "role": "user-data", "data_bearing": true, "data_reason": "device is mounted", "total_bytes": 983351140352, "used_bytes": 6590349312, "used_fraction": 0.00670192878369056, "durable_id": "uuid:47a3361a-91e0-4831-a69d-27f540ed3f48", "wipe_durable_id": "byid:wwn-0x5000039ddb108568", "guest_attached": false, "backup_target": true, "guest_path": "/mnt/felhom-drives/hdd_1", "bound_under_parent": true, "smart": {"health": "PASSED", "model_name": "TOSHIBA MQ04ABF100", "temperature_c": 35, "power_on_hours": 5449, "reallocated_sectors": 0, "pending_sectors": 0, "offline_uncorrectable": 0, "udma_crc_errors": 0, "critical_warning": null, "media_errors": null, "percentage_used": null}}, {"name": "local", "type": "local", "stat +/api/backup/status -> 200 {"ok": true, "data": {"enabled": true, "running": false}} +/api/offbox/status -> 404 {"ok": false, "error": "endpoint not found"} +/api/backup/offsite/status -> 404 {"ok": false, "error": "endpoint not found"} +/api/selfupdate/status -> 200 {"ok": true, "data": {"running": false, "last_check": {"current_version": "0.314.0", "latest_version": "0.314.0", "update_available": false, "checked_at": "2026-10-15T12:56:24Z"}, "last_state": {"status": "success", "previous_version": "0.313.0", "previous_image": "gitea.dooplex.hu/admin/felhom-controller:0.313.0", "target_version": "0.314.0", "target_image": "gitea.dooplex.hu/admin/felhom-controller:0.314.0", "initiated_at": "2026-10-15T12:55:48Z", "initiated_by": "auto-floor", "completed_at": "2026-10-15T12:55:54Z"}}} +/api/storage/backup-target -> 200 {"data": {"degraded": false, "known": true, "label": "Külső tárhely (hdd_1)", "target": "felhom-backup"}, "ok": true} +/api/storage/media/status -> 200 {"data": {"pending": false, "drives": null, "apps": null}, "ok": true} +/api/storage/ -> 404 {"_raw": "404 page not found\n"} + + +{'path': '/mnt/felhom-drives/hdd_1', 'label': 'Külső tárhely (hdd_1)', 'schedulable': True} +keys: ['password_hash', 'filebrowser_admin_state', 'filebrowser_admin_decided_at', 'claimed', 'claim_code_hash', 'claim_code_generation', 'claim_code_issued_at', 'claim_consumed_generation', 'offbox_enlarge_notice_seeded', 'app_update_events_seeded', 'unhealthy_stop_event_seeded', 'hub_escrow_identity_present', 'hub_escrow_superseded_present', 'hub_escrow_superseded_at', 'hub_escrow_key_sha256', 'hub_escrow_key_checked_at', 'app_backup', 'offsite_data_at', 'backup_window_start', 'storage_paths', 'last_guest_boot_id', 'hub_verified', 'hub_verified_at', 'hub_last_check', 'applied_config_version', 'offbox'] +offbox: {"enabled": true, "host": "u629488-sub1.your-storagebox.de", "port": 23, "user": "u629488-sub1", "repo_path": "/home/felhom-repo", "schedule": "daily", "quota_gb": 50, "transport": "rclone-pinned", "last_run": "2026-10-15T02:15:10Z", "last_status": "ok", "last_success": "2026-10-15T02:15:10Z", "last_integrity_check": "2026-10-11T04:00:00Z", "last_integrity_ok": true, "last_integrity_depth": "100%", "proved_snapshots": {"opengist": "0ef3edb5"}, "last_proof_run": "2026-10-15T03:30:00Z", "last_proof_stack": "opengist", "last_proof_snapshot": "0ef3edb5", "last_proof_result": "pass", "last_duration": "7s", "repo_size_human": "181.6 KB", "repo_size_bytes": 185936, "snapshot_count": 15, "stats_know +app_backup: {"opengist": {"enabled": false, "cross_drive": {"enabled": true, "method": "rsync", "destination_path": "/mnt/felhom-drives/hdd_1", "schedule": "daily", "last_run": "2026-10-15T01:30:00Z", "last_status": "ok", "last_success": "2026-10-15T01:30:00Z", "success_tracked": true, "unit_package_date": "2026-10-15T00:30:00Z", "last_duration": "0s", "last_size_human": "202.8 KB"}, "offbox": true}} +offsite_data_at: {'opengist': {'pushed_at': '2026-10-15T02:15:05Z', 'data_at': '2026-10-15T02:15:00Z'}} diff --git a/documentation/audits/n100-lived-in-2026-10-15/B/06-deploy-fields.txt b/documentation/audits/n100-lived-in-2026-10-15/B/06-deploy-fields.txt new file mode 100644 index 00000000..63ec1c08 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/B/06-deploy-fields.txt @@ -0,0 +1,10 @@ +qbittorrent 200 [('DOMAIN', 'domain', True, None), ('SUBDOMAIN', 'subdomain', True, None), ('HDD_PATH', 'path', True, None), ('QBT_ADMIN_PASSWORD', 'password', True, None)] + deployed: False +prowlarr 200 [('DOMAIN', 'domain', True, None), ('SUBDOMAIN', 'subdomain', True, None)] + deployed: False +sonarr 200 [('DOMAIN', 'domain', True, None), ('SUBDOMAIN', 'subdomain', True, None), ('HDD_PATH', 'path', True, None)] + deployed: False +radarr 200 [('DOMAIN', 'domain', True, None), ('SUBDOMAIN', 'subdomain', True, None), ('HDD_PATH', 'path', True, None)] + deployed: False +plex 200 [('DOMAIN', 'domain', True, None), ('SUBDOMAIN', 'subdomain', True, None), ('PLEX_CLAIM', 'text', True, True), ('HDD_PATH', 'path', True, None)] + deployed: False diff --git a/documentation/audits/n100-lived-in-2026-10-15/D/01-install.txt b/documentation/audits/n100-lived-in-2026-10-15/D/01-install.txt new file mode 100644 index 00000000..25d59320 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/D/01-install.txt @@ -0,0 +1,18 @@ +16:36:53 qbittorrent: deploy (fields sent: ['DOMAIN', 'QBT_ADMIN_PASSWORD', 'SUBDOMAIN']) -> 202 {"ok": true, "message": "Telepítés elindítva – az állapot a kártyán követhető"} + qbittorrent: state=running after 13s; pinned={'qbittorrent': 'qbittorrentofficial/qbittorrent-nox:5.2.4-1'}; HDD_PATH: /mnt/felhom-drives/hdd_1 +16:37:06 prowlarr: deploy (fields sent: ['DOMAIN', 'SUBDOMAIN']) -> 202 {"ok": true, "message": "Telepítés elindítva – az állapot a kártyán követhető"} + prowlarr: state=running after 28s; pinned={'prowlarr': 'lscr.io/linuxserver/prowlarr:version-2.6.5.5623'}; +16:37:34 sonarr: deploy (fields sent: ['DOMAIN', 'SUBDOMAIN']) -> 202 {"ok": true, "message": "Telepítés elindítva – az állapot a kártyán követhető"} + sonarr: state=running after 33s; pinned={'sonarr': 'lscr.io/linuxserver/sonarr:4.0.20'}; HDD_PATH: /mnt/felhom-drives/hdd_1 +16:38:07 radarr: deploy (fields sent: ['DOMAIN', 'SUBDOMAIN']) -> 202 {"ok": true, "message": "Telepítés elindítva – az állapot a kártyán követhető"} + radarr: state=running after 28s; pinned={'radarr': 'lscr.io/linuxserver/radarr:6.4.4'}; HDD_PATH: /mnt/felhom-drives/hdd_1 +cloudflared Up 41 hours (healthy) +felhom-controller Up 2 hours (healthy) +filebrowser Up 21 hours (healthy) +opengist Up 12 hours (healthy) +prowlarr Up About a minute (healthy) +qbittorrent Up About a minute (healthy) +radarr Up 15 seconds (healthy) +sonarr Up 56 seconds (healthy) +traefik Up 12 hours + diff --git a/documentation/audits/n100-lived-in-2026-10-15/D/02-stranger.txt b/documentation/audits/n100-lived-in-2026-10-15/D/02-stranger.txt new file mode 100644 index 00000000..9c20af6c --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/D/02-stranger.txt @@ -0,0 +1,23 @@ +14:38:45 qbittorrent / -> HTTP/2 404 +14:38:46 qbittorrent /api/v3/system/status -> HTTP/2 404 +14:38:46 qbittorrent /api/v1/system/status -> HTTP/2 404 +14:38:46 qbittorrent /initialize.json -> HTTP/2 404 +14:38:46 qbittorrent /api/v2/app/version -> HTTP/2 404 +14:38:46 prowlarr / -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fprowlarr.demo-felhom.eu%2F +14:38:47 prowlarr /api/v3/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fprowlarr.demo-felhom.eu%2Fapi%2Fv3%2Fsystem%2Fstatus +14:38:47 prowlarr /api/v1/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fprowlarr.demo-felhom.eu%2Fapi%2Fv1%2Fsystem%2Fstatus +14:38:47 prowlarr /initialize.json -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fprowlarr.demo-felhom.eu%2Finitialize.json +14:38:47 prowlarr /api/v2/app/version -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fprowlarr.demo-felhom.eu%2Fapi%2Fv2%2Fapp%2Fversion +14:38:48 sonarr / -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fsonarr.demo-felhom.eu%2F +14:38:48 sonarr /api/v3/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fsonarr.demo-felhom.eu%2Fapi%2Fv3%2Fsystem%2Fstatus +14:38:48 sonarr /api/v1/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fsonarr.demo-felhom.eu%2Fapi%2Fv1%2Fsystem%2Fstatus +14:38:48 sonarr /initialize.json -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fsonarr.demo-felhom.eu%2Finitialize.json +14:38:49 sonarr /api/v2/app/version -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fsonarr.demo-felhom.eu%2Fapi%2Fv2%2Fapp%2Fversion +14:38:49 radarr / -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fradarr.demo-felhom.eu%2F +14:38:49 radarr /api/v3/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fradarr.demo-felhom.eu%2Fapi%2Fv3%2Fsystem%2Fstatus +14:38:49 radarr /api/v1/system/status -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fradarr.demo-felhom.eu%2Fapi%2Fv1%2Fsystem%2Fstatus +14:38:50 radarr /initialize.json -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fradarr.demo-felhom.eu%2Finitialize.json +14:38:50 radarr /api/v2/app/version -> HTTP/2 302 location: https://felhom.demo-felhom.eu/__gate/start?rd=https%3A%2F%2Fradarr.demo-felhom.eu%2Fapi%2Fv2%2Fapp%2Fversion +(the qbittorrent lines above used the wrong name; its address is torrent.demo-felhom.eu) +14:39:24 torrent / -> HTTP/2 200 body:
HTTP/2 403 body: Forbidden diff --git a/documentation/audits/n100-lived-in-2026-10-15/D/03-wiring.txt b/documentation/audits/n100-lived-in-2026-10-15/D/03-wiring.txt new file mode 100644 index 00000000..57941f2c --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/D/03-wiring.txt @@ -0,0 +1,27 @@ +== the controller's wiring runs: +2026/10/15 14:36:47 [INFO] [stacks] media_library qbittorrent: per-drive binds 0 []; drives not bound: [] +2026/10/15 14:37:28 [INFO] [stacks] media_library sonarr: per-drive binds 0 []; drives not bound: [] +2026/10/15 14:38:01 [INFO] [stacks] media_library radarr: per-drive binds 0 []; drives not bound: [] +2026/10/15 14:39:15 [INFO] [media] wiring the drives into the media apps (a media app came up: radarr) +2026/10/15 14:39:18 [INFO] [mediawire] 1 drive(s) wired in 3.504s: folders=done(0) qbittorrent=done(3) sonarr=done(4) radarr=done(4) prowlarr=done(2) + +== per-drive binds (docker's own view): + qbittorrent: /var/lib/docker/volumes/qbittorrent_qbittorrent_config/_data -> /config; /mnt/felhom-drives/hdd_1/userdata/media/torrents -> /downloads; /mnt/felhom-drives/hdd_1/userdata/media/torrents -> /mnt/felhom-drives/hdd_1/userdata/media/torrents; + sonarr: /var/lib/docker/volumes/sonarr_sonarr_config/_data -> /config; /mnt/felhom-drives/hdd_1/userdata/media -> /mnt/felhom-drives/hdd_1/userdata/media; + radarr: /var/lib/docker/volumes/radarr_radarr_config/_data -> /config; /mnt/felhom-drives/hdd_1/userdata/media -> /mnt/felhom-drives/hdd_1/userdata/media; + prowlarr: /var/lib/docker/volumes/prowlarr_prowlarr_config/_data -> /config; +== sonarr: root folders ['/mnt/felhom-drives/hdd_1/userdata/media/tv'] + tags ['hdd-1'] + download clients [('qBittorrent hdd-1', 'QBittorrent', ['qbittorrent', 'tv-hdd-1'], [1])] +== radarr: root folders ['/mnt/felhom-drives/hdd_1/userdata/media/movies'] + tags ['hdd-1'] + download clients [('qBittorrent hdd-1', 'QBittorrent', ['qbittorrent', 'movies-hdd-1'], [1])] +== prowlarr: apps [('Radarr', 'fullSync', 'http://radarr:7878'), ('Sonarr', 'fullSync', 'http://sonarr:8989')] +== qbittorrent categories: Forbidden +== qbittorrent (its own API, after its login): +{"movies-hdd-1":{"download_path":"/mnt/felhom-drives/hdd_1/userdata/media/torrents/.temp","inactive_seeding_time_limit":-2,"name":"movies-hdd-1","ratio_limit":-2,"savePath":"/mnt/felhom-drives/hdd_1/userdata/media/torrents/movies","seeding_time_limit":-2,"share_limit_action":"Default"},"tv-hdd-1":{"download_path":"/mnt/felhom-drives/hdd_1/userdata/media/torrents/.temp","inactive_seeding_time_limit":-2,"name":"tv-hdd-1","ratio_limit":-2,"savePath":"/mnt/felhom-drives/hdd_1/userdata/media/torrents/tv","seeding_time_limit":-2,"share_limit_action":"Default"}} +"auto_tmm_enabled":true +"save_path":"/mnt/felhom-drives/hdd_1/userdata/media/torrents" +"save_path_changed_tmm_enabled":false +"temp_path":"/mnt/felhom-drives/hdd_1/userdata/media/torrents/.temp" +"temp_path_enabled":true diff --git a/documentation/audits/n100-lived-in-2026-10-15/D/04-app-backup-settings.txt b/documentation/audits/n100-lived-in-2026-10-15/D/04-app-backup-settings.txt new file mode 100644 index 00000000..c46ed36c --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/D/04-app-backup-settings.txt @@ -0,0 +1,35 @@ +{ + "opengist": { + "enabled": false, + "cross_drive": { + "enabled": true, + "method": "rsync", + "destination_path": "/mnt/felhom-drives/hdd_1", + "schedule": "daily", + "last_run": "2026-10-15T01:30:00Z", + "last_status": "ok", + "last_success": "2026-10-15T01:30:00Z", + "success_tracked": true, + "unit_package_date": "2026-10-15T00:30:00Z", + "last_duration": "0s", + "last_size_human": "202.8 KB" + }, + "offbox": true + }, + "prowlarr": { + "enabled": false, + "offbox": true + }, + "qbittorrent": { + "enabled": false, + "offbox": true + }, + "radarr": { + "enabled": false, + "offbox": true + }, + "sonarr": { + "enabled": false, + "offbox": true + } +} diff --git a/documentation/audits/n100-lived-in-2026-10-15/D/05-capture-sets.txt b/documentation/audits/n100-lived-in-2026-10-15/D/05-capture-sets.txt new file mode 100644 index 00000000..e81d22fe --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/D/05-capture-sets.txt @@ -0,0 +1,23 @@ +== qbittorrent: 1 classifiable bind(s), classified=true + bind userdata:media/torrents class=optional origin=explicit + tier offsite takes [] + tier secondary takes [/mnt/felhom-drives/hdd_1/felhom-data/userdata/media/torrents (optional)] +== sonarr: 1 classifiable bind(s), classified=true + bind userdata:media class=excluded origin=explicit + tier offsite takes [] + tier secondary takes [] +== radarr: 1 classifiable bind(s), classified=true + bind userdata:media class=excluded origin=explicit + tier offsite takes [] + tier secondary takes [] +== prowlarr: 0 classifiable bind(s), classified=true + tier offsite takes [] + tier secondary takes [] +--- PASS: TestN100CaptureSetTmp (0.00s) +2026-10-15 04:59:17 INFO: including mount point mp0 ('/var/lib/felhom') in backup +2026-10-15 04:59:17 INFO: excluding bind mount point mp8 ('/mnt/felhom-drives') from backup (not a volume) +2026-10-15 04:59:17 INFO: excluding bind mount point mp9 ('/etc/felhom-bootstrap') from backup (not a volume) +mp0: local-lvm:vm-9201-disk-3,mp=/var/lib/felhom,backup=1,size=250G +mp8: /mnt/felhom-drives,mp=/mnt/felhom-drives +mp9: /var/lib/felhom-agent/guests/9201/bootstrap,mp=/etc/felhom-bootstrap,ro=1 +Tier 2 with ONE data drive (backup/tier2.go selectTier2TargetFrom): no other drive -> the internal SSD, STATE-ONLY set (never the optional media/torrents), and only if the SSD has headroom; so no film or download reaches tier 2 on the N100 today. diff --git a/documentation/audits/n100-lived-in-2026-10-15/F/01-before.txt b/documentation/audits/n100-lived-in-2026-10-15/F/01-before.txt new file mode 100644 index 00000000..d5c2e52f --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/F/01-before.txt @@ -0,0 +1,9 @@ +{'path': '/mnt/felhom-drives/hdd_1', 'label': 'NVME 1TB', 'is_default': True, 'schedulable': True} +{'path': '/mnt/sizing-bench', 'label': 'Tárhely (sizing-bench)', 'schedulable': True} +total 16 +drwxr-xr-x 4 root root 4096 Oct 15 01:30 . +drwxr-xr-x 5 root root 4096 Oct 14 20:43 .. +drwxr-xr-x 3 root root 4096 Oct 15 01:30 backups +drwxrwsr-x 6 root 1000 4096 Oct 14 20:43 userdata +2026/10/15 14:41:46 info.go:13: [DEBUG] [system] GetDiskUsage: path="/mnt/sizing-bench" total=31.2 GB used=1.3 GB avail=28.3GB (4.3%) +2026/10/15 14:42:21 info.go:13: [DEBUG] [system] GetDiskUsage: path="/mnt/sizing-bench" total=31.2 GB used=1.3 GB avail=28.3GB (4.3%) diff --git a/documentation/audits/n100-lived-in-2026-10-15/F/02-remove.txt b/documentation/audits/n100-lived-in-2026-10-15/F/02-remove.txt new file mode 100644 index 00000000..387469db --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/F/02-remove.txt @@ -0,0 +1,9 @@ +16:44:24 POST /settings/storage/remove storage_path=/mnt/sizing-bench -> HTTP/2 302 | location: /storage?storage_msg=success&storage_detail=Adatt%C3%A1rol%C3%B3+elt%C3%A1vol%C3%ADtva%3A+%2Fmnt%2Fsizing-bench +2 +2026/10/15 14:44:24 settings.go:1632: [INFO] [settings] Removed storage path: /mnt/sizing-bench +2026/10/15 14:44:24 handlers.go:3527: [INFO] [web] Storage path removed: /mnt/sizing-bench +2026/10/15 14:44:25 handlers.go:3805: [INFO] [web] FileBrowser mounts synced (recreated) — 1 storage path(s), config updated + +/app_backup/calibre-web/cross_drive/destination_path = /mnt/sizing-bench +/app_backup/paperless-ngx/cross_drive/destination_path = /mnt/sizing-bench +storage paths now: ['/mnt/felhom-drives/hdd_1'] diff --git a/documentation/audits/n100-lived-in-2026-10-15/F/03-hub-after.txt b/documentation/audits/n100-lived-in-2026-10-15/F/03-hub-after.txt new file mode 100644 index 00000000..d4446771 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/F/03-hub-after.txt @@ -0,0 +1,3 @@ +14:56:26 atus-dot-nominal"> Demo HP OK 1 1 just now 28% 26% 27%/22% 17/17 – + +[exited with code 0] diff --git a/documentation/audits/n100-lived-in-2026-10-15/README.md b/documentation/audits/n100-lived-in-2026-10-15/README.md new file mode 100644 index 00000000..ef9ca6c1 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/README.md @@ -0,0 +1,19 @@ +# The N100 becomes the lived-in box (2026-10-15) + +Rule: `architecture/09-update-architecture.md` §3 decision 254. Diary: `documentation/lived-in/n100.md`. +Read first: `runbooks/target-selection.md`, `operations/nodes.md`, `07-backup-architecture.md`, `15-media-library.md`. + +| folder | what | +|---|---| +| `B/01-state.txt` | the host and guest: versions, memory, disks, `/dev/dri` (host yes, guest no) | +| `B/02-drive.txt`, `B/03-drive-detail.txt` | the USB drive (ADATA HD710 PRO / TOSHIBA MQ04ABF100 `65NOP3HDT`) and its 6.2 GB: vzdumps, app backups, leftovers — no family files; PVE storage `felhom-backup` = the whole-guest backup target | +| `B/04-sizing.txt` | the five media apps by the estimator's rule: ~2 GB needed of 12 GB | +| `B/05-dashboard-view.txt` | the dashboard's own view: one enrolled drive, `backup_target: true`, off-site on (182 KB) | +| `B/06-deploy-fields.txt` | the install fields per app | +| `D/01-install.txt` | qBittorrent, Prowlarr, Sonarr, Radarr through the deploy call — no drive sent; the box chose `hdd_1` | +| `D/02-stranger.txt` | a stranger from the internet: the gate on Prowlarr/Sonarr/Radarr; qBittorrent's own login page and 403 API | +| `D/03-wiring.txt` | what the box wired, from the apps' own APIs | +| `D/04-app-backup-settings.txt`, `D/05-capture-sets.txt` | **Part C:** the controller's classifier over the deployed files — off-site takes no media; tier 2 only qBittorrent's downloads and only if switched on (not on; with one drive state-only to the SSD); vzdump excludes the drives | +| `F/` | demo-hp: `/mnt/sizing-bench` removed through the dashboard; the hub's next report | +| `SHEET.md` | the operator's sheet | +| `tools/` | `n100.py` (the box-walk library pointed at the N100), `install_media.py`, `read_wiring.py` | diff --git a/documentation/audits/n100-lived-in-2026-10-15/SHEET.md b/documentation/audits/n100-lived-in-2026-10-15/SHEET.md new file mode 100644 index 00000000..0b1d6e1e --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/SHEET.md @@ -0,0 +1,50 @@ +# Your sheet — the N100 becomes the lived-in box (about 30 minutes) + +Do these when it suits you. Use one browser. Sign in to the dashboard first: then the apps let you through. + +## 1. The addresses + +- Dashboard: **https://felhom.demo-felhom.eu** +- qBittorrent: **https://torrent.demo-felhom.eu** +- Prowlarr: **https://prowlarr.demo-felhom.eu** +- Sonarr: **https://sonarr.demo-felhom.eu** +- Radarr: **https://radarr.demo-felhom.eu** +- Plex (after you install it): **https://plex.demo-felhom.eu** + +## 2. Plex + +1. Dashboard → Alkalmazások → Plex → install. It asks no code. +2. Wait until Plex runs. Open Plex's page in the dashboard. +3. Open **plex.tv/claim**. Copy the code. Paste it on Plex's page within 4 minutes. +4. The box opens Plex by itself when Plex is claimed. If it asks, press „Kész, beállítottam". +5. Wait 2 minutes. Open Plex. **If Plex shows no library,** press „Bekötés most" on the dashboard (the card about the + drives and the apps), and tell me that you had to. (I expect this; it is R-1065.) + +## 3. Prowlarr, Sonarr, Radarr + +1. Open each address. The app asks you to make its admin login. Make one for each. +2. On each app's page in the dashboard, press „Kész, beállítottam". Until you do, only you can reach the app. +3. Add your download sources **in Prowlarr only.** They reach Sonarr and Radarr by themselves (the box linked them). + +## 4. One show, one film + +1. Sonarr: add one show. Radarr: add one film. +2. When they finish, open Plex. Check that both are there. + +## 5. Passwords + +- qBittorrent: user `admin`. The password is on qBittorrent's page in the dashboard (the password row, show button). + The same value is in a private file on DooPlex: `~/.felhom-demofelhom/qbittorrent-admin`. +- Prowlarr, Sonarr, Radarr, Plex: the logins you make. None is written here. + +## 6. qBittorrent — the legal line + +„Csak olyan tartalmat tölts le, amihez jogod van. A letöltés a háztartásod internetcíméről történik, és a torrent +természetéből adódóan a többi résztvevő látja a címedet." + +## 7. Anything odd + +Tell any CC session. It goes into the diary (`documentation/lived-in/n100.md`) and the register. + +When you are done, say „done". I then read back: Plex claimed, its libraries, the show and the film imported as +hardlinks, and visible in Plex. diff --git a/documentation/audits/n100-lived-in-2026-10-15/tools/install_media.py b/documentation/audits/n100-lived-in-2026-10-15/tools/install_media.py new file mode 100644 index 00000000..93ee613c --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/tools/install_media.py @@ -0,0 +1,26 @@ +"""install_media.py — Part D1: qBittorrent, Prowlarr, Sonarr, Radarr through the dashboard's deploy call, with the fields +the wizard sends (no HDD_PATH for a media app — the box picks its drive). Admins and indexers are the operator's.""" +import json, os, time, n100 +w = n100.w +w.login() +for app in ("qbittorrent", "prowlarr", "sonarr", "radarr"): + if w.stack(app).get("deployed"): + print(f"{app}: already installed — skipped"); continue + c, d = w.ctl("GET", f"/api/stacks/{app}/deploy-fields") + fields = (((d.get("data") or {}).get("metadata") or {}).get("deploy_fields")) or [] + sub = next((f.get("default") for f in fields if f.get("env_var") == "SUBDOMAIN"), None) or app + values = {"DOMAIN": w.DOMAIN, "SUBDOMAIN": sub} + if any(f.get("env_var") == "QBT_ADMIN_PASSWORD" for f in fields): + values["QBT_ADMIN_PASSWORD"] = open(os.path.expanduser("~/.felhom-demofelhom/qbittorrent-admin")).read().strip() + t0 = time.time() + code, d = w.ctl("POST", f"/api/stacks/{app}/deploy", {"values": values}) + print(f"{time.strftime('%H:%M:%S')} {app}: deploy (fields sent: {sorted(values)}) -> {code} {json.dumps(d, ensure_ascii=False)[:120]}") + for _ in range(120): + time.sleep(5) + st = w.stack(app) + if st.get("deployed") and (st.get("app_config") or {}).get("pinned_images") and st.get("state") in ("running", "unhealthy"): + break + st = w.stack(app) + hdd = w.guest(f"grep -E '^\\s*HDD_PATH:' /opt/docker/stacks/{app}/app.yaml | head -1").strip() + print(f" {app}: state={st.get('state')} after {time.time()-t0:.0f}s; pinned={(st.get('app_config') or {}).get('pinned_images')}; {hdd}") +print(w.guest("docker ps --format '{{.Names}} {{.Status}}' | sort")) diff --git a/documentation/audits/n100-lived-in-2026-10-15/tools/n100.py b/documentation/audits/n100-lived-in-2026-10-15/tools/n100.py new file mode 100644 index 00000000..889ac279 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/tools/n100.py @@ -0,0 +1,12 @@ +"""n100.py — the box-walk library pointed at the N100 (demo-felhom guest 9201). Import this, not box_walk, for the N100. +box_walk.py has no demo-felhom row; this overrides the target AFTER import (no catalog change). Every call is the +dashboard's own endpoint, as box_walk documents.""" +import os, sys +os.environ.setdefault("TARGET", "9201") +os.environ.setdefault("SC", os.path.expanduser("~/.felhom-demofelhom")) +sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts") +import box_walk as w # noqa: E402 +w._T = {"hp": "demo-felhom", "ssh": "felhom-pve", "jump": None, "guest": "9201", + "base": "https://192.168.0.149", "domain": "demo-felhom.eu"} +w.GUEST, w.BASE, w.DOMAIN, w.HP = "9201", "https://192.168.0.149", "demo-felhom.eu", "demo-felhom" +w.HOSTHDR = "Host: felhom.demo-felhom.eu" diff --git a/documentation/audits/n100-lived-in-2026-10-15/tools/read_wiring.py b/documentation/audits/n100-lived-in-2026-10-15/tools/read_wiring.py new file mode 100644 index 00000000..87505ef1 --- /dev/null +++ b/documentation/audits/n100-lived-in-2026-10-15/tools/read_wiring.py @@ -0,0 +1,23 @@ +"""read_wiring.py — Part D2: what the box wired by itself, read from each app's OWN API inside its container (keys read +from the app's config at use, never printed) and from the controller's log. Read only.""" +import json, shlex, n100 +w = n100.w +def arr(app, port, path, ver="v3"): + script = ("K=$(sed -n 's:.*