v0.162.0 — R-71(a): the apply-bridge settle-gate (kills the F10 day-0 race)
The day-0 race (DIAG-f10): a fresh box boots below the operator floor, the apply-bridge consumes the single-use offsite password, then ~35s later the managed auto-floor update replaces the container mid-install -> the new process finds no installed key -> consume -> 404 -> offsite dead until an operator Re-issue. Recurs on every onboarding whose ISO floor lags the managed floor. Ordering-only fix (consume/install/persist internals + the 404-no-oracle contract + the Consumer UNTOUCHED; R-71(b) rejected-by-design): - New seam offsiteapply.SettleProvider.SettleState() + SettleFunc adapter over the self-updater's own GetFloor()/IsUpdateRunning() (no second floor path). - Bridge.AwaitSettle polls 10s BEFORE the 3-min Reconcile ctx: defers while an update runs or the box is below the known floor; GOes at/above floor on the first poll with zero added latency (B'). Bounds 90s floor sub-bound / 5min overall, both GO+WARN (hub that can't serve a floor can't serve a consume -> no burn risk; R-71c is the belt). ReconcileWhenSettled = gate then reconcile. - main.go: bridge goroutine moved after the updater is built; wired only when an updater exists (nil Settle = reconcile immediately, old behavior). Finding: the floor is in-memory (report-ACK ~5-10s), NOT persisted -> unknown on any restart until the first ACK; the 90s sub-bound is sized to that. Tests (injectable clock, fake SettleState, recorded Consumer): A-E + nil-provider + cancelled-gate. Four red-proofs all observed FAIL then restored: gate removed / updateRunning branch / floor sub-bound / overall bound. Deferral paths ship unit-proven + red-proofed, NOT live-fired -- their precondition is now structurally prevented by the v1.25.0 build gate. Layering: gate prevents, (a) defers, (c) heals. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7Drmtm2RzoqbkJZCNSFNQ
This commit is contained in:
@@ -1,5 +1,50 @@
|
||||
## Changelog
|
||||
|
||||
### v0.162.0 — R-71(a): the apply-bridge waits for the dust to settle (settle-gate) (2026-07-24)
|
||||
|
||||
No agent coupling; MinAgent unchanged. Origin:
|
||||
`felhom.eu/documentation/audits/DIAG-f10-demo-hp-offsite-2026-07-23.md` — the day-0 race. A fresh box
|
||||
boots below the operator floor (ISO 0.153.0 < floor 0.156.0), the apply-bridge consumes the
|
||||
single-use offsite password, then ~35 s later the managed auto-floor update replaces the container
|
||||
mid-install → the new process finds no installed key → consume → **404** → offsite dead until an
|
||||
operator Re-issue. This recurs on **every** fresh onboarding whose ISO floor lags the managed floor;
|
||||
demo-felhom escaped by timing alone. The v1.25.0 golden≥floor build gate PREVENTS the trigger for
|
||||
fresh installs; R-71c (hub) HEALS a burn after the fact; this (a) removes the SYSTEMATIC trigger for
|
||||
every restart shape.
|
||||
|
||||
**The change (ordering only — the bridge's consume/install/persist internals, the 404-no-oracle
|
||||
contract, and the Consumer are UNTOUCHED; R-71(b) stays rejected-by-design):**
|
||||
- New seam `offsiteapply.SettleProvider.SettleState() (version, floor string, updateRunning,
|
||||
floorKnown bool)` — a thin adapter (`SettleFunc`) over the self-updater's OWN knowledge in main.go
|
||||
(`GetFloor()`/`IsUpdateRunning()`); the bridge never fetches the floor a second way.
|
||||
- `Bridge.AwaitSettle` polls every 10 s (bounds: 90 s floor-knowledge sub-bound, 5 min overall)
|
||||
BEFORE the 3-minute Reconcile context is created (the deferral never eats the reconcile budget).
|
||||
Releases: `updateRunning` → wait (the swap supersedes us); `floorKnown && version<floor` → wait
|
||||
(auto-floor update imminent — do NOT burn the password); `floorKnown && at/above floor` → **GO on
|
||||
the first poll, zero sleep** (the B′ invariant); `!floorKnown` past 90 s → GO+WARN (a hub that
|
||||
can't serve a floor can't serve a consume → no burn risk); overall bound → GO+WARN (R-71c is the
|
||||
belt). `ReconcileWhenSettled` runs the gate then Reconcile.
|
||||
- The bridge goroutine MOVED in main.go to after the self-updater is constructed (so the adapter can
|
||||
read it). Wired ONLY when an updater exists — with no update mechanism there is no floor-update to
|
||||
race, so the bridge reconciles immediately (`Settle` nil = old behavior).
|
||||
|
||||
**Finding (cited in the sub-bound rationale):** the floor is in-memory (report-ACK-derived), NOT
|
||||
persisted — so on any restart it is unknown until the first report ACK. The startup report fires ~5 s
|
||||
after boot and `SetFloor` runs synchronously in its ACK handler, so the floor is normally known in
|
||||
~5–10 s (≤~45 s across the 3×15 s report retries); the 90 s sub-bound is headroom over that.
|
||||
|
||||
**Tests (injectable clock, no real sleeps; fake SettleState + recorded Consumer):** A below-floor
|
||||
defers then GOes at floor (one consume); B update-running defers then GOes; C floor-unknown GOes at
|
||||
the sub-bound + WARN; D perpetually-below GOes at the overall bound + WARN; E (B′) at-floor GOes on
|
||||
poll 1 with zero wait; plus nil-provider immediate-reconcile and cancelled-gate-skips-reconcile.
|
||||
**Four red-proofs, all observed FAIL then restored:** remove the gate → below-floor consumes
|
||||
immediately (0 deferral sleeps); remove the updateRunning branch → mid-swap box GOes immediately;
|
||||
drop the sub-bound → floor-unknown drags 90 s→5 m; drop the overall bound → perpetual below-floor
|
||||
loops forever (20 s test timeout). The deferral paths ship **unit-proven + red-proofed, NOT
|
||||
live-fired** — their precondition is now structurally prevented by the v1.25.0 build gate, which is
|
||||
the point: **gate prevents, (a) defers, (c) heals.** Live-observable leg = the B′ first-poll GO line
|
||||
on both above-floor demo boxes.
|
||||
|
||||
### v0.161.0 — R-70: the hub-managed offsite empty state tells the truth (2026-07-23)
|
||||
|
||||
No agent coupling; MinAgent unchanged. Origin: `felhom.eu/documentation/audits/DIAG-f10-demo-hp-offsite-2026-07-23.md`
|
||||
|
||||
Reference in New Issue
Block a user