Commit Graph

228 Commits

Author SHA1 Message Date
admin 30b932bb10 website: publish the closed-test legal set (R-813 narrowed)
gates / gates (push) Successful in 5m34s
Two new Hungarian pages, live on push: /adatkezeles (privacy notice) and
/feltetelek (what the free closed test is, and is not). Operator rulings of
2026-10-09: no company exists yet, so the operator is named as a PRIVATE
PERSON with no postal address and no phone; publish before the lawyer has
seen it, because the site was collecting data with no notice at all; the full
ASZF, the impresszum and the review wait for the company (R-802, R-809).

- All 18 pages carry the operator, info@felhom.eu and both links in the
  footer. Counted, not assumed: 18 pages found = 18 with both links = 18
  structurally valid. English footers say the legal texts are Hungarian.
- The contact form stopped claiming something untrue. The old consent said
  "az adatokat harmadik felnek nem adjuk ki" while Resend, Cloudflare and
  Google carry the message. Both languages replaced; the link opens in a new
  tab so a filled form is not lost.
- site_gates.py NO_TWIN gains the two pages ON PURPOSE, with the reason in a
  comment: an unreviewed English legal text would be worse than an honest
  pointer from the English footer.
- documentation/legal/{adatkezelesi-tajekoztato,feltetelek}-1.0.md are the
  text of record, DERIVED from the published HTML so they cannot drift. The
  drafts are kept and marked superseded for the closed test.

FOUR LOAD-BEARING CLAIMS WERE MEASURED, not copied from a vendor or a README:

  cookies      zero, and no local storage - checked in the browser WITH A
               POSITIVE CONTROL (a probe cookie WAS visible to the same
               method) after the tracker fired; no Set-Cookie on any response
  beacon       the exact Umami payload: site id, screen, language, title,
               url, referrer - no visitor identifier
  Cloudflare   DNS only: the public A record 37.191.56.193 is not a
               Cloudflare address, so site traffic cannot be proxied
  fsn1         Falkenstein, Germany (Hetzner's own location list)

Also measured: felhom-ep0-copy-gc.timer is installed and RAN SUCCESSFULLY
(2026-10-09 08:00, exit 0), so "deleted within 30 days" is true today where
on 2026-10-08 it was written but not switched on.

Three retentions are stated as having NO deadline, deliberately and with the
operator's word: website statistics, web server logs and contact messages
have no automatic deletion, and the pages say so instead of promising a date
nothing enforces. Every other period is enforced by configuration and cited.

No placeholder survived onto either page (0 of "[[", control: the draft still
has 36). The impresszum and the full ASZF are NOT published.

R-813 -> NARROWED. R-915 unblocked: the operator enters the two URLs in the
Meta app's Basic settings; the Live switch stays a separate decision.
R-917 and R-920 -> DEFERRED on the operator's (c): park, publish as posts
once posting starts.
2026-10-09 12:11:37 +02:00
admin 4cee21acf7 dooplex-offsite: Vaultwarden (the password manager) rides the nightly encrypted copy (R-923); R-923 filed (operator finding); R-922 ruling A recorded
gates / gates (push) Successful in 5m32s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 11:53:35 +02:00
admin 97d3c29f9c facebook: Page details — categories added, hours and Messenger FAQ refused by Meta
gates / gates (push) Successful in 5m24s
Second Facebook task of the day. Page settings changed by hand in the operator's
Chrome; every edit read back from a channel other than the one that made it,
because Meta's toasts have lied here before (2026-10-08: "A modositas nincs
mentve" arrived with a partial save).

- Contact (B1) was ALREADY SET, by the operator, before this run: Graph reads
  emails ["info@felhom.eu"] and phone "+36702378499". Verified, not typed.
- Place (B2) already city-only Budapest, as the operator chose. Service area
  REFUSED: Facebook offers the field but its picker has no "Magyarorszag",
  only cities. Control: "Szeged" returns Szeged. Left unset rather than
  narrowed to Budapest, which would shrink a coverage claim nobody authorised.
- Categories (B3) DONE: Informatikai vallalat (kept first, the only one shown)
  + Internetes ceg + Szoftverceg. Facebook's Hungarian list has no IT-support,
  IT-consulting or cloud category; eleven terms searched, and the one true
  match is a repair counter, which the fences rule out.
- Hours (B4) CANNOT be set and need not be: Facebook requires a street address
  first, which the fences forbid. Measured on the rendered page with controls
  present -- Zarva 0, Nyitva 0 while Budapest 1, Informatikai vallalat 1. The
  Page will never show "Zarva".
- Messenger FAQ (B5) REFUSED -> R-920: the automation does not exist for this
  Page. Catalogue holds exactly three templates; search "kerdes" returns none
  while the control "uzenet" returns two. COPY.md section 5 is written anyway,
  questions verbatim from gyik.html and answers condensed from each question's
  own answer, and waits like section 2 does (R-917).
- Link preview correct in both languages, re-scraped once each; only the
  expected fb:app_id warning, deliberately not fixed. Both report HTTP 206
  where a plain curl gets 200 -- Facebook's scraper, preview complete.

fb_probe.py read now also reports emails, phone, category_list, location,
single_line_address and hours, ONE FIELD PER CALL: a batched fields= list fails
whole when any member is unreadable, which would let one refused field hide the
other five. Refusals are logged verbatim and never retried; "null" and "not
returned" are logged apart. hours is never returned by Graph, which is why B4's
read-back had to come from the rendered page.

Also corrects the "Business & legal" header, which read 12 rows (P2 5) over a
section holding 11 (P2 4); with R-920 it is 12 (P2 4, P3 1, P4 7). Only the
section this commit edits -- the other drifting headers belong to a session
that owns the register.

No post, no invite, no money, no app or portfolio change, website unchanged.
2026-10-09 10:28:30 +02:00
admin 02a54e26f5 dooplex-offsite: failure mail survives the shared config's unset variable (found by the live dry run); Part B push + restore evidence
gates / gates (push) Successful in 5m6s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 10:15:10 +02:00
admin 1707c928a9 dooplex-offsite: nightly encrypted copy of Gitea + DooPlex secrets to ep0, restore test, failure mail (R-232 b/h)
gates / gates (push) Successful in 5m4s
Part A plan + readings, Part E read-backs (R-861 a, R-518) in audits/dooplex-survival-2026-10-09/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 10:08:31 +02:00
admin 69fa9cf784 ep0-copy-gc: read ep0's real {"data": [...]} namespace answer; any other shape aborts (found on the first live dry run, guard held)
gates / gates (push) Successful in 4m31s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-09 07:30:18 +02:00
admin e9e6300cfc Spike: Facebook Page reached after the operator's Page click; scheduled post + photo created, read back byte-equal, deleted
gates / gates (push) Successful in 4m35s
Read phase passes (Page 1360018983863273, CREATE_CONTENT/MODERATE/ANALYZE, page token PAGE expires_at 0, three insights
metrics alive on v26.0). Write test: removal check accepts Meta's code-10 'Object does not exist' (fixed without a row,
4 tests); run 1 evidence kept. R-914 READY, R-915 narrowed to Live mode.
2026-10-08 18:38:25 +02:00
admin ff276ed7d9 Spike: Facebook Page access probe — key valid and non-expiring, reaches no Page (R-914, R-915 opened)
gates / gates (push) Successful in 4m34s
scripts/facebook/fb_probe.py (stdlib, read + write-test, no real-post command) with tests; read run twice:
SYSTEM_USER, expires_at 0, /me/accounts empty, so D/E did not run and nothing was posted. Findings, redacted
evidence, CONTEXT decision home, STATUS item, scripts CHANGELOG, REPORT-facebook-page-api.md.
2026-10-08 18:03:27 +02:00
admin fe0dc0d03f Decision sheet D1-D10: hub CHANGELOG, architecture notes (01, 04, 05, 07, 08, 10), register (VERIFY states, R-912), STATUS, report; decoy suite runs in a git worktree
gates / gates (push) Successful in 4m32s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-08 15:18:31 +02:00
admin 87af859fc3 hub: operator actions for a box (D1, R-314/R-279/R-177, decision 185)
Host page "Operator Actions" card: run off-site backup now, run a check now
(fixed job list), stop / extend (1-30 days) a deletion countdown. POST
/hosts/{id}/operator-action validates against the CLOSED list before
storing (unknown -> 400, no row), stores operator_actions(id, customer_id,
action, arg, requested_at, requested_by, done_at, outcome, message), logs
who pressed (channel + address) and bumps the box's intent. The report ACK
lists pending rows as operator_actions until the box's
operator_action_results closes them (matched on id AND reporting
customer); each closed row becomes a hub-minted operator_action event
(stored, never dispatched). Unanswered after 24 h: expired. A customer
RESET cancels pending rows. Wire gate: new root + field-by-field mirror
(controller report.OperatorAction) — needs the controller commit first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-08 15:17:06 +02:00
admin 42519a776a gallery.js v2: when the last 'next' turns off, focus moves to the close button instead of the page behind (seen in the live check)
gates / gates (push) Successful in 4m29s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 13:18:40 +02:00
admin 79c53b5f1a website: one picture viewer (assets/gallery.js) for app and dashboard pictures — declared data-gallery sets, a click on the big picture closes, JS-off still opens the file; site gate 20 + 4 decoys; demo-hp language read back (hu); R-908 (old Resend key in homelab-manifests history); 131 -> 132
gates / gates (push) Successful in 4m25s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 13:14:24 +02:00
admin aaac24b05c website: the dashboard shown — 4 real screenshots per language on the home page, 2 on the technology page (controller 0.303.0, demo-hp household guest, privacy-scanned); site gate 19 (pictures in the page's language) + decoy; R-906, R-907 (dashboard defects seen); 129 -> 131
gates / gates (push) Successful in 4m12s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 12:47:48 +02:00
admin 0b6758d440 R-902 search: contact-mailer source NOT FOUND (DooPlex disks, web editor + history, 10 Gitea repos, build cache); binary kept in git; replacement plan; decoy suite takes a lock (two sessions' runs left a decoy planted)
gates / gates (push) Failing after 11m42s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 10:35:27 +02:00
admin 83e6167145 ep0-copy-gc: fail-safe guards (partial ep0 list aborts, one deletion per run, HOLD file) — from the commit security review; still not installed
gates / gates (push) Successful in 4m0s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-08 09:58:00 +02:00
admin 05becb04d0 R-901: a deleted customer's audit rows go 1 year after the deletion (hub, unreleased); ep0-copy removal job written, not installed (decision 181); both times in the privacy draft
gates / gates (push) Successful in 4m9s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-08 09:54:39 +02:00
admin aa843a2fa0 decoy suite: fake register ids R-903..907 -> R-99903..99907 (the real register reached R-903; the hook refused the push)
gates / gates (push) Successful in 3m55s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 09:25:26 +02:00
admin 803af4798d website: the language switch becomes a globe like the dashboard's (Magyar / English list, current marked, no JS); site.css v3; gate 13 checks the globe from one LANGS list; 5 decoys
gates / gates (push) Successful in 3m54s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 09:13:23 +02:00
admin 67b3fd23d1 website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
gates / gates (push) Failing after 13m1s
Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected
from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed
mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube,
radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins,
nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py
twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11,
§10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-08 08:29:17 +02:00
admin ab3b7ea2f4 hub v0.143.0 (code): the kernel lane — the day-before household mail, the night instruction, the operator's kernel set (R-836, decision 172)
gates / gates (push) Successful in 2m47s
KernelDue / KernelNotify (09-20 h Budapest, one per 20 h, max 3, registered
address, only an accepted mail counts) / os_update.kernel {kver, tonight}
(no mail, no step) / layer kernel ingest + operator events / Approve kernel
set after every ring-0 box booted it healthily after a night stage / two
System page cells. 11 §5.11 written; §5.10 status corrected (proven).
Installer uninstall knows the two GRUB generators (unreleased).
Evidence: audits/kernel-lane-2026-10-07/ (red-proofs, boot timing).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-07 15:34:14 +02:00
admin f5400268a7 CHANGELOG: R-444 hub half (unreleased), R-502 full-run gate
gates / gates (push) Successful in 2m41s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 11:31:12 +02:00
admin a411cde7c4 R-444: hub half — the System page shows each box's last disk trim
sysfacts reads the agent's top-level guest_disk_trim stanza (schedule + per-guest
last attempt: vmid, last_attempt_at, ok, bytes_trimmed, mounts, duration_seconds,
last_ok_at, error) into a field-by-field mirror. The System page's new 'Last disk
trim' column shows the last successful trim and the GiB it freed; amber when the
newest attempt failed (error shown) or last_ok_at is older than 14 days (judged on
the success time, never the attempt time); '—' when the agent sends no stanza.
wire_contract_gate: SUBTREE_MIRRORS checks guest_disk_trim field by field BOTH
ways against sysfacts.DiskTrim; decoys (ok renamed, last_ok_at dropped) in
test_gate_decoys.py. Decision 139.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 11:29:17 +02:00
admin 9d39faabf8 R-502: the ISO first-boot harness is a gate, full runs only, "not checked" without docker
iso_bootstrap_gate.py runs scripts/iso/test/bootstrap-modes.sh in felhom-iso-assistant:trixie
(staged copy, read-only mount, --network none), registered fast=False in repo_gates.py so the
pre-push hook and CI (both --fast) never run it (decision 147). No docker / no image / docker
error -> exit 2 NOT CHECKED. Every green run is followed by a built-in decoy: the harness must
FAIL a bootstrap whose pairing banner never paints (R-496 shape), or the gate convicts the
instrument as blind. Docker-free decoys in test_iso_bootstrap_gate.py (fake docker on a
one-directory PATH), run from test_gate_decoys.py (COVERS).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 11:29:17 +02:00
admin 8c65ff0cf2 ten operator rulings recorded (09 §3 139-148, A for all; CC's pick differed on 2, 8, 9); decoy test survives a missing REPORT.md; session REPORT.md
gates / gates (push) Successful in 2m24s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 11:12:43 +02:00
admin e6cfe6d6ae installer 1.32.0 published and read back (sha = tag); its nine rows closed (164 -> 155); golden 0.299.0 baked (pinned) for controller v0.299.0 (R-889)
gates / gates (push) Successful in 2m37s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 08:14:36 +02:00
admin d41ea5486b burn-down night: decoy exemptions emptied (R-426 closed); R-889 opened (disk percent vs df); ctrl-d rows recorded; decision 136; section counts recounted (164)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 02:12:31 +02:00
admin e6fe731987 decoy coverage: 8 exemptions removed (agent + catalog suites, R-426; 4 left, controller)
gates / gates (push) Successful in 2m25s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:45:49 +02:00
admin 6534876e88 burn-down night: R-426 felhom.eu decoys (16 -> 12 exemptions; three foolable gates fixed), decision 135
gates / gates (push) Successful in 2m9s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:16:45 +02:00
admin 1ed0eba41d R-426: decoy-coverage names stale exemptions; dead offbox-rename entry removed
controller/offbox-rename kept its EXEMPT entry after R-425 gave it decoys, so
the debt list read longer than the debt. The gate now prints a STALE EXEMPTION
line for any exempt gate that has a decoy (named, not convicted: the decoy lands
in a sibling repo, and failing this repo's push for it would couple the two).
A check in test_gate_decoys.py plants a stale entry and asserts it is named;
seen to fail with the notice removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:15:19 +02:00
admin b4e4b1b3c6 R-426: one-register reads the leading verdict; decoys added, exemption removed
DONE/IDEA were searched over the whole state cell, so an open ROADMAP row whose
state named ANOTHER row's verdict (`READY — split out after R-86 CLOSED`)
escaped as shipped — R-87's shape from R-378, one file over. The gate now reads
register_table.leading_verdict(state); all 28 current rows classify unchanged.
Decoys: that shape (seen to PASS against the old gate), an id present in the
register only as prose (seen to PASS when `have` is loosened to any mention),
the existing suffix-id row; genuine: a row with a counterpart, and an `idea` row
asserted BY DESIGN — R-424's hole, accepted by the operator 2026-10-05.
EXEMPT drops `felhom.eu/one-register`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:15:19 +02:00
admin dc9ecba9bf R-426: due-checks gate gets decoys; exemption removed
Four cases in test_gate_decoys.py, planted inside the real DUE-CHECKS block:
an orphaned check whose id survives only in prose, the due-TODAY boundary with
due-tomorrow as the genuine article (today pinned via FELHOM_GATE_TODAY to a
date before every real check), and the block's marker named in prose (exit 2).
Each convicting decoy was seen to PASS under a mutation of the gate (row match
loosened to the bare id; `<=` to `<`; duplicate-marker refusal removed). The
gate itself is unchanged — no hole found. EXEMPT drops `felhom.eu/due-checks`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:15:19 +02:00
admin c6c6cb7676 R-426: hostinstall gate gets decoys; two live holes closed, exemption removed
The R-185 check counted the bare word `felhom-backup-target-apply grant`, so the
dry-run echo stood in for a deleted real grant (2 resolutions, 2 "grants"); now
only path-qualified invocations at a command start count. The age check matched
a commented-out install; now comment lines are excluded. Decoys (plus a version
const in a new hub sub-package, and a comment naming the identifier that must
pass) live in test_gate_decoys.py; all three convicting decoys were seen to PASS
against the pre-fix gate. EXEMPT drops `felhom.eu/hostinstall`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 01:15:19 +02:00
admin d4f8efa1b3 golden 0.298.0 baked (pinned Docker set; the first unpinned bake replaced before any vouch); golden gate test on the gate's UTC clock; bake runbook names GOLDEN_DOCKER_PKGS
gates / gates (push) Successful in 2m21s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-06 00:47:45 +02:00
admin 68df84bcaa R-426: instructions gate decoy moved into the felhom.eu suite; its exemption retired
A version literal in a CLAUDE.md's effective text must convict; the same inside an HTML comment
must pass. Seen failing with the version regex disabled.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:45:04 +02:00
admin bf1798479d R-422: reuse_refs_check checks .md citations too
PATH_RE gains .md. The false-positive walk across all four repos found one: an audit document cited
by app-catalog's REUSE.md, hidden by the evidence-copy exclusion — excluded trees are now walked for
.md documents only, so a .go evidence copy there still never satisfies a citation. The KNOWN HOLE
decoy now expects a conviction.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:45:04 +02:00
admin 7ee00d59a8 R-325 (felhom.eu half): hub_copy_gate accepts the controller gate importing the shared stem list
Once retrieval_promise_gate.py imports customer_copy_vocab and drops its STEMS literal, the drift
check reads "ok — single source" instead of failing on the missing literal. An import only in a
comment, or beside a stale literal, is still drift. Pinned by scripts/test_hub_copy_drift.py.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:45:04 +02:00
admin 900e6d86e2 R-315: wire-contract gate checks mirrored roots field-by-field and prints each root's check kind
The escrow/retained and escrow-ACK wires are now compared path-by-path against the receiver's named
mirror type, so the measured mutation (agent renames superseded_at, the old name still a local-API map
key) convicts. Decoy pair in test_gate_decoys.py, seen failing with the mirror removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:45:04 +02:00
admin 86def579ed burn-down night: installer 1.32.0 on main (R-275 R-276 R-881 R-306 R-130 R-180 R-179 R-310 R-274; ships with installer-v1.32.0), decision 131; agent halves R-349/R-25 recorded; R-444/R-99 need the operator; R-531 closed stale (196 -> 195)
gates / gates (push) Successful in 2m2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:27:42 +02:00
admin f790734ec2 R-274: the BYO disclosure names the golden it reuses; the local-golden check is pinned
The check itself shipped with R-297 (golden_local_matches_manifest: sha256 or controller version
against the hub manifest; mismatch re-fetches, a named --golden is refused). This adds the
disclosure line the row also asked for and tests that pin the check's place before the adopt.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin b43705ac7b R-310: the golden refusal states the vouched version once; an uninstall with no terminal refuses in words
- The R-297 named-golden refusal no longer repeats "The vouched golden is X." when its reason
  already says it (kept when the reason does not name the version).
- --uninstall checks it can open /dev/tty before the typed vmid confirmation and, if not, refuses
  with a sentence (deliberate; --force does not skip it) instead of "/dev/tty: No such device".
scripts/test_hostinstall.py: test_golden_refusal_* (2), test_require_tty_* (3, with a pty control).
The runbook line naming the pty requirement is a documentation edit for the lead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin c11d4fbf2e R-179: the uninstall removes the NAS network-storage units
Units carrying the agent's network-storage marker (mnt-*.automount first, then mnt-*.mount) are
disabled --now, reset-failed and removed before the drive umount loop; a share that will not stop is
not forced — its unit is kept and named in KEPT with the commands. Enrolled-drive and foreign units
are never touched. scripts/test_hostinstall.py: test_net_units_* (5).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin 7f3944eff9 R-180: refuse in pre-flight an archive storage the agent's token will not be granted on
The step-8 restore reads the golden as the agent's token; a storage outside PVE_STORAGES (and not
the backup target, which step 6 grants since R-185) 403'd at step 8/8 — after the token was minted
and root@pam rotated. Pre-flight now refuses it with the two remedies (move the golden, or add the
storage to --acl-storages). scripts/test_hostinstall.py: test_archive_storage_* (4).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin efe76093ce R-130: the local-lvm minimum is named as what it does — a recommendation that warns
HARD_MIN_LVM_GIB -> RECOMMENDED_MIN_LVM_GIB; the warning says the install continues and to proceed
only with deliberately sized grows (the day0-install runbook's wording). Behaviour unchanged.
scripts/test_hostinstall.py: test_lvm_minimum_is_named_as_what_it_does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin 17af3b65f6 R-306: --preflight-only writes no state
_state_put and _state_mark are no-ops under --preflight-only as well as --dry-run, so the banner
"no state written" is true and the dnsmasq ownership answer is recorded only by the real install's
own preflight. The log says "would be recorded at install" on a preflight-only run.
scripts/test_hostinstall.py: test_preflight_only_writes_no_state (+ its control and a no-other-writer check).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin 85de3f9b87 R-275, R-276, R-881: the uninstall removes every copy of the agent config, the WireGuard tunnel and felhom-priv-apply
- R-275: the agent's own config dir is purged as a directory (the .bak* glob missed all five
  demo-hp copies); a custom config path loses agent.json + every agent.json.* sibling only.
  Sudoers dotted copies go too. At install, a freshly created service user cannot read what an old
  install left in /etc/felhom-agent (sealed root 0600, named, never deleted). vmbr9 and the ISO
  first-boot files are now NAMED under KEPT.
- R-276: wg-quick@wg-felhom is disabled --now and its conf removed, then observed down; the hub-side
  peer is named under KEPT (removing it is the hub's job).
- R-881: /usr/local/sbin/felhom-priv-apply is removed; the disclosure says it and the guest hook
  come from the config bundle.
- scripts/test_hostinstall.py: lifts the functions verbatim and runs them with PATH stubs (13 tests,
  BusyBox-safe); harness GL4-D here-string (SIGPIPE false miss), GL8-F1 follows the new purge.
- SCRIPT_VERSION 1.32.0 (not published; no tag).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:25:21 +02:00
admin c8da8e0439 burn-down night: rulings §1 recorded (09 §3 decisions 128-130); R-888, R-337, R-375 closed by ruling; R-126/R-856 rulings in their rows; night log (199 -> 196)
gates / gates (push) Successful in 1m57s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 21:09:04 +02:00
admin 557629d2bf hub v0.137.0 source + burn-down round 2 in felhom.eu: R-277 R-581 R-600 R-544 R-855 R-134 R-92 R-292 R-599 R-725 R-728 (hub), R-819 R-857 R-555 R-364 R-587 (gates/tools), R-571 R-129 R-124-runbook (docs); 28 rows closed incl. catalog + agent v0.147.0 rows, R-350 merged into R-132, R-888 opened, R-887 mechanism (249 -> 222)
gates / gates (push) Successful in 2m3s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 19:43:37 +02:00
admin 40d34c5576 hub-db-backup: parse the snapshot time in a form BusyBox date reads (CI red since ab2b304: 9/15 on the Alpine runner)
gates / gates (push) Successful in 1m46s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 17:29:05 +02:00
admin 8012ce4640 burn-down: R-423 site page walk (exemption dropped); STATUS Part C list (45 rows for the operator); REPORT; register 336 -> 291 (0 opened, 45 closed)
gates / gates (push) Failing after 13m1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 17:15:02 +02:00
admin b26d292a64 burn-down Part B: 14 small rows fixed and closed across four repos (306 -> 292); no :latest in the hub build; gate list pinned; closed-id duplicates refused; R-262 subset pinned
gates / gates (push) Failing after 1m40s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-05 17:10:38 +02:00