Skip to content

fix(pr-pipeline): explain turns above max-turns and report max-turns as a sizing stop #7901

Closed

Description

@kyle-sexton

Refs: #7644

Summary

Run 39089680523 (work-resolve-issue, issue #7644) ended with:

work-resolve-issue exited with: failure class=max-turns credential=CLAUDE_CODE_OAUTH_TOKEN turns=140 max-turns=75 models=claude-sonnet-5-5 (infrastructure error, not a code-quality signal — e.g. usage limit, OIDC failure, SDK crash, is_error result, or max-turns exhaustion).

Two problems:

  1. The run went to 140 turns under --max-turns 75, and nothing in the docs explains how.
  2. A max-turns result is reported as an infrastructure error. It means the work is bigger than one run allows, so it is a sizing stop.

Where turns= comes from

turns= is the SDK result message's num_turns. Nothing in this code counts assistant messages or subagent transcripts.

  • ci-workflows report-lane-outcome (pinned at v0.43.0, 64fd515; the action directory is unchanged at v0.45.0), .github/actions/report-lane-outcome/classify.cjs:206: const turns = result?.num_turns; read from the last type == "result" message, printed at classify.cjs:233 as turns=${turns}.
  • max-turns= is the caller's input (pr-run-activity-write.yml:1119, max-turns: ${{ steps.config.outputs.max-turns }}), 75 from the standard profile (docs/conventions/pr-pipeline.yaml:259). The run log shows claude_args: ... --max-turns 75.
  • classify.cjs:131-137 assigns max-turns when subtype === "error_max_turns" or when subtype === "success" and num_turns > maxTurns. This run hit the second branch. The log shows {"subtype":"success","is_error":false,"num_turns":140,...}.
  • The failure itself comes from claude-code-action at a26b07d (v1.0.250), base-action/src/run-claude-sdk.ts:241-250. That code throws Claude reported a successful result after 140 turns, exceeding the configured maximum of 75 on a success result whose num_turns is over maxTurns. The CLI did not stop at 75. It finished, and the action failed the step afterwards.

What the docs say

  • --max-turns (https://code.claude.com/docs/en/cli-reference): "Limit the number of agentic turns (print mode only). Exits with an error when the limit is reached. No limit by default."
  • maxTurns (https://code.claude.com/docs/en/agent-sdk/agent-loop): "You can cap the loop with max_turns / maxTurns, which counts tool-use turns only." The limits table gives it as "Maximum tool-use round trips". When the limit is hit, "the SDK returns a ResultMessage with a corresponding error subtype (error_max_turns ...)".
  • num_turns (https://code.claude.com/docs/en/agent-sdk/typescript, SDKResultMessage): the field is listed as num_turns: number with no definition. The same page does define its neighbours: usage is "main agent loop only. Excludes subagent and auxiliary model calls", and modelUsage "includ[es] the main loop, subagents, and internal calls". It does not say which of these scopes num_turns uses.

Is 140 > 75 explained?

No. The docs say a run that reaches the cap stops with error_max_turns. This run returned success at 140. One possible cause is that num_turns counts subagent or non-tool-use turns while the cap counts only main-loop tool-use turns. That is UNVERIFIED: the docs do not say it, and the lane does not keep the execution file (only reply.txt and act-turns.json are uploaded, pr-run-activity-write.yml:1121-1131), so main-loop and subagent turns for this run cannot be counted afterwards. A one-turn difference (the final non-tool turn) cannot explain a gap of 65.

How the outcome is reported

  • ci-workflows .github/actions/report-lane-outcome/action.yml:237-245: any class other than rate-limit gets the text (infrastructure error, not a ${signal} signal — e.g. usage limit, OIDC failure, SDK crash, is_error result, or max-turns exhaustion). That puts max-turns in the same group as OIDC failures and SDK crashes.
  • pr-run-activity-write.yml:1671 and 1679-1680 write the class into lane.json as {branch, class, resets}.
  • .github/scripts/work-resolve-issue/report-outcome.mjs:629-641 (readLimit) reads only class == "rate-limit". Every other class, max-turns included, gets no special handling.
  • report-outcome.mjs:434- (decide): an unread outcome becomes stopped and goes to handBack (report-outcome.mjs:267-302). That function posts <!-- work-resolve-issue outcome=stopped --> with the generic text "stopped partway through this issue and needs a person", and adds the human-gated label (needs-human by default, report-outcome.mjs:442). Neither the comment nor the labels mention turns.
  • In this run the skill had already written a done outcome and committed, so report-outcome opened #7896 ("report-outcome: opened PR refactor(hooks): remove the unused --skip-if-all-false flag from exec-bash.mjs #7896 for issue refactor(hooks): remove the unused --skip-if-all-false flag from exec-bash.mjs and its 25 copies #7644"). The resolve-issue / run check is still red and labelled an infrastructure error, even though the work completed.

Fix (proposed)

  1. ci-workflows report-lane-outcome: drop "max-turns exhaustion" from the infrastructure-error text. Give class=max-turns its own message, for example <lane> stopped: turn budget used (turns=N max-turns=M); the work is too big for one run, split it. Keep class=max-turns as the bare token.
  2. report-outcome.mjs: read class == "max-turns" from lane.json (next to readLimit).
    • When the run left no readable outcome, post outcome=stopped with a note like "too big for one run (turns=N of M); split it into smaller issues". Add needs-triage instead of a bare hand-back. Remove agent-ready, so the lane does not retry the same oversized issue.
    • When the run left a done outcome with commits, as in this run, keep opening the PR. Put a line in the body saying the run went past its turn budget.
  3. Keep the execution file, or a projection of main-loop and subagent turn counts from it, as a run artifact, so the next 140-of-75 case can be explained from evidence.
  4. Separately, find out why num_turns was 140 under --max-turns 75: check the CLI or SDK source for what num_turns counts, and file upstream if the cap and the count disagree.

Verification (how to test)

  • ci-workflows: add a classify.test.cjs / outcome-step.test.cjs case for a success result with num_turns over maxTurns. Assert the annotation has class=max-turns and does not contain "infrastructure error". Repeat for subtype error_max_turns.
  • report-outcome.test.mjs: with lane.json {class: "max-turns"} and no work-outcome.json, assert decide returns exit: "stopped", a comment with the marker outcome=stopped and the split note, addLabels with the triage label, and removeLabels with agent-ready. With a done outcome and a branch, assert it still returns open-pr.
  • Re-run the lane on an issue sized to exceed 75 turns. Check the issue comment, the labels, and the check-run text.

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_01PfAeL8XHnWAexMLmaSzZZH

Activity

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

    @github-actions
    Contributor

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

    Size: Medium
    Complexity: Medium
    Uncertainty: Knowable
    Flags: none
    Blocked by: none

    Decision recorded.

    This answers the four open questions in intake's refinement (comment 6392103943), read against origin/main 0ad858ec05. It replaces the 2026-10-26 record (comment 6407928079), which quoted only general standing direction and moved item 1 to a ci-workflows issue that was never filed.
    [quote truncated; the full decision is at the link]

    #7901 (comment)

    That decision settles the open questions, so nothing is asked again. I understand the work as: give class=max-turns its own report text, flag over-cap runs in the PR body, split the act-turns counts into main-loop and subagent counts in a shared script, and bump the pins. The one host-run step, reading act-turns.json from an over-cap run, is already recorded in the decision.

    Automated triage, applied by the lanes App.

  3. added
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 18, 2026
  4. kyle-sexton commented on Oct 18, 2026

    @kyle-sexton
    MemberAuthor

    Adding a progress heartbeat to this issue's scope.

    The lane reports turns only when a run ends, so a run that hits the job timeout leaves no turn count and no diagnosis. On 2026-10-18:

    For comparison, the 40 most recent successful resolve-issue jobs took p50 3.5 min, p90 10 min and max 15.4 min. The timeout is being cut to 25 minutes in a separate PR.

    Proposal: alongside uploading the execution file, write the running turn count and the last tool call to a small file every N turns, and upload it with if: always(). A timed-out or cancelled run then shows how far it got and what it was stuck on.

  5. kyle-sexton commented on Oct 20, 2026

    @kyle-sexton
    MemberAuthor

    Remaining scope after #8253 and #8281, checked criterion by criterion against main at 419f77d.

    Already done: the turn-cap marker, the hand-back and agent-ready removal, sizing by issue fields, and resume (#8281); an over-cap success no longer fails the check (#8253). One deviation from the original brief: a turn-cap stop adds needs-human rather than needs-triage (report-outcome.mjs:387-416).

    Remaining:

    1. ci-workflows report-lane-outcome: drop "max-turns exhaustion" from the infrastructure-error annotation (action.yml ~268-269 on main) and give class=max-turns its own "stopped: turn budget used (turns=N max-turns=M)" text, with classify.test.cjs/outcome-step.test.cjs cases for an over-cap success and for error_max_turns. Then bump this repo's pin (pr-run-activity-write.yml:1422, still v0.43.0).
    2. When a run finishes done with commits but over its cap (now recorded as a plain success by fix(pr-pipeline): report an over-cap successful run as success #8253), say so in the PR body. That needs the act-result step to pass an over-cap flag through to report-outcome.
    3. Keep turn evidence: upload main-loop and subagent turn counts taken from the execution file, plus a periodic heartbeat (running turn count and last tool name, uploaded if: always()), so a cancelled or timed-out run shows how far it got.
    4. Find out what num_turns counts compared with --max-turns (CLI/SDK source), and file upstream if they disagree.
  6. removed
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 25, 2026
  7. kyle-sexton commented on Oct 25, 2026

    @kyle-sexton
    MemberAuthor

    Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.

    To hold this issue again, add needs-human (or status: needs-decision) and say why in a comment.

  8. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    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 25, 2026
  9. 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.
    on Oct 25, 2026
  10. 9 remaining items

  11. added
    host-runNeeds an unattended run on a host; the host runner takes it, not a person or the issue lane.
    on Oct 31, 2026
  12. kyle-sexton commented on Oct 31, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded.

    This answers the four open questions in intake's refinement (comment 6392103943), read against origin/main 0ad858ec05. It replaces the 2026-10-26 record (comment 6407928079), which quoted only general standing direction and moved item 1 to a ci-workflows issue that was never filed. No branch and no PR exists for this issue in either repository: fix/max-turns-annotation-7901 and fix/max-turns-sizing-stop-7901 both return 404. The PRs that did #7901 work are #8253 and #8281, already counted done in the 2026-10-20 comment. #8280 also references it; it made triage set the issue fields. Agents decided this on evidence under standing direction §1.

    1. Is item 1 (the annotation text) already done at the current pin? Decided: no. This repository pins report-lane-outcome at ci-workflows 2476d5d (pr-run-activity-write.yml:1821). At that commit, every class but rate-limit still gets the infrastructure-error text ending "is_error result, or max-turns exhaustion" (ci-workflows .github/actions/report-lane-outcome/action.yml:375-376).
    2. Do items 1 and 4 stay in this issue? Decided: both stay.
      • Item 1 has no other home. No ci-workflows issue or branch carries it. ci-workflows#903 asks for an over-cap record, not this text. So item 1 is a cross-repo step plus the pin bump here.
      • Item 4 also stays. ci-workflows#903 asks the same question of run-claude-cli, the issue lane's launcher (pr-run-activity-read.yml:1529). It is related, not a replacement: it has no main-loop and subagent split, and item 3 produces that split here.
      • The docs now say the cap counts "each turn with tool calls, plus one for the final text-only response" (agent-loop, "You can cap the loop"). num_turns is listed with no definition (TypeScript reference, SDKResultMessage). That does not explain 140 turns under a cap of 75, so the item stays open. Item 3's split is the evidence it needs.
    3. How does the over-cap flag reach report-outcome? Decided:
      • The flag cannot come from an act-result step. The issue lane's skill runs in the read runner on run-claude-cli (pr-run-activity-read.yml:1529, :1581, :1627), and the write runner refuses an issue skill (pr-run-activity-write.yml:790-797). The read runner has no act-result step; the write runner's returns at once on a successful skill step (pr-run-activity-write.yml:1635-1638).
      • Runs past the cap with a successful step do happen. ci-workflows#903 lists 4 of 42 work-resolve-issue runs from 2026-10-27 and 2026-10-28, for example 183 turns under a cap of 150.
      • So the flag comes from the read runner's act-turns step, which runs when whichever leg ran succeeded or failed (pr-run-activity-read.yml:1723-1730) and already sets a turns output from num_turns (:1799). The step that builds lane.json from step outputs writes max-turns but no turns (:2015, :2034-2037); it adds turns, and the flag is turns over max-turns.
      • report-outcome.mjs reads the flag next to its turn-cap reader (.github/scripts/work-resolve-issue/report-outcome.mjs:1528-1542).
      • Today, an over-cap done run's PR body says nothing about the cap. The run's turns and cap reach only the check run (.github/actions/report-check-run/report-check-run.mjs:106).
    4. What shape does the turn evidence take? Decided:
      • Add two counts to act-turns.json: assistant messages in the execution file whose parent_tool_use_id is null (main loop), and those where it is set (subagents). This repository already uses that field to mark subagent events (plugins/harness-ops/skills/behavior-probes/scripts/probe.py:410).
      • The file keeps its 32768-byte cap (pr-run-activity-write.yml:1759-1764).
      • The step is inline script in both runners today (pr-run-activity-read.yml:1723-1809, pr-run-activity-write.yml:1699-1796). A fixture test therefore means moving its logic into a script under .github/scripts/ that both runners call.
      • Whether claude-code-action's execution file records subagent messages is UNVERIFIED. If it records none, the subagent count reads 0 and the file says so.
      • The heartbeat stays out. The 2026-10-26 04:31 comment dropped it, a session reading based on run-claude-cli's leg-end write (ci-workflows lane.cjs:776-792). That comment also says a job cancel or step timeout still loses the turn record.
      • The case that first prompted the heartbeat was fix(planning): collapse archived cards in the interview page's Groups rail #7750's run, cancelled at the job timeout (comment 6246204268). That case stays uncovered.
      • The issue lane's legs run on run-claude-cli (pr-run-activity-read.yml:1529), so the leg-end write applies to it: a leg timeout keeps the turn record, and a job cancel, as in fix(planning): collapse archived cards in the interview page's Groups rail #7750's run, does not.

    Acceptance criteria:

    • A run that ends done with commits and num_turns over its --max-turns opens its PR with a body line saying the run went past its turn budget (turns=N max-turns=M). A report-outcome.test.mjs case asserts that line and that decide still returns open-pr, and it passes in CI.
    • A run within its cap opens its PR with no such line. A test case asserts that, and it passes in CI.
    • The act-turns logic sits in a script under .github/scripts/ that both the read and write runners call. act-turns.json carries the count of assistant messages with a null parent_tool_use_id and the count with one set, under the same 32768-byte cap. A test with a fixture holding both kinds asserts both counts, and it passes in CI.
    • ci-workflows report-lane-outcome gives class=max-turns its own text naming the turns and the cap, and its infrastructure-error text no longer lists max-turns exhaustion. classify.test.cjs or outcome-step.test.cjs cases cover an over-cap success and an error_max_turns result, and they pass in ci-workflows CI.
    • Every report-lane-outcome pin in this repository moves to a ci-workflows release that carries that text.

    Host-run step, outside the criteria: once item 3 ships, read act-turns.json from one over-cap run and state in this issue the main-loop and subagent counts against its cap. That answers item 4 from evidence. No upstream report follows: the owner ruled "no upstream issues to 3rd party / external repos" (2026-10-30), so the result is recorded in this issue only. Until that step is done, a PR for these criteria writes Refs: #7901.

    Route: builder session. The act-turns move and the over-cap flag edit workflow files, which the lanes App cannot push, and the annotation text is a ci-workflows change. Labels: add host-run. status: confirmed stays. No agent-ready.

  13. 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.
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 31, 2026
  14. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    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 31, 2026
  15. kyle-sexton commented on Nov 1, 2026

    @kyle-sexton
    MemberAuthor

    Claimed by the Backlog HITL host session; work in progress.

  16. kyle-sexton commented on Nov 1, 2026

    @kyle-sexton
    MemberAuthor

    Host run. The Backlog HITL host session built this repository's part of the 2026-10-31 decision: the PR-body note for a done run past its cap, and the main-loop and subagent turn counts. The ci-workflows part is written up below for Automation Lanes.

    What ran (Claude Code 2.1.316)

    • A new worktree from origin/main. The earlier worker's branch fix/max-turns-sizing-stop-7901 was 1282 commits behind and kept the logic inline, so it was used only as a reference.
    • scripts/check-affected.sh --tests on the committed head: 11 static checks passed. The 68 selected suites are left to CI because the workflow files changed. The directly affected suites, run locally, all passed:
      • report-outcome.test.mjs, callers.test.mjs and .github/scripts/lib/act-turns.test.mjs: 572 pass.
      • scripts/act-turns-denied.test.sh: 63 pass, 0 fail.

    Acceptance criteria

    1. A done run over its cap gets the PR-body line. Done in the PR, CI pending. report-outcome.mjs reads turns beside max-turns from lane.json (readOverCap). The read runner now writes turns. A done run past its cap gets the Summary line The run went past its turn budget (turns=N max-turns=M), and decide still returns open-pr; a test asserts both.
    2. A run within its cap gets no line. Done in the PR, CI pending. A test asserts that.
    3. act-turns script and turn counts. Done in the PR, CI pending.
      • The act-turns logic now sits in .github/scripts/lib/act-turns.mjs, which both runners call.
      • Each runner copies the script from .base before the head checkout and records its SHA-256. The step loads only bytes that match.
      • act-turns.json now carries turn_counts:
        • main_loop: assistant messages with a null parent_tool_use_id.
        • subagent: assistant messages with one set.
        • Distinct model turns by message id, for each of the two.
        • When there are no subagent messages, a note saying the file holds main-loop messages only.
      • The 32768-byte cap is unchanged. A fixture with both kinds of message asserts both counts.
    4. ci-workflows report-lane-outcome text. Not done: this belongs to Automation Lanes, so no ci-workflows PR was opened. The change needed is already drafted on ci-workflows branch fix/max-turns-annotation-7901 (local commit 587c78b, never pushed; it is 35 commits behind main):
      • In .github/actions/report-lane-outcome/action.yml, a class=max-turns failure reads <lane> stopped: turn budget used (<lane> exited with: <outcome> class=max-turns turns=N max-turns=M ...); the work is too big for one run, split it.
      • The infrastructure-error example list drops "or max-turns exhaustion".
      • The bare class=max-turns token and the exited with: phrase stay.
      • outcome-step.test.cjs gets cases for an over-cap success result and an error_max_turns result, plus updated snapshots.
    5. Pin bump. Not done; it depends on criterion 4. Once a ci-workflows release carries that text, every report-lane-outcome pin moves to it: 2 in pr-run-activity-read.yml and -write.yml, and 7 in pr-review-main.yml, all at 2476d5d today.

    Host-run step. Not run yet. Once this PR merges, read act-turns.json from one over-cap run and state its main-loop and subagent counts against its cap.

    Process note. The claim comment on this issue was posted before the write gate cleared: the breaker had tripped at the time. Every later write waited on the gate.

    PR: #11839 (Refs: #7901), opened as a draft and then marked ready through the ready gates. Main is merged in, the verify gate passed on the merged head, and the code and security reviews were left to the CI lanes. Both review lanes passed on ef5b122447 and opened one thread. It was valid: the setup-env step's comment had ended up over the new act-turns copy step in the write runner. The fix is 2cc2bdd102; the thread has a reply and is resolved.

  17. kyle-sexton commented on Nov 1, 2026

    @kyle-sexton
    MemberAuthor

    Host-run step. I read act-turns.json from one over-cap run after #11839 merged (2026-11-01T06:03Z).

    The run: 41313113933, issue lane on #11881. It opened #11934, whose body carries the new "went past its turn budget" line.

    Source Field Value
    lane.json max-turns 113
    lane.json turns 121
    lane.json class empty
    act-turns.json subtype success
    act-turns.json num_turns 121
    act-turns.json turn_counts main_loop / subagent (assistant messages) 202 / 43
    act-turns.json turn_counts main_loop_turns / subagent_turns (distinct model turns) 78 / 32
    act-turns.json denied_total 0

    Against the cap:

    • The run reported num_turns 121 against a cap of 113 and still ended success, not error_max_turns.
    • Its main-loop model turns were 78, under the cap. Subagent turns were 32.
    • One reading fits these numbers: the cap applies to main-loop turns, and num_turns adds other turns on top. It is a single run, so this is UNVERIFIED. Main-loop plus subagent model turns (110) do not add up to 121.
    • The CLI source check in criterion 4 of the body still owes the answer.

    Criteria 4 and 5 (the ci-workflows report-lane-outcome text and the pin bump) belong to Automation Lanes, on ci-workflows 587c78b. With this step done, no host-run work is left, so host-run comes off.

    Target labels: add none; remove host-run.

  18. removed
    host-runNeeds an unattended run on a host; the host runner takes it, not a person or the issue lane.
    on Nov 1, 2026
  19. kyle-sexton commented on Nov 2, 2026

    @kyle-sexton
    MemberAuthor

    Closing as completed. Each acceptance criterion of the 2026-10-31 decision record, which replaced the earlier records, is met. Checked against origin/main a33d0b315f and ci-workflows c41e345 on 2026-11-01.

    1. A done run over its cap gets a PR-body line, with a passing test. Met.

    • .github/scripts/work-resolve-issue/report-outcome.mjs:1386 adds The run went past its turn budget (turns=N max-turns=M) to the Summary when readOverCap (:1707) finds turns over max-turns in lane.json.
    • report-outcome.test.mjs:2392-2399 asserts that line, its place in the Summary, and that decide still returns open-pr.
    • Shipped in #11839, merged 2026-11-01T06:03Z. ci-status passed on head 2cc2bdd102.
    • It also works on a live run. Run 41313113933 went over its cap (121 turns against 113) and opened #11934 with the line (host-run record).

    2. A run within its cap gets no line, with a passing test. Met. report-outcome.test.mjs:2401-2405 asserts open-pr and that the body has no turn-budget text. It shipped in #11839 under the same ci-status.

    3. The act-turns script is shared, and act-turns.json carries the two counts. Met.

    • .github/scripts/lib/act-turns.mjs holds the logic.
    • Both runners copy it from .base and load it: pr-run-activity-read.yml:1291, :1758 and pr-run-activity-write.yml:1439, :1757.
    • turnCounts (act-turns.mjs:23-33) splits assistant messages by a null or set parent_tool_use_id. The cap stays at 32768 bytes (CAP, :13).
    • act-turns.test.mjs:33 asserts both counts on a fixture that holds both kinds of message, and :59 checks that they survive the cap.
    • Shipped in fix(pr-pipeline): note an over-cap done run in its PR and split act-turns counts #11839.

    4. ci-workflows report-lane-outcome text. Met.

    • ci-workflows#946 merged as c41e345.
    • class=max-turns now reads <lane> stopped: turn budget used (... class=max-turns turns=N max-turns=M); the work is too big for one run, split it.
    • The infrastructure-error text no longer lists max-turns exhaustion (.github/actions/report-lane-outcome/action.yml:369-385).
    • outcome-step.test.cjs covers an over-cap success result (the test at about line 424) and an error_max_turns result (about line 443). Both assert that "infrastructure error" is absent.
    • These tests run in ci-workflows' test-contracts job (pr-require-checks.yml:552). That job and ci-status passed on fix(guardrails): restore path-detection prefilter fail-open fix (0.9.8) #946 (run 41278770645).

    5. Every report-lane-outcome pin moves to a ci-workflows version that carries the text. Met, at a main commit rather than a tagged release.

    • #11964, merged 2026-11-01T17:03Z with ci-status passing, moved all 57 pins to c41e3457e01c9ff6ca2c3d10e5bf470551383e11.
    • A git grep "report-lane-outcome@" on origin/main finds no uses: line at any other SHA.
    • No ci-workflows tag contains c41e345; the newest release is v0.69.0, from 2026-10-31.
    • The pin it replaced, 2476d5d, was also an untagged main commit, and so are the other ci-workflows pins. ci: pin report-lane-outcome at c41e345 for the max-turns sizing stop #11964's "Pin choice" section gives that practice as the reason. This repository's runs therefore already use the new text.

    Host-run step (outside the criteria). Done. The 2026-11-01 record gives one over-cap run's counts against its cap:

    • num_turns: 121, against a cap of 113.
    • Main loop: 78 model turns, under the cap. Subagents: 32.

    Under the decision record, this step answers body item 4, and no upstream report follows. Two gaps remain open as notes, not criteria:

    • Main-loop and subagent turns (110) do not add up to 121.
    • No one has read the Claude Code source to see what num_turns counts.

    This was generated by AI.

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

    priority: mediumReal value, no hard deadline; normal backlog flow.status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.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