mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #85] [MERGED] fix(groom): a PRE-agent finder failure no longer counts as a spent audit (BE-4814) #92
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#92
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/85
Author: @mattmillerai
Created: 7/28/2026
Status: ✅ Merged
Merged: 8/4/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-4814-groom-preagent-failure📝 Commits (7)
4018935fix(groom): a PRE-agent finder failure no longer counts as a spent audit (BE-4814)142f013fix(groom): count a timed-out/cancelled finder as a spent audit (BE-4814)5ccf951docs(groom): refresh the _AUDITED_CONCLUSIONS note for the widened evidence set (BE-4814)2592314fix(groom): walk the NEWEST earlier attempts and anchor on the audited one (BE-4814)f42b758docs(groom): follow the audited_run_anchor rename through the comments (BE-4814)b2aab89fix(groom): never anchor the cadence clock on a re-run timestamp (BE-4814)de43620Merge remote-tracking branch 'origin/main' into matt/be-4814-groom-preagent-failure📊 Changes
5 files changed (+763 additions, -370 deletions)
View changed files
📝
.github/groom/README.md(+35 -15)📝
.github/groom/interval.py(+244 -99)📝
.github/groom/tests/test_interval.py(+458 -251)📝
.github/workflows/groom.yml(+16 -0)📝
.github/workflows/test-groom-scripts.yml(+10 -5)📄 Description
ELI-5
Groom runs on a daily cron but only really runs every
GROOM_INTERVAL_DAYS; a gate decides "did we already do this recently?" by looking at whether a previous run's finder job finished. The problem: it counted a failed finder job as "we did the audit" — even when the job blew up in checkout, before the expensive agent step ever started. So one typo'd input could make groom go silent for a whole week, when it should have kept failing loudly every day until someone noticed. Now a failure only counts if we can see that the agent step actually started.What changed
interval.py:run_auditedno longer treats everyfailureconclusion as a spent audit.successstill counts on the job conclusion alone. Afailurecounts only with positive evidence from the jobs API's per-jobsteps[]that the billed agent step (Run finder) started — new helperagent_step_started().steps[], an empty one, the step absent (a job that died early reports only the steps it reached), stillqueued,skipped,cancelled, or a malformed entry all read as not audited → the next tick re-runs. A duplicated audit costs one run; a suppressed one hides a broken caller for a full interval.scoped_job_markeruses: the literal lives ininterval.py(agent_step_name()),groom.ymlcarries a load-bearing comment on the step, andtest_interval.pypins both halves — scoped to theaudit_find:job block, so the pin means "the billed step is named this", not "the string appears somewhere in the file".test-groom-scripts.ymlnow also triggers on.github/workflows/groom.yml. Without this the pin is decorative: renaming the step touches no file under.github/groom/, so the test that catches the rename would never run on that PR..github/groom/README.mdbullet describing the evidence rule.Falsification / evidence
The whole change rests on "the jobs API returns
steps[], with step names verbatim even for a job nested inside a reusable workflow". That is a claim about a live API, not something a unit test I wrote can establish — tests would just assert my own premise. So I checked it against a real failed groom run (GET /repos/Comfy-Org/github-workflows/actions/runs/30258329036/jobs):steps[]is present and populated on thegroom / Audit — finderjob, and step names come back unprefixed (Run finder), unlike the job name (groom / Audit — finder).Run finderstep wascompleted/failure— a genuine post-agent failure — so under this change it still counts as a spent audit. The old behavior is preserved exactly where it should be.completed/skipped(Assert finder produced JSON,Upload finder candidates), confirming the shape the pre-agent case takes: a job that dies in checkout leavesRun finderascompleted/skipped, which this change correctly reads as "never started".Post Run finderstep, which is exactly what a substring match would have swallowed — hence the exact-match rule and a test case for it.Tests
python3 -m unittest discover -s .github/groom/tests -p 'test_*.py' -v→ 99 pass. NewPreAgentFailureTestcovers the ticket's four cases plus: theskipped/cancelledstep shapes, the truncated-steps[]shape, exact-vs-substring matching, malformed entries, and two end-to-endevaluate()assertions — a pre-agent failure yesterday leaves an 8-day-old real run as the anchor and the tick runs; a post-agent failure yesterday still skips. The sibling suites (cursor-review, agents-md-integrity) were re-run untouched and are green.The producer pin was mutation-tested: renaming the step to
Run the finder agentfailstest_groom_yml_names_exactly_the_agent_step_this_module_matches(AssertionError: 0 != 1), so the pin is not decorative.Judgment calls
Run findersince groom.yml was introduced (#49, verified withgit log -S), so a rename would be churn that also breaks the match against every historical run the gate walks. I pinned + documented the existing name instead._AUDITED_CONCLUSIONScame from #56 (BE-4004) with the stated rationale "counting a failure keeps a run that spent money but died at a later step from re-spending on the very next daily tick". That rationale is preserved by the evidence path; only the case it never contemplated (dying before the agent) changes. The change is deliberate and is the ticket's whole point.status/conclusionreads as no-evidence → not audited. The live API always sendsstatus, so this is the unknown-shape case, and resolving it fail-open matches every other branch here.run_auditedbody to add path scoping, so git will flag a conflict — deliberately, since it needs a human resolve rather than a silent take-one-side. The two conditions compose: keep #83's scope-marker matching as the job filter, then apply this PR'sconclusion in _AUDITED_CONCLUSIONS or (conclusion in _AGENT_EVIDENCE_CONCLUSIONS and agent_step_started(job))in place of itsconclusion not in _AUDITED_CONCLUSIONS: continue. Neither behavior subsumes the other. This PR is based onmain, not stacked on #83 — the defect predates path scoping and applies to whole-repo runs too.Risk
Low, and one-directional. The only behavior that changes is which runs anchor the cadence clock; the worst case of a wrong answer here is one extra groom run, never a suppressed one. No consumer-facing input or output changed, so callers need no update beyond the usual SHA bump.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.