Alert on leading-edge memory exhaustion (swap drain + PSI) before livelock blackout #184
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#184
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
kai-server livelocked from memory exhaustion two nights running (2026-05-29 ~06:22 and 2026-05-30 ~06:51). Root cause: a 3am
brew upgrade(viacoily-update.service) spawned a swarm of ~16cc1pluscompilers (~1GB RSS each) building a formula from source, which drove anon memory to ~30.7GB on a 31GB-usable box with only 2GB swap. Swap hit 0, the kernel entered unbounded__alloc_pages_slowpathreclaim, and the box thrashed for ~3 hours (one OOM stack trace took 03:14 to 06:51 to finish printing) before a power-cycle recovered it ~07:00.Key constraint: in-host telemetry goes dark during the livelock
node_exporteron kai-server has a hard data gap from ~03:15 to ~07:10 PDT on 2026-05-30 - the exact livelock window. SwapFree was observably draining (0.72 -> 0.23 GiB) right up to 03:15, then total blackout until reboot. You can only ever see up to the cliff, never through it. So post-hoc logging cannot diagnose the terminal phase. The only useful signal is an alert that fires on the leading edge (03:00-03:13 ramp) while the box can still emit a notification.Ask
Add a vmalert rule (or equivalent) on data that already exists in vmsingle from node_exporter:
node_memory_SwapFree_bytes{instance="kai-server"}low for N minutes (e.g. < 15% of SwapTotal).rate(node_pressure_memory_waiting_seconds_total{instance="kai-server"}[1m])rising (PSI memory stall = reclaim thrash starting).node_memory_MemAvailable_bytescollapsing.Route to a push notification (Discord / the existing alert path) so the spiral is caught before the blackout.
Notes
node_memory_Swap{Total,Free,Cached}_bytesandnode_pressure_memory_{waiting,stalled}_seconds_totalfor kai-server. No new exporter needed.coily-updatecap (separate issue) and the heartbeat-ingestion fix (separate issue).Found during the 2026-05-30 crash investigation.
I closed this as stale and I should not have. Recommend reopening.
Closed in the 2026-08-28 burn-down (#981) on age and dormancy. That was wrong, and I already held the evidence contradicting it when I made the call.
From
get_node_pressure_stallson kai-server earlier today, cumulative since boot 49 days ago:13,769 OOM kills and 20.4 million swap-out pages. Direct reclaim is running at roughly a billion pages scanned and stolen. That is the memory-pressure regime this issue was filed about, still operating, on the same host.
Current instantaneous PSI is calm (
memory some avg300: 0), so the box is not in a spiral right now. But this issue is not about the instantaneous state, it is about the leading edge going undetected, and its central observation stands untouched: node_exporter went dark for the entire livelock window, so post-hoc telemetry can never diagnose the terminal phase. The alert has to fire on the ramp or not at all.The dependency has also improved since filing. #680 records the kai-server observability stack scaled to zero with ser8 now canonical, so the vmalert rule this asks for would target ser8 rather than a local vmsingle. That is a change of target, not a reason the work is obsolete.
Recommend reopening.
state:closed label:burndown-2026-08recovers it, and it is worth doing individually rather than waiting for a bulk reversal.Why I got it wrong
I sorted the stale batch by age, priority and comment count, and closed on those signals without re-reading the bodies against evidence I had gathered hours earlier in the same session. The measurement was in my hands and I did not connect it. Same failure as the two merge errors recorded in #981: judging an issue by its metadata rather than by what is currently true about the system it describes.