v0.164.0: deliberately stopped apps no longer alarm (banner + email)
A UI stop (Leallitas -> compose down -> StateStopped) is the user's own
action, not a fault, and must not raise the deadapp banner OR the
app_start_failed event. Filter at the single fix-3 derivation point:
extract scanDeployedAppRunStates's pure core to classifyRunStates and
change the down predicate to IsDownState(st.State) && st.State !=
StateStopped. Suppresses StateStopped from both the banner dead-list and
the notifier Down-set at once.
Rests on two invariants (recorded at the seam, README, CONTEXT):
I1 StopStack = compose down => zero containers => StateStopped
I2 P2 census: all catalog services unless-stopped => faults never rest
at stopped (they surface as exited/degraded).
IsDownState unchanged; out-of-band 'compose stop' (containers remain ->
exited) still alerts. Tests +4 (notify 3->4, main 4->7), both red-proofs
verified. No template/funcmap/notifier/counter/copy change.
This commit is contained in:
@@ -1,5 +1,41 @@
|
||||
## Changelog
|
||||
|
||||
### v0.164.0 — Deliberately stopped apps no longer alarm (banner + email) (2026-07-24)
|
||||
|
||||
No agent coupling; MinAgent unchanged. Operator finding on 9201: stopping an app via the UI
|
||||
(Leállítás) raised the global warning banner "Telepített alkalmazás nem fut: … (stopped)" on every
|
||||
page — including the launcher, where the tile already shows the greyed state — and fired the
|
||||
`app_start_failed` notification event on the running→down transition. A deliberate user action is not
|
||||
a fault; it must not alarm the user anywhere. Genuine faults keep alerting exactly as before.
|
||||
|
||||
- **The fix is a one-line filter at the single fix-3 derivation point.** `scanDeployedAppRunStates`
|
||||
(cmd/controller/main.go) is the only place both the banner dead-list and the notifier Down-set are
|
||||
computed. Its pure core was extracted to `classifyRunStates([]stacks.Stack)` (testable without a
|
||||
live Manager), and the down predicate changed from `stacks.IsDownState(st.State)` to
|
||||
`stacks.IsDownState(st.State) && st.State != stacks.StateStopped`. `StateStopped` is therefore
|
||||
suppressed from BOTH surfaces: no banner on any page (launcher included) and `Down=false` fed to
|
||||
the notifier ⇒ no `app_start_failed` event and a clean transition tracker.
|
||||
- **Why `StateStopped` ⇒ deliberate (two invariants, recorded at the seam and in CONTEXT.md):**
|
||||
(I1) the UI stop path `Manager.StopStack` runs `docker compose down` → containers are removed, and
|
||||
a deployed stack with zero containers aggregates to `StateStopped` (refreshStatusLocked). (I2) the
|
||||
P2 restart-policy census (2026-07-21, 53 templates / 78 services) found every catalog service on
|
||||
`unless-stopped`, so a crashing app never comes to rest at `stopped` — faults surface as
|
||||
`restarting` / `unhealthy` / `exited` / `degraded`. **If either invariant changes, revisit this
|
||||
suppression.** An out-of-band `docker compose stop` leaves containers present → `StateExited` →
|
||||
still alerts (out-of-band tampering is reportable — acceptable).
|
||||
- **`IsDownState` deliberately UNCHANGED** — other callers (e.g. `CommittedMemory`, bootrecon) rely
|
||||
on stopped counting as down. The suppression lives ONLY at the scan; no template, funcmap,
|
||||
notifier, dashboard-counter, or Hungarian-copy change. The launcher tile still shows greyed +
|
||||
"Leállítva"; the monitoring page and dashboard RunningCount/StoppedCount are unchanged (factual
|
||||
display is not an alarm). A pre-existing banner self-clears on the next health cycle (state-based).
|
||||
- **Tests +4** (notify 3→4, main 4→7): Group A — `classifyRunStates` over [running, stopped, exited,
|
||||
degraded] yields dead={exited,degraded} and Down flags {false,false,true,true} (red-proof: revert
|
||||
the filter → both assertions fail, verified). Group B — fault parity: exited+degraded both in the
|
||||
dead list, both Down=true, raw state string carried through. Group C — stop→start→crash drives
|
||||
`NotifyAppStartFailures` to exactly ONE event for the crash and zero for the stop (red-proof: mark
|
||||
the stop Down=true → the zero-for-stop assertion fails, verified). Plus a skip test for
|
||||
deploying/undeployed.
|
||||
|
||||
### v0.163.1 — Launcher polish: monogram reveal-on-failure + placeholder on every icon surface (2026-07-24)
|
||||
|
||||
No agent coupling; MinAgent unchanged. Two live findings from the v0.163.0 operator browser pass on 9201.
|
||||
|
||||
Reference in New Issue
Block a user