Treat Docker OOMKilled as an observation, not a status verdict (#151) - #152
Merged
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #151
A running container keeps status 'executing' with 'oomKilled true' exposed alongside; a stopped container reports its real .State.ExitCode; 137 is only used when the container is gone and neither a log footer nor an exit code can be recovered (preserving the #148 invariant).
$ --status reports executed / exitCode 137 from the container OOM flag while docker inspect still says running (session later exits 0)
konard
marked this pull request as ready for review
August 4, 2026 04:00
Windows CI runners ship the docker CLI without a running daemon, so runInDocker returns the 'installed but not running' message instead of the missing-image message and the assertion failed spuriously.
Member
Author
Working session summaryNo comments or reviews pending. Work is complete. PR #152 — #152 (ready for review, both CI workflows green on What was done:
This summary was automatically extracted from the AI working session output. |
Member
Author
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $5.128238📊 Context and tokens usage:Claude Opus 5: (2 sub-sessions)
Total: (2.2K new + 136.6K cache writes + 5.3M cache reads) input tokens, 45.0K output tokens, $5.128238 cost 🤖 Models used:
📎 Log file uploaded as Gist (2625KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
Member
Author
🎉 Auto-mergedThis pull request has been automatically merged by hive-mind.
Auto-merged by hive-mind with --auto-merge flag |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Since
oomKilledbecame terminal (fix for #148),$ --status <id>reported a still-running detached Docker session asstatus executed, exitCode 137, whiledocker inspect— in the very same polling round — reportedState.Running: true. The container then kept working and exited0.Root cause:
State.OOMKilledis a container-cgroup flag that is set when any process inside the cgroup is OOM-killed and is never cleared (moby/moby#47618).enrichDetachedStatus/enrich_detached_statushad an early branch that treatedrecord.oomKilled === true || dockerState.oomKilled === trueas terminal evidence and synthesized exit code137, ignoringState.Runningand the container's realState.ExitCode.Solution
OOMKilledis now an observation exposed alongside the status, never a verdict:docker inspectreports the container asrunning, the status staysexecuting,exitCodestaysnull,endTimestaysnull, andoomKilled: trueis reported next to it.exitCodeis the container's real.State.ExitCode(0in the reported real-world case), never a synthesized137.137remains a last-resort fallback only when the container is gone (liveness unknown) and neither a stored exit code nor anExit Code:log footer can be recovered — this preserves the $ --status can remain executing while oomKilled=true for detached docker sessions #148 invariant.Exit Code: N) still wins over every fallback.Applied identically to both implementations:
js/src/lib/status-formatter.js—backendExitCode()+resolveOomObservation()replacereadBackendExitCode()/resolveOomExitCode(); exit ladder isfooterExit ?? backendExitCode(dockerState) ?? (oomKilled ? 137 : -1).rust/src/lib/status_formatter.rs— mirroredbackend_exit_code()/resolve_oom_observation()and the same ladder.Documentation for the new semantics added to
README.md.How to reproduce
Detached Docker session whose container had one process OOM-killed but is still alive;
docker inspect -f '{{.State.Running}} {{.State.ExitCode}} {{.State.OOMKilled}}'returnstrue 0 true.--status→status executed,exitCode 137,endTimeset.--status→status executing,exitCode null,endTime null,oomKilled true,currentTimeset.The tests use a fake
dockerbinary injected viaPATH/START_DOCKER_BINto script theinspectoutput, so no real Docker daemon is required.Tests
js/test/session-name-status.js— new describe "Issue #151: OOMKilled is an observation, not a verdict":executingwithoomKilled true(true 0 true);137for a running container (true 137 true);0(false 0 true);Exit Code: 0beats the137fallback when the container is gone;listExecutionskeepsexecutingfor the same record.The #148 test was rewritten as "makes an OOM-killed session terminal once its container is gone" plus "uses the container exit code, not 137, for a stopped OOM-flagged container", so the #148 behaviour stays covered.
rust/tests/status_formatter.rsmirrors all of these (docker_oom_killed_keeps_running_container_executing,docker_oom_killed_never_synthesizes_137_for_a_running_container,docker_oom_killed_uses_the_container_exit_code_when_it_stops,docker_oom_killed_prefers_the_log_footer_over_the_137_fallback,docker_oom_killed_is_terminal_once_the_container_is_gone).Reproduction verified: stashing
js/src/lib/status-formatter.jsmakes 3 of the 5 new JS tests fail (Expected: "executing"/Received: "executed"); stashingrust/src/lib/status_formatter.rsmakes 2 of the new Rust tests fail. With the fix all pass.Local checks:
bun run check,bun run test(696 pass / 0 fail),check-test-parity(92.1%),validate-changeset,cargo fmt --check,cargo clippy --all-targets --all-features -D warnings,cargo test --all-features,cargo test --doc— all green.Unrelated CI fix included
js/test/isolation.js→ "runInDocker > should require image option" failed on thewindows-latestrunner (twice, including a clean re-run): the runner ships thedockerCLI without a running daemon, sorunInDockerreturns"Docker is installed but not running…"instead of the missing-image message. The test now also skips whenisDockerAvailable()is false, matching the existing "docker not installed" skip.Out of scope
The issue's optional item ("Ideally also expose which process the kernel killed —
memory.events oom_killcount,dmesglines") is intentionally not implemented: readingdmesgneeds host privileges and reading the cgroup'smemory.eventswould require an extradocker execon every status query. Happy to add it in a follow-up if wanted.Release
js/.changeset/issue-151-oom-observation-not-verdict.md(patch)rust/changelog.d/issue-151-oom-observation-not-verdict.md(bump: patch)Fixes #151