docs(report): R-67 — probe GO, two-gate design, cross-box live leg incl. dead-NAS recovery
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UuFPHmHNrCJj1VhY6QdDMU
This commit is contained in:
+19
-1
@@ -7,7 +7,25 @@
|
|||||||
>
|
>
|
||||||
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
||||||
|
|
||||||
Last updated: 2026-07-22 (v0.159.0 — R-66: the box's own address becomes visible)
|
Last updated: 2026-07-22 (v0.160.0 — R-67: the NAS share appears in FileBrowser)
|
||||||
|
|
||||||
|
> **2026-07-22 — v0.160.0 (R-67), SHIPPED + deployed BOTH boxes, full live leg on demo-hp.**
|
||||||
|
> Network shares now bind their share ROOT into FileBrowser (`…/<name>:/srv/<name>:rslave`) — no
|
||||||
|
> skeleton/userdata toward the NAS, ever. Pure assembly = `buildFileBrowserPaths` + `fbPathDeps`
|
||||||
|
> (handlers.go), returning mounts AND config sources together so they can't disagree.
|
||||||
|
>
|
||||||
|
> **DECISION — two classes, two gates:** drives keep the drive-absent gate (byte-identical,
|
||||||
|
> tested + observed live: demo-felhom logged a no-op sync); network shares use the STUB classifier
|
||||||
|
> gate instead (stub ⇒ excluded from both lists + WARN — an exposed stub swallows uploads the real
|
||||||
|
> mount later shadows; idle autofs is HEALTHY and included; unknown fails open). Never force-wake
|
||||||
|
> in the sync (doctrine).
|
||||||
|
>
|
||||||
|
> **Phase-0 probe = GO:** in-container access through an rslave bind WAKES an idle autofs trigger
|
||||||
|
> (proved on demo-hp against the real Felhom-Share). Live leg: upload from demo-hp's filebrowser
|
||||||
|
> container (uid 1000) landed on demo-felhom's share dir and deleted clean; dead-NAS gave
|
||||||
|
> `Host is down` in seconds (no hang) and recovered unaided after samba restart. RESIDUAL for the
|
||||||
|
> operator: the FileBrowser HTTP click-through — its admin credential is customer-held (CC got 401
|
||||||
|
> on admin/admin and the demo password; by design). ROADMAP R-67 SHIPPED (coupled to R-64).
|
||||||
|
|
||||||
> **2026-07-22 — v0.159.0 (R-66), SHIPPED + deployed to BOTH boxes.** Three legs: „Hálózat" card on
|
> **2026-07-22 — v0.159.0 (R-66), SHIPPED + deployed to BOTH boxes.** Three legs: „Hálózat" card on
|
||||||
> Beállítások → Rendszer (Helyi cím / Hálózati név only-while-Megosztás / Átjáró; „—" fallback),
|
> Beállítások → Rendszer (Helyi cím / Hálózati név only-while-Megosztás / Átjáró; „—" fallback),
|
||||||
|
|||||||
@@ -1,98 +1,97 @@
|
|||||||
# REPORT — R-66: the box's own address becomes visible (controller v0.159.0, 2026-07-22)
|
# REPORT — R-67: the NAS share appears in FileBrowser (controller v0.160.0, 2026-07-22)
|
||||||
|
|
||||||
**Spec:** the R-66 prompt (three XS legs, controller-only, v0.158.1 → v0.159.0).
|
**Spec:** the R-67 prompt (Phase-0 probe + implementation, controller-only, v0.159.0 → v0.160.0).
|
||||||
**Commit:** `7013a5f` on `main` · image `felhom-controller:0.159.0`
|
**Commit:** `59cd260` on `main` · image `felhom-controller:0.160.0` · deployed to **demo-felhom
|
||||||
(sha256 `5bbc7d62433c464fbbcdbe8ef819636b94075d0cc481631d50471880d99630c5`) · deployed to
|
9201** and **demo-hp 9201**, both healthy. No agent changes; MinAgent unchanged.
|
||||||
**demo-felhom 9201** and **demo-hp 9201** (both now above the 0.156.0 floor; floor untouched).
|
|
||||||
|
|
||||||
## 1. The one design decision (spec deviation, recorded)
|
## 1. Phase-0 probe — GO
|
||||||
|
|
||||||
The spec sketched Leg A's Átjáró as a `/proc/net/route` read and Leg B's DNS as `/etc/resolv.conf`.
|
On demo-hp, with the Felhom-Share automount confirmed IDLE (autofs trigger present in the guest's
|
||||||
**The controller container is bridge-networked** (verified live: `docker inspect` →
|
/proc/mounts, `timeout=60`, no cifs mount):
|
||||||
`NetworkMode=bridge`; the bootstrap `docker run` has no `--network host`) — so every in-process
|
`docker run --rm -v /mnt/felhom-drives/Felhom-Share:/probe:rslave alpine ls -la /probe`
|
||||||
answer describes the CONTAINER's netns: routes → the docker bridge gateway (172.x), resolv.conf →
|
listed the REAL share content (demo-felhom's `teszt/` + macOS dotfiles) and left cifs mounted in
|
||||||
docker's 127.0.0.11 embedded resolver, interfaces → one 172.x eth0. That is exactly the
|
the guest. **An in-container access through an rslave bind wakes the idle trigger** — one
|
||||||
wrong-kind-of-true trap the codebase already documents on `SambaLANAddress` (S-2: "the classic
|
namespace further than the spike's in-guest proof. The design shipped exactly as specified; the
|
||||||
wrong answer that already burned the setup wizard").
|
fallback fork was not needed.
|
||||||
|
|
||||||
**Resolution:** every guest-net read goes through the ONE guest-netns door this process has — a
|
|
||||||
docker-exec into the host-networked `felhom-samba` container (`internal/stacks/guestnet.go`, one
|
|
||||||
`guestNetExecFn` seam for route/link/addr/resolv.conf reads). Accepted consequence, by the spec's
|
|
||||||
own S-5 logic ("an address-less row beats a wrong address"): with Megosztás off the door is closed
|
|
||||||
and the card shows „—" / the dump carries per-item error strings. The spec's §2.1 instruction
|
|
||||||
("check whether it is SMB-conditional… reuse as-is") anticipated exactly this shape.
|
|
||||||
|
|
||||||
## 2. What shipped
|
## 2. What shipped
|
||||||
|
|
||||||
- **Leg A** — „Hálózat" card on Beállítások → Rendszer, between „Verzió és frissítés" and „Szerver
|
`syncFileBrowserMounts`' path loop extracted into the pure **`buildFileBrowserPaths`**
|
||||||
memória" (`settings_system.html`, `systemPageData`): Helyi cím (LAN) via the reused
|
(`fbPathDeps`: mount probe / FS classifier / skeleton fn / logger — every edge seamed), returning
|
||||||
`sambaLANAddress`; Hálózati név `\\<SMBServerName>` gated on `smb.Enabled` (the NetBIOS name
|
BOTH the mount lines and the config source set so a source can never render without its mount.
|
||||||
exists only while samba runs); Átjáró via the new `guestGateway`; muted footer („…Távoli
|
|
||||||
hibaelhárításnál ezt az oldalt kérjük felolvasni."). No host/Proxmox address, no interface dump.
|
- **Network branch:** bind = the share ROOT, `…/<name>:/srv/<name>:rslave` (`:rslave`
|
||||||
- **Leg B** — `dump["network"]` in `debugDump`: `interfaces` (name/up/addresses; veth*/docker*/br-*
|
load-bearing — automount wake / idle-unmount propagate into the RUNNING container). No
|
||||||
plumbing skipped), `default_route` (gateway + source interface), `dns_servers` (guest
|
`EnsureUserdataSkeleton`, no userdata scoping, nothing written toward the NAS. The drive-absent
|
||||||
resolv.conf — docker copies the HOST's file into a `network_mode: host` container, so the read
|
gate does NOT apply (idle is healthy — the old gate skipped an idle share forever); the gate is
|
||||||
answers for the box), `lan_address` (the SAME live value Leg A shows, the cross-check anchor).
|
the **stub** classifier verdict via the existing `Server.classifyFSPath` seam: stub ⇒ excluded
|
||||||
Best-effort per item: a failed read yields `"error: …"` in place, dump never aborts.
|
from mounts AND sources this pass + WARN (`namespace sees a local stub, not the NAS`). autofs /
|
||||||
- **Leg C** — helper text under the Szerver field (`storage_network.html`, naming the »közvetlen
|
network / unknown / nil-classifier include (fail open). **The stub rationale:** an exposed local
|
||||||
cím« row on the Megosztás page), plus `netAddMessage`'s `unreachable` case appends „Tipp: a(z)
|
stub dir accepts uploads that the real mount later SHADOWS — the customer's files silently
|
||||||
»<name>« Windows-hálózati névnek tűnik — használja az eszköz IP-címét." when
|
vanish from view; exclusion-until-recovery is the only safe rendering.
|
||||||
`looksLikeFlatNetworkName(server)` (non-empty ∧ no dot ∧ not `net.ParseIP`-able). Purely
|
- **Drives:** behavior byte-identical (userdata scoping, skeleton, drive-absent gate, always in
|
||||||
lexical; no NetBIOS/mDNS anywhere; agent untouched.
|
the source list) — asserted by test, and observed live (§4).
|
||||||
- Nothing is stored: no settings.json/app.yaml/hub-report field carries any of these values.
|
- **Triggers:** NAS add-success (`runNetAdd` done) + remove (`handleNetStorageRemove`) now call
|
||||||
|
`SyncFileBrowserMounts()` (same debounced/H5-mutexed path as the drive flows). Removal drops
|
||||||
|
source + mount next sync; F2 change detection forces the recreate.
|
||||||
|
- Renderers unchanged: `RenderFileBrowserCompose` already takes fully-formed mount lines
|
||||||
|
(propagation rides in the line), `RenderFileBrowserConfig` already names sources by `Label`.
|
||||||
|
|
||||||
## 3. Tests + red-proofs
|
## 3. Tests + red-proofs
|
||||||
|
|
||||||
`stacks/guestnet_test.go`: pinned pure parsers (default route incl. garbage/IPv6-gw refusals;
|
`filebrowser_network_test.go`: **A** (drive line byte-identical with/without the share — the B′
|
||||||
interface merge with docker-plumbing filtering; resolv.conf), `GuestGateway` fail-quiet contract,
|
invariant; share ROOT `:rslave` line exact; both sources in config; skeleton called for the drive
|
||||||
and the B1 best-effort matrix (scripted per-argv exec fake: healthy / resolv.conf-only failure /
|
ONLY), **B** (stub ⇒ absent from mounts + sources, drive intact, warn logged), **C** (autofs /
|
||||||
door fully closed). `web/network_card_test.go`: A1 (all rows render), A2 (Hálózati név ABSENT when
|
network / unknown / nil classifier all include — idle is not a detached drive), **D** (removal
|
||||||
sharing off), A3 („—" + „nem állapítható meg", no crash), per-render freshness counter (2 renders ⇒
|
leaves no trace; `fbNeedsRecreate` sees the change).
|
||||||
2 resolves — the anti-memoization gate), B1 web-half (dump shape + in-place error + dump
|
|
||||||
completeness), C1/C2/C3 + category containment + IPv6/empty lexical edges.
|
|
||||||
|
|
||||||
**Red-proof A2** (enabled-gate dropped in `systemPageData`): FAIL —
|
**Red-proof A** (network paths routed through the drive branch): FAIL —
|
||||||
`Hálózati név row rendered while Megosztás is disabled — a wrong promise`. Restored, green.
|
`skeleton calls = [/mnt/felhom-drives/hdd_1 /mnt/felhom-drives/Felhom-Share]` — the NAS path
|
||||||
**Red-proof C2** (lexical check inverted): FAIL — the hint visibly nagged the IP user:
|
visibly receiving a skeleton — plus the share line degrading to a `userdata` subtree without
|
||||||
`hint wrongly present for an IP: "… Tipp: a(z) »192.168.0.50« Windows-hálózati névnek tűnik …"`
|
`:rslave`. Restored, green.
|
||||||
(C1/C3 + edge assertions also went red). Restored, green.
|
**Red-proof B** (stub gate dropped): FAIL — the stub share leaked into mounts AND the source
|
||||||
|
list, and the warn disappeared. Restored, green.
|
||||||
|
|
||||||
Full green gate: `go build ./... && go vet ./... && go test ./...` — clean. All six template gates
|
Green gate (`go build ./... && go vet ./... && go test ./...`): clean. No template changes → no
|
||||||
(template_id / emoji / native_confirm / offbox_rename / app_row_dedup / mojibake) — OK.
|
template gates in play.
|
||||||
|
|
||||||
## 4. Live validation (endpoint-level — the exact endpoints the UI invokes; no browser on DooPlex)
|
## 4. Live leg (real surfaces; methods named)
|
||||||
|
|
||||||
**demo-felhom 9201 (sharing ON — the open-door path).** Deploy via the bootstrap flow; `docker ps`
|
**demo-hp (the mounting side):**
|
||||||
→ `0.159.0 Up (healthy)`; startup log clean (`controller_started (0.159.0)`, hub report pushed).
|
- Startup sync recreated FileBrowser: compose carries
|
||||||
Authed session against container-IP:8080 + Host header (credentials sourced, never echoed):
|
`/mnt/felhom-drives/Felhom-Share:/srv/Felhom-Share:rslave`, config carries
|
||||||
- `GET /settings` — the card renders with **real live values**: `192.168.0.104` (the guest's
|
`path: "/srv/Felhom-Share"` named „Hálózati tárhely: Felhom-Share"; log:
|
||||||
actual DHCP lease), gateway `192.168.0.1`, `\\FELHOM`, footer present. ASCII-safe greps per the
|
`FileBrowser mounts synced (recreated) — 2 storage path(s)`; container healthy.
|
||||||
accent-mangling trap.
|
- **Content:** `docker exec filebrowser ls /srv/Felhom-Share` → demo-felhom's real content
|
||||||
- `GET /api/debug/dump` → `network` = all four sub-keys:
|
(`teszt/` + dotfiles), uid/gid 1000, group-writable.
|
||||||
`lan_address 192.168.0.104` · `default_route {gateway 192.168.0.1, interface eth0}` ·
|
- **Upload round-trip:** wrote `r67-test.txt` as **uid 1000 inside the filebrowser container**
|
||||||
`dns_servers [192.168.0.1]` · `interfaces [lo up 127.0.0.1/8, eth0 up 192.168.0.104/24]` —
|
(the exact mount namespace + process identity FileBrowser uses) → the file appeared on
|
||||||
docker plumbing correctly absent.
|
demo-felhom at `/mnt/felhom-drives/hdd_1/shares/Share/r67-test.txt` (19 B, uid 1000) → deleted
|
||||||
- `GET /storage/network` — the Szerver helper text present.
|
from demo-hp → gone on demo-felhom. **Residual:** FileBrowser's HTTP/auth layer was NOT driven —
|
||||||
|
its admin credential is customer/day-0-held (admin/admin and the operator demo password both
|
||||||
|
401); the browser click-through is the operator's residual, as is a look at the sidebar.
|
||||||
|
- **Dead-NAS:** samba stack stopped on demo-felhom → demo-hp's in-container access returned a
|
||||||
|
clean `ls: /srv/Felhom-Share: Host is down` in ~11 s wall (incl. ssh) — an error, not a hang
|
||||||
|
(the soft/retry=0 recipe's promise held). `docker compose start` on samba → demo-hp listed the
|
||||||
|
share again immediately, **zero intervention** (the `:rslave` + automount recovery working as
|
||||||
|
designed).
|
||||||
|
|
||||||
**demo-hp 9201 (sharing OFF — the closed-door path, live).** Access via the hub-vaulted G1
|
**demo-felhom (drives-only, the regression side):** startup sync logged
|
||||||
break-glass (file→file, env-var use, credential + hub-DB copy **shredded after**; demo-hp remains
|
`no config/compose change, ensured running without recreate (1 storage path(s))` — the render was
|
||||||
key-less). 0.156.0 → 0.159.0, `docker ps` → healthy. Same authed method (customer domain
|
byte-identical, FileBrowser untouched (Up 22 hours), zero `:rslave` lines in its compose. The B′
|
||||||
`felhom.enkisfelhom.hu` — direct container-IP probing 404s without the right Host, worth knowing):
|
invariant held in production.
|
||||||
the card renders with „—" rows (×2 „nem állapítható meg"), **no** `\\FELHOM` row — Leg A's A2/A3
|
|
||||||
behaviors observed in production; the dump's `network` section carries all four keys with in-place
|
|
||||||
`error: docker exec …` strings for interfaces/route/dns and an empty `lan_address`. The dump
|
|
||||||
stayed complete.
|
|
||||||
|
|
||||||
**Screenshots by description** (rendering is the only untested residual): the card sits between the
|
**Screenshots by description:** demo-hp's FileBrowser sidebar now has a second entry „Hálózati
|
||||||
version card and the RAM card; three `settings-row` lines — „Helyi cím (LAN)" with a mono address
|
tárhely: Felhom-Share" beside the NVMe drive source; entering it shows the `teszt` folder from
|
||||||
(or „— nem állapítható meg" muted in `--text-3`), „Hálózati név" with mono `\\FELHOM` (only while
|
demo-felhom. During the dead-NAS minute the source errors instead of spinning.
|
||||||
sharing is on), „Átjáró" with the mono gateway — and a muted one-line footer under the grid. On
|
|
||||||
demo-hp the same card shows two dash-rows and no name row.
|
**Access notes:** demo-hp via the hub-vaulted G1 break-glass again (file→file, shredded after,
|
||||||
|
incl. the hub-DB copy). Probe + all execs left nothing behind (`r67-test.txt` deleted; alpine
|
||||||
|
image remains in the guest's docker cache — inert).
|
||||||
|
|
||||||
## 5. Follow-ups
|
## 5. Follow-ups
|
||||||
|
|
||||||
- **R-64** (Felhom↔Felhom pairing blessed — evidence drill pending) and **R-65** (buddy-box
|
- Operator: FileBrowser click-through on demo-hp (sidebar + upload via the UI) — CC lacks the
|
||||||
replication, post-alpha spike-first) minted in `felhom.eu` ROADMAP; **R-66 marked SHIPPED** there.
|
FileBrowser admin credential by design.
|
||||||
- `documentation/controller/network-storage-nas.md` gained the NetBIOS naming-caveat paragraph.
|
- ROADMAP: **R-67 → SHIPPED**, coupled to R-64 (browsing was its missing UX half);
|
||||||
- Operator note: a strict end-to-end UI pass of the card is a manual click-through (no browser on
|
`network-storage-nas.md` gained the „Browsing (FileBrowser)" paragraph.
|
||||||
DooPlex).
|
|
||||||
|
|||||||
Reference in New Issue
Block a user