Skip to content

fix(test): the local verify gate fails a passing suite that ran past its time share on a loaded host #10847

Closed

Description

@kyle-sexton

Refs: #8757

Problem

The local verify gate that /source-control:pull-request ready runs (scripts/check-affected.sh --tests, which runs scripts/run-plugin-tests.sh with --budget 120) fails a test suite that passes, because the suite took longer than its time share. A failure recorded by that gate stops the draft-to-ready flip, and an unattended run cannot skip verify. So a passing test can hold a PR in draft until the host's load drops.

Measured on the dev WSL host for #10842, where the diff does not touch the suite:

The share is suite_share in scripts/run-plugin-tests.sh: the suite's median in scripts/suite-seconds.txt times PLUGIN_TEST_SHARE_MARGIN (3), floored at PLUGIN_TEST_SHARE_DEFAULT (30). This suite has no line in suite-seconds.txt, so it gets the 30s floor, whatever it costs and however loaded the host is.

Fix

The share should come from the suite's own baseline and the host's current load, so that a passing suite never blocks a flip:

  • Give every selected suite a measured baseline: add post-merge-demotion-alert.test.sh to suite-seconds.txt, and have the selection report a suite with no median instead of applying the floor without saying so.
  • Scale the share by measured load, for example by max(1, loadavg / nproc), read when the run starts. Or, in the local gate only, report a passing suite over its share as a warning and keep the failure for suites that fail. CI's legs, where the budget protects the lanes, keep it as a failure.

Verification

Related

🤖 Generated with Claude Code

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 29, 2026
  2. github-actions commented on Oct 29, 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

    Decision recorded. The refinement's four questions, answered from the code on main and the 2026-10-29 cause comment (#10847 (comment)):
    [quote truncated; the full decision is at https://github.com//issues/10847#issuecomment-6511728954]

    I understood the issue as follows. The local verify gate fails a passing suite that runs past its time share. The recorded decision settles every open question. The local gate warns instead of failing, and an env var set by check-affected.sh selects that behavior. Suites with no median get a stderr note. A stay-quiet test is added. No open questions remain from this issue's text. I found no duplicates among the open issues.

    Automated triage, applied by the lanes App.

  3. added
    priority: highSignificant impact, or blocks an imminent release; staff this cycle.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 29, 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 29, 2026
  5. melodic-automation-lanes commented on Oct 29, 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 29, 2026

    @melodic-automation-lanes
    Contributor

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

  7. melodic-automation-lanes commented on Oct 29, 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: The local verify gate stops failing a passing suite that runs past its share on a loaded host, the demotion-alert suite gets a baseline, and a suite with no median is reported by name.

    Related work

    Open questions

    1. Which mechanism should the fix use for the loaded-host problem: scale each share by max(1, loadavg/nproc), or downgrade a passing over-share suite to a warning in the local gate?
      RECOMMENDED: Downgrade to a warning, because a passing suite should never block a flip. Load scaling needs a load read that Git Bash on Windows lacks (/proc/loadavg), and the measured loads of 5-16 could still leave 30s shares too tight. Basis: scripts/run-plugin-tests.sh:437-446 fails any passing suite over its share. The issue lists the two options with 'or'.
    2. What median should post-merge-demotion-alert.test.sh get in scripts/suite-seconds.txt? The issue measured 32-44s on a loaded WSL host, and the file holds CI runner medians that a run cannot measure.
      RECOMMENDED: Use about 15, an estimate of the CI median, which gives a 45s share with the margin of 3. This needs the owner to confirm it from a CI timing. Basis: judgment; scripts/run-plugin-tests.sh:44-48 says the medians are CI runner measurements, and the suite has no line in scripts/suite-seconds.txt.
    3. How should the runner tell the local gate from CI when only the local gate may downgrade the failure? CI's test legs pass no --budget, and only maintenance-audit-test-selection.yml passes --budget 1500.
      RECOMMENDED: Add a flag or env var such as PLUGIN_TEST_SHARE_WARN_ONLY=1 that check-affected.sh sets, and keep the default as a failure for other --budget callers. Basis: .github/workflows/maintenance-audit-test-selection.yml:140; scripts/check-affected.sh:217,687
    4. How should the selection report a suite with no median: as a stderr line, a ::warning:: annotation, or a failure?
      RECOMMENDED: A one-line stderr note per unlisted suite that names it and the default share applied, and no failure. Basis: scripts/run-plugin-tests.sh:361-365 applies the floor silently.

    Sources read

    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/run-plugin-tests.sh:40-49: BUDGET doc says a suite over its share fails by name; the share is the median times the margin (3), floored at 30s.
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/run-plugin-tests.sh:354-365: suite_share applies the floor silently to a suite with no median.
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/run-plugin-tests.sh:437-446: a suite over its share sets failed=1 even when its exit code is 0.
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/run-plugin-tests.test.sh:547-586: the existing budget tests, where the new stay-quiet test would go.
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/check-affected.sh:121,217,687: the gate defaults to a budget of 120 and passes it to the runner and to affected-tests.sh.
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/scripts/suite-seconds.txt: no post-merge-demotion-alert line.

    To answer, post a comment that starts with this line:

    **Decision recorded.** <answer>
    

    Automated refinement by the lanes App. Answer with a comment whose first line is **Decision recorded.**.

  8. kyle-sexton commented on Oct 29, 2026

    @kyle-sexton
    MemberAuthor

    Cause found: scripts/post-merge-demotion-alert.test.sh (added in #10730) has no row in scripts/suite-seconds.txt, so it gets the 30 s default share. It runs 30-31 s even alone on an idle host. It failed the local verify gate in 13 of 18 tries for one builder and 10 of 11 for another tonight (#10876, #10842). Smallest fix: add its measured median to suite-seconds.txt. The load-scaling proposal above still covers the general case.

  9. removed
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    status: needs-decisionAwaiting a human or maintainer judgment call.
    on Oct 30, 2026
  10. kyle-sexton commented on Oct 30, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded. The refinement's four questions, answered from the code on main and the 2026-10-29 cause comment (#10847 (comment)):

    1. Downgrade, not load scaling. In the local gate, a suite that passes but runs past its share prints a warning and does not fail. A suite that fails still fails. Basis: scripts/run-plugin-tests.sh:490-493 fails a passing suite on time alone. Load scaling needs a load reading the Windows Git Bash host lacks. That comment measured 30-31 s for this suite alone on an idle host, so the failure is not tied to load.
    2. Already done. scripts/suite-seconds.txt:793 gives post-merge-demotion-alert.test.sh a median of 100, measured from whole-tree run 40892244877 (header, lines 19-20). This was that comment's "Smallest fix".
    3. scripts/check-affected.sh sets an env var (for example PLUGIN_TEST_SHARE_WARN_ONLY=1), and run-plugin-tests.sh keeps failure as the default. The other --budget caller, maintenance-audit-test-selection.yml:140, keeps today's behavior, and no workflow file changes.
    4. A one-line stderr note for each selected suite with no row in suite-seconds.txt, naming the suite and the default share applied. No failure. This replaces the silent floor at run-plugin-tests.sh:411-414.

    Dropped: "check-affected.sh --tests on #10842's diff passes on the dev WSL host at load 5-16". #10842 has merged, a lane cannot run on that host, and the stay-quiet test covers the case.

    Since this was filed, /source-control:pull-request ready stopped running the local verify step in this repository (docs/conventions/source-control.yaml:31-38). The pre-push check-affected run still uses the share, so the defect still applies there.

    • Every selected suite has a measured baseline: post-merge-demotion-alert.test.sh is in suite-seconds.txt, and the selection reports a suite with no median instead of applying the floor silently. (body, amended: the baseline row has landed on main, and the unlisted-suite report remains)
    • In the local gate only, a passing suite over its share is reported as a warning, and a failing suite still fails. CI's and other --budget callers keep the failure. (body, amended: this picks the body's second option, "Or, in the local gate only...")
    • A stay-quiet test in scripts/run-plugin-tests.test.sh: a suite that passes but runs past its fixed share on a simulated loaded host is not failed by the local gate. The test fails before the fix. (body, unchanged)
  11. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    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: highSignificant impact, or blocks an imminent release; staff this cycle.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