hub v0.104.0: the guest network gets a reader (R-319), and the hub half of the naming (R-295)
gates / gates (push) Successful in 14s

Four paper debts and one fact given a reader. Hub-only — nothing to bake.

A4 — the entry about "the tester's machine" named a risk correctly and labelled it
in a way that invited deleting it. Established from the hub's own store: `peti-felhom`
is a REAL machine (482 reports, 2026-02-27 → 2026-07-15, a named person's own box) and
the 3.6 GB with no key and no backup is real. `david` → `tester-1` is a DIFFERENT record
with no host, no escrow and no report, ever — deleted 07:55:49 and re-created 07:56:47
this morning. The prompt's premise conflated the two; the register now says which is which.

A1 — R-312/R-313/R-303 recorded as DECIDED with their re-open triggers, and moved out
of STATUS's "Waiting on you", which is now empty.

A3 — day0-install §C.1 said pushing the installer publishes it. It has not since
R-110. Corrected, with the two manifest pins named and an outside-verification command;
the one copy that repeated it (a dated audit, true when written) carries a superseded note.

A5 — standing rule 5: evidence comes off the machine at the end of the phase that
produced it, before any revert. Earned twice in three days on the same box at the same
point (R-320). Four homes, plus what to do when it is already gone.

R-295 hub half — „Beállító kód" everywhere; „Visszaállító kód" retired. New `reenroll`
mail kind so the mail names the page a REBUILT box actually shows („A szerver
beállítása"), not the „Elfelejtett jelszó" page it has no login screen to reach.
Naming only; the acceptance pin proves the secret is untouched.

R-319 — the hub models `guest_net` after 23 days of receiving and discarding it. The
signal is `heals_last_hour`, not `state`: a guest the watchdog keeps repairing reads
healthy between repairs. `heal_succeeded` decoded too (R-260's lesson). Unknown is never
drawn as healthy — three absences, three sentences. No alarm, deliberately.
Three red-proofs, mutations asserted applied. Wire-gate checked tags 182 → 190.

B1 — the operator's 2026-08-12 dispositions were NOT in the register; they are now.
Third allowlist kind for the five ruled "no reader wanted"; `reporting_disabled`
reclassified redundant. 8 read · 5 deliberately unread · 1 redundant · 6 still owed.

Also filed: R-321 (a deliberately-silent box still alarms stale/down — the checker is
age-only, and decoding the flag would not have fixed it), R-322 (the claim guard has
never scanned the hub; a hand scan returns zero, so it is a scope gap, not a defect).
This commit is contained in:
2026-08-13 10:50:12 +02:00
parent 2d05b29b82
commit 4d6ec7c7bb
22 changed files with 1253 additions and 115 deletions
@@ -317,6 +317,82 @@
{{end}}
</section>
<!-- Guest network (R-319): the R-54 watchdog's verdict per owned guest, and — the reason this
card exists — HOW OFTEN IT HAD TO REPAIR EACH ONE. A guest the watchdog keeps fixing is
healthy every time anyone looks and is nevertheless failing; showing only the state would
give it a green tick, which is the failed-disk-drawn-as-a-healthy-empty-disk defect.
An unknown is NEVER drawn as healthy. Three absences, three sentences: an agent too old to
report it, a capable agent that reported nothing, and a guest whose own state the watchdog
did not assert. Each branch of this gate has its own render test (the template-gate rule).
The agent has sent this on every heartbeat since v0.92.0 and nothing read it until now. -->
<section class="card">
<h2>Guest network
{{if .GuestNet.AgentTooOld}}<span class="badge badge-neutral" title="This agent predates the guest-network watchdog">unknown</span>
{{else if not .GuestNet.Reported}}<span class="badge badge-neutral" title="A capable agent sent no guest-network stanza">unknown</span>
{{else if .GuestNet.Degraded}}<span class="badge badge-warn" title="A guest is unhealthy, or is being repaired repeatedly">needs attention</span>
{{else if .GuestNet.UnknownCount}}<span class="badge badge-neutral" title="The watchdog did not assert a state for every guest">partly unknown</span>
{{else if .GuestNet.Guests}}<span class="badge badge-ok" title="Every owned guest has an address, a default route and a live dhclient">healthy</span>
{{end}}
</h2>
{{if .GuestNet.AgentTooOld}}
<p class="hint" style="color: var(--text-muted); font-size: 0.85rem;">
This host's agent (<code>{{.AgentVersion}}</code>) does not run the guest-network watchdog &mdash;
its guests' networking is <strong>unknown</strong>, not healthy. Needs agent <code>0.92.0</code> or newer.
</p>
{{else if not .GuestNet.Reported}}
<p class="hint" style="color: var(--text-muted); font-size: 0.85rem;">
This host reported no guest-network state, so it is <strong>unknown</strong> &mdash; not healthy.
The watchdog is default-on; a silent capable agent means it was switched off
(<code>guest_net.disable</code>), or this report predates it on this box.
</p>
{{else if .GuestNet.Guests}}
<table class="data-table">
<thead>
<tr><th>Guest</th><th>State</th><th>Address</th><th>Route</th><th>dhclient</th><th>Repairs (1h)</th></tr>
</thead>
<tbody>
{{range .GuestNet.Guests}}
<tr>
<td><code>{{.VMID}}</code></td>
<td>
{{if .Unknown}}<span class="badge badge-neutral" title="{{.Message}}">unknown</span>
{{else if eq .State "healthy"}}<span class="badge badge-ok" title="{{.Message}}">healthy</span>
{{else if eq .State "static_fault"}}<span class="badge badge-warn" title="{{.Message}}">static fault</span>
{{else}}<span class="badge badge-error" title="{{.Message}}">unhealthy</span>{{end}}
{{if .HealFailed}}<span class="badge badge-error" title="The watchdog TRIED to repair this guest and did not succeed">repair failed</span>{{end}}
{{if .Damped}}<span class="badge badge-neutral" title="Repairs are rate-limited on this guest">damped</span>{{end}}
</td>
<td>{{if .IP}}<code>{{.IP}}</code> <span class="text-muted">({{.Mode}})</span>{{else}}<span class="text-muted">&mdash;</span>{{end}}</td>
<td>{{if .HasRoute}}yes{{else}}<strong>no</strong>{{end}}</td>
<td>{{if .DHClientAlive}}yes{{else if eq .Mode "static"}}<span class="text-muted">n/a</span>{{else}}<strong>no</strong>{{end}}</td>
<td>
{{if .Repairing}}<span class="badge badge-warn" title="The watchdog repaired this guest's network {{.RepairCount}} time(s) in the last hour — last at {{.LastHealAt}}">{{.RepairCount}}</span>
{{else}}<span class="text-muted">0</span>{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
{{if .GuestNet.RepairingCount}}
<p class="hint" style="font-size: 0.85rem; margin-top: 0.5rem;">
<strong>{{.GuestNet.RepairingCount}} guest(s) had their networking repaired in the last hour.</strong>
A guest that keeps being repaired reads healthy between repairs and is not. A killed
<code>dhclient</code> once took a tunnel down for 1 h 15 m with nobody told; this row is that signal.
</p>
{{end}}
<p class="hint" style="color: var(--text-muted); font-size: 0.85rem; margin-top: 0.5rem;">
Last swept {{.GuestNet.CheckedAt}}. One row per owned <em>running</em> guest the watchdog has probed.
</p>
{{else}}
<p class="hint" style="color: var(--text-muted); font-size: 0.85rem;">
The watchdog ran and has no guest to report (swept {{.GuestNet.CheckedAt}}). This is
distinguishable from silence: the stanza arrived, its guest list is empty.
</p>
{{end}}
</section>
<!-- DR / Backup -->
<section class="card">
<h2>DR / Backup</h2>