hub v0.67.0 — auto-minted self-bind link, post-RESET staleness, unprovisioned-offsite warning
Four small items, each a case where the hub already knew something and said
nothing. Green: build, vet, tests all pass.
(a) Self-bind link is minted automatically at customer creation AND at RESET
completion (R-36 sub-item). The console banner tells the customer to open
"az e-mailben kapott link"; until now that email existed only once the
operator remembered the button, so the banner could point at something that
did not exist — during the 2026-07-18 rehearsal the box waited ~11.7 min on
exactly that. handleSelfBindLinkSend's body was extracted into a shared
mintAndSendSelfBindLink core so the button and the auto-mint callers cannot
drift apart on the honesty rules: F1 (no address -> mint nothing) and F2
(send failed -> delete the token, never leave it live). The wrapper NEVER
fails the operation it rides on — a create that provisioned Cloudflare,
offsite and PBS must not 500 over a courtesy email.
Gap found and closed while wiring it: PurgeCustomerResetDBState does NOT
clear selfbind_tokens, so a link minted BEFORE a reset would have stayed
live across it. A successful mint already replaces it (delete-then-insert,
single-active); the skip paths would not have, so they now clear stale
tokens too. Invariant: after auto-mint runs the only live link is one it
just issued, or none.
(b) Post-RESET staleness banner (R-37). When a RESET COMPLETED after the newest
report, every health figure on the page describes a lifecycle that no longer
exists, and the page kept showing pre-RESET warnings as current. Narrow on
purpose: an in-flight reset does not trigger it, and it clears itself when a
report arrives. Ties resolve to STALE — SQLite timestamps are second-
resolution and a same-second report almost certainly predates the reset;
erring the other way would hide the banner exactly when it matters.
(c) Unprovisioned-offsite warning (R-36 interim). enabled==true with type=="" is
a real, stable, silent state: provisioning is Save-triggered and the
re-enroll auto-re-issue deliberately skips an unprovisioned target, so
nothing self-heals it. Reuses the exact predicate the offsite re-issue
handler already refuses on.
(d) pbsdr_reissued rendered an EMPTY flash box — the key had no template branch,
so re-issuing PBS credentials showed a success box with no words (observed
live 2026-07-18). Now describes what was staged plus the R-39 caveat:
confirm `pvesm status` shows the entry active, because a converged agent can
report `applied` while the storage still 401s.
New .flash-warn (amber, --warn tokens) for the deviation tier between success
and error — exception-color principle: only on deviation, never on a healthy
page.
Tests assert each banner is ABSENT in the nominal cases as well as present in
the deviating one — a banner that always renders is worse than none. Both
red-proofed: deleting the pbsdr_reissued branch reproduces the original empty
box; neutering the staleness predicate fails the banner assertion. New
read-only store accessor CountSelfBindTokens makes the single-active invariant
assertable.
NOT in this train: the R-39 hub-side generation-bump fix the pre-travel task
made conditional. Its condition was REFUTED (SetHostDesired bumps
unconditionally; applyPBSDR is idempotent as documented) — the real mechanism is
the agent's descriptor-hash convergence and needs its own spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
This commit is contained in:
@@ -1,5 +1,67 @@
|
||||
# Felhom Hub — Changelog
|
||||
|
||||
## v0.67.0 — the hub stops keeping things to itself: auto-minted self-bind link, post-RESET staleness, unprovisioned-offsite warning (2026-07-18)
|
||||
|
||||
Four small items, each one a case where the hub already knew something and said nothing. Green:
|
||||
`go build ./... && go vet ./... && go test ./...` all pass.
|
||||
|
||||
- **(a) The self-bind link is minted automatically — at customer creation AND at RESET completion**
|
||||
(R-36 sub-item). The box's console banner tells the customer to open „az e-mailben kapott link";
|
||||
until now that email existed only once the operator remembered to press *Send self-bind link*, so
|
||||
the banner could be instructing someone to look for something that did not exist. During the
|
||||
2026-07-18 rehearsal the box sat in pairing mode for ~11.7 minutes waiting on exactly that.
|
||||
`handleSelfBindLinkSend`'s body was extracted into a shared `mintAndSendSelfBindLink` core so the
|
||||
button and the two auto-mint call sites **cannot drift apart on the honesty rules**: F1 (no
|
||||
registered address → mint nothing, because a link nobody can receive is worse than none) and F2
|
||||
(send failed → delete the token, never leave it silently live). The auto-mint wrapper **never
|
||||
fails the operation it rides on** — a customer create that provisioned Cloudflare, offsite and PBS
|
||||
must not 500 because a courtesy email bounced; every outcome is logged instead, and the operator
|
||||
can still re-send from the Setup tab.
|
||||
**Gap found and closed while wiring this:** `PurgeCustomerResetDBState` does **not** clear
|
||||
`selfbind_tokens`, so a capability link minted *before* a RESET would have stayed live across it.
|
||||
A successful mint already replaces it (minting is delete-then-insert, single-active), but the skip
|
||||
paths would not have — so the wrapper now clears stale tokens on those paths too. The invariant is
|
||||
now: after auto-mint runs, the only live link is one it just issued, or none.
|
||||
|
||||
- **(b) Post-RESET staleness banner** (R-37). When a RESET **completed** after the newest report,
|
||||
every health figure on the customer page describes a lifecycle that no longer exists — and the
|
||||
page went on showing pre-RESET warnings as if they were current. It now says so, quoting the
|
||||
customer-facing phrasing („RESET óta nincs adat") and the reset's timestamp. Deliberately narrow:
|
||||
an in-flight reset does **not** trigger it (only a completed one), and it clears itself the moment
|
||||
a report arrives. Ties resolve to *stale* — SQLite timestamps are second-resolution, and a
|
||||
same-second report almost certainly arrived just before the reset destroyed what it describes;
|
||||
erring the other way would hide the banner exactly when it matters most.
|
||||
|
||||
- **(c) Unprovisioned-offsite warning** (R-36 interim). `offsite.enabled == true` with no
|
||||
descriptor (`type == ""`) is a real, stable, silent state: provisioning is *Save*-triggered
|
||||
(`applyOffsite`), and the re-enroll auto-re-issue deliberately skips an unprovisioned target, so
|
||||
nothing self-heals it. The page now names the state and the fix (press Save once, then verify),
|
||||
reusing the exact predicate the offsite re-issue handler already refuses on.
|
||||
|
||||
- **(d) `pbsdr_reissued` rendered an EMPTY flash box.** The flash key had no branch in the template,
|
||||
so re-issuing PBS credentials showed the operator a success box containing nothing — observed live
|
||||
on 2026-07-18. It now describes what was staged **and** carries the R-39 caveat: confirm
|
||||
`pvesm status` shows the entry *active*, because a converged agent can report `applied` while the
|
||||
storage still authenticates 401.
|
||||
|
||||
- **Styling:** new `.flash-warn` (amber, `--warn`/`--warn-dim` tokens) for the deviation tier between
|
||||
success and error — per the exception-color principle it appears ONLY on deviation, never on a
|
||||
healthy page.
|
||||
|
||||
- **Tests** (`customer_state_banners_test.go`, `selfbind_automint_test.go`) assert each banner is
|
||||
**absent** in the nominal cases as well as present in the deviating one — a banner that renders
|
||||
unconditionally is worse than none, because operators stop reading it. Auto-mint covers F1, F2,
|
||||
the no-mailer case, and the pre-RESET-token invariant. **Both red-proofed:** deleting the
|
||||
`pbsdr_reissued` branch reproduces the original empty-box bug, and neutering the staleness
|
||||
predicate fails the banner assertion. New store accessor `CountSelfBindTokens` (read-only, keyed
|
||||
by a customer id the operator already knows) makes the single-active invariant assertable.
|
||||
|
||||
**Not in this train:** the R-39 hub-side generation-bump fix the pre-travel task made conditional.
|
||||
Its condition was **refuted** — `SetHostDesired` bumps unconditionally and `applyPBSDR` is
|
||||
idempotent as documented; the real mechanism is the agent's descriptor-hash convergence, which needs
|
||||
its own spec. Nothing was improvised here.
|
||||
|
||||
|
||||
## v0.66.0 — Customer self-bind (R-27 slice 1): tokenized capability link + public two-factor `/bind/` page (2026-07-17)
|
||||
|
||||
Lets a customer bind their OWN freshly-installed appliance without the operator. Until now every
|
||||
|
||||
Reference in New Issue
Block a user