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:
2026-07-24 07:48:45 +02:00
parent ce8531426c
commit cb8bf14599
9 changed files with 654 additions and 68 deletions
+18 -1
View File
@@ -7,7 +7,24 @@
>
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
Last updated: 2026-07-23 (v0.161.0 — R-70: truthful hub-managed offsite empty state)
Last updated: 2026-07-24 (v0.162.0 — R-71a: the apply-bridge settle-gate)
> **2026-07-24 — v0.162.0 (R-71a), CODE COMPLETE + green; deploy/live-verify on the publish train.**
> The structural fix for the F10 day-0 race (DIAG-f10): the apply-bridge no longer consumes the
> single-use offsite password while a managed floor-update is in flight or imminent (below floor).
> New seam `offsiteapply.SettleProvider.SettleState()` + `SettleFunc` adapter over the updater's own
> `GetFloor()`/`IsUpdateRunning()` (no second floor path); `Bridge.AwaitSettle` polls 10 s BEFORE the
> 3-min Reconcile ctx (deferral never eats the reconcile budget), bounds 90 s floor sub-bound / 5 min
> overall (both GO+WARN — the "hub that can't serve a floor can't serve a consume → no burn" argument,
> R-71c is the belt). At/above floor → GO first poll, zero wait (B). Bridge goroutine MOVED after the
> updater in main.go; wired only when an updater exists. **Ordering-only** — consume/persist/404
> contract untouched; R-71(b) rejected-by-design. **FINDING:** the floor is in-memory
> (report-ACK-derived ~510 s), NOT persisted → unknown on any restart until the first ACK (sized the
> 90 s sub-bound to that). 5 test scenarios (AE) + nil-provider + cancelled-gate; **4 red-proofs all
> observed FAIL then restored** (gate/updateRunning/sub-bound/overall-bound). Deferral paths NOT
> live-fired (precondition now structurally prevented by the v1.25.0 build gate). **Layering: gate
> prevents, (a) defers, (c) heals.** ROADMAP R-71 → SHIPPED (a)+(c). Live leg = the B first-poll GO
> line on both above-floor boxes.
> **2026-07-23 — v0.161.0 (R-70 controller leg), SHIPPED + deployed BOTH boxes.** When
> `offsite.enabled` is in controller.yaml but no `offbox` target exists (pre-apply window / burned