Files
felhom.eu/documentation/backlog
admin b080ecf411 hub v0.99.0 — the hub can see whether the operator can get in (R-260); G-1 gate closes, R-247 closes
oobDegraded tested five things and the sixth never arrived.

The agent has emitted `operator_key_configured` on every heartbeat since v0.72.0 — the SAME version
that introduced the `oob` stanza carrying it — and store.HostOOBRow mirrored five of the agent's
eight OOB fields. With no field for it, encoding/json discarded the fact on arrival, so a box with
felhom-sshd active, reachable, a valid config and a configured peer reported `ok` with NO OPERATOR
KEY INSTALLED AT ALL. Not a wrong answer: an answer to a question nobody was asking.
`operator_peer_configured`, which the hub did read, only says the peer IP is in desired-state — that
OOB is MEANT to work, not that entry is possible.

Now decoded: operator_key_configured, plus wg_handshake_age_s and healed_at. The last two ride the
ALERT TEXT and are deliberately NOT in the predicate — widening a check beyond the fact that is now
arriving is how a check stops being read.

SCENARIO F, decided on a measurement rather than a preference. operator_key_configured decodes as a
POINTER: nil = the agent never said, reported distinctly and never as ok. The version gate was
rejected because the field and its stanza shipped in the SAME agent version (v0.72.0), so a stanza
without the field cannot come from any released agent; the fleet is 0.113.0/0.127.0 and the vouched
floor is 0.127.0. Handled explicitly anyway and pinned, because "cannot happen" is a claim this
project has been burned by.

THE MESSAGE NAMES THE FAULT. oobDegradedReason is the single source for both predicate and text, so
the alert can never name a different fault from the one that fired. The old form derived it
separately and had a vocabulary of two — unreachable, or config invalid — with no way to say the key
is missing. The operator reads this at 07:00.

TESTS DRIVE THE DECODE BOUNDARY. Every hub OOB test before this built a HostOOBRow by hand, and a
test written that way CANNOT SEE A FIELD THAT NEVER DECODES — which is how this held a green suite
for five weeks. The pre-existing fixture oobReport() also omitted the field, so those scenarios ran
against a report shape no released agent produces (same family as R-262). Both fixed.

Red-proofs, 8 expected outcomes and 0 wrong, each with the mutation asserted applied: dropping the
field returns the false ok; an unconditional check alerts a healthy box; unknown-as-ok restores the
silent pass.

G-1 CLOSED — scripts/wire_contract_gate.py shipped as ranked, built BEFORE the fixes and seen
failing on 40 fields (documentation/tests/wire-contract-gate-2026-08-08/BEFORE.md). Two instrument
defects the control caught first: a substring false negative (grep -F healed_at matched
privsep_healed_at) and treating dr_recipe as wholly opaque when its top-level sections ARE decoded
through an allow-list that already cost offsite_restic (R-122).

The prompt for this session said "465 emitted tags, eight unreachable". Checked against the repo:
R-260 said "at least eight DECISION-BEARING facts", never eight tags. The real count is 40.

R-260 CLOSED (class gated, sharpest instance fixed). R-247 CLOSED (controller v0.209.0). R-264
MINTED and OPEN — the 21 facts with no consumer, allowlisted with reasons so that gating the class
could not be mistaken for deciding them. Still open and named: R-246, R-255..R-259, R-261..R-263,
and C7's test-comment half.

Capability map checked: it claims OOB access is implemented, never monitored, so no row was untrue;
what was untrue sat one layer down and the row now records it.

repo_gates --fast: all 8 OK. go build/vet/test green in hub, run separately from this commit.
2026-08-08 08:47:02 +02:00
..

documentation/backlog/

OPEN-ITEMS.md is the register of open work and the file to read first — it holds only what is open, one row per item, every row with a state and an owner. ROADMAP.md is the full history and reasoning behind the R-n IDs, including shipped and killed items; an ID is minted there, and a new instance of an existing item attaches to that ID rather than getting its own.

The rest of this folder: verified-LIVE findings with implementable fix plans that are not yet implemented. Preserved here (instead of on git branches) per the trunk-based, no-branches rule — the fix itself is implemented later directly on main, during a normal/supervised session.

  • FIX-M18-NOTES.md — dump re-validation runs every 5 min (perf). FIXED in controller v0.62.0 @ f8afe5c (2026-06-14). (was on the deleted felhom-controller branch fix/m18-dump-validation-cache.)

  • FIX-M19-NOTES.mdderiveStackName misattribution edge (low-incidence correctness). FIXED in controller v0.62.0 @ 6bab68b (2026-06-14). (was on the deleted branch fix/m19-stackname-crossref.)

  • FOLLOWUP-golden-default-controller-tag.md — the golden bakes a stale controller (:0.43.0 when queued; had rotted again to :0.85.1 by resolution). FIXED in felhom-agent @ ceca355 (2026-07-03): build-golden.sh v2.0.0 makes the controller tag a MANDATORY argument (a required arg cannot rot) and golden 0.98.3 was baked + clean-room-validated (bake → first-boot-current → self-manage → app deploy, on the drill VM — no supervised touch of live guests needed) + published + vouched. Evidence: ../audits/DRILL-golden-098-2026-07-03.md.

Related: the live-drive fixspec (../audits/live-drive-fixspec-2026-06-14.md) carries the deferred supervised items F9 (HDD provisioning/guest-attach), F20-BUG2 (durable_id scheme), F20-BUG3 (async mkfs) — to be implemented in the agent/golden supervised session.