Commit Graph

92 Commits

Author SHA1 Message Date
admin db0812b6f2 Golden 0.227.1 baked, vouched, floor raised — and the floor delivered the new job by itself
gates / gates (push) Successful in 16s
Second full delivery of the day. golden_currency_gate.py went red -> green on
the same command, so the --no-verify bypass declared on the previous push is now
historical rather than standing.

  GOLDEN_VERSION  0.227.1
  GOLDEN_SHA256   66754491dc9bd0130ef8ded9562f63c53a5ffdcfd91baa551141e55fa083ea32
  size            657 403 203 B
  baked           gitea.dooplex.hu/admin/felhom-controller:0.227.1
  MinAgent        0.129.0  (read from the controller CHANGELOG header, not assumed)

THE EVIDENCE IS THE ROUND TRIP. The published bytes were downloaded back -- size
and sha256 identical to what the bake reported -- and ./etc/felhom-controller-
image was read OUT of the downloaded archive: felhom-controller:0.227.1. That is
the delivered artifact naming the controller it will start, from the bytes a
customer's box would actually fetch.

Markers counted: docker OK (overlay2 = 1, mount point rootfs = 1, mp0 = 1,
upload OK (HTTP 201) = 1; excluding = 0, FATAL = 0, mp1 = 0. 404 pre-gate passed
before the run and the script's own pre-delete agreed, so nothing was
overwritten.

Three-field vouch, all three checked: agent_version 0.130.0 >= min_agent 0.129.0
(NOT the R-216 shape), wrapper_sha256 carried through explicitly because the
handler clears it when omitted. Verified by RE-READING the manifest rather than
trusting the flash. The R-120 gate on that POST passed on its own terms rather
than being worked around.

AND THE LINE WORTH KEEPING. demo-felhom self-updated 0.226.1 -> 0.227.1 in under
30 seconds and then logged:

  [INFO] [scheduler] Daily job offsite-integrity scheduled for 2026-08-31 06:00 CEST

A box nobody deployed to now runs today's off-site integrity check on its own
schedule. That is a floor DELIVERING rather than merely recording, observed
instead of assumed -- and it is the strongest evidence R-242 has carried.

Token hygiene: file->file, read inside the VM by a runner script, never on a
command line (systemctl show ... grep -c -F token = 0). The leak grep on the
committed log was PROVEN TO WORK before its 0 was believed.

Teardown: guest 9100 destroyed --purge, secrets shredded AFTER the log was
copied out, VM powered off, disk reverted to virgin.

R-242 now records the cadence as MEASURED: five convictions and two full bakes
in one day. Every bypass declared, every debt paid -- and the pattern the row
exists to name is exactly that a release and its delivery are separate acts. Its
other half stays open: nothing gates the VOUCH itself.
2026-08-30 21:48:15 +02:00
admin 99af997ab9 R-359/R-397 closed, R-398 corrected, R-399/R-400 filed with measured numbers
gates / gates (push) Failing after 18s
THE MEASUREMENT IS THE STORY, and it re-frames the row it was filed under. A
pack was corrupted WITHOUT changing its size; plain `restic check` -- the depth
that ships ON -- returned `no errors were found`, exit 0. Only --read-data
caught it. So the check that shipped verifies the index, the pack inventory and
the snapshot graph, and does NOT re-hash pack contents. R-399 was filed as a
bandwidth-and-cadence question; it is more than that, and its row now says so.

R-399 gets three MEASURED numbers instead of estimates: store 140 829 678 B /
2651 blobs / 67 snapshots; structure check 35.0 s; curve 10% 35.9 s, 50% 37.3 s,
100% 39.2 s. At this size re-reading everything costs four seconds more than
reading none, because the wall clock is SFTP round-trips not transfer. The row
states the limit too: these do NOT extrapolate.

R-400: the sweep the task asked for found EIGHT dead debug buttons, not one. 24
endpoints referenced in debug.html, 17 dispatched. Single dispatcher, exact
match, default NotFound -- so they 404. A third of a debug page does nothing, on
the surface an operator reaches for when something is already wrong.

R-398 is CORRECTED AND LEFT OPEN, not closed. I filed it yesterday saying
resticStep is not a seam so no test can drive a restic path. The layer below it
has been injectable since the off-site tier shipped. The row survives as the
record that the seam EXISTS so nobody re-files it.

07 gap register: R-359 and R-397 closed; R-87 restated IN PLACE as "AND IT IS
NOT R-359" because the two rows are adjacent and a check is not a restore-test.
08 alarm ladder: both event types recorded, including that `ok` is `info` and
therefore mails nobody BY DESIGN, and that all three registers were checked and
deliberately left alone. 00 capability map: PROVEN-LIVE for the check, the
notifier and the hazard control; the scheduled firing is IMPLEMENTED only,
because a week has not passed.

wire_contract_gate: `offsite.last_integrity_ok` allowlisted WITH A REASON. The
gate was right -- the controller emits a field no hub struct can decode.
Building the display is a hub change and R-331 ruled that class the operator's
decision; the entry says to delete it when a surface exists.

This push used `git push --no-verify`. golden-currency is CONVICTED and right:
0.227.1 is released and the golden carries 0.226.1. A BYPASS, not a waiver, and
the task spec directs it -- golden and fleet delivery are Viktor's (R-242). It
is item 3 under "Waiting on you".

Register 163 -> 165 -> 163.
2026-08-30 21:29:37 +02:00
admin 4f875174fe Golden 0.226.1 baked, vouched, and the fleet floor raised — the debt is paid
gates / gates (push) Successful in 17s
golden_currency_gate.py had been CONVICTED four times today across three
controller releases. One bake covers all three, and the gate went red -> green
on the same command, which is its proof that it measures something real. THE
THREE DECLARED BYPASSES ARE NOW HISTORICAL RATHER THAN STANDING.

  GOLDEN_VERSION  0.226.1
  GOLDEN_SHA256   70ed8e9377dec22a9b493e55f222b0e25a49d7f3caec8c506e0412fd6baefe69
  size            657 197 592 B
  baked           gitea.dooplex.hu/admin/felhom-controller:0.226.1
  MinAgent        0.129.0  (read from the controller CHANGELOG header, not assumed)

THE EVIDENCE IS THE ROUND TRIP, NOT THE BUILD LOG. The published bytes were
downloaded back -- size and sha256 both identical to what the bake reported --
and ./etc/felhom-controller-image was read OUT of the downloaded archive:
`felhom-controller:0.226.1`. That is the delivered artifact naming the
controller it will start, from the bytes a customer's box would actually fetch.

Acceptance markers counted, not eyeballed, each string captured from this run's
own log rather than paraphrased from the runbook (two of the three the runbook
named until R-233 could not match anything the script prints): docker OK
(overlay2 = 1, including mount point rootfs = 1, mp0 = 1, upload OK (HTTP 201) =
1; excluding = 0, FATAL = 0, mp1 = 0. The 404 pre-gate passed before the run, so
nothing was overwritten.

THE VOUCH IS A THREE-FIELD CHANGE AND ALL THREE WERE CHECKED: agent_version
0.130.0 >= min_agent 0.129.0, so NOT the R-216 shape; wrapper_sha256 carried
through explicitly because the handler clears it when omitted. Verified by
RE-READING the manifest rather than trusting the flash -- golden option 0.226.1
SELECTED, all four shas matching.

THE FLOOR IS PROVEN ACTING, NOT MERELY SET. demo-felhom self-updated within 30
seconds: "[selfupdate] Post-update startup: update successful (0.225.0 ->
0.226.1)". Both demo machines now run 0.226.1 and only one of them was deployed
to by hand.

Token hygiene: copied file->file, read inside the VM by a runner script, never
on a command line (systemctl show ... | grep -c -F token = 0). THE LEAK GREP ON
THE COMMITTED LOG WAS PROVEN TO WORK BEFORE ITS 0 WAS BELIEVED -- a throwaway
copy with the token appended grepped 1, was shredded, and only then was the real
log's 0 taken as evidence.

Teardown: build guest 9100 destroyed --purge, secrets shredded AFTER the log was
copied out (standing rule 5), VM powered off, disk reverted to virgin.

R-242's OTHER half is untouched and still open: nothing gates the VOUCH itself.
2026-08-30 20:23:52 +02:00
admin 68a9f5475c hub v0.107.0: the hub rewrote a severity and said nothing (R-387); golden 0.223.0
gates / gates (push) Successful in 17s
One handler, two fields, opposite discipline. An unknown event_type is rejected
with a loud 400. An unknown severity was rewritten to "info" without a word -
and severityNotifies drops "info" before BOTH legs, so the event was stored,
answered 200, and mailed to nobody.

Two shipped features went out that way: DiskAlertKind.Severity emitted "warn"
until controller v0.215.0, app_start_failed until v0.223.0. Measured on the live
hub DB today: 91 app_start_failed events stored all-time, ZERO notification_log
rows before this session - not one, on any channel.

The mechanism built to catch this class was structurally blind to it: the
dispatcher's `unrecognized severity` line cannot execute for anything arriving
over the API, because the coercion one line earlier guarantees the value it
looks for cannot arrive.

The coercion STAYS - a rejected event is a lost event, and losing an alarm is
worse than mis-routing one. Only the silence is fixed: a WARN naming the
customer, the event type and the rejected value.

The dispatcher branch is KEPT, not deleted as dead, and the reason is evidence
rather than caution: cmd/hub/main.go wires dispatcher.ProcessEvent DIRECTLY as
the monitor.EventNotifyFunc for the staleness, host-staleness and offsite-box
checkers, which never pass through the handler. For those it is the only
severity guard there is. All 90 severity literals in internal/monitor are
already valid, so the guard is silent because the producers are correct.

Test count 702 -> 709. Red-proof seen failing: delete the WARN line and the
coercion test fails with "the hub rewrote a severity and said nothing".

Golden 0.223.0 baked and published (sha 9eaf39ac3921...), round-trip HTTP 206.
Vouching is the operator's act and was not done here.
2026-08-23 11:57:26 +02:00
admin 55274d5ef3 R-385: make an UNRECORDED golden fail the currency gate; file R-386; own the alarm ladder
gates / gates (push) Successful in 17s
The gate failed only on `released > baked`, so it could catch a forgotten bake
and nothing else. A golden AHEAD of the record passed silently - and that is
how controller 0.221.1 was built, baked AND vouched while the newest CHANGELOG
heading still read v0.221.0, with every gate green. Reproduced on the real
history: newest released 0.221.0 / newest golden baked 0.221.1 -> exit 0.

The gate now asks whether the version being shipped is WRITTEN DOWN: the baked
version must have its own `## vX.Y.Z` heading anywhere in the CHANGELOG.
Membership rather than `baked > released` deliberately - a comparison against
the newest heading alone goes green the moment any later entry is written,
leaving the unrecorded version permanently unrecorded. INCONCLUSIVE (exit 2)
preserved; every refusal names a reason and a route.

Red-proofed both directions: old gate/old record exit 0, new gate/old record
exit 1, new gate/fixed record exit 0, absent clone exit 2, post-bake exit 0.

08-alarm-ladder.md is new, and its absence was itself the finding: no document
owned "when does a broken app raise an alarm?". The rules lived as comments in
four packages, each locally correct, with the ordering between them legible only
by reading one function top to bottom - which is how R-384 survived review.

R-383 and R-384 closed into CLOSED-ITEMS with their rules kept. R-385 filed
closed. R-386 filed OPEN: a single-container app stopped out of band raises no
alarm, and a comment claims the opposite - measured live, 9 scans, 0 events,
against a positive control from the same box 17 minutes earlier. Not fixed here.

Golden 0.222.0 baked and published; vouching is the operator's act.
2026-08-23 07:59:52 +02:00
admin 1eb64bec51 R-361 docs: the [FACT], the negative that cancelled Part 2, R-383/R-384, golden 0.221.1
gates / gates (push) Successful in 17s
07-backup-architecture.md gains a dated [FACT] on R-361 - a comment asserting an
invariant the code did not have, for four months - and a [DESIGN] on the db_dumps
decision INCLUDING the trap it created: a stable list lets the already-current
early return fire, so per-capture housekeeping must sit above it.

00-capability-map.md records the NEGATIVE from Part 3 so it is not re-derived: a
held app does NOT raise the dead-app alarm. It aggregates to unhealthy, which
IsDownState excludes. Measured on the shipped build with the scans demonstrably
running over it. No suppression was built and no row opened.

R-383: the double-failure message names an undo copy that is not there - R-361's
own class, one surface over, observed on both 0.220.2 and 0.221.1.
R-384: an app whose database has died reads unhealthy and raises no alarm.

R-361 closed and compressed. OPEN-ITEMS 325236 -> 327266 bytes.

Golden 0.221.1 baked, published and round-trip verified. The golden-currency gate
blocked this push and that block is not circular, so it was satisfied rather than
bypassed - no --no-verify anywhere in this session.
2026-08-23 00:33:12 +02:00
admin a8caa0fdde R-379/R-380 docs: the failure ladder, the drill record, register housekeeping
gates / gates (push) Successful in 17s
07-backup-architecture.md 6.3 gains a dated [DESIGN] paragraph on replay ->
rollback -> hold, including why no engine flag closes it: --single-transaction
makes Postgres atomic, MariaDB DDL is not transactional, so the rollback is the
fix and the flag is a belt.

Drill record for the live walk, including the TWO defects the walk found in the
fix itself (a rollback into a re-created container; an operator route that
cleared the file while the running controller kept refusing) and the ONE
red-proof that PASSED, which is reported rather than omitted.

R-379..R-382 compressed into CLOSED-ITEMS.md. OPEN-ITEMS 330683 -> 325236 bytes.

STATUS.md restates the outcome and names the next operator step.
2026-08-22 18:40:22 +02:00
admin 8c9f1b798b golden 0.219.0 baked, published and round-trip verified (NOT vouched)
gates / gates (push) Successful in 18s
Baked in the drill VM per RUNBOOK-manual-build.md 4.0/4.1, carrying controller
v0.219.0 (R-356).

  GOLDEN_VERSION 0.219.0
  GOLDEN_SHA256  67b46f78f8ed9c7b1876265ab1bde9ec6798897898b1836acece9f3864a2aeb6
  656832571 bytes

All five pass markers matched, both negative controls at 0. Verified by ROUND
TRIP - the published object downloaded again and its sha recomputed - not by the
number the script printed.

Both token-leak greps were proved able to convict before their zeros were
believed: planted copy grepped 1, shredded, then the 0 accepted.

Teardown complete: guest 9100 purged, four secret/script files shredded after the
log was copied out, qemu exited, disk reverted to virgin. The revert first
refused while qemu held the image, which is the runbook's own no-holder proof.

NOT vouched - that is a three-field operator save (golden_version 0.219.0,
agent_version 0.130.0, min_agent 0.129.0).
2026-08-22 13:56:33 +02:00
admin 877fcd2a38 R-354 + R-355 CLOSED, proven live; golden 0.218.0 baked; R-367 filed
gates / gates (push) Successful in 16s
Both of the drill's HIGH findings are fixed in controller v0.218.0 and confirmed on demo-hp with
a negative control first — the same planted, hash-recorded fixture run through the same steps on
both builds.

R-355: paperless-ngx's PostgreSQL was dumped into a directory for a stack that does not exist, so
it never entered the recovery unit, the off-site copy or the restore; and because the same wrong
name reached writeSafetyDump, a destructive restore took no undo copy and the fail-closed refusal
was never reached. Fixed by reading the compose project label. Sweep proven able to convict
before its count was trusted: one affected app of 53.

R-354: the off-site restore had no named-volume leg. Now it replays them from the scratch unit,
before the database and inside the stopped window, and VolumesReplayed reaches the sentence.
The half-false comment beside the skip is corrected and the half that still holds is named.

Golden 0.218.0 baked and published, sha 8e427869d13eafb71562b77d1535eef6c7f32b4db24f659b988ec6d7db8f478b,
verified by round trip on the downloaded bytes. NOT vouched and the floor NOT raised — both are
the operator's decision, and raising the floor is what puts this on demo-felhom, which is still
on 0.217.0 and still has both defects.

R-367 filed: the dumps already written under the wrong name are stranded. Nothing deletes them
(an existing guard), they are adoptable by hand, and doing it automatically would be a migration.

Ceiling R-366 -> R-367.
2026-08-22 10:11:46 +02:00
admin 059adfb8b8 golden 0.217.0 baked and published — evidence, markers and the token-leak proof
gates / gates (push) Successful in 14s
GOLDEN_VERSION = 0.217.0
GOLDEN_SHA256  = 0276c5f638d140a861daba4ef25129896e259937eec0ae5cba7af42391315ad0
archive volid  = local:backup/vzdump-lxc-9100-2026_08_21-21_40_05.tar.zst
MinAgent       = 0.129.0 (unchanged from 0.216.0)

Acceptance markers counted in this run's own bake.log, not paraphrased:
  docker OK (overlay2       1
  including mount point     2   (rootfs and mp0 — there is no mp1)
  upload OK (HTTP 201)      1
  excluding                 0
  FATAL                     0
Published package fetched back over HTTPS: HTTP 200.

Token handling: copied file->file, read by a runner script inside the VM, never on a command
line. systemctl show of the live unit contained it 0 times. The committed bake.log greps 0 for
the literal token AND the grep was first PROVEN to work on that same file by appending the token
to a throwaway copy (grep = 1) then shredding it — a 0 from an untested grep is not evidence.

Evidence copied off the VM BEFORE teardown. Then destroy 9100 --purge, shred token+runner+script
+log inside the VM (0 left), poweroff, waited for qemu using `ps -eo comm` (never `pgrep -f`,
which self-matches), and reverted the drill VM to `virgin`.

This unblocks the golden-currency gate, which correctly refused the previous push of the register
rows: "controller v0.217.0 is released and NO golden carries it". No --no-verify was used.

NOT DONE: the vouch. It is operator-gated and is a THREE-field change; vouching golden_version
alone would ship this controller onto an agent older than it declares it needs.
2026-08-21 21:43:16 +02:00
admin 7d81681d6e golden 0.216.0: baked, published, vouched — gates green again
gates / gates (push) Successful in 13s
Closes the two-release day-0 gap that has been convicting CI since
2026-08-14. Run against RUNBOOK-manual-build.md 4.0 + 4.1.

  GOLDEN_VERSION = 0.216.0
  GOLDEN_SHA256  = ac004dc90d8cefccc5448377892f9cff3a4c3e1e27d0e11129120e38ac31c34b
  archive        = 656,970,239 bytes, controller image 0.216.0
  template       = debian-13-standard_13.6-1_amd64.tar.zst (listed live, not reused)

Baselines re-read on the machine and all four matched the sheet: controller
v0.216.0, its MinAgent 0.129.0, agent v0.129.0, previous golden 0.214.0. The
published agent artifact for the vouched agent_version was confirmed present
in the package registry rather than inferred from a CHANGELOG, and the R-216
check passed on the machine: MinAgent is EQUAL to, not above, the newest
published agent.

Verified beyond the script's own claim: the artifact was downloaded back out
of Gitea and hashed, and it matches GOLDEN_SHA256 exactly. A script printing
a digest and the registry serving those bytes are two different claims.

Pass markers (corrected post-R-233 list) all present, quoted with line
numbers in pass-markers.txt; excluding/FATAL absent; there is no mp1.

Token never reached a command line: copied file->file, read inside the VM by
the runner. systemctl show grep = 0. Token-leak grep on the COMMITTED log run
with its positive control FIRST -- seeded copy 1, real log 0 -- because a
grep -c that matches nothing also returns 0.

Teardown: guest destroyed and purged, token/runner/script/log shredded AFTER
the log was copied out, qemu exit confirmed with ps -eo comm (not pgrep -f),
disk reverted to virgin.

Vouched by the operator; verified by reading the hub's own store: golden
0.216.0 / agent 0.129.0 / min_agent 0.129.0, and the hub's recorded sha256
matches the independently downloaded artifact. That check was necessary
because golden_currency_gate.py says of itself that it checks the BAKE, not
the vouch.

repo_gates.py --fast now rc=0, all nine gates OK -- first fully green run
since 2026-08-14.

Capability map deliberately NOT changed: the day-0 row cites drill documents,
and the map's only golden literal is a dated historical citation on the
recovery-journey row which bumping would falsify.

R-334 is closed in a follow-up commit quoting this push's CI run id, since
closing it without one would leave the ambiguity a third time.
2026-08-18 13:04:37 +02:00
admin 8b188bea68 hub v0.103.0 — a host can read the packages we kept for it (R-311)
gates / gates (push) Successful in 37s
ListSupersededEscrow had zero production callers for nineteen days. It is the only
reader of a retained identity_blob, so the retention shipped in v0.93.0 was
material the product could not reach - proven on the fixture 2026-08-12, where a
code that opens a retained package was answered as a code that opened nothing.

New GET /api/v1/hosts/<id>/escrow/retained: self-scoped exactly as the current-row
GET, same recovery-mode gate, same audit event written BEFORE the bytes leave,
capped at 16. Rows with a NULL identity_blob are WITHHELD and returned as
unopenable_count - they retain the PBS key, not the repository password, so they
can never open what the caller is asking about, and serving them would let the
screen claim an earlier package is openable on exactly the boxes the original
defect hurt. The count is returned because their existence is load-bearing and
underivable by the caller.

The trade, stated rather than waved through: the hub still cannot read any of it -
sealed bytes in, sealed bytes out, no decrypt path, no recovery code ever held.
What widens is volume, bounded by self-scope, the recovery-mode gate and the cap.

The response is a NAMED TYPE, not a map, so the wire-contract gate can resolve it;
the wire is declared as a fourth ROOT and the gate now checks 182 tags rather than
174. A positive control shows that check is name-presence, not decodability -
filed as R-315 rather than reported as coverage.

Also: golden 0.214.0 baked, published and round-trip verified; the countdown on
demo-felhom cancelled on the operator's ruling (R-307); the spike that halted
Part 3 recorded as R-312; the set-aside store found unrecoverable as R-313.
Six hub tests through the real endpoint; four red-proofs asserted applied.
2026-08-12 18:56:44 +02:00
admin fbe1155fbb R-302 docs: register rows, the two rules earned twice, STATUS
gates / gates (push) Successful in 27s
Closes R-296 (verified: shipped in v0.212.0) and R-301 (premise confirmed, fixed
in v0.213.0). Files R-302 with WHY the obvious condition was rejected, and R-303
for the missing markOrphaned guard - the co-render is now harmless, not
impossible. Bake evidence for golden 0.213.0.
2026-08-12 15:38:11 +02:00
admin 238954405c golden 0.212.0 baked and published; bake evidence
gates / gates (push) Successful in 23s
GOLDEN_SHA256=4b0a7dacc503c38732ed0a44949398639248c7fbd90758a1e4a047c21a7a15d8
Round-trip verified on the served bytes. Not vouched - the operator's.
2026-08-12 14:00:11 +02:00
admin 999b0a35f8 golden 0.211.0 baked and published; bake evidence
gates / gates (push) Successful in 22s
GOLDEN_SHA256=8593516889eb93fe1691410d7306be8cb87ee835b8d2378740eb34022272f849
Round-trip verified on the served bytes. Not vouched - that is the operator's.
2026-08-10 14:18:57 +02:00
admin 4a4a1e245a R-265 CI timeout + golden 0.210.0 baked; R-221/R-259/R-258 closed, R-266 minted, G-3 unblocked
gates / gates (push) Successful in 32s
Four defects of one family, all shipped today: something the box already knows, thrown away or drawn
as its opposite. Agent v0.128.0, controller v0.210.0. NO HUB CODE, no hub bump, no ArgoCD sync.

R-265 (this repo). timeout-minutes: 5 on the gates job — every honest run in the observed session
finished in 18-34s, so this is ~9x the slowest and far under whatever reaped run 264 at 834s with no
log. The alarm mail now carries Elapsed (start stamp via $GITHUB_ENV; an absent stamp prints
"unknown (no start stamp)", never a bogus 1.7-billion-second figure) and its "names itself in the run
log" sentence is qualified so it cannot mislead when there is no log.

⚠ THE UNKNOWN IS NOT CLOSED. Whether the if: failure() alarm fires for a REAPED job is still
unverified. The timeout makes the reap unreachable in practice; it does not answer what happens in
one. Demonstrating it means deliberately hanging a run on main, which would leave the branch red for
a parallel session. Said in the workflow comment, the changelog, R-265 and the report — none of them
claiming it is answered.

GOLDEN 0.210.0 baked, published, round-trip verified, NOT VOUCHED. The currency gate went red the
moment the controller was bumped — correct — and is closed by the bake, never --no-verify. No
--no-verify anywhere this session.

⚠ THE AGENT WAS NOT PUBLISHED UNTIL THIS SESSION CHECKED, AND IT MATTERED. R-221's fix is in the
AGENT, and a fresh install takes its agent from the Day-0 manifest. The binary had been hand-deployed
to felhom-pve and never published, so agent_version 0.128.0 was not selectable and a fresh install
would have received 0.127.0 — the golden would have carried the controller fixes and NOT the one the
headline defect needed. Caught by checking each Day-0 value was FETCHABLE rather than assuming.
Published from the live-deployed bytes, sha-verified across the hop first.

Registers. R-221, R-259, R-258, R-265 CLOSED. R-266 MINTED (READY): the failed root statfs still
travels to the hub as a 0-of-0 disk; ranked LOW because it is the quiet direction — it can only miss
a true alarm, never raise a false one — and it is now a two-repo wire change governed by G-1's gate.
Highest ID moved R-265 -> R-266.

CONTEXT S-39 rules the convention this project was missing: "we do not know" is never drawn as
"fine", and the codebase has ONE way of saying it — an explicit ...Known bool companion checked in
the template. ROADMAP G-3 was explicitly blocked on that decision and is unblocked; what remains
there is a survey-and-convert of existing sites, not the gate.

Capability map row 93 CHECKED and it was NOT claiming something untrue — it is about the operator
notification path. But its narrative ("the page you open to ask whether ONE app is backed up")
invites the wrong reading, and the adjacent thing WAS false until v0.210.0, so the row now records
that the two halves disagreed and only the operator half was true.

Six red-proofs across the two code repos, each with the mutation asserted applied. The one that
matters: Part 1 Scenario A FAILED against today's tree, with the intended message.

Part 1's operator-present live validation is OWED and is the session's STOP.

repo_gates --fast: all 8 OK.
2026-08-08 16:52:39 +02:00
admin dd55a3f98c correct the vouch state: the operator vouched 0.208.0 DURING this session
gates / gates (push) Successful in 33s
Recorded on arrival as 0.207.0, re-read from live hub_settings at the end and it is 0.208.0 — the
operator acted while the session ran. The ask is therefore 0.208.0 -> 0.209.0, not 0.207.0 ->
0.209.0, and STATUS.md plus the golden evidence now say so.

Caught only because the state was re-read rather than carried forward from the arrival note. A fact
recorded at the start of a long session is a fact about the start of the session.
2026-08-08 09:25:25 +02:00
admin 3bf62b95bb fix(gate): the wire-contract search shelled out to grep and read its failure as a finding
gates / gates (push) Successful in 33s
CI convicted ALL 174 checked tags while the pre-push hook was green. Cause, read from the run log
rather than guessed at the second attempt: the search used `grep -rnE --include=…`, and the CI
runner's image carries python3 and git and deliberately little else — its grep does not support
`--include`, so stdout was empty and the gate read empty as "the tag is absent".

That is a gate silently treating a tool failure as a finding, which is worse than no gate, and it is
exactly the error-swallowing this repo forbids. A green from it would have been just as untrustworthy
as the red.

Fixed by removing the dependency, not by working around it: the search is now pure Python — one
token index per receiving repo, built in a single pass, no subprocess. Faster too (one walk instead
of ~350 greps), and unreadable-file / empty-repo cases now exit 2 INCONCLUSIVE rather than reporting
absence.

THE BEFORE CAPTURE WAS RE-VERIFIED, NOT RE-GENERATED — the stronger claim. All 40 fields recorded in
BEFORE.md were re-tested against the new implementation: agree=40, disagree=0, i.e. exactly the four
this session fixed are now present and the other 36 still absent. The number 40 stands under both
implementations; only the mechanism changed. The whole-token property survives by construction — a
token index treats `healed_at` and `privsep_healed_at` as distinct tokens.

This is the THIRD instrument defect this gate's own controls caught before it was trusted, after the
substring false negative and the dr_recipe over-opacity. The first two were caught by re-finding the
known instances; this one by the CI-versus-hook disagreement the workflow's alarm mail explicitly
says outranks whatever the push was for.
2026-08-08 09:10:59 +02:00
admin 2ce3c2a0f2 golden 0.209.0 BAKED, PUBLISHED, ROUND-TRIP VERIFIED — the currency gate goes green (R-242)
gates / gates (push) Failing after 29s
The G-1 session released controller v0.209.0 (R-247), which made golden_currency_gate.py correctly
red and REFUSED THE PUSH: no golden carried the newest release. The honest answer to that is the bake
it asks for, not --no-verify. The gate's own docstring says the cost of a trip is one bake, which is
the operation this project wants to be routine.

656 697 956 B, sha256 c9c4bcd6..e818ff. Round-tripped: the published bytes downloaded back, hashed
independently, size and sha identical, and ./etc/felhom-controller-image read OUT of the downloaded
archive says felhom-controller:0.209.0 — the delivered artifact naming the controller it will start.

Acceptance markers all green (overlay2 x1, mount points x2 rootfs+mp0, upload HTTP 201 x1,
excluding/FATAL/mp1 x0), Result=success, ExecMainStatus=0. 404 pre-gate with a 200 control on
0.208.0 so a 404 could not mean "wrong URL". Token file->file into a 0600 file read inside the VM;
systemctl show grep = 0; committed-log grep = 0 WITH a control returning 1 to prove the grep works.
Bake VM destroyed, /root residue clean, qemu confirmed gone, drill disk restored to virgin.

IT ALSO CONSOLIDATES THE OPERATOR'S APPROVAL. Golden 0.208.0 was baked last night and never vouched;
0.209.0 contains everything it did plus R-247, so it supersedes rather than wastes it. One Save, not
two — STATUS.md updated accordingly and back to its 93-line screen.

NOT VOUCHED. Fresh installs still land on 0.207.0 until the operator saves. And R-242's untouched
half showed itself again: this gate flipped green on the presence of the evidence DIRECTORY, with no
vouch anywhere near it. Recorded, not built — ROADMAP G-8.

repo_gates --fast: all 8 OK, including wire-contract and golden-currency.
2026-08-08 09:01:26 +02:00
admin 560f0d4451 G-1: a gate for the dropped field — built first, and seen failing on 40
Campaign 12 ranked this first of eight gating candidates. It is built BEFORE the fixes it finds,
because last night an off-the-shelf tool for a neighbouring class (deadcode, for C6) was made to
prove itself first and found NEITHER of the two defects it was meant for. A gate nobody has watched
fail has not been shown to work.

scripts/wire_contract_gate.py, registered in repo_gates.py as --fast (no network, no container, so
it runs in BOTH the pre-push hook and CI — the R-29 constraint).

THE TEST. For every json tag reachable from a declared wire ROOT, does that literal tag occur
anywhere in the receiving repo's production Go or templates? A tag occurring nowhere cannot be
decoded by any struct, named OR anonymous. That last clause is why a string test is used instead of
comparing struct to struct: Campaign 12's first attempt paired types by shape and false-positived
badly, because the hub decodes one report through several ad-hoc anonymous structs.

RESULT ON TODAY'S TREE: 210 tags checked across 3 declared wires, 51 skipped (generic / opaque /
allowlisted), 40 CONVICTED. Captured verbatim in documentation/tests/wire-contract-gate-2026-08-08/
BEFORE.md, which is deliverable 1 of this session.

The prompt for this session said "465 emitted tags, eight unreachable". Checked against the repo
rather than quoted: R-260's wording was "at least eight DECISION-BEARING facts", not eight tags in
total. The real count on the three declared wires is 40, and R-260's own census already listed more
than eight. Recorded because this prompt's own rule 6 says not to quote a document as source.

TWO THINGS THE CONTROL CAUGHT, both before the gate was trusted:

1. A SUBSTRING FALSE NEGATIVE. `grep -F healed_at` also matches `privsep_healed_at`, so a genuinely
   dropped field read as received — and R-260 named healed_at, so its absence from the output was
   the tell. Now a whole-token regex; healed_at is convicted.
2. dr_recipe IS NOT WHOLLY OPAQUE. The hub stores each half as json.RawMessage and re-emits nested
   shapes verbatim, so the LEAVES are genuinely not on this wire. But the TOP-LEVEL SECTION KEYS are
   decoded by hostHalfShape/appHalfShape, and those are ALLOW-LISTS: a section an emitter adds is
   silently dropped until named in both. That already cost `offsite_restic` (R-122). So the gate is
   opaque BELOW depth 1, not opaque — the sections are checked and pass.

Self-test: `--selftest` plants an unreachable tag on a real root in a throwaway copy and asserts
conviction. Verified: exit 1, planted tag named.

Blind spots are in the module docstring AND in the gate's own output, because Campaign 12's C1 guard
turned out blind to one of the three shapes it was written for: generic tag names are not checked;
reachability of a NAME is not use of a VALUE; only declared ROOTS are covered, and the hub's
desired-state (served as raw stored JSON, no typed emitter) and the agent local API are NOT.

Allowlist entries carry a stated reason. A quiet exclusion is a dropped field with paperwork.

Not pushed alone: the fixes follow in the next commit so main is never red on this check.
2026-08-08 08:28:53 +02:00
admin b7fb2117ae CAMPAIGN 12 — the class sweep: golden 0.208.0 baked (awaiting vouch), R-256..R-263 filed, gating ranked
gates / gates (push) Successful in 20s
Part 1. Golden 0.208.0 baked on the drill VM, published and ROUND-TRIP VERIFIED — 656 150 362 B,
sha256 ba668f59..5ffb82, and ./etc/felhom-controller-image read OUT of the downloaded archive says
felhom-controller:0.208.0. Acceptance markers all green (overlay2 x1, mount points x2 rootfs+mp0,
upload HTTP 201 x1, excluding/FATAL/mp1 x0), Result=success. Token file->file, read inside the VM;
systemctl show grep = 0; committed-log grep = 0 WITH a control proving the grep works. Bake VM
destroyed, drill disk restored to virgin. NOT VOUCHED — the campaign halts there deliberately.

golden_currency_gate.py was correctly RED on arrival and is green after the bake. No --no-verify
was needed anywhere in this session.

Parts 2-4. Seven defect classes swept for siblings by class rather than by feature. Analysis only:
no product code, nothing deployed, no machine touched beyond the bake VM.

Eight new rows R-256..R-263 (ceiling moved from R-255), grouped by class in OPEN-ITEMS.md. C1
produced no new instance and has no row. The sharpest is R-260: the agent reports
operator_key_configured every heartbeat, the hub has no field for it, so the check that answers
"can the operator get into this box" returns ok for a box with no operator key installed.

Every class states whether its method re-found the known instances, because a method that cannot
re-find them has not been shown to work: C1 2/3 (verified by replaying the pre-fix templates),
C2 2/2, C3 2/3 + 1 as fixed, C4 fix-pattern re-found, C5 re-found, C6 deadcode 0/2 and bespoke 1/2,
C7 weakest and said so. Blind spots stated per class; seven suspicions investigated and DISPROVED,
including two of my own methods.

Part 4's ranking is in ROADMAP.md as G-1..G-8. Gate C5 (cross-repo tag reachability — cheap,
--fast-eligible, would have caught every R-260 instance on the introducing commit). Do NOT gate C6:
golang.org/x/tools/cmd/deadcode was measured against a PLANTED probe and is blind to unreachable
METHODS on widely-used types, which is exactly the shape both known instances have.

R-242's untouched half is recorded, not built: this bake demonstrated it, the currency gate flipping
green the moment the evidence DIRECTORY existed, before the round trip finished and with no vouch
near it.

Correction the campaign owed its own brief: escrow_stale was described as closed; it is R-247 and
READY. The live repo is the source.

Sampled rather than swept, exactly: C7 60 of 2652 production invariant comments and NONE of the 1440
test comments (that half is owed); C2 19 of 221 refusals; C3/C4 controller only. No finding was
reproduced live. STATUS.md is 100 lines against its 93-line one screen.
2026-08-07 23:07:42 +02:00
admin f651b31a7a golden 0.207.0 BAKED, PUBLISHED, ROUND-TRIP VERIFIED and VOUCHED — the currency gate goes green
gates / gates (push) Successful in 22s
Closes the delivery gap v0.207.0 opened this session. Until now the gate was
correctly red and a machine installed today would have received 0.206.0 — the
release written, tested and pushed, and not delivered.

Round trip is the evidence, not the build log: the published bytes were downloaded
back (656 879 192 B, sha256 20ec9602…22995, both identical to what the bake
reported) and ./etc/felhom-controller-image read OUT of the downloaded archive
says felhom-controller:0.207.0 — the delivered artifact naming the controller it
will start.

Acceptance markers were the ones R-233 re-captured from a real log: docker OK
(overlay2…) x1, including mount point rootfs AND mp0 x2 (there is no mp1 since
build-golden.sh v3.0.0), upload OK (HTTP 201) x1, excluding 0, FATAL 0.

The 404 pre-gate ran WITH a control so a 404 could not mean 'wrong URL': 0.206.0
-> 200, 0.207.0 -> 404.

The token never crossed a shell — copied file->file, read by a runner script
inside the VM; systemctl show grep for the value returned 0. The token-leak grep
on the COMMITTED log returned 0, and that 0 is evidence because a planted copy
returned 1 before being shredded.

Vouch was a three-field change with all three checked deliberately: MinAgent
0.127.0 read from the golden's controller CHANGELOG header, agent_version already
>= it, min_agent not above agent_version (not the R-216 shape). Verified by
re-reading the manifest rather than trusting the flash. The R-120 gate did not
refuse.

Drill VM restored to virgin; qemu confirmed exited with ps -eo comm, not a
self-matching pgrep -f.

R-242: the bake half is done and the --no-verify bypass declared earlier today is
now historical. Its remaining half is UNCHANGED — nothing gates the VOUCH itself,
so a baked-but-unvouched golden still passes the currency gate silently.
2026-08-07 20:59:37 +02:00
admin c1dec41328 walk5 venue TORN DOWN — census 168 rows -> 67, and R-244 grew by 30 as predicted
gates / gates (push) Failing after 13s
Operator-confirmed. Stopped under a name guard (demo-hp carries its own 9201),
aged past the hub's stale_threshold read from the DEPLOYED ConfigMap (30m), and
polled delete-impact until deletable:true — treating an empty response as retry,
never as success. Cascade + qm destroy --purge, guarded a second time.

Every layer verified absent against a positive control that must survive and does:
VM 300 drill-r50 and demo-hp's own guest 9201 still there; ep0 namespaces
demo-felhom + demo-hp still there; wg peers .2 .3 .4 .250 still on the live wg0;
hub rows for demo-felhom, demo-hp, peti-felhom untouched. 16.64 GiB returned
against 17 G measured.

RECORDED FOR THE NEXT TEARDOWN: the WG peer is removed on a ~5-minute SCHEDULE,
not by the cascade. Immediately after the delete the hub row was gone while
10.77.0.5 was still on ep0's live wg0; wgsync had last run 37 seconds before the
cascade, and the next push (4 peers) removed it, verified on the live interface at
16:57:07Z. The previous ledger checked this after it had already converged, so it
read as instantaneous — a teardown that checks too soon would file a false finding.

R-244 grew by 30 rows (app_log_issues), PREDICTED in the pre-run enumeration
rather than discovered afterwards. Running total across torn-down venues ~101.
Nothing here claims a clean teardown.

Storage Box layer evidenced from the hub's own deprovision log: the HETZNER_API
token in ~/.config/credentials cannot see box 611421 (subaccounts -> 404,
storage_boxes -> 200 with 0 entries) — it is scoped to another project.
2026-08-07 18:58:55 +02:00
admin 3f4fb3825f R-201 CLOSED — the unaided recovery journey passes, both halves, on the fifth walk
gates / gates (push) Successful in 17s
Capability map: the unaided-recovery row turns FAILED -> PROVEN-LIVE, scoped, with
what it still does not claim stated in the row itself: shape (c) did not fire
positively (with the mint guard holding there is no local key, so the offer comes
from shape (a)); and 'unaided' here means possible-without-a-shell, not obvious,
because two obstacles are unsignposted.

OPEN-ITEMS: R-201 closed with its evidence. Five new rows R-249..R-253 (the
retrieval passphrase in page HTML; the host-key scan ladder vs AAAA settle; the
listing's per-tag rows; the two unsignposted restore steps). R-243 annotated
rather than re-filed: on a REBUILD offsite_delivery_stuck does not skip, so the
row's gap is narrower than it reads.

STATUS.md: headline changed, and trimmed 97 -> 92 lines rather than extended, per
its own header.

Teardown recorded as OWED with its before-measurements, the stop-and-age gate, and
the positive controls that must survive.
2026-08-07 17:24:27 +02:00
admin 0691bc59a5 walk5 (R-201): Phase B + the verdict — BOTH HALVES PASS
THE DATA: PASS. All three sentinels byte-identical out of snapshot 5b0f20f7,
including the accented filename's bytes, read back as bytes from the live path.

THE JOURNEY: PASS — the first time in five walks. Zero guest command lines were
needed to progress; the previous walk needed three. The reset-code hatch was used
once, in Phase A only.

§5's observation, which stands on its own whatever the verdict: at 14:58:52Z the
rebuilt box collected its re-staged credential, configured the transport, and
REFUSED TO MINT a repository password over the sealed package the hub holds. At
the equivalent moment the previous walk minted a fresh key and lost the journey
silently at 03:18. Sampled every 20s from T0: no key at any moment.

Honest about which shape fired: with the mint guard holding there is no local key,
so the offer comes from shape (a), not shape (c). Shape (c) was measured in Phase A
in its NEGATIVE half (equal hashes, correctly silent). This proves the mint guard
positively and the discriminator negatively.

RTO 71.7s login to open store, of which 12.44s was the unseal and ~22s my own
CSRF harness retry.

Two new customer-facing obstacles, neither needing a shell but neither signposted:
the restore refuses on unattached drives, and refuses because the app is not
installed on a page that says the restore reinstalls it.
2026-08-07 17:18:37 +02:00
admin 879007aaec walk5 (R-201, fifth walk): Phase A journal — fixture built, sentinels proved by name
gates / gates (push) Successful in 21s
Written before the destruction, per §9.9. A fresh install landed on the VOUCHED
set with no hand upgrade (controller 0.206.0, agent 0.127.0) — R-239's delivery
gap is closed for this run, which is the first of the five walks where the box
under test is the box a customer receives.

Both §4.6 pre-destruction checks pass, neither previously exercised on a clean
box: the recovery offer is correctly SILENT (shape (c) compares equal — the two
key hashes are byte-identical on box and hub), and the restore page lists the app
with the future-backup toggle OFF (R-237's fix, which the last walk measured
failing).

Also recorded: the §4.5 gate caught a harness fault (a toggle sent as enabled=1
rather than enabled=on) that had produced a green 'ok' over a zero-snapshot
repository — the exact shape the gate exists for.
2026-08-07 15:05:35 +02:00
admin 721297ed5e golden 0.206.0 baked, published, round-trip verified — NOT vouched; the gate goes green
gates / gates (push) Failing after 10m43s
Controller v0.206.0 shipped the R-241 fixes on 2026-08-07 while the vouched
golden still carried 0.205.0, so a machine installed this morning would have
received neither - and the next recovery walk would have measured the old
behaviour and failed for a reason nothing to do with the walk. Same gap as
R-239, one day after R-239 was closed.

  version  0.206.0
  sha256   c85230b42f53baa9c1ee9986ac312c751d6cbc29fbe070d87bb2214429a9108e
  size     656,750,694 bytes (uncompressed 2,003,138,560)
  MinAgent 0.127.0

Round-trip verified rather than trusted: the published bytes were fetched
back, re-hashed independently (match), zstd-tested, and
./etc/felhom-controller-image was read OUT of the download ->
felhom-controller:0.206.0. That last step is the one that matters, because
GOLDEN_VERSION is derived from the tag argument and could be right over stale
content.

All acceptance markers pass; unit Result=success ExecMainStatus=0. Secret
hygiene: token file->file, in-VM runner so it never reached a command line
(unit-property grep 0), literal-value leak grep on the COMMITTED log 0 - with
a positive control proving the grep works before the 0 was believed.

Bake VM torn down: CT 9100 purged, secrets shredded, qemu observed gone via
ps -eo comm, drill.qcow2 reverted to virgin.

THE GATE BUILT EARLIER THIS SESSION NOW PASSES. It was shown CONVICTED against
the pre-bake state and is OK now - red to green on the same check, the same
command, which is its proof that it measures something real. Note it went
green on the BAKE, not the vouch: that is its stated limitation, and the vouch
is still pending the operator.

NOT VOUCHED - the operator's act. Only one field moves: golden_version
0.205.0 -> 0.206.0 (+ its derived sha). agent_version and min_agent both stay
0.127.0. wrapper_sha256 is unchanged but is CLEARED if omitted from the POST.
2026-08-07 13:05:40 +02:00
admin 094e93e828 finalwalk teardown complete; R-244 filed; session report
gates / gates (push) Successful in 13s
All five layers gone, each verified with a positive control that must
survive and does:
  VM 324 + 4 disks   -> absent (VM 300 drill-r50 remains)
  hub: 13 tables at 0, incl. BOTH escrow tables (demo-felhom/demo-hp/peti remain)
  Storage Box u629488-sub4 -> gone (sub1/2/3 remain)
  ep0 PBS ns finalwalk     -> gone (demo-felhom, demo-hp remain)
  WireGuard 10.77.0.5      -> gone from the LIVE wg show on ep0, not just
                              the hub DB (.2/.3/.4/.250 remain)
14.06 GiB reclaimed against 15 G measured before deletion.

R shredded with a planted-copy control: plant -> search finds both ->
shred -> the same search finds 0. The zero was not believed until the
instrument was proven.

R-244 (NEW): a FULL census after the cascade logged COMPLETE full teardown
found 61 rows still matching finalwalk. Four sources are deliberate
provenance; the fifth, app_log_issues (29 rows), is NOT covered by the
residue purge - and it is systematic: c11 40, rewalk 20, part4 24 still
present from the 2026-08-06 teardown, whose ledger recorded zero
occurrences. That claim used a narrower query than a census and does not
hold; the correction is recorded in both the prior ledger and the register
rather than the measurement quietly redone.

No secret material is involved. The table is a fleet-wide aggregate: 12 of
the 29 rows are finalwalk-only orphans, 17 are shared with LIVE customers
and must be de-referenced, not deleted - very likely why the leg was never
written. Not fixed; a cascade change needs its own red-proof.

Lesson, and it is the reusable part: a per-table absence query is not a
census.
2026-08-07 09:59:16 +02:00
admin 08b75e602e golden 0.205.0 baked, published and round-trip verified — NOT vouched (R-239)
gates / gates (push) Successful in 13s
Closes the delivery gap's build half. The vouched golden carried controller
0.203.0 while 0.205.0 was released, so a machine installed last night got
neither R-237 (restore list keyed on the store) nor R-234 (skipped-app
verdict). Both were measured from the customer's side on that box.

  version  0.205.0
  sha256   8f49b2e8ccbc86a49df821fee9fb00c07293758811d3d0f0512dd0cf5fd54ee8
  size     656,937,561 bytes (uncompressed 2,003,343,360)
  MinAgent 0.127.0

Round-trip verified rather than trusted: the published bytes were fetched
back, re-hashed (match), zstd-tested, and ./etc/felhom-controller-image was
read OUT of the downloaded archive -> felhom-controller:0.205.0. That last
step is the one that matters, because GOLDEN_VERSION is derived from the tag
argument and could have been right over stale content.

Acceptance markers all pass; unit Result=success ExecMainStatus=0.
Secret hygiene: token file->file, in-VM runner so it never reached a command
line (unit-property grep 0), literal-value leak grep on the COMMITTED log 0 -
with a positive control proving the grep works before the 0 was believed.

Bake VM torn down: CT 9100 purged, secrets shredded, qemu observed gone via
ps -eo comm, drill.qcow2 reverted to virgin.

NOT VOUCHED - that is the operator's act. Only ONE field actually moves:
golden_version 0.203.0 -> 0.205.0 (+ its derived sha). agent_version and
min_agent both stay 0.127.0, because the new golden's MinAgent is also
0.127.0. The R-120 gate passes exactly: the newest controller the fleet
reports is 0.205.0, so a 0.204.0 golden would have been refused.
2026-08-07 09:05:59 +02:00
admin 2228c0bff6 final walk COMPLETE — data PASS, journey FAIL; R-241 filed
gates / gates (push) Successful in 15s
THE DATA: PASS. All three sentinels byte-identical out of snapshot f5c53b03,
including the 12 MB binary and the accented Hungarian filename whose NAME BYTES
are identical too. Disk -> restic -> SFTP -> Storage Box -> rebuilt machine ->
disk, intact.

THE JOURNEY: FAIL, and further from the line than the previous walk. The claim
worked first try (302 in 0.164s). Then: / lands on the launcher with no recovery
pointer, /recovery 302s away, and the remote page offers to CREATE a new recovery
code — which would orphan the history the customer's code protects. There is no
field anywhere to enter the code they hold. The operator's documented remedy also
refuses, correctly and fail-closed. Recovery needed three guest command lines.

R-241 — and the cause is a success this same walk proved six hours earlier.
OffsiteRecoveryOffer() shows the screen only when (a) there is NO repository
password (pristine rebuild) or (b) one exists but the history will not open under
it. Overnight the credential self-heal collected the staged credential and applied
the tier, writing a FRESH key at 03:18Z — so (a) is false; and (b) is unreachable
because orphan detection needs a run, and runs are blocked by escrow_state=pending.
The gap is self-locking. Measured keys: on-disk 9b4a9a9d... vs recovered-from-R
30ef574f... This is R-218's shape one level up: succeeding at the self-heal stopped
the box OFFERING the recovery it still needed.

Registers: R-201 moved to its outcome; R-241 filed; capability map's recovery row
stays FAIL with both halves and the cause named; STATUS rewritten for the operator.
Highest ID R-238 -> R-241.

The venue is left with the recovered key in place and the self-heal key moved
aside, never deleted. Teardown still owed.
2026-08-07 06:45:36 +02:00
admin 1ff6f8f8e0 final walk §7: the credential chain runs end to end, unaided, on an UNCLAIMED box
gates / gates (push) Successful in 12s
Three questions answered from the hub's own log, not inferred:
  1. the rebuilt, still-unclaimed box DOES report (host-report + Received report)
  2. it DOES declare offsite.state=needs_credential, and offsite-delivery correctly
     declines once a minute, naming internal/offsiteheal as the owner
  3. offsiteheal re-staged UNAIDED at 03:15Z, after two reports carried the
     declaration, with no provider credential minted — about 32 minutes after the
     rebuild, matching the documented 2x15-minute debounce

And then the box COLLECTED it on its own 5-minute tick:
  [offsite-apply] credential retry: the staged credential was collected and the
  tier applied

That success line shipped in v0.203.0 and this is the FIRST time it has been seen
live: yesterday's walk only produced its sibling before I intervened at 102s and
mistook my own button press for the cause — the error that produced R-236 and
forced its withdrawal. Here nobody touched anything and the box was not even
claimed. R-218's consume half, R-236's withdrawal and the previous walk's dead
end 1 are all settled by one unattended observation.
2026-08-07 05:23:03 +02:00
admin 1b490c8cbf final walk: destroyed, rebuilt, and HALTED at the claim screen
gates / gates (push) Successful in 27s
Destroyed 02:40:31Z (guarded on hostname — demo-hp also has a guest 9201), drives
wiped to 20K with the mounts deliberately left in place because the surviving raw
mount IS the R-220 condition. Reinstalled through the published day-0 path,
installer v1.25.0 fetched live; Day-0 provision SUCCESS in 2m32s.

R-239 measured a second time, from the other side: the rebuild landed on agent
0.127.0 (no downgrade, no hand upgrade — that half is right) and controller
0.203.0. The box a customer would recover on tonight also lacks R-234 and R-237.

The machine is AT THE CLAIM SCREEN awaiting the operator. A claim code has already
been requested through the customer-facing path and emailed, so the morning is
paste-a-code rather than request-then-paste. The reset-code hatch was NOT used and
will not be: it is a guest command line and would fail the rule the walk measures.

Stated plainly in the journal: journey steps from the destruction onward are driven
over HTTP from the appliance to the guest's island address, as a browser would;
some instrumentation reads are guest command lines and are counted as such, but
none changed state or was needed to progress the journey.
2026-08-07 04:46:11 +02:00
admin 502078bebf final walk: the soak DID catch a scheduled cycle; both directions recorded
gates / gates (push) Successful in 20s
Window 2 (01:56-02:36Z) caught the off-site nightly at 02:15:03Z — snaps 1->2,
last_run advanced with no prompting. Window 1 had already caught the local legs
(db-dump 00:30:25Z, tier + fill-watch 01:30:19Z). My 04:15 prediction was wrong in
the other direction; recorded rather than quietly fixed.

What should have fired and did not: NOTHING. Six registered jobs were never seen
in the log and none is a finding — four are quiet by construction
(scheduler.go:267, quiet := job.Interval <= 30s) and two run every 6h, outside a
4h window. Checked the source rather than filing four phantom defects.

What fired and should not have: nothing. No alert, notification, email or digest.
The only WARN lines in five hours were three of mine.

Observation kept: offbox-backup ticked twice 62s apart and produced ONE new
snapshot — the second silently dropped by the single-flight, which is correct for
the nightly path and is the same mechanism that produced R-234 on the manual path.
2026-08-07 04:39:42 +02:00
admin f873c557ca final walk: the soak, and the window correction stated as mine
gates / gates (push) Successful in 20s
Window 1 (22:44-01:54Z, untouched): every periodic job fired at its declared
cadence — agent-channel-health 185x/1m, stack-scan 108x/2m, the 5-minute trio 44x
each, hub-report 14x/15m. offsite-credential-retry ran 44 times and did no work
and said nothing, which is R-218's asserted healthy-box behaviour on a box that
never saw the defect. No alert, notification or digest fired; nothing on the
must-not list fired.

The off-site state never moved during that window — and that is NOT a finding.
The daily jobs run on the controller's clock and the guest is UTC while the
appliance is CEST, so the nightly local (~02:30) and off-site (~04:15) fall at
02:30Z and 04:15Z. I sized the window against CEST and it closed at 01:54Z, before
either. Reporting 'the nightly did not fire' would have been a false finding
produced by a badly-chosen window.

Window 2 (corrective, 01:56-02:35Z) covers the 02:30Z local backup. The 04:15Z
off-site nightly is deliberately NOT covered and is recorded as not run with the
reason: leaving the machine at the claim screen before 07:00 is the primary
deliverable, and waiting would have put the destruction at ~06:35 CEST with no
margin. The off-site tier was exercised four times manually instead, including a
full listing by name.
2026-08-07 03:57:18 +02:00
admin 2d2d8d3ddc final walk Phase A + the five checks; R-239 (delivery gap) and R-240 filed
gates / gates (push) Failing after 13m22s
Phase A complete on a NEW venue (demo-hp VM 324, customer finalwalk). Installed
from the published ISO — verified byte-identical to iso.felhom.eu — claimed, app
deployed, three sentinels placed, escrow ceremony 6/6 with restic_pw_sealed=true,
R held in one 0600 file on DooPlex, off-site backup taken and the three sentinels
PROVEN IN THE SNAPSHOT BY NAME (snapshot 1da4f80d, 12.0 MB).

THE HEADLINE: a fresh install lands on agent 0.127.0 (vouched, no hand upgrade —
that half works) and controller 0.203.0, while the newest is 0.205.0. The vouched
golden still bakes 0.203.0, so tonight's box has neither R-237 nor R-234. Filed as
R-239: a delivery gap, not a regression. Every closure claimed for those two is
true of the code and false of the fleet until a golden is baked and vouched.

The five checks, on that box:
  T1 ok + the old bare-count warning (no next step)
  T2 FAILS — both runs say "elindult", the second as a success flash
  T3 FAILS — toggle off hides an existing snapshot; wizard 302s away
  T4 ok, and the wording is still "Sikeres" beside "nothing is selected" -> R-240
  T5 PASSES — driven as a browser does, prepare -> full_prep -> confirm -> commit
     completed; R-238 confirmed a harness artifact, not a product defect

HARNESS FAULT, caught by the §4 gate: the first off-site run reported ok with a
26.6 KB repo — impossible for a 12 MB sentinel. I had placed the files under
.../adatok/felhom-data/userdata/... while this box's namespace root is
/mnt/felhom-drives/adatok directly. The product was correct throughout; proving by
listing rather than by a green status is what caught it before any destruction.

Nothing destroyed. The venue stands.
2026-08-07 00:42:59 +02:00
admin fca85498e1 Part 5: the last venue torn down after its findings were written
gates / gates (push) Successful in 8s
part4 (VM 323) was kept while Parts 1 and 3 read it — it was standing in the exact
failed half-B state and tearing it down first would have destroyed the evidence.
Destroyed after the diagnoses were committed (70b6260): VM, hub host, hub customer,
u629488-sub6, ep0 namespace, wg peer 10.77.0.7, all verified absent with demo-hp as
the positive control.

Final: demo-hp holds only VM 300 (drill-r50) and its own CT 9201; ep0 holds only
demo-felhom and demo-hp. 53.4 GB reclaimed across the three venues.

The cascade purges all escrow ciphertext, so R_C11_REWALK and R_PART4 in the
operator's credentials file are now inert.
2026-08-06 17:25:20 +02:00
admin 70b62608b0 teardown of two venues; R-218/R-220 CLOSED, R-236 WITHDRAWN, R-238 reclassified
gates / gates (push) Successful in 18s
Part 0 — c11 and rewalk destroyed, three layers each plus the off-site side and
the WireGuard peer, via the hub's own cascade (external teardown FIRST, DB purge
LAST). 37.3 GB reclaimed on c11-scratch, matching the 20G+17G measured. Positive
control after each: part4 must still be found, and was. ep0 namespaces now exactly
demo-felhom, demo-hp, part4.

The cascade refuses to delete a live host and there is no decommission endpoint,
so both boxes were stopped and aged past the hub's 30m stale_threshold first.

Register corrections — the durable record was wrong about two shipped fixes:
  R-218 REOPENED -> CLOSED. Shipped controller v0.203.0, proven live on a
        genuinely rebuilt box: the hub re-staged at 13:24:57Z and the box
        collected it on a tick, no guest command line, no operator action.
  R-220 "OPEN — NOT FIXED" -> CLOSED. Shipped agent v0.127.0, proven live after a
        real guest purge with both raw mounts still on the surviving host:
        /disks/candidates returned both drives (before: two empty lists) and both
        re-attached through the customer endpoint.

R-236 WITHDRAWN — I FILED THIS WRONGLY. The hub log shows offsiteheal re-staged
the stored secret at 13:24:57Z after its documented two-report debounce, with no
provider credential minted. My Re-issue at 13:26:39Z came 102s LATER, was
redundant, and minted an unnecessary provider credential (subaccount 284735) —
the very double-issue the offsite-delivery guard warns about once a minute in the
log. "Nincs teendod" is true; I did not wait ~16 minutes. Operational lesson, not
a product defect.

R-238 reclassified as a harness artifact (mode=full without confirm=1 is step 1 of
a deliberate two-step and starts no job by design); its real residue — the total
silence of that step — is fixed in controller v0.204.0.

R-237 CLOSED by controller v0.204.0.
2026-08-06 16:53:38 +02:00
admin 5810e1f552 Part 4 half 2: upgrade path PASSES, recovery journey dead-ends (R-236/237/238)
gates / gates (push) Successful in 8s
Destroyed guest 9201 (guarded on hostname — demo-hp also has a 9201), wiped both
drives leaving the raw /mnt/<name> mounts in place, reinstalled from the
published installer v1.25.0.

PASS — the upgrade path:
  agent 0.127.0 -> 0.127.0 across the rebuild. The previous re-walk DOWNGRADED
  0.126.0 -> 0.125.0 (R-216 part 4). Controller 0.203.0 from the baked golden,
  Day-0 provision SUCCESS in ~2m50s, nothing applied by hand.

R-220 FIXED, proven on a genuinely rebuilt box: with both devices mounted raw
AND managed, /disks/candidates offered both drives (before the fix: two empty
lists), and both re-attached through the customer endpoint.

R-218's consume half proven live end to end: credential re-staged at 13:26:32Z,
collected on a tick, tier configured — no guest command line. Previously this
exact situation was dead end 1 and needed a guest shell.

FAIL — the data half, NOT reached. Three new findings, in the order they bite:
  R-236 nothing re-stages the off-site one-time password after a rebuild, so the
        "Nincs teendod" promise stalls until an operator re-issues. The retry job
        is NOT at fault — it retries correctly and logs why.
  R-237 the restore surface is keyed on installed + remote-marked apps, so after
        a rebuild the customer is shown no backups at all — a circular dead end.
  R-238 "Teljes visszaallitas elokeszitese" returns 302 and does NOTHING: no job,
        no state change, no error, no line in the controller's own debug ring.
        mode=unit on the same form works. This is why the sentinel byte-identity
        criterion was not met — nothing came back, rather than coming back wrong.

No guest command line was used at any point in either half — the property the
previous walk could not claim.
2026-08-06 16:03:04 +02:00
admin ac451f9667 Part 4 half 1: fresh install lands on vouched 0.127.0/0.203.0 with no hand upgrade
gates / gates (push) Successful in 9s
Venue: demo-hp VM 323 part4-appliance / guest 9201 / hub customer part4.
Bind 13:53:40 -> agent 0.127.0 ONLINE 13:55:34, no "floor held", controller
0.203.0 from the baked golden. The previous re-walk's reinstall DOWNGRADED the
agent (R-216 part 4); this one did not, because the vouch moved all three fields
(golden_version + agent_version + min_agent) together.

R-218 on a real installation: offsite-credential-retry registered (every 5m0s)
and ticking, 0 "credential retry" lines, and the tier configured unaided 14s
after the settle gate — the previous walk's dead end 1 is gone. Stated precisely
in the journal: this venue proves the SILENT half only; the collecting half was
proven separately with a positive control.

R-225 visible in both states on a live box: "még ismeretlen" before any
snapshot, "12.0 MB / 50 GB" after. Unknown is not zero.

Fixture complete with NO guest command line — the claim used the emailed code
through the real /claim form (the hub keeps only a hash), and the sentinels were
written over SMB with the share mounted so the accented filename never crossed a
shell (verified as hex on both sides, no U+FFFD).

Two new findings, both "presence is not success":
  R-234 an offsite run reports success while omitting an app just toggled on —
        found ONLY because the pre-destruction verification restore was run
        instead of trusting the green tick.
  R-235 the console still shows the pairing banner 25 min after the bind, while
        promising it refreshes itself.

Half 2 (destroy -> reinstall -> recover -> compare) is owed and NOT started; the
venue is standing and its teardown is owed.
2026-08-06 14:56:14 +02:00
admin 1c47e3b6fd golden 0.203.0 baked + published; runbook acceptance markers fixed (R-233)
gates / gates (push) Successful in 13s
Bake evidence: documentation/tests/golden-0.203.0-2026-08-06/ (bake.log + README).
sha256 3039c6ffa7a5a8b2d959daddb2895c58b44de70f8d4f4a7e12ad4b1c0d61dc88, verified
by an independent round-trip download and by reading /etc/felhom-controller-image
out of the published archive itself. NOT vouched — the hub still serves 0.201.0.

R-233: RUNBOOK-manual-build.md §4.1 named three pass markers, two of which the
script cannot print (`overlay2 OK` does not exist; `mp1` stopped existing in
build-golden.sh v3.0.0 under R-165), and a 404 pre-gate URL with the wrong
filename, which would 404 for the wrong reason and pass even when the version
already existed. A grep for an impossible string reads 0 forever and 0 is
indistinguishable from failure. Markers re-captured from the real log; token
handling moved off the command line into an in-VM runner script; a positive
control is now required on the token-leak grep; the vouch step rewritten as the
three-field change it is (golden_version + agent_version + min_agent).
2026-08-06 13:23:22 +02:00
admin 0c4411e54b R-201 re-walk: the data PASSES again, the journey still FAILS — two dead ends, down from four
gates / gates (push) Successful in 9s
Asked Campaign 11 Phase 1's question a second time, on the fixed build, on a
NEW appliance (VM 322, customer rewalk). The Campaign 11 venue was untouched.

THE DATA: PASS. All three sentinels byte-identical out of the pre-destruction
snapshot a7bc23bd in 23s through the customer's own restore flow — including a
12 MB binary and an accented Hungarian filename whose NAME BYTES are identical
too (verified as hex, not as rendered text).

THE JOURNEY: FAIL, two dead ends against Phase 1's four.
 1. R-218's CONSUME half. The hub re-staged the credential at 11:44:57 saying
    'the box re-consumes on its next cycle'; a full cycle ran at 11:55:46/54
    (with a positive control that it ran) and it did not. A census of the
    customer-reachable actions found none that fetches it. Only a command line
    INSIDE THE GUEST moved it — 18s, confirming nothing was wrong with the
    credential, target or key: only the trigger. R-218's row said SHIPPED and
    over-claimed; it is corrected to REOPENED for the consume half.
 2. R-220. Drives still unenrollable after a rebuild, needing a Proxmox-host
    unmount; without it no app redeploys and the restore page stays empty.

Unaided RTO STILL UNDEFINED. Attended: +45s key placed, +24m12s tier up,
+30m13s data verified. The 30m must not be quoted as the customer number.

What passed and is new: the recovery screen appeared WITHOUT being sought,
answered all three questions with a seal date matching the hub exactly, the
emailed reset code worked first try, the unlock was a real 1.528s unseal, and
R-225's fix was seen working in the wild (unknown, not a false zero).

R-216 part 4 reproduced live: the reinstall downgraded the hand-installed agent
0.126.0 -> 0.125.0.

DELIVERY GAP recorded as owed and NOT conflated with the journey: a fresh
install landed on controller 0.201.0 / agent 0.125.0 — the vouched versions,
neither carrying the fixes — installed by hand. Nothing was vouched.

Capability map row STAYS FAIL. Campaign 11 doc gets a dated ADDENDUM, not a
rewrite.
2026-08-06 12:18:29 +02:00
admin 6a835ad9ec Re-walk R-201: Phase A record, written BEFORE anything is destroyed
gates / gates (push) Successful in 8s
The fixture is built and the gate passed: all three sentinels are in snapshot
a7bc23bd BY NAME and at the right sizes, and the accented filename survived
into restic intact.

Recorded because they are results, not incidentals:
- what a FRESH install actually landed on — controller 0.201.0, agent 0.125.0,
  golden 0.201.0. Neither carries the fixes. Brought to 0.202.0/0.126.0 BY HAND,
  and the delivery gap is recorded as owed: this proves the journey, NOT that a
  customer would receive that build.
- baseline drift caught on arrival: one documentation-only R-229 commit per repo,
  and the highest register ID is R-229, not the runbook's R-228.
- the runbook's installer baseline (1.25.0) is stale; the published artifact is
  1.26.1, verified byte-identical to demo-hp's local copy.
- credentials DISCOVERED not assumed: HUB_PW mapped and verified live; nothing
  else was needed from the file.

A harness fault worth keeping: the accented sentinel's filename was destroyed at
creation by my own base64->bash->pct exec chain, producing U+FFFD replacement
characters. A Python decode('utf-8') check called it VALID UTF-8, because U+FFFD
is valid UTF-8 — only a hex dump of the filename bytes exposed it. Rewritten
from explicit bytes inside Python on the guest.

R claimed one-shot, streamed file->file to a 0600 store on DooPlex, never
rendered, shape verified without printing (10 words, 75 chars). The runbook's
§5.5-vs-§9.4 tension about where R may live is flagged in the journal rather
than resolved silently.
2026-08-06 11:19:19 +02:00
admin 9c1d05d360 CAMPAIGN-11: hygiene, what-did-not-run, venue end state, and the session report
gates / gates (push) Successful in 8s
The recovery codes are shredded with the plant->find->shred->fail-to-find
control the brief asks for, and THE CONTROL PAID FOR ITSELF ON ITS FIRST RUN:
it found the Phase 0 code in ~/.config/credentials as R_CAMPAIGN_11 — a copy
this session did not create and would never have looked for. Without it, a
'codes shredded' claim would have been false. That key was removed from the
shared file with a verified diff (every other line identical, nine keys intact)
and HUB_PW re-tested at hub:200.

Consequence stated plainly rather than left to be discovered:
/home/felhom-repo.orphaned-20260805 (12 535 KB, the three Phase 0 sentinels) is
now permanently unopenable — which is what the set-aside screen promises, and
teardown removes it anyway.

Venue left WORKING and said so: ONLINE, 4 containers healthy, backup target not
degraded, off-site on 2 snapshots. Two things a future session needs: the raw
/mnt/{adatok,mentes} mounts are deliberately left unmounted (R-220's
workaround), and the appliance root credential was shredded — re-fetch it from
the hub.

REPORT-campaign11-phase24.md rather than REPORT.md, per the repo's
parallel-session rule.

No product code changed. No version bumped.
2026-08-06 04:32:56 +02:00
admin df6081e60b CAMPAIGN-11 Phase 4: the soak passed, with two absences answered honestly
gates / gates (push) Successful in 8s
All five daily jobs fired exactly once and completed on time. The 04:15 offsite
run produced snapshot_count 1 -> 2, last_status ok, 24.9s — unprompted, on a box
rebuilt twice and set aside four hours earlier. Nothing on the must-not list
fired, including offsiteheal: that is R-218's NEGATIVE control passing (a box
with a target must not declare), which does not substitute for its positive
half, still owed.

Investigated and DISPROVED: tier2-backup completing in 118ms looked like a
silent no-op; the copy is real and on the backup drive (818.5 KB verified).

Correction to my own pre-registration: backup_run_digest is a TEST FILENAME, not
an event type. The real one is backup_run_failures, a failures digest whose
silence on a clean night is correct — reporting it as a miss would have been a
finding I invented. What survives: the offsite run emits no hub event while both
lesser tiers announce success; failures and staleness are covered elsewhere, so
it is a consistency wrinkle, recorded not filed.

Two absences answered rather than assumed: the restore-test's silence was
PRE-REGISTERED as correct (6h eval, 24h settle); the agent's whole-guest tier is
left explicitly UNRESOLVED because routine local-api calls are not logged at INFO
— a 5h search returns 0 on a box that demonstrably served such calls, so the
instrument cannot answer.

No product code changed.
2026-08-06 04:21:13 +02:00
admin 07998dcff2 CAMPAIGN-11 Phase 4: pre-registered expectations, both directions, before the window
gates / gates (push) Successful in 9s
Written BEFORE the soak so the comparison cannot be fitted afterwards. Sources
are the box's own [scheduler] Registered lines and the agent's backup tier armed
lines, read at 23:56.

MUST happen: db-dump 02:30, tier2-backup + fill-watch 03:30, metrics-prune
04:00, offbox-backup 04:15 (snapshot_count 1 -> 2), a backup_run_digest event,
reports every ~15m.
MUST NOT happen: host_stale/host_recovered, offsite_selfheal_restaged (this is
also R-218's negative control — a box WITH a target must not declare),
offbox_repo_orphaned, offsite_repo_key_changed, escrow blob SERVED, any
controller self-update.
Genuinely uncertain and recorded as such: the restore-test has a 24h settle and
every archive here is hours old, so NOT running is correct, not a gap.
2026-08-05 23:59:19 +02:00
admin f88faad50b CAMPAIGN-11 Phase 2 complete: F7/F9/F10/F11, and R-228 (the set-aside history is invisible)
gates / gates (push) Successful in 8s
F11 PASS  ok->stale->ok, an operator mail each way, customer mail correctly
          pairing-gated. DOWN (>1h) not reached — stated, not implied.
F7  the set-aside PASSES decisively: move-aside to
          /home/felhom-repo.orphaned-20260805, mtime and du -s (12535 KB) and
          snapshot f3d9cd67 all unchanged; a fresh empty repo beside it.
          NOTHING DELETED.
    the afterwards FAILS -> R-228: settings.json records
          "orphaned_renamed_to" and OrphanedRenamedTo has ZERO references in
          any template or handler. 12.5 MB of retained customer data at a path
          the box knows and never shows. Seam built, never wired.
F9  R-215's fix PROVEN LIVE on a narrower shape: with recoveryOffer() false,
          GET /recovery now 302s instead of rendering its story. The literal
          never-had-offsite precondition was not staged (it needs a rebuild,
          which the brief forbids before Phase 4) — recorded as partial.
F10 NOT INJECTED, harness not product. Three attempts, each with a control:
          the app, then the controller's monitor, then the run itself recreate
          the mandatory directory within ~1 s. Kept as an observation: at
          capture the directory held only a recreated metadata.db and NOT the
          customer's file, and the run still said ok.

Also reproduced live for a third time: R-220 (candidates empty; unmounting only
the raw mounts flips both drives back) — still OPEN.

Venue left WORKING: 4 containers healthy, backup target not degraded, off-site
fresh repo last_status ok, escrow escrowed.
No product code changed.
2026-08-05 23:55:52 +02:00
admin 04ac465da6 CAMPAIGN-11 Phases 2+4: the fault journal, the campaign document, and hub v0.97.1's missing heading
gates / gates (push) Successful in 8s
Phase 2 (eleven injected faults) and the §4 positives that were owed.

- §4.1 MEASURED, twice: the box's rendered GetFloor() is 0.200.0, and a
  cold-started controller logs "settle-gate: GO — at/above floor 0.200.0"
  against the same line reading "floor still unknown" while the hold was in
  force. Also corrects the brief's plan: SetFloor's line is u.dbg(), gated on
  logging.level=debug and written to the logger, so it can NEVER reach the
  debug ring — a restart alone would not have produced it.
- §4.2 still NOT measured, deliberately: the venue has an off-site target, so
  needsOffsiteCredential correctly returns false. Recorded, not inferred from
  the unit test.
- F1 PARTIAL, F2 PASS, F3 FAIL, F4 FAIL, F5 PASS, F6 PASS, F8 PARTIAL.
  F3+F4: a hub outage and a stopped agent are both rendered as "this code does
  not open your package", in 0.056 s and 0.030 s — no unseal attempted. The
  agent's own err field distinguishes them exactly and it is discarded at the
  HTTP boundary; the R-216 capability gate answers source=version and cannot
  see reachability.
- R-217's fix HOLDS under exactly its fault (F5), verified with the false-claim
  strings absent and accented positive controls present.

hub/CHANGELOG.md: v0.97.1 had no heading of its own — the change was written
into the v0.97.0 entry while the deployed tag is 0.97.1. Given its own entry,
marked as added retroactively. Second occurrence of the class (agent 0.90.1).

Evidence: documentation/tests/campaign11-evidence-2026-08-05/journal-phase24.md
No product code changed.
2026-08-05 23:13:47 +02:00
admin 3a539ea530 docs: R-223 CLOSED by a golden rebake — and it was never a dropdown
gates / gates (push) Successful in 11s
The first vouch of agent 0.125.0 was REFUSED by R-120's gate: the artifacts form saves as
a unit, and golden 0.192.0 was older than the newest controller the fleet reports. The
golden had been stale since before controller 0.193.0, so the Day-0 manifest had been
effectively unvouchable for days and nobody had cause to notice. Correcting STATUS.md and
OPEN-ITEMS, which said "one dropdown".

Golden 0.201.0 baked in the drill VM, round-trip verified from Gitea
(e730d7cab343eb35...f007654, 658165766 B), teardown clean, 0 token hits in the saved log.
Manifest now agent=0.125.0 golden=0.201.0 min_agent=0.125.0, read back after the save.

The held floor: the HOLD is established positively (hub log + the box's own "floor still
unknown"). Its RELEASE is not — no HELD line and no dashboard reason are both absences,
the served path logs nothing by design, and the box-side positive needs a restart the
venue cannot take before Phase 2. Recorded as deduction plus a pinned test, not a live
positive.
2026-08-05 22:29:30 +02:00
admin 1a0f7db92f docs: CAMPAIGN-11 — the journey FAILED, R-198's retention PROVEN, six findings fixed
gates / gates (push) Successful in 8s
Registers and evidence for the campaign and its fix pass.

OPEN-ITEMS: R-214..R-223. Six SHIPPED (R-215/216/217/218/219/222); three deliberately
still open and each blocks a real flow (R-214 console banner, R-220 drives unenrollable
after a rebuild, R-221 a rebuilt box cannot run the escrow ceremony); R-223 minted and
WAITING-ON-OPERATOR (vouch agent 0.125.0). R-213 and R-202 untouched.

Capability map: a new row for the customer's UNAIDED journey, recorded FAILED and staying
failed until a re-walk passes — fixes are not a journey. The existing rebuild row is
corrected where it said R-198's retention was unit-proven only: it was proven in production
on the first supersession since the fix, identity_blob retained at 572 B byte-length exact.

CLAUDE.md comment-vs-code table: eighth entry — ResolveManagedFloor, the first where the
false invariant was a GUARD rather than a comment alone.

STATUS: the headline is now "the backup promise is proved, the recovery journey is not",
and the one thing waiting on the operator.
2026-08-05 18:04:13 +02:00
admin e34b614e5b docs: R-182 closed, R-90 closed on measurement, R-86 unblocked, ep0 record corrected
gates / gates (push) Successful in 7s
R-182 CLOSED (controller v0.194.0 + hub v0.90.0/.1), proven live on demo-hp. The
hub's notification_log for the run reads: two per-app failures RECORDED, one
digest SENT naming both, and the customer channel SKIPPED with operator_only.
Against the measured previous behaviour — two failures, one email naming one
app, one leaving no trace anywhere.

Scenario D proved itself on an event I had not planned: disk_critical alarmed on
two filesystems, the second was collapsed by the cooldown, and that collapse is
now visible WITH ITS KEY. Yesterday it would have left nothing at all.

A gap the spec did not anticipate is recorded with its fix: the per-app event
also fires from the periodic sweep, outside any run, so making it record-only
would have created a NEW silence. The sweep emits a digest too, with no run_id,
so it stays under the ordinary hourly cooldown.

ep0: MEASURED on the box — 7757 MB (8 GB), 4 vCPU, and the 4 GiB swapfile
SURVIVED the resize and is active (checked, because a resize is a stop/start).
The 40 GB local disk is UNCHANGED, so no disk figure was touched anywhere.

Five documents corrected — three of which the task's list did not name, found by
searching. Two audit/evidence documents ANNOTATED, body untouched: they record
what was true when written and that is their value.

R-90 CLOSED. R-86 unblocked and re-ranked, stated honestly: 8 GB is comfortable,
not unbounded — the original OOM was a 14.46 GB restore — so the restore-test
cadence should still be paced, just not by fear of the endpoint.

target-selection.md's "D-d did not name ep0 either way" is deliberately left
standing. It is the operator's question, not CC's.

STATUS.md 127 -> 83 lines, items rather than sentences.
2026-08-03 14:00:54 +02:00