mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #392] [MERGED] feat(cursor-review): make the per-cell agent cap an input (cell_timeout_minutes) #393
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#393
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/392
Author: @mattmillerai
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @mattmillerai
Base:
main← Head:matt/cell-timeout-input📝 Commits (3)
3476cd7feat(cursor-review): make the per-cell agent cap an input (cell_timeout_minutes)c8474acfix(cursor-review): compute derived timeout caps in preflight, not in expressions9288f87fix(cursor-review): floor cell_timeout_minutes at 10, keep the judge step at 30+, reject overlong values📊 Changes
5 files changed (+484 additions, -30 deletions)
View changed files
📝
.github/cursor-review/README.md(+1 -0)📝
.github/cursor-review/tests/test_stop_on_submit.py(+6 -1)➕
.github/cursor-review/tests/test_workflow_cell_timeout.py(+349 -0)📝
.github/workflows/cursor-review.yml(+127 -29)📝
docs/callers/cursor-review.md(+1 -0)📄 Description
The per-cell agent cap is a hardcoded
timeout-minutes: 15with no way for a caller to raise it, and it is now the dominant cause of red panels on the two busiest consumers.Evidence
Every panel cell from 56 completed panels on one consumer — 372 cells, 43 red, classified from run annotations:
resource_exhaustedIt is a clipped tail, not a hang catcher. Of the 329 cells that did submit:
18% finished within three minutes of the cap.
Caveat on the 22/43 split, added after review. That window mixes panel configurations — 372 cells over 56 panels is ~6.6 per panel, more than the current panel runs, and the 10
gpt-5.6-sol-maxtimeouts predate #378 notching that model down. So the split describes an older panel than the one running today, and should not be quoted as a forecast. What is not config-mixed, and is what this PR actually rests on: the duration histogram above (one metric, every submitting cell, panel-size independent), andgrok-4.7-highon the current config — every cell that reached ~17 minutes died, 11 of 20, while the lanes with a 4-6 minute median never failed once.Also corrected: #388 retries
resource_exhaustedonly twice (30s, then 90s), so it does not "clear the capacity half" — a model that stays capacity-bound still fails its leg, as bothkimi-k3-highcells did on one consumer PR. The timeout cap and the capacity errors are independent failure modes; this PR addresses only the first. The other busy consumer shows the same shape on a different lane: everygrok-4.7-highcell that reached ~17 min died (11 of 20), while the lanes with a 4–6 min median never failed once. A cell that honestly needs 20 minutes has no way to ask.The change
cell_timeout_minutes(number, default 15). The default reproduces today's four numbers exactly, so an unset input changes nothing.The coupling is now in the workflow. Three further caps have to move with the cell cap, and until now a comment asked the next editor to do it by hand — "COUPLED to
consolidatebelow — bump this and you must bump those too". That is the shape of every drift this repo has had. They are derived instead — computed in preflight's shell and exposed as job outputs (cell_job_timeout,judge_step_timeout,judge_job_timeout), which the three jobs read viafromJSON(needs.preflight.outputs.*), because Actions expressions have no arithmetic operators (${{ x + 15 }}fails the workflow at load):cell_timeout_minutes+ 15(checkout, CLI install, artifacts)× 2, never below 30 (reads every cell's findings at the same tier; its workload scales with the panel, not the cell cap)+ 10(its own overhead)Why each ordering matters rather than being tidiness:
Fail the leg when the cell did not submitnever reads the artifact back, so a red leg becomes a cancelled run. For the judge it means every panel cell is discarded instead of falling back to the degraded union-of-findings review.Bounded, not clamped
New preflight step, running before the panel fans out.
type: numberbuys only numeric-ness —0,-5,1.5and600all parse, and the judge's job cap doubles whatever gets through, so a typo'd 600 would mint a 20-hour job.Bounded rather than clamped on purpose: silently correcting a caller's 600 to 45 would review a long diff on a budget nobody chose and report success. The step also prints every derived cap, since they are no longer visible in a diff of this file.
Floor 10 because the stop-on-submit wrapper may start its last
resource_exhaustedretry as late as 300s in (--retry-window 300), and that attempt still needs room for a healthy 3–7 minute review (at 5 a retried cell was all but certain to hit the cap); values longer than two digits are rejected before the numeric test, so an all-digit value past 64 bits cannot slip through an erroring[ -lt ]; ceiling 45 because that is already a 100-minute judge job, and anything past it is a diff-size problem, not a timeout problem.Tests
test_workflow_cell_timeout.pypins it from four directions:+ - * /inside any${{ }}incursor-review.yml(with a self-test proving the check catches the original+ 15text) — a text-only pin of an invalid expression stays green while the workflow fails to load;type: numberstill admits, and reading the derived caps back from a real$GITHUB_OUTPUT.test_stop_on_submit.pyis updated too — it pinned the literal.Docs
Both places —
docs/callers/cursor-review.mdand.github/cursor-review/README.md.test_inputs_docs_drift.pychecks that table two-way for this workflow, so an undocumented input fails CI. The caller guide spells out the "is it a tail or a hang" test, so the knob gets raised on evidence rather than by reflex.Not in this PR
Nothing changes for any caller until one passes the input. The two consumers that need it get it in their own caller PRs once this lands and the fleet bump rolls.
Provenance
Authored by: agent-work loop
Verified:
python3 -m unittest discover -s .github/cursor-review/tests: 1280 tests OK at9288f87.github/cursor-approve/testsand.github/workflow-pins/testsOK;check_workflow_pins.pyOKcheck_agents_md.py --root .passed;check-org-repo-literals.shOKactionlintoncursor-review.ymlatc8474acreported notimeout-minutesexpression errors; not re-run at9288f87, which changes only the preflight shell and commentsDeviations:
max(30, 2 × cell), not a plain2 × cell🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.