Files
felhom.eu/documentation/README.md
T
admin a08bd3cbd5
gates / gates (push) Failing after 5m29s
architecture: the system poster committed, its facts given a home, and a rule to keep them together
PART A -- the poster. documentation/architecture/felhom-system-poster.html
(307 KB). Secret scan first: ZERO IPv4, zero PEM blocks, zero ssh keys, zero
Bearer. The one EAA... match is base64 inside an embedded "mime":"font/woff2"
blob, not a Facebook token. "token"/"secret"/"password" appear 11 times and
every one is a NAME ("6. ep0 read token", "the hub seal key"); the poster
itself says "Names only; no secret values". All five long base64 blobs are
declared assets: 1 image/png, 3 text/javascript, 1 font/woff2.

It renders with NO network: the source mentions cdn.jsdelivr.net and Google
Fonts, but the loaded requests are only the HTML plus blob:/data: URLs -- the
bundler inlined everything. Measured, not assumed, and it matters: this is a
disaster-recovery document, so needing the internet to draw would be a defect.
No console errors.

The operator's three Claude Design fixes are all present: (a) no "WG" badge,
WireGuard only for the tunnel, no badge on the ep0-copy tile; (b) the box ->
ep0 arrow reads "encrypted on the box, sent through WireGuard"; (c) "Known
gaps" holds two items and NOT the household-keys sentence, which is now a
neutral "By design" note under the ep0 household namespace.

ONE FACT ON IT WAS WRONG. The felhom.eu tile said "served from DooPlex through
Cloudflare". It is not: Cloudflare is DNS only and the traffic goes direct --
measured this morning for the privacy notice, which states exactly that. The
poster would have contradicted a published page. Fixed in place (a label):
"served from DooPlex, Cloudflare DNS only". The first wording overflowed the
fixed-size tile, so it was shortened to fit and the evidence lives in the
facts file instead -- checked by re-rendering, not by hoping.

PART B -- the facts and the rule. DESIGN-PROMPT-...md is renamed
felhom-system-poster.facts.md (one home per fact), with the three fixes folded
in as explicit instructions so a regeneration cannot undo them, plus a new
"Badges" section saying a "WG" chip must never come back.

New rule, section 6 "The system poster stays true", added IDENTICALLY to all
five copies of unprompted-work.md (the four repos and the workspace root on
DooPlex; verified identical by diff before and after) and to
PROMPT-TEMPLATE.md's end-of-session checklist as a FIFTH coupled artifact.

scripts/poster_facts_gate.py WARNS when the facts file has a newer commit than
the poster. It never fails a push, deliberately: a refresh needs Claude Design
and the operator, --no-verify is forbidden here, so a blocking gate would leave
deleting it as the only way out. It compares COMMIT times, not mtimes, because
a checkout rewrites mtimes and every fresh clone would shout.

RED-PROOF -- and it found a real bug in the gate. The first run warned
correctly but exited 1: a single non-ASCII character in its own warning raised
UnicodeEncodeError on this cp1250 console. A gate whose entire contract is
"never fails a push" was failing pushes. Fixed (ASCII output + an encode
guard), and the decoy now asserts BOTH the warning and exit 0. Three branches
proven: facts newer -> warns, rc 0; poster newer -> quiet, rc 0; poster
missing -> "could not tell", rc 2, not a false all-clear.

The decoy itself was seen to fail, twice, on Linux (the suite needs fcntl and
cannot run on Windows): breaking the warning gives STALE_WARNS=False, and
making it exit 1 gives RC_STALE=1. All 80 felhom.eu decoys behave.

PART C -- do box reports pass through Cloudflare? NO. Two channels. DNS from
PUBLIC resolvers (not DooPlex's own, which answers the LAN address):
hub.felhom.eu is a CNAME to dooplex.hopto.org -> 37.191.56.193, not a
Cloudflare address, and no cf-ray comes back. The manifest: an ordinary k3s
Ingress, Cloudflare named only in a DNS setup comment. THE CONTROL that makes
the negative mean something: iso.felhom.eu resolves to 172.67.x / 104.21.x,
real Cloudflare addresses -- so the method does detect proxying.

So nothing is added to the Cloudflare row: the hub path does not touch it.
06-offsite-connectivity.md section 1 claimed the public edge is a
Cloudflare-Tunnel and "DooPlex has no public IP" -- both untrue today. Kept
and marked STALE with the measurement rather than rewritten, because that
paragraph is the reason ep0 exists and the argument needs its premise visible.
total-loss-of-dooplex.md's "today a CNAME to dooplex.hopto.org" is confirmed
correct.

Register: 137 before, 137 after, 0 opened, 0 closed -- every finding here was
small and fixed in the session.
2026-10-09 18:09:50 +02:00

57 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Felhom — Documentation
Felhom is a managed home-server service for Hungarian households, built on a **three-component model**
over Proxmox:
- **Hub** — operator backend on k3s (`hub.felhom.eu`). Repo: `felhom.eu/hub/`.
- **Host agent** — one per Proxmox host; operator-tier; owns all Proxmox interaction. Repo: `felhom-agent/`.
- **In-guest controller** — one per customer LXC; Docker-only; manages the customer's apps. Repo: `felhom-controller/`.
This directory is the central, code-verified documentation home for all three components plus the
platform and the security-audit record.
## Sections
### Controller (in-guest) — `controller/`
The Docker-only app-domain controller. Full per-area docs grounded in current source (v0.59.0).
→ [`controller/README.md`](controller/README.md): module map, deploy & stack lifecycle, backup
architecture, storage/monitoring/metrics, auth/hub/sync/integrations.
### Where we stand — `architecture/where-felhom-stands.*`
The operator's one-page picture of what is proven, built, partial and missing.
- [`architecture/where-felhom-stands.html`](architecture/where-felhom-stands.html) — **generated**; do not hand-edit
- [`architecture/where-felhom-stands.yaml`](architecture/where-felhom-stands.yaml) — the data behind it; every claim cites its source. Gate: `scripts/check_stands.py`; regenerate with `scripts/render_stands.py`
- [`architecture/where-felhom-stands-2026-08-09-snapshot.html`](architecture/where-felhom-stands-2026-08-09-snapshot.html) — **a dated snapshot, NOT maintained.** The original React bundle, kept for the record; its statuses are those of 2026-08-09 before the verification pass
### The whole system on one page — `architecture/felhom-system-poster.*`
A poster for the operator: every machine, path, backup tier, time and key on a single sheet.
- [`architecture/felhom-system-poster.html`](architecture/felhom-system-poster.html) — the drawing. **Made in Claude Design, NOT generated by anything in this repo**, so do not expect a renderer; it is self-contained (fonts and scripts are inlined — it opens with no network)
- [`architecture/felhom-system-poster.facts.md`](architecture/felhom-system-poster.facts.md) — **the source of every fact on it. Change the facts here first.** Rule: `.claude/rules/unprompted-work.md` §6. Gate: `scripts/poster_facts_gate.py` WARNS (never fails) when this file has a newer commit than the drawing
### Host agent & platform — `architecture/`, `proxmox-platform.md`
The operator-tier agent and the Proxmox platform.
- [`architecture/01-topology-and-trust.md`](architecture/01-topology-and-trust.md) — topology & trust model
- [`architecture/03-host-agent.md`](architecture/03-host-agent.md) — the host agent (Go; v0.29.1)
- [`architecture/04-control-plane-authorization.md`](architecture/04-control-plane-authorization.md) — signing, escrow, authz
- [`architecture/02-controller-module-map.md`](architecture/02-controller-module-map.md) — **historical** v0.33 planning map; the live map is [`controller/module-map.md`](controller/module-map.md)
- [`proxmox-platform.md`](proxmox-platform.md) — Proxmox platform reference
- [`architecture/11-os-updates.md`](architecture/11-os-updates.md) — operating-system updates: host, guest, Docker engine (**NOT RATIFIED**, 2026-10-04)
### Hub (operator backend) — `architecture/05`
- [`architecture/05-hub-architecture.md`](architecture/05-hub-architecture.md) — hub architecture (v0.11.0)
### Security audits & remediation — `audits/`
- [`audits/deep-sweep-2026-06-13.md`](audits/deep-sweep-2026-06-13.md) — cross-repo deep audit (controller + agent) with remediation status
- [`audits/bughunt-reconcile-2026-06-13.md`](audits/bughunt-reconcile-2026-06-13.md) — reconciliation of the v0.30.3 BUGHUNT against current code + merged fix list
### Spike & test findings — `tests/`
Per-slice spike/validation findings (phases 0–5, slices 7–10). See [`tests/`](tests/).
## Conventions
- **Code-verified, not memory-derived.** Architectural claims here are checked against the actual
current source; if a claim can't be verified it is omitted and flagged, not guessed.
- Per-repo operational working files (`CLAUDE.md`, `CONTEXT.md`, `CHANGELOG.md`, `BUGHUNT.md`,
`REPORT.md`, `TASK.md`) live in their own repos — they are operational, not published docs.
- Authoritative versions at last refresh: controller **v0.59.0**, agent **v0.29.1**, hub **v0.11.0**.