Commit Graph

62 Commits

Author SHA1 Message Date
admin ea09ead806 docs: controller updates — Phase 1 shipped (agentic), Phase 2 next
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
2026-06-26 21:43:25 +02:00
admin 89a2e508a7 scripts: felhom-host-install.sh v1.0.0 — Day-0 host bootstrap (live-validated)
Operator-run Day-0 automation for a fresh PVE host: pveum token -> hub
POST /host-enroll (single secret, option C) -> agent config -> felhom-agent
--selftest=provision -> verify. Idempotent/resumable (state.json), --dry-run,
--resume, --force, --preserve-from; --mode dr is a documented 10D stub.

Live-validated on felhom-pve: authorized wipe of demo guest 9201 + full
re-provision from the golden -> controller config-pull + public tunnel HTTP 200
+ host-report of 9201; idempotent --resume no-op. Found+fixed one ordering bug
during the run (token ACL must be applied AFTER token rotation — token-remove
purges the ACL).

Adds scripts/README.md (operator runbook) + scripts/CHANGELOG.md; REPORT
overwritten; spike doc pointer added. No service code changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
2026-06-26 20:04:25 +02:00
admin 8098237ce1 hub v0.14.0: passphrase-authed host enrollment (Day-0 option C)
New POST /api/v1/host-enroll (handleHostEnroll): X-Retrieval-Password authed,
body {customer_id} -> {host_id, api_key}. Mint-once-reuse (201 first, 200
reuse) so re-running the host-bootstrap never orphans a running agent's key;
auth checked before any mint. Backed by new Store.GetHostByCustomer
(ORDER BY updated_at DESC LIMIT 1, idx_hosts_customer).

GET /config/{id} and global-key POST /admin/hosts left untouched. Exact-match
route (path == "/host-enroll") to avoid the /hosts/ prefix collision.

Tests: host_enroll_test.go (mint/reuse/401-no-mint/404/400) + GetHostByCustomer
store test; companion red-proof verified always-mint fails the reuse assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
2026-06-26 15:35:24 +02:00
admin 230980f7a8 spike(day0): findings — first-boot trust handshake (operator-deploy)
Empirically validates the composed Day-0 chain against the LIVE hub: host
mint (POST /admin/hosts), agent host-auth via the real internal/hub client
(host-report + FetchDesiredState), and controller config-pull
(GET /config/{id} + X-Retrieval-Password). All links + wrong-cases pass.
Option A works end-to-end with zero new code; option C (single-secret enroll)
feasible + recommended for cutover. Throwaway customer/host cleaned up.

No production code, no version bump (spike).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
2026-06-26 15:12:27 +02:00
admin 347546e597 test(nomercy): Phase 5 + deliverable summary — campaign complete
Demo restored to healthy baseline (test apps removed, drives at stable, sys_drive
separate, settings UI clean). Deliverable summary: 4 findings (F3 onboot=0 guest
no-auto-start [highest impact], F2 FileBrowser bounce on controller restart, F1
restic dead-weight, F4 stable double-bind), all report-not-fixed. Method per test,
PBS floor (unused), end state, coverage gaps (1.3/1.4/1.8 loop-whitelist, 4.7
operator-gated). No data-loss/path-escape/corruption found.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:20:50 +02:00
admin 2c1441f5dd test(nomercy): Phase 4 complete — 4.4 mountpoint-gate, 4.6 concurrency; 4.7 deferred
4.4 drive yank: belt skips ensure (manager.go:143), no rootfs write, clean
reconnect recovery. 4.6 concurrency: eject-in-use warned via impact, concurrent
backup+enroll no corruption. 4.7 capstone deferred (operator-gated, needs golden
volid+passphrase; compensating coverage via 1.2/3.3/4.1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:16:38 +02:00
admin cd6715d592 test(nomercy): 4.3 intent-gate PASS (ejected drive not auto-rebound)
ReassertGuestBinds skips ejected da9e7089 (+ leftover ce9d1d81), re-binds enrolled
flash; usb stays 0 binds. Brief post-restart transient (rslave+F4) cleared in one
tick. Restored usb.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:12:53 +02:00
admin de4ff8b39b test(nomercy): Phase 4 part 1 — host reboot (4.1/4.2/4.5); F3 onboot=0, F4 double-bind
4.1 plain host reboot: drives re-bind by UUID at stable, sys_drive separate, apps
recreate, registry stable. FINDING F3: 9201 onboot=0 -> did NOT auto-start (whole
guest down until manual pct start). 4.2 REAL sdb<->sdc swap, drives still map by
UUID to correct stable path (v0.37 ruled out). 4.5 double-bind stable at 2x (not
leaking); FINDING F4 pre-existing 2x bind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:09:16 +02:00
admin 14e2ac98f4 test(nomercy): pre-4.1 host-reboot marker (committing before host reboot, guardrail 8)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:04:55 +02:00
admin e7517c4185 test(nomercy): Phase 3 complete — server restart PASS; F2 FileBrowser bounce
3.3 full-server restart (live UI): drives re-bind stable, sys_drive separate
(2.5 reboot-survival), all apps recreate-on-boot, registry intact, no placeholders.
3.4 controller-only restart: guest + customer apps keep running BUT FINDING F2 —
SyncFileBrowserMounts force-recreates FileBrowser unconditionally (handlers.go:1543),
bouncing it on every controller restart vs the "apps keep running" promise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 20:03:35 +02:00
admin c50bd55392 test(nomercy): Phase 3 partial — 3.1 banner gone, 3.2 routes; pre-3.3-reboot commit
3.1 banner retired (0 occurrences) + card present; 3.2 /api/storage/activate 404,
/api/server/reboot wrapped RequireAuth+CsrfProtect (auth-gate not demonstrable on
passwordless demo). Committing before the 3.3 live guest reboot (guardrail 8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 19:58:13 +02:00
admin c6cb8a51e7 test(nomercy): Phase 2 complete — sys_drive split holds (2.1/2.2/2.3/2.4 PASS)
sys_drive=disk-2 distinct, selftest [PASS] System data path; disk-full ENOSPC
confined to disk-2 (/ + docker-data unaffected, apps healthy); mp1 in vzdump;
SSD-fallback app (radarr) data lands on disk-2. 2.5 size=50G; reboot-survival
in 3.3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 19:56:38 +02:00
admin 4baed17e89 test(nomercy): Phase 1 complete — stable-path model holds; F1 restic dead-weight
1.6 deploy/HDD_PATH stable, 1.7 eject clean stable removal (v0.80 ruled out) +
impact names apps, 1.9 migrate flips stable->stable w/ verify-before-cleanup,
1.10 decommission via raw agentWhere + reconnect restore, 1.11 backups under
stable namespace. FINDING F1: restic binary still apt-installed (Dockerfile:58)
though all restic code moved to agent — dead weight. navidrome now on flash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 19:52:38 +02:00
admin 8746c0fb7b test(nomercy): Phase 1 partial — 1.1/1.2/1.5/1.12 PASS, 1.3/1.4/1.8 by-design block
Stable-path model: registry stable (1.1), deregister+re-add registers stable not
raw (1.2, the v0.78 path), disk card shows stable+Regisztrálva (1.5 live UI),
free-form raw add rejected/no symptom (1.12). Loop devices refused by agent
block-device whitelist (validate.go:124) -> 1.3/1.4/1.8 inconclusive-by-design;
compensating unit-test + 1.2 coverage noted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 19:41:05 +02:00
admin 234e827b21 test(nomercy): Phase 0 floor + baseline captured
PBS floor ct/9201/2026-06-23T17:28:25Z; baseline host/guest/container/agent state;
invariant (no rootfs placeholders) PASS; Phase 2.3 (mp1 in vzdump) PASS captured
opportunistically. Flagged: onboot:0, two leftover absent drive-intents.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 19:29:47 +02:00
admin e8a5bdc492 docs(audit): DIAGNOSE re-enrolled drives not binding after 9201 re-provision
Root cause: controller handleStorageRegister registers the raw /mnt/<name> path
instead of the stable /mnt/felhom-drives/<name> path the agent binds the drive at.
Drives ARE live in guest+container at the stable path; controller watches an empty
rootfs placeholder. Not v0.40.0 mp1; not stale agent state. Read-only diagnosis,
no fix applied. Recommended fix direction documented.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
2026-06-23 17:15:30 +02:00
admin add5be5bd5 docs(tests): test campaign #3 'NO MERCY' findings (brutal chaos/edge, demo 9201)
7 phases. No silent-corruption, no path-escape/exfil found. Findings: S1 settings.json
crash-loop (medium, no safe-defaults), F2 restore stack_name traversal not validated
upfront (medium defense-in-depth, no escape observed), S3 corrupt quiesce marker silently
ignored (low). All else fail-safe held. Phase4 time-chaos SKIP (unprivileged LXC shares
host clock). No code changes. Demo restored to baseline.

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 22:06:00 +02:00
admin 445db9a625 docs(controller): storage doc — v0.75.0 drive-absent userdata MkdirAll gate (1c)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:55:10 +02:00
admin e4f49491a3 docs(tests): Finding #1 re-diagnosis — TEST ARTIFACT (docker kill != crash); controller auto-recovers
Read-only diagnosis: restart-manager works (natural-exit probe RestartCount climbs;
manualRestart=false); docker kill is a manual stop so restart is correctly suppressed.
Definitive: kill -9 the controller PID (real crash) -> unless-stopped auto-restarts it,
RestartCount=1 healthy in 5s. Daemon stable (NRestarts=0, no OOM). Finding #1 downgraded
in the campaign-2 doc. Separate minor obs: boot-time drive-ordering race. No fix applied.

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:35:08 +02:00
admin 58fe93034f docs(tests): test campaign #2 findings (chaos/edge-cases, demo 9201)
Storage lifecycle (unblocked by v0.74.0), break-and-recover C1-C8, backup edge cases.
Headline finding: docker restart-policy not honored -> a crashed felhom-controller has
no automatic recovery (oneshot bootstrap + dead restart policy). Plus disconnect-recreate
race, agent loopback whitelist, carried-forward #1 gaps. Demo restored to baseline.

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:10:51 +02:00
admin a9ca5b4e68 docs(tests): 8443 unreachability ROOT CAUSE — controller http.Transport leak (read-only diagnosis)
Confirmed H5 (ephemeral-port exhaustion): agentClient() builds a new http.Transport
per call (IdleConnTimeout:0, never CloseIdleConnections) -> ~5.8k leaked idle ESTABLISHED
sockets/day to 162:8443, exhausts the 28k ephemeral range in ~5 days of controller uptime
-> EADDRNOTAVAIL. :8006 immune (controller never dials pveproxy). Cleared by restart.
H1/H2/H3/H4/H6 ruled out with positive evidence. Fix is controller-side (reuse one
Client), NOT an agent rebind. No changes applied.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:00:24 +02:00
admin f70c011749 docs(tests): unattended test campaign findings (2026-06-22, demo 9201)
Full-feature validation across the running demo: PBS backup, komga/gitea HC fixes,
deploy sweep, backup+restore, DR rebuild, storage, monitoring/alerts/hub, guest reboot.
Headline finding: controller->agent local-API (8443) unreachable from the controller
container, gating storage UI + host metrics + whole-guest backup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:29:10 +02:00
admin 228dac4c06 docs(audit): SPIKE — Phase 2 DR recipe + storage diagnosis (report-only)
Part 0 (live): flash apps on 9201 were down due to an operator pct reboot at
10:26 UTC + a boot-ordering race — dockerd auto-starts unless-stopped flash apps
~18s before the agent re-binds felhom-flash, so the create-time bind mkdir fails
(permission denied) and RestartCount=0 never retries. Drive healthy, data intact,
no USB drop, durable-id fine, drive-gate uninvolved. v0.70.0 self-restart RULED
OUT (container restart, not a guest reboot; +38min after exits). Fix: restarted
the 7 apps via the controller (drive present) — all Up. Flagged the intermediary
mount app-start race as an architectural gap.

Parts 1-3 (cited): characterized escrow (K + identity under recovery code R,
fingerprint-gated, hub zero-knowledge) + PBS whole-CT contents (rootfs/secrets in,
external drives out) + capstone DONE vs PENDING (agent-side recovery orchestration
not wired, syncer.go:92). Defined the secret-free DR recipe (guest sizing + drive
durable-id/role inventory + PVE storage + app bindings + PBS coords), sourced from
facts the agent/controller already hold, landing in the reserved
WireDesiredState.storage_manifest placeholder. Field-by-field boundary proof + a
no-secrets test spec. Fork list + recommendation: spec/emit/store the recipe now,
defer re-enrollment auth to slice 10D, never touch the escrow/PBS secret path.

No code changes, no version bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:18:39 +02:00
admin 2f7acb7d07 docs(audit): SPIKE — characterize Infra Backup (revive vs retire)
Report-only audit. Confirms the infra-backup push died at slice 8C
(controller v0.37.0) — builder deleted, PushInfraBackup +
NotifyBackupCompleted left as caller-less stubs; agent never
re-implemented it. Same root cause as the daily deadline-check email
(no backup_completed emitter). Live hub records inspected read-only:
plaintext secrets at rest (AES master key + restic pw + Cloudflare
tokens) = zero-knowledge violation; disk_layout is bare-metal-era.
Recommends phased retire-now / revive-concept-later (secret-free DR
recipe) + fork list. No code changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 10:04:55 +02:00
admin d105657355 docs: M3 live re-verification addendum (closes E14/E15 residual) + two controller UI fixes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:53:10 +02:00
admin 9ee929ba6d docs(audit): storage lifecycle completion + acceptance sweep (incl. live host reboot)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 20:42:21 +02:00
admin f1df01b5c5 docs(spike): stable intermediary mount — swap drive underneath (C1-immune, no-restart)
Live-validated on demo guest 9201 (felhom-flash throwaway): shared/slave mount
propagation delivers host->guest drive swaps live with no restart and no pct
change; bind source = permanent stable dir => inherently C1-immune (clean boot
with drive absent). nsenter fallback non-viable on unprivileged LXC; ro-tmpfs
placeholder is the CAP_DAC_OVERRIDE-proof fail-close. Report-only, no code change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 15:26:37 +02:00
admin 4fe77fcd1b docs: B3 live storage-lifecycle exercise + feature sweep (2026-06-15)
Live unattended UI exercise of migration/decommission/re-enroll/eject +
feature sweep on shipped controller v0.66.2 / agent v0.32.0 (guest 9201).
No production code changed.

Migration engine solid (all moves checksum-verified identical, sources
cleaned, HDD_PATH flipped, apps healthy). Lifecycle gaps found:
- C1 (critical): decommission/eject leave a stale LXC mp (no pct delete)
  -> guest fails pre-start hook on next reboot, ALL apps down. Recovered
  live via pct set --delete mp1.
- H1: /api/storage/{disconnect,reconnect,restart-apps} are 404 (unrouted)
  though settings.js calls them.
- H2: no UI button for /api/storage/decommission.
- H3: no one-click re-enroll for a decommissioned drive.
- M1: decommissioning the default drive doesn't reassign the default.
- M2: eject does NOT auto-remount (intent-gated like decommission).
- M3: userdata/import/calibre created 755 at enroll; migrate-all doesn't
  re-assert setgid on pre-existing dirs (16/17 preserved 2775).
- M4: felhom-usb mount unit had stale UUID; M6: test-email fails (no SMTP).

End-state sane: apps healthy on felhom-flash (now default), both data
drives Aktiv, reboot-safe, sda/PBS/controller untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:39:44 +02:00
admin f24125ecdd docs: SPIKE raw-drive plug-and-enroll (GATE, 2026-06-15)
Report-only spike + one live throwaway FORMAT experiment on /dev/sdc.
No production code, no version bump.

- Q1: raw-disk discovery gap confirmed — Observe AND localapi GET /disks
  are both built only from PVE storages (ListStorage/NodeStorage); a
  not-yet-storage disk is invisible. proxmox client has no /disks/* method.
- Q3: safety classifier (RoleForRawDevice/SystemDisks/RoleForStorage)
  already protects sda/felhom-pbs live, but needs two hardening checks:
  whole-disk-granularity enrolled-subtraction + LVM-PV membership.
- Q6: FORMAT path proven end-to-end live — pvesh disks/directory create
  -> agent Observe -> controller "Regisztralas" enroll. sdc left as the
  clean enrolled felhom-flash B3 migration target. sda/sdb untouched.
- Premise correction: felhom-pbs is remote (no local PBS disk).
- Fork list for the build spec in the audit doc + REPORT.md.
2026-06-15 10:57:33 +02:00
admin ebf3c0cbea docs(spike): userdata/ layout + shared-storage ownership mapping (report-only gate)
Maps current namespace dir creation/ownership (live on 9201), the 9-app/13-mount
media blast radius, run-identity table (FileBrowser=uid1000, komga/audiobookshelf=root),
LXC idmap, and proposes the setgid GID-1000 convention. Flags: MigrateAll's merge walk
drops setgid+owner on userdata. Ends with a 7-item fork list. No code/deploy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:15:24 +02:00
admin 45052da4dc docs(spike): bake in locked fork decisions (B0 gate cleared)
1) keep operator-signed decommission; 2) Q4 both — intent-aware
ReassertGuestBinds load-bearing/sufficient, GuestBindStore.Remove hygiene
(re-commission re-Records via recordGuestBind, B2 to state); 3) data move
= controller via rsync copy-verify-remove (not cp -a); 4) decommission
role-gated unmount. Gate cleared; B1/B2 may proceed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 18:14:08 +02:00
admin 326aa1ca17 docs(spike): decommission/migration feasibility (TASK B0)
Report-only feasibility spike: data-move layer (controller, proven live),
vestigial migrate button, self-serve POST /disks/decommission design,
re-bind gap (intent-unaware ReassertGuestBinds + no GuestBindStore.Remove),
soft-marker registry. Gates B1/B2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:52:26 +02:00
admin b5a961477d docs(f9): reject recommendation #1 auto-register-on-attach (A3)
Contradicts the new->enrolled manual-enrollment model; manual enroll is
by design. The additive-discovery sub-point was adopted (controller
v0.64.0 A1) but only for paths deployed apps reference, not auto-register
of agent-attached drives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:33:33 +02:00
admin 1fd6e1a22f docs(diagnosis): post-F9 storage-registration gap (read-only diagnosis, no fix)
HDD attached at the agent layer (F9 bind) but never entered the controller storage
registry: enroll/register flows (runStorageInit/runStorageAttach/handleStorageRegister)
are the only paths that call registerStoragePath, and F9 attached via the agent directly;
AutoDiscoverStoragePaths is a one-time seed scanning only deployed-app HDD_PATHs. So the
HDD is 'Nem regisztrált' + absent from the deploy dropdown (GetSchedulableStoragePaths).
Verdict: F9 NOT closed. Fix direction: auto-register-on-attach + clearer manual register.
2026-06-14 16:04:36 +02:00
admin c1c8fe2a7d docs: F9/F20-BUG2/F20-BUG3 FIXED (agent v0.31.0, live-validated); queue golden controller-tag follow-up 2026-06-14 15:43:07 +02:00
admin 98fa8b299a docs(backlog): mark M18 + M19 FIXED in controller v0.62.0
M18 (dump re-validation perf) @ f8afe5c and M19 (deriveStackName misattribution) @
6bab68b implemented trunk-based on controller main with regression tests + deployed.
Notes retained for provenance.
2026-06-14 14:17:59 +02:00
admin 751941ca6a docs(audits/backlog): preserve live-drive findings+fixspec and M18/M19 fix-plans
Relocates the 2026-06-14 live-drive findings + fixspec from the felhom-controller
repo root into documentation/audits/ (alongside the bughunt-reconcile/deep-sweep
records), and preserves the M18/M19 implementable fix-plans (from the deleted
controller fix/m18 + fix/m19 branches) into a new documentation/backlog/. Part of
the trunk-based no-branches reconciliation.
2026-06-14 11:00:26 +02:00
admin 4c0eb2f5d4 docs: close doc-gaps (hub v0.11.0, onlyoffice:nextcloud occ internals, metricsDBPath verified)
- 05-hub-architecture.md: stale 'felhom-hub v0.6.3' -> v0.11.0 (design-draft note).
- auth-hub-sync-integrations.md: full onlyoffice:nextcloud occ command sequence.
- storage-monitoring-metrics.md: metricsDBPath verified to coincide with the volume-backed
  data_dir on the bootstrap guest (persists; hardcoding is latent fragility only).
- REORG-NOTES: gaps 2/3 CLOSED, gap 5 partially closed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 23:10:04 +02:00
admin 280781115d docs(audits): AGENT-001 -> MERGED + DEPLOYED (agent v0.30.0)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 22:32:23 +02:00
admin e68fe3eb19 docs(reorg-notes): correct controller/README handling (banner, not full slim)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 19:42:50 +02:00
admin 21d0e7cf4c docs: centralize controller documentation + top-level index (code-verified, v0.59.0)
New documentation/controller/ subtree (module map + deploy/stack-lifecycle, backup,
storage/monitoring/metrics, auth/hub/sync/integrations) grounded in current source;
top-level documentation/README.md index across controller/agent/platform/hub/audits;
REORG-NOTES with the verification ledger + flagged doc-gaps. Supersedes (keeps) the
v0.33 controller planning map. Additive only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 19:40:25 +02:00
admin 4320c01915 docs(audits): authoritative remediation records (deep-sweep + bughunt-reconcile)
Brings the 2026-06-13 audit + reconciliation under documentation/audits/ with
per-finding remediation status (controller v0.59.0 fixes deployed to demo;
AGENT-001 fix prepared/pending review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 19:28:25 +02:00
admin 3457415117 slice 10D (hub): DR capstone — recovery mode + re-enroll + directive serving (hub v0.11.0)
Recovery-mode toggle (global key, bounded auto-expiry) gates re-enroll +
restore-directive serving. Re-enroll rotates the agent<->hub credential to the
new box (old key revoked); returns the opaque escrow blobs + non-secret
directive. Store gains recovery_mode_until + identity_blob + directive_json.
Hub holds no usable secret + no Cloudflare write-power (operator-side rotation).
Doc 03 §9: slice 10 CLOSED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 09:48:38 +02:00
admin a22b87e6e3 docs: slice 10D core spike findings (identity-escrow + tunnel re-establishment) — GO
Validated both unvalidated 10D mechanisms: (1) identity-bundle escrow round-trip
via age scrypt+AEAD (recover on a secret-less box, wrong-R fails closed), (2)
Cloudflare tunnel re-establishment — running the recovered token on a new box
routes the hostname there immediately (no DNS change); the old connector is a
hot standby, superseded in routing but not auto-retired -> 10D must rotate the
tunnel/PBS token + retire the stale connector for host-loss security. Redacted;
secrets shredded; live demo untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 23:17:53 +02:00
admin a98210ae00 docs: slice 10C escrow consumption productionized (doc 03 §8a/§9)
Agent-only implementation (felhom-agent v0.17.0 escrow.Consume); no hub code
change. 10C done; 10D is the last piece of slice 10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 22:18:10 +02:00
admin 0c843286a2 slice 10B: signed-op job completion (DELETE clear-job) (hub v0.10.0)
Add DELETE /hosts/{id}/jobs/{job_id} (per-host self-scoped, idempotent) so the
agent clears a job after executing or terminally rejecting it. The hub stores
the operator-signed blobs opaquely (no signing key — cannot forge or open);
the agent verifies + executes. Doc 03 §4/§6/§9 updated (operator-signed path
live; 8C wipe completes; 10B done).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 20:14:32 +02:00
admin e54f882e70 slice 10A: hub desired-state serving + signed-jobs queue (Down channel) (hub v0.9.0)
Serve operator intent to authenticated hosts: PUT /admin/hosts/{id}/desired-state
(global key) bumps desired_generation; GET /hosts/{id}/desired-state + /jobs are
per-host self-scoped; the host-report envelope now carries the real generation +
has_signed_ops. New signed_jobs table + store methods. Desired-state stored/served
opaquely (agent owns the schema). Cross-repo golden (envelope + desired-state)
byte-identical with felhom-agent; doc 03 §4/§9 updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 19:03:14 +02:00
admin f9af3243b9 docs: slice 10C escrow-consumption spike findings (GO)
Validated escrow consumption end-to-end on a genuinely key-less box against
the real felhom-spike datastore: recover K from (blob,R) via the real
escrow.Unwrap, restore REAL data (spike-lxc rootfs, 2.5G) with the recovered
key only, wrong-R fails closed (no plausible-but-wrong key), live K
byte-unchanged. Redacted (no R/K/secret). GO to spec 10C + build 10D.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:10:31 +02:00
admin 4590fc0ee0 slice 9 docs + wire-contract: host.cpu_temp_c golden + doc 03 GET /host/metrics
Update the cross-repo host-report golden byte-identical with felhom-agent
(host.cpu_temp_c). Document GET /host/metrics in doc 03 section 6 and define
slice 9 in the section 9 roadmap. No hub code change / no version bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:16:38 +02:00
admin 5dc363771b doc 03 §8/§9: slice 8B.2 implemented — resume at snapshotted (downtime ~24s->~3s) (2026-06-10)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:02:14 +02:00