controller/sharing.md (code-verified vs controller v0.144.0 + felhom-samba
1.0.0); capability map 'Files from Windows Explorer / Mac Finder (SMB server)'
MISSING -> IMPLEMENTED (PROVEN-LIVE pending Viktor's Explorer leg); ROADMAP R-7
-> shipped-slice-1 with the slice-2 remainder, and the backup design fork split
out as R-7b (shares are classified but not in any live backup run yet).
Let a customer bind their own freshly-installed appliance without the
operator: operator "Send self-bind link" mints a 7-day tokenized
capability link, emailed (Hungarian, sibling sender) to the customer, who
opens a public /bind/<token> page and proves two factors — the console
pairing code shown on the box screen + their retrieval passphrase — and
the hub stages the bind via the same BindAppliance (provenance
customer_selfbind). The box's ~30s appliance poll delivers.
Viktor's three rulings verbatim: console pairing code (no appliance list
ever rendered), operator-sent tokenized link, 5-attempt lockout ->
"call support". Wrong code == wrong passphrase (one generic failure, no
oracle, both factors compared unconditionally); expiry falls back to
operator-bind unchanged.
THE TRAP: one public prefix /bind/, exempt from auth+CSRF at both /login
gate sites via a single isPublicBindPath predicate (tight trailing-slash
match; ServeMux ..-cleans; handler rejects '/' in token). 9 tests
(Scenarios A-F + F1/F2); 4 red-proofs verified red-then-green (lockout,
oracle, widened-prefix, single-active). GC verdict: no appliance GC ->
the 7-day TTL stands alone. Controller/agent untouched; R-27b deferred.
Green: full hub build/vet/test (17 ok) + bash -n + hub confirm gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qDiBqKKQ5vPB5fXBqu7Kp
Closes N100 F1 (HIGH): cheap AMI (AN3PLUS 0.01-class) UEFI firmware can't
relocate the ISO's stock signed GRUB from USB (relocation 0x0). The run's live
grub-mkimage workaround is now a first-class pipeline mode.
- build-felhom-iso.sh: --loader shim|mkimage (default shim, byte-for-byte
unchanged; profile-settable FELHOM_LOADER; --loader wins). Loud banner +
manifest loader:/grub-mkimage: fields + -mkimage filename suffix.
- mkimage-surgery.sh (new): post-prepare-iso, in the assistant container. Builds
a monolithic grub-mkimage loader from the ISO's own GRUB (module set from its
grub.cfg; embedded search --fs-uuid -> configfile the real menu). Swaps it into
the ISO9660 tree (real lowercase path) + the efi.img ESP; xorriso re-master
preserves BIOS-hybrid + UEFI + GPT-ESP, drops only Apple HFS+/APM. Recipe from
the N100 run evidence, not re-derived.
- Dockerfile.assistant: grub-common + grub-efi-amd64-bin + mtools + dosfstools.
profiles/n100.profile (new, mkimage + SB-off note).
- Validated on nested VM 311 (RUNBOOK-B legs): leg1 shim boots+installs under
OVMF SB-enforcing + SeaBIOS; leg2 mkimage boots+installs under SB-off; leg3
(red-proof) mkimage under SB-enforcing FAILS Access Denied (unsigned -> SB must
be OFF); leg4 surgery byte-identical payload. bash -n + shellcheck clean.
Physical N100 closure folds into the rehearsal (n100-safety match-nothing ISO
built + sha-recorded, unbooted). PXE stays a deferred R-21 note.
- DeleteHost(deleteEscrow) demotes current host_escrow into host_escrow_superseded (copy-before-delete, same tx), spares existing; one shared demoteCurrentEscrowTx (reused by SaveHostEscrow). F-14 provenance/gate unchanged.
- DeleteCustomerConfig now purges both escrow tables for all the customer's hosts incl. already-deleted (F-14 provenance UNION) — the one true purge point.
- Wording: checkbox/refusal/Danger-zone → demotion. S6b OBSOLETE. Red-proofs TestDeleteHost_Demotes + TestDeleteCustomer_Purges + wording guard.
Opened every citation in 00-capability-map.md and judged each of the 55 rows
against the specific scenario (not topic adjacency). 23 confirmed (incl. 5
MISSING proven-absent by code sweep), 26 citation-corrected, 6 demoted; no
upgrades. Status: 32 PROVEN-LIVE / 15 IMPLEMENTED / 3 PARTIAL / 5 MISSING
(was 38 PROVEN-LIVE).
Demotions PROVEN-LIVE->IMPLEMENTED: B6 (post-deploy config — T-PAGE-ALL is
render-only), E7 (FileBrowser access — no browse/download proof), F1 (health
email — cited P3-DELIVERY is the enlarge-block trigger), F4 (metrics — cited
legs are H1/H2 harness artifacts), F6 (operator alerting — no corpus doc),
G6 (offsite fill/staleness/freeze — no live-fired leg, freeze inconclusive).
Key corrections: D6 cited CAMPAIGN-3 F10/F11/F12 which are the CRITICAL
failures — fixes shipped agent v0.85 and were re-validated live in CAMPAIGN-4
/6A; C6 cited offbox-restic doc for a PBS-restore claim -> CAMPAIGN-2 T-P9;
C1/C5/B5 cited defect-discovery docs instead of the fix-validation legs.
Closed ROADMAP R-20: operator-key pinning is fully automatic in day-0
(felhom-host-install.sh step_agent_config, L2044/2146-2156/2332-2337).
Header draft caveat swapped for the verified stamp. Full per-row verdict
table in REPORT.md.
felhom-host-install.sh installs felhom-selfupdate-guarded (sh -n), the rollback
unit + the [Unit] start-limit drop-in (daemon-reload) so day-0 boxes get
operator-signed self-update from birth; non-fatal on pre-D1 agent repos.
03-host-agent.md §11 updated to the shipped mechanism (signed op, A/B wrapper,
OnFailure rollback, tuned start-limit backstop).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
escrow-create -storage felhom-offsite -identity-bundle -directive -upload on
felhom-pve: fresh R (operator-recorded off-transcript) wraps K + WG key + offsite
PBS token; uploaded to hub. Independently verified in host_escrow (demo-felhom-01:
key_fingerprint=offsite b0:fe:2a…, identity blob 499B, directive present,
created_at=now) with zero knowledge of R. S5 (DR consume) now UNBLOCKED.
This re-run also remediated an earlier escrow whose R had leaked into an agent
transcript (last-write-wins overwrote it with the clean-R blob).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
Offsite restore-test now runs unattended on the agent-token path (agent v0.68.0):
tier-aware restore-task timeout (pbs→120m, local→10m). The scratch-band
VM.Allocate follow-up was a phantom — the scratch restores INTO /pool/felhom
(ACL already grants it); the earlier 403 was the 10m-timeout consequence. No
ACL/host-install change. doc-06 S4 row + runbook §4b updated.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
The CGNAT smoke test's OPEN DECISION is made: fleet-wide, permanent,
family-agnostic client MTU 1280 (RFC 8200 IPv6-minimum floor), implemented in
felhom-agent v0.65.0.
- §4.3: OPEN DECISION → made decision + rationale + rejected alternatives
(auto-probe/per-type = fragility for a non-metric; MSS-clamp = unneeded).
"ships MTU 1420" → 1280; corrected "fixed-line unaffected" (DS-Lite ~1452,
PPPoE would also black-hole at 1420 — one floor covers all).
- §4.2: 1280 is family-agnostic so MTU correctness is decoupled from v4/v6
resolution; v4-pin noted as a separate optional determinism item.
- §3.2 wire-field note + §8 S6 row: MTU 1420 → 1280; S6 residual now only the
true-CGNAT-SIM retest.
- REPORT.md overwritten.
Docs-only; the constant change is in felhom-agent v0.65.0.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
S3 appendix CGNAT smoke test run live on felhom-pve (agent v0.64.0) with a
USB-tethered phone. Tunnel established + held its NAT mapping across a 32-min
idle soak on PersistentKeepalive=25 alone (0 stalls, final ping no-bounce).
- §7: open-validation CLOSED; two honest caveats kept (SIM had a public mobile
IPv4 so true CGNAT 100.64/10 not reproduced — retest-when-able; + MTU).
- §4.3: mobile outer path MTU ~1400 black-holed bulk data at the shipped 1420;
MTU 1340 restored the PBS page. OPEN DECISION: permanent vs per-connection.
- §4.4: keepalive 32-min mobile-NAT hold datapoint.
- §4.2: dual-stack v6 trap (wg-quick prefers endpoint AAAA, rides un-NATed v6).
- §8: S6 row CGNAT closure marked done.
- REPORT.md: overwritten with this operational-validation summary.
Runbook: RUNBOOK-s3-cgnat-smoke. Docs-only; no agent/hub/controller code.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
Records the settled transport decisions (plain WG, host-side agent-managed pilot,
one hub-driven endpoint VM running WG+PBS, hub source-of-truth over WireDesiredState,
one datastore + per-customer namespaces, relay-through-DooPlex rejected). Grounded
at file:line vs felhom.eu@bf099f6 + felhom-agent@4ba1b14. Backlog line resolved to
cite spike + design doc. Docs-only; slices are separate future tasks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
- 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>
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>
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>
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>
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>
§9: the provision front half, guest-loss DR front half, and golden recipe are now
implemented (agent v0.8.0, internal/reconcile/bringup.go; configs/build-golden.sh).
Identity reset settled + implemented: provision resets MAC (unconditional, F1) +
hostname host-side; machine-id + SSH host keys regenerate guest-side (systemd + the
baked first-boot felhom-regen-hostkeys unit, F3) — agent stays host-side-only. Slice
mapping table statuses updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- hub/internal/web/templatefetcher.go: raw-template URL now points at the renamed
repo (was relying on Gitea's post-rename redirect)
- documentation/ (moved here from the felhom-agent repo): fix controller-source path
refs (deploy-felhom-compose -> felhom-controller) and the platform repo name
(proxmox-controller -> felhom-agent)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>