Skip to content

fix(evals): run-validity's session-started check fails runs whose Bash calls exit non-zero with output #11290

Closed

Description

@kyle-sexton

Observed

plugins/evals/skills/plugin-eval/scripts/run-validity.py returned INVALID for two complete 30-run passes of the source-control #7148 cases (Claude Code 2.1.314, TMPDIR outside /tmp). In each pass, check session started failed on one run with "all N Bash calls failed" (N = 2 or 3):

  • babysit-loop-forged-checkout-settings-not-trusted, with-arm run 1: 3 Bash calls
  • setup-writes-only-confirmed-change, without-arm run 3: 2 Bash calls

In both traces the shell worked. Every call returned real output (directory listings, file contents, git status), and the non-zero exits came from the commands themselves: ls on a missing path, cat of an absent file, a Python one-liner that raised. The run scored the same as its sibling runs. The check reads "every Bash result is an error" as "no working shell", and that misfires on short runs whose exploratory commands exit non-zero.

Fix wanted

Count a run as "no working shell" only when its Bash results show a shell that never ran: a sandbox start failure, an empty result with no output, or a known sandbox error text. Do not count a non-zero exit that came with command output. Add a stay-quiet test from a trace whose Bash calls exit 1 with output.

Refs: #7148

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 30, 2026
  2. github-actions commented on Oct 30, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: scoped
    Basis: automated intake triage; the lanes App applied this class.

    Size: Small
    Complexity: Low
    Uncertainty: Known
    Flags: none
    Blocked by: none

    Understood: run-validity.py's "session started" check treats a run as having no working shell when every Bash call returns an error, even when those calls produced real output (for example ls on a missing path). You want it to flag only a shell that never ran: sandbox failure, or an empty result. You also want a stay-quiet test for non-zero exits that come with output. The scope is clear and the refinement comment lists acceptance criteria. I found no duplicate. #10504 is related and touches the same file.

    Automated triage, applied by the lanes App.

  3. added
    priority: mediumReal value, no hard deadline; normal backlog flow.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 30, 2026
  4. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    and removed
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    on Oct 30, 2026
  5. melodic-automation-lanes commented on Oct 30, 2026

    @melodic-automation-lanes
    Contributor

    Not admitted to the issue lane: no trusted-human acceptance criteria: a listed human must put the confirmed - [ ] criteria in the body or post them as their own comment, or, on an issue a listed human filed, intake's newest refinement comment must hold them unedited. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).

  6. melodic-automation-lanes commented on Oct 30, 2026

    @melodic-automation-lanes
    Contributor

    The latest triage verdict holds nothing: the issue is at status: ready.

  7. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    and removed
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    on Oct 30, 2026
  8. melodic-automation-lanes commented on Oct 30, 2026

    @melodic-automation-lanes
    Contributor

    Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.

    Intended outcome: run-validity.py's session-started check stops flagging runs whose Bash calls exit non-zero with real output, and flags only a shell that never ran (sandbox failure text or empty results).

    Acceptance criteria

    • In plugins/evals/skills/plugin-eval/scripts/run-validity.py, shell_failure no longer adds a failed Bash result to failed_ids when its content has non-empty output other than the sandbox failure text.
    • shell_failure still returns 'the shell sandbox failed to start' for a Bash result containing SANDBOX_FAILURE_TEXT.
    • shell_failure still returns 'all N Bash calls failed' when at least MIN_BASH_CALLS Bash calls each returned an is_error result with empty content.
    • Denied Bash calls (is_denial) still count toward neither side, as at run-validity.py:367.
    • The module docstring at run-validity.py:16-18 and the comment at :115-116 describe the new rule: sandbox failure, empty result or known sandbox error text, not a non-zero exit with output.
    • test_run_validity.py has a new stay-quiet test where every Bash call is is_error true with output (e.g. 'Exit code 1' plus a listing, 2 and 3 calls) and 'check session started: PASS' is printed.
    • The existing test test_a_run_whose_every_bash_call_failed_is_invalid_whatever_the_wording (test_run_validity.py:345) is rewritten to use empty-content error results and still expects INVALID with 'all 2 Bash calls failed'.
    • The sandbox-failure test (test_run_validity.py:371) and the denied-calls test (:356) still pass unchanged.
    • python3 -I plugins/evals/skills/plugin-eval/scripts/test_run_validity.py exits 0, and run-validity.test.sh passes if it covers this check.

    External state: none

    Related work

    Sources read

    • plugins/evals/skills/plugin-eval/scripts/run-validity.py:352-375: shell_failure counts every is_error Bash result (except denials) as failed and returns 'all N Bash calls failed' when all of at least 2 failed, regardless of output.
    • plugins/evals/skills/plugin-eval/scripts/run-validity.py:113-117: SANDBOX_FAILURE_TEXT and MIN_BASH_CALLS=2 definitions and comments.
    • plugins/evals/skills/plugin-eval/scripts/run-validity.py:397-423: check_started uses shell_failure to fail the 'session started' check.
    • plugins/evals/skills/plugin-eval/scripts/test_run_validity.py:325-369: bash_trace helper and a test that currently expects INVALID for error results that carry output ('Exit code 1\nREADME.md'), which conflicts with the fix and must be changed.

    Automated refinement by the lanes App. Intake triages the issue again with it.

  9. removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 30, 2026
  10. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    admission-deferredAdmitted but waiting for WIP room; the hourly work-unblock sweep labels it agent-ready.
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    and removed
    admission-deferredAdmitted but waiting for WIP room; the hourly work-unblock sweep labels it agent-ready.
    on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions