Commit Graph

103 Commits

Author SHA1 Message Date
admin 7fb20d5fb0 docs: architecture Part 06 — offsite-connectivity design-of-record (slice roadmap S1-S6)
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
2026-07-03 23:02:31 +02:00
admin bf099f6a10 docs: SPIKE — offsite-backup connectivity: plain WireGuard wins the ladder (transport decision made)
P0-P7 probe ladder on real ends (demo-felhom PVE host <-> throwaway Hetzner).
Verdict: GO at H1 — plain host-side WG, box-dials-out to a small public endpoint;
Headscale is a separable fleet layer, not a traversal necessity. Line is plain-NAT
(not CGNAT) with zero IPv6 — recorded honestly; CGNAT vantage deferred to Peti VM 110.
Real 2 GiB worst-case PBS backup over the tunnel at the full home uplink, pin intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 22:04:51 +02:00
admin 7ad111cfb5 docs: golden 0.98.3 live — D.1b retired, drill B1/B5 fixed, backlog note resolved + evidence doc
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 18:38:28 +02:00
admin 2e33a8b86b docs: D.1b narrowed + drill B2/B3 marked FIXED (agent v0.63.0)
Restart-the-agent step in day0-install.md is now conditional on agent <
v0.63.0 (reload-on-miss shipped; Day-0 manifest still vouches 0.62.0).
Troubleshooting row + drill ledger + go/no-go item 8 updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 17:27:39 +02:00
admin 0fa79cd90d Go-live package: Day-0 install runbook + clean-room drill + host-install v1.9.1
- documentation/runbooks/day0-install.md (NEW): operator Day-0 guide, every
  command drill-executed verbatim (Parts A-F incl. the mandatory one-time
  controller update D.1b and the OQ-3 prereq checklist).
- documentation/audits/DRILL-day0-cleanroom-2026-07-03.md (NEW): nested-PVE
  clean-room drill evidence D0-D6, residue tables, OQ-1/2/3 answers, findings
  ledger (B1-B5), go/no-go for Peti (GO).
- scripts/felhom-host-install.sh v1.9.1: residue-free uninstall (agent config,
  shared-parent unit/script/mount, mkfs wrapper, hook snippet, dnsmasq
  snippets; zero-residue diff proven) + post-provision guest reboot (R6) +
  header/version sync.
- CONTEXT.md, REPORT.md, scripts/CHANGELOG.md updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 15:14:47 +02:00
admin 5e3dfcb714 docs: SPIKE — A1 pool-membership read for the stale-lock reaper
Live-probed on felhom-pve under the PRODUCTION scoped token vs root:
enumeration IS pool-filtered (T1: token sees [9201] of 4 guests); pool read
403s naming Pool.Audit (T2); Pool.Audit@/pool/felhom alone suffices (T3,
throwaway identity, torn down); /cluster/resources withholds the pool field
without Pool.Audit (T7); local ownership records all partial (T5).

Recommendation for the A1 impl spec (now unblocked): Pool.Audit added to
FelhomAgentGuest + GET /pools/felhom cross-check in staleLockController,
fail-safe skip on read failure. Appendix: committed-secrets rotation
micro-runbook (operator follow-up).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-03 13:00:00 +02:00
admin 43189e8972 D3 Part 4: docs — .tag/.badge addendum, website CHANGELOG, REPORT
- design-system.md: the .tag (outline+dot, state) vs .badge (filled
  chip, static informational label) distinction the D1 unified view
  left implicit, + a Website (TASK-D3) section (shared site.css,
  self-hosted fonts, external sprite, mask-based CSS marks, ?v=
  cache-busting, site_gates.py enforcement).
- website/CHANGELOG.md created (newest-on-top) with the D3 entry.
- REPORT.md overwritten per §15 (baselines, commits, gate outputs +
  all three red-proofs, 84-problem/182-emoji baseline → 0, contact-form
  freeze proof + live TESZT submission resend id, live checks, the
  narrow-viewport limitation, observations).
2026-07-02 22:19:58 +02:00
admin a336fe3123 docs(design): design system v2 canonical reference (TASK-D0)
Tokens, component semantics (meter/tag/metarow/panel/list/section-h/
stats/buttons), the state truth tables incl. the stopped->neutral
exception-color change, vendored typography (latin-ext) + Lucide
iconography, chart palette, and the grep-gate enforcement list.
Shipped in controller v0.96.0; D1-D4 build from this document.
2026-07-02 15:00:11 +02:00
admin 8c8196e82b docs: AUDIT — host-root + local-API blast radius (non-Proxmox-token axes)
Companion to CAMPAIGN-pool-effects: red-teams the four axes the pool campaign
did not cover (provenance-gating of destructive ops, sudoers↔fine-gate coverage,
local-API within-scope blast radius, mkfs/claim classifier, signed-vs-self-serve
boundary). Verifies the v0.60.0 F1 fix is complete; finds no new HIGH/MED. One
F1-sibling (stale-lock pool-blind reaper, LOW) + LOW/INFO defense-in-depth
residuals. Read-only static trace against felhom-agent @cc93dae/v0.60.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 10:43:19 +02:00
admin 6dae9d7558 docs: F3 provisioning runbook (vmid from full host list) + campaign F1/F2 resolution banner
Companion to felhom-agent v0.60.0 (proof-of-launch destroy gating + restore-
test band-advance). New documentation/runbooks/provisioning.md; campaign doc
updated with the resolution status and the operator manifest-bump follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 10:27:17 +02:00
admin e59e3c0ae2 docs: pool-effects no-mercy campaign — op-matrix 16/16, B1 rollback-destroy finding, fix list (F1-F6)
Full validation of the felhom pool + scoped-token migration on felhom-pve:
- Track A: complete agent op surface under the scoped token — 16/16 pass
- Track B: vmid origin traced (externally supplied); adversarial collision
  probes prove the compensating rollback/teardown attempts to destroy a
  guest the job never created (contained only by the pool ACL)
- Track C: containment + 3b-fix intact; Track D: no pool leaks, adopt/
  uninstall pool handling correct
- Findings doc: documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md
No code change, no version bump. Demo left as found.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 09:16:46 +02:00
admin d775fda326 docs: spike status — Impl-2b DONE (raw enrollment live: ctrl v0.95.0 + agent v0.58.0)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 21:27:48 +02:00
admin 850ed78ad6 docs: spike status — Impl-2a (SQ4/SQ5) done in agent v0.55.0; Impl-2b/3 pending
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 17:39:36 +02:00
admin f5e45840e3 docs: REPORT for host-install v1.8.0 + spike-doc status (Impl-1 SQ3 implemented)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 17:02:04 +02:00
admin 9e5bbc13d5 docs: SPIKE drive-enrollment — raw-device discovery + safe-to-format filter
Read-only spike on felhom-pve. Verdicts: (SQ1) customer drives need NOT be PVE
storages — track in the intent registry (durable-id + host mount + bind), the
dir-storage is legacy. (SQ2) an unclaimed-disk filter (OS/LVM-PV/ZFS/PVE-storage/
VM-CT/mounted/RO/registry signals, fail-safe exclude-on-unknown) returns EXACTLY
{/dev/sdd} on the demo, never sda/sdb/sdc. (SQ3) mkfs sudoers is /dev/* — the
agent code is the only guard; DataBearing (wipe-confirm) is insufficient (OS disk
is data-bearing), so a mandatory agent unclaimed-gate + guarded-mkfs-wrapper
sudoers + a shared-box operator gate for self-serve format. (SQ4) new
/disks/candidates raw-scan endpoint feeding both wizards, registry-based
enrollment. (SQ5) migrate existing drives to the registry. Implementation plan +
open risks included. No product code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:14:27 +02:00
admin 7c14e64a68 docs: RUNBOOK result — USB enrollment on pool-scoped ACL (residual CLOSED)
Live supervised validation on felhom-pve: NO 403 on drive management under the
scoped token (agent has no storage-registration/pvesm path — all host-ops +
Datastore.Audit which is now box-wide). 3b-fix confirmed in the real UI (drives
Regisztrálva, no detach alert). A full physical wizard enroll couldn't complete
because a raw new device (SD-card reader, no PVE-storage entry) doesn't surface
in the init wizard (Observe() lists PVE storages only) — ACL-independent; flagged
as a separate new-drive-registration follow-up. No code change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:52:44 +02:00
admin 1be1e0d6a3 docs: REPORT + spike-doc status for host-install v1.6.0 (pool-scoped ACL, live-migrated)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:02:16 +02:00
admin 554845b44b docs: SPIKE pool-scoped ACL — empirical validation (PASS, findings for 3b)
Throwaway-token spike on felhom-pve: the agent's 16 privs scope from / to
/pool/felhom + /storage/<targets> (+Pool.Allocate) without breaking the flow.
CRUX proven: restore a fresh vmid INTO the pool works at /pool/felhom (T1 200).
T1-T7 all pass; blast radius contained (out-of-pool guests 403). Findings:
3-role layout (per-path subsets need separate roles); Datastore.Audit filters
so needn't be box-wide; Store scope MUST include felhom-pbs (offsite default);
restore-test scratch band (9990xx) not in pool → 3b must handle. All spike
objects cleaned up; live FelhomAgent/9201 untouched. No product code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:10:41 +02:00
admin e51e03bd7b docs(audit): hub GUI vs current architecture findings (2026-06-30)
Categorized STALE/DEAD/MISSING/POLISH/CORRECTNESS findings for the hub web
GUI. No GUI code changed, no version bump — findings doc only, for operator
prioritization.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxLA1mZurFq9kt8hneFeCs
2026-06-30 20:13:48 +02:00
admin f133355e34 audit: §D supervised reboot done — F2-a + F2-b red-proofs PASS (findings closed)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162BnMpUXscPsUB1cU8Tr6K
2026-06-30 10:04:59 +02:00
admin 06727e3228 docs+config: operator email enabled (Part A, proven) + TESTRUN findings closed
Part A: hub-config operator_email/operator_enabled (committed earlier);
operator + customer email paths proven end-to-end via real Resend sends.
Append the "Findings closed" section to the TESTRUN audit (Part A proof,
F2-a root cause + deploy fix, F2-b fix + live validation, pending §D
supervised reboot) and remove the stale duplicate "Final state" block.
REPORT overwritten. hub/CHANGELOG entry. No hub image change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162BnMpUXscPsUB1cU8Tr6K
2026-06-30 09:21:17 +02:00
admin c978ea1951 testrun: coverage gaps RESOLVED — capability->hub alert fired live; 2 reboot findings (doubling NOT self-corrected, backup-lock)
Phase 1: capability->hub operator alert fired live (event captured, English, names cap+feature);
email is operator-config-gated in demo (not a defect). Phase 2: drive re-propagation + zero false
pages PASS, but TWO findings — F2-a the §4 doubling did NOT self-correct (boot script runs as root,
never needed the grant → hypothesis falsified), F2-b a vzdump backup in flight at reboot left a stale
snapshot-delete lock blocking guest autostart. Phase 3 referenced (host_leaf_changed proven on v0.22.1).
Final parity known-good.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 23:56:54 +02:00
admin f4d88c1ff4 docs: felhom.eu REPORT (HostLeafChecker) + hub README + self-health arc complete (spike doc)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 23:32:12 +02:00
admin dd2bb5fc01 audit(testrun): F1 RESOLVED — swap verify RestartCount+dwell (agent v0.47.0), live rollback confirmed
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 22:50:17 +02:00
admin cbba20aa73 docs: felhom.eu REPORT (hub F2 + install-script preservation) + TESTRUN F2-closed
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 22:01:57 +02:00
admin a297639c58 testrun: full-stack no-mercy campaign — capstone pin-mismatch detection PASS (~25s), swap happy PASS + rollback finding, multi-drive reboot PASS
Headline: leaf-regeneration (original-incident class) DETECTED by channel-health in ~25s + recovered.
Controller-swap happy PASS (byte-exact tee) + negative controls denied; FINDING F1: no-healthcheck
crash-loop image slips the point-in-time swap verify (low sev — real controller has a healthcheck).
Multi-drive guest-reboot re-propagation PASS, no flapping. Stack restored to known-good parity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 21:10:33 +02:00
admin 26a6dde2fb audit(channel-health): IMPLEMENTED — controller v0.90.0 + hub v0.20.0 allowlist; live-validated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pg8ANF97SEeKYSN5Jxw3qJ
2026-06-29 20:42:38 +02:00
admin 0d470b1e05 spike: controller-agent channel health — GO (Q1 classify map; Q2 memoized client self-heals, fresh probe faithful)
Q1: 6 modes classified — pin-mismatch/401/refused/timeout/no-such-host are RUNTIME (per-call),
malformed-fp is a CONSTRUCTION error (latches via sync.Once). Q2: across a clean agent restart the
memoized /api/disks path self-heals in ~1s with NO controller restart (Up 7h); a fresh-client probe
agrees at every phase. Recommend: probe GET /storage via the memoized client, classify, N>=2 debounce
for transient reasons, hub relay. Throwaway probe removed, no config changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 20:06:06 +02:00
admin 6b1c2892d6 docs: controller-swap narrow-grant Option A IMPLEMENTED (agent v0.45.0) — spike + multidrive pointers resolved
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 19:46:17 +02:00
admin 1141d74532 spike: narrow-grant controller-swap mechanics — GO (stdin tee + sudoers * spans spaces, grants stay scoped)
Q1 stdin->pct exec->tee writes byte-identical image\n (PASS); Q2 all 5 narrow grants match,
* spans spaces, negatives denied (PASS); Q3 deployed bootstrap reads via $(cat), tee-written
file consumed identically (PASS). Scratch drop-in + file removed, /etc/sudoers re-validated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 19:27:15 +02:00
admin eea3cd4040 docs: hub REPORT (v0.19.0 capability alert) + multidrive audit countermeasure pointer
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 18:57:23 +02:00
admin c6bae9515a audit(multidrive): §8 Outcome — FIXED via sudoers completeness pass; controller-swap surfaced
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 16:06:41 +02:00
admin 66a001de0b spike: multi-drive mutual-exclusion — root cause is bound_under_parent detection bug (lxc-info denied under non-root agent), not propagation/gate
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 15:33:44 +02:00
admin 1777c89fb9 spike(pin-mismatch): §9 Outcome — R1 executed, controller↔agent service restored
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 15:08:58 +02:00
admin 8254b8823e spike(pin-mismatch): follow-up — aside-var-lib holds matching token store; R1 = one-copy fix for pin+token
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 14:44:10 +02:00
admin 2de9659592 spike: controller↔agent TLS leaf-pin mismatch — root→non-root migration regenerated agent leaf (findings)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
2026-06-29 14:38:43 +02:00
admin 0719db0d53 spike: NAS network storage (media automount + restic backup target) — findings
Empirical validation on a DooPlex-simulated NAS (SMB+NFS). Verdict READY for the
production network-storage TASK. Key findings: mount must be host-side (unprivileged
LXC blocks NFS/CIFS mount) + bind-propagated into the guest; NFS soft fails-clean +
auto-recovers (SMB hangs-but-contained); UID mapping = container uid + 100000 LXC
offset; ~128MB/s adequate; write integrity intact (atomic-write apps safe on soft);
restic-SFTP backup/restore works + fails-as-job not hang; systemd automount gives
on-demand + idle-unmount. Distinct network-storage class bypasses the drive lifecycle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 11:44:40 +02:00
admin b4ce6c10b5 docs: FINDING — app-email rollout mechanism gaps (calcom/nextcloud/immich)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:32:56 +02:00
admin feea06062a secrets: rotate + de-git Resend key; source from out-of-band Secret/resend-api
Resend send-scoped key was committed in plaintext in manifests/hub.yaml (ConfigMap)
and manifests/felhom.secret.yaml. Rotated to a new key and removed from git.

- hub: new RESEND_API_KEY env override (cmd/hub/main.go), mirrors REGISTRY_TOKEN;
  ConfigMap resend_api_key now an empty placeholder; Deployment injects from
  Secret/resend-api. Image 0.17.0.
- contact-mailer: secretKeyRef repointed contact-mailer-config -> resend-api.
- felhom.secret.yaml: contact-mailer-config Secret removed; healthchecks
  EMAIL_HOST_PASSWORD blanked (workload not deployed).
- documentation/runbooks/secrets.md: out-of-band secret model + create/rotate steps.

Secret/resend-api is created imperatively out-of-band and is NOT committed.
No secret value appears in this repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 07:50:30 +02:00
admin 35c6632a64 docs(audit): SPIKE findings — on-box SMTP app-relay (apps → shim → hub → Resend)
Verdict READY. Real Vaultwarden test email travelled app → on-box go-smtp
shim → relay-leg → Resend → real inbox, From felhom.eu, TLS/DKIM-aligned,
Resend key never on the demo guest. Q4 central finding: raw-MIME passthrough
via Resend SMTP delivers faithfully; parse-then-API silently drops inline
(CID) images — hub leg should be SMTP passthrough, not the structured-API path.
Probe code throwaway (not committed); cleaned up from guest 9201 + host 180.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NB4fVgvEurdKgyG8KoQSzC
2026-06-28 19:27:07 +02:00
admin 6c285ba033 REPORT + Day-0 doc: BUNDLE slice (hub v0.16.0 artifact manifest + host-install v1.1.0 self-install)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 09:03:34 +02:00
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