This commit is contained in:
+53
@@ -7,6 +7,59 @@
|
||||
>
|
||||
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
|
||||
|
||||
Last updated: 2026-08-02 (v0.190.0 — R-157 A · R-170 · R-171: boot recovery finished)
|
||||
|
||||
> **2026-08-02 — v0.190.0 (R-157 mechanism A · R-170 · R-171).** Three items, one live validation
|
||||
> cycle, because all three are boot behaviour and all three are proven by hard-resetting the box.
|
||||
>
|
||||
> **DIAGNOSE BEFORE THEORISING — and the first diagnosis was a FALSE NEGATIVE.** A hole was reasoned
|
||||
> out of the v0.189.0 diff (a drive-gate-stopped app has zero containers and `desired_state: running`,
|
||||
> so it now reads as a boot orphan) and confirmed on hardware BEFORE any fix was written. **Attempt 1
|
||||
> produced `no boot-orphaned apps` and would have been reported as a disproof.** It was a race:
|
||||
> unmounting only the parent bind is healed by the agent within ~60 s, so the drive gate's startup
|
||||
> reconcile restarted the apps **one second before** the sweep looked. Holding the drive genuinely
|
||||
> absent reproduced the defect immediately. **"It didn't happen this time" is not a mechanism.**
|
||||
>
|
||||
> **The confirmation moved the severity in BOTH directions.** The write hazard did not materialise —
|
||||
> compose failed `mkdir …/userdata: permission denied` because the unbound mountpoint is
|
||||
> host-root-owned and the guest is unprivileged. **That protection is ACCIDENTAL**: no code chose it,
|
||||
> no test pinned it, and it is one `chown` or one privileged guest away from gone. But the harm that
|
||||
> DID occur was not in the hypothesis and is real on every box: two wasted attempts and a **false
|
||||
> dead-app alarm for an app the drive gate is deliberately holding**.
|
||||
>
|
||||
> **The fix already existed one path over.** `startGatedByMissingDrive` (the API) refuses a customer's
|
||||
> start on an absent drive; the sweep bypassed it by calling `Manager.StartStack` directly.
|
||||
> **`StartStack` HAS NO GATE OF ITS OWN** — carry this: every caller that is not the customer must
|
||||
> decide for itself whether the app may run. New consumer-side `bootrecon.StartGate`, fail-safe
|
||||
> (cannot determine ⇒ do not start).
|
||||
>
|
||||
> **Widening a window makes previously-unreachable overlaps reachable — a design input, not an
|
||||
> afterthought.** The old T+5 s sweep never met a quiesce or an in-flight app-data operation; a 50 s
|
||||
> window can. All three holders answer ONE seam because they differ only in the reason string.
|
||||
>
|
||||
> **A TEST REJECTED MY FIRST CONSTANT, and the comment says so.** `settle + budget + one retry` must
|
||||
> fit inside `deadAppBootGrace`; 60 s gave 95 s against 90 s. The budget is 50 s **because a test said
|
||||
> so** — recorded in the code rather than presented as taste. Widening the grace was rejected: it
|
||||
> hides a late recovery instead of reporting one (`recordLateRecovery`).
|
||||
>
|
||||
> **THE FIX HAD ITS OWN DEFECT, FOUND LIVE AND NOT BY REVIEW.** The window sampled `GetStacks()` — the
|
||||
> Manager's map, refreshed by the scheduler every **10 s** — every 5 s, so two identical samples could
|
||||
> mean *the cache did not update*. Observed: a container removed ~5 s before the window closed was
|
||||
> still in the sampled fleet and the sweep logged `no boot-orphaned apps` for an app that had none.
|
||||
> `sampleBootFleet` now refreshes first. **Generalise: a settle detector is only as good as the
|
||||
> freshness of what it samples — if the source is cached, refresh it, or you are watching the cache
|
||||
> settle rather than the system.**
|
||||
>
|
||||
> **R-170:** `shouldRecreateOnBoot` reads intent with the identical three-way table; absent keeps the
|
||||
> old `hasContainers` behaviour exactly; `presentStable` untouched and still load-bearing. Its comment
|
||||
> argued at length FOR the count and was rewritten. Agreement pinned from BOTH sides against one
|
||||
> fixture table (an import cycle prevents testing the two gates together).
|
||||
>
|
||||
> **Live: 6/6 hard resets** (every app back; the customer-stopped app down all six), settle times
|
||||
> 10/40/10/10/15/15 s. Sharpest evidence: same app, same box — missed at 18:08:35, recovered at
|
||||
> 18:18:50. R-170 proven in one reboot (calibre-web recreated, immich left stopped). 27/27 packages;
|
||||
> 7 red-proofs. Detail: `REPORT.md`.
|
||||
|
||||
Last updated: 2026-08-02 (v0.189.0 — R-166 / D-b: the box stops guessing what the customer wanted)
|
||||
|
||||
> **2026-08-02 — v0.189.0 (R-166, operator decision D-b).** When an app was not running the box had
|
||||
|
||||
Reference in New Issue
Block a user