Skip to content

Fail a SLURM job the scheduler marked FAILED, whatever its exit code - #1879

Open
sbryngelson wants to merge 2 commits into
masterfrom
fix/slurm-monitor-honors-job-state
Open

Fail a SLURM job the scheduler marked FAILED, whatever its exit code#1879
sbryngelson wants to merge 2 commits into
masterfrom
fix/slurm-monitor-honors-job-state

Conversation

@sbryngelson

Copy link
Copy Markdown
Member

monitor_slurm_job.sh decided pass/fail from SLURM's ExitCode alone, ignoring the job state it had already queried and printed. SLURM intermittently reports State=FAILED alongside ExitCode=0:0, and on those jobs the log reads:

[20:05:16] Job 13132145 reached terminal state: FAILED
Job 13132145 completed successfully

The GitHub job then goes green with the test failures still in its log.

Impact

Five of nine "successful" Phoenix gpu-acc runs on master were hiding 23 failing tests. Same 23 tests, same main.py finished with a 23 exit code in the log — the only difference between a red run and a green one was which value SLURM happened to put in ExitCode.

That is long enough for a real regression to go unnoticed (it hid #1878 for five days) and it makes a green self-hosted job worthless as evidence.

The bug

run_monitored_slurm_job.sh:40 already re-checks via sacct and correctly requires COMPLETED and 0:0 — but only when the monitor exits non-zero. Nothing verified the state on the success path. That asymmetry is the whole bug; this makes both paths agree.

The guard is deliberately conservative: if no terminal state was recorded it falls back to the previous exit-code-only behaviour, so it cannot invent new red CI.

Tests

Written test-first — the new case reproduced the false green (monitor returned 0 where 1 was expected) before the fix, and passes after. A second test pins the other direction so a genuinely COMPLETED job still passes and the guard can't over-correct.

test_monitor_ci_summary.py's stub reported FAILED for every job, including the one named "a successful job" — a pairing SLURM does not produce for a clean run, and only harmless while state was being ignored. Its state now tracks the exit code; a test wanting the pathological combination asks for it explicitly.

671 toolchain tests pass.

Suggested review order

Independent of #1878 and #1879, but worth landing early: until it does, a green Phoenix job doesn't mean the tests passed, which makes verifying anything else on that lane harder than it should be.

https://claude.ai/code/session_017zrZooJPhZtZYgg9fJiYhg

…code

monitor_slurm_job.sh decided pass/fail from SLURM's ExitCode alone and
ignored the job state it had already queried and printed. SLURM
intermittently reports State=FAILED alongside ExitCode=0:0, and on
those jobs the log reads:

    [20:05:16] Job 13132145 reached terminal state: FAILED
    Job 13132145 completed successfully

The GitHub job then went green with the test failures still in its
log. Five of nine "successful" Phoenix gpu-acc runs on master were
hiding 23 failing tests this way, which is long enough for a real
regression to go unnoticed and makes a green self-hosted job worthless
as evidence.

run_monitored_slurm_job.sh already re-checks the state via sacct and
requires COMPLETED *and* 0:0 -- but only when the monitor exits
non-zero, so nothing verified the state on the success path. That
asymmetry is the bug; this makes both paths agree.

The guard is deliberately conservative: if no terminal state was
recorded it falls back to the previous exit-code-only behaviour, so it
cannot invent new red CI.

Tests: the first case reproduces the false green (the monitor returned
0 where 1 was expected) and the second pins the other direction so a
genuinely COMPLETED job still passes.

test_monitor_ci_summary.py's stub reported FAILED for every job,
including the one named "a successful job" -- a combination SLURM does
not produce for a clean run, and only harmless while the state was
being ignored. Its state now tracks the exit code, and any test that
wants the pathological pairing asks for it explicitly.

Claude-Session: https://claude.ai/code/session_017zrZooJPhZtZYgg9fJiYhg
Copilot AI lite review requested due to automatic review settings September 13, 2026 14:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The monitor now validates terminal state with regression coverage for failed and completed jobs.

Pull request overview

Updates SLURM monitoring so jobs marked FAILED cannot pass with exit code 0:0.

Changes:

  • Validate terminal state alongside exit code.
  • Add regression tests for failed and successful jobs.
  • Align CI-summary fixtures with realistic SLURM states.
File summaries
File Description
toolchain/mfc/test_monitor_exit_codes.py Tests failed-state and successful-job handling.
toolchain/mfc/test_monitor_ci_summary.py Updates SLURM state stubs.
.github/scripts/monitor_slurm_job.sh Validates terminal state and exit code.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Exercising both versions of the monitor through run_monitored_slurm_job.sh
against a stubbed SLURM, over every terminal state crossed with several
exit codes, puts the behaviour change at exactly one column of that
matrix: a state other than COMPLETED reported alongside ExitCode 0:0.
COMPLETED is untouched at every exit code, every non-zero code already
failed and still does, and 77 still relays in every state.

That last one matters most and had no coverage: the submit wrapper uses
77 to exclude a bad node and resubmit, so flattening it to a generic
failure would strand the job on that node. It is now pinned for each
state rather than only for the default.

Worth a second opinion on one point: NODE_FAIL, BOOT_FAIL and
OUT_OF_MEMORY paired with 0:0 now come back as 1, a test failure, when
they describe an unusable node. Previously they came back as 0, so this
is strictly better than reporting them green, but 77 is arguably the
truer answer and would let the existing exclude-and-resubmit path take
them. Left alone here because routing them to 77 changes resubmit
behaviour, which is a separate decision from fixing the false green.

Claude-Session: https://claude.ai/code/session_017zrZooJPhZtZYgg9fJiYhg
@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.25%. Comparing base (dc0aec1) to head (558f7ec).
⚠️ Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1879      +/-   ##
==========================================
- Coverage   61.26%   61.25%   -0.02%     
==========================================
  Files          84       84              
  Lines       22330    22336       +6     
  Branches     3265     3266       +1     
==========================================
+ Hits        13680    13681       +1     
- Misses       6207     6211       +4     
- Partials     2443     2444       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants