mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[GH-ISSUE #286] [groom] reviewers.yml has two hand-ported parsers whose parity is asserted by two independent suites and no shared corpus #7
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#7
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?
Originally created by @cloud-code-bot[bot] on GitHub (Sep 14, 2026).
Original GitHub issue: https://github.com/Comfy-Org/github-workflows/issues/286
Groom auto-builder — Comfy-Org/github-workflows: this CONFIRMED finding could not be auto-built (patch modifies a CI-privileged or dataset-of-record path (per .github/groom/patch_policy.py — workflow/action defs, lockfiles, build/test config that executes in pre-review CI, graded eval cases under a suites/**/cases/ tree, or a symlink into such a tree) — a human must author these changes), so it is filed for a human. · run
Problem
parseReviewerConfig (JS, inline at assign-reviewers.yml:424) and parse_reviewer_config (Python, generate.py:172, under a header at 131 reading "parity with parseReviewerConfig") are a line-by-line port: same comment-stripping quote-state machine, same unquote, same flow-sequence parser, same indent helper, same dash/list-key walk. globToRegExp is ported the same way (generate.py:96, docstring "Port of assign-reviewers.yml's globToRegExp"). Parity is asserted only by two independent hand-written suites (.github/assign-reviewers/tests/assignment.test.cjs and .github/refresh-reviewers/tests/test_generate.py); there is no shared corpus, so a case exercised on one side proves nothing about the other.
Candidate divergences visible on a read, offered as corpus seeds rather than as claims: the JS splits lines on a CR-optional newline regex while the Python splits on a bare newline; the JS unquote has no length guard, so a one-character double-quote would slice to empty, while the Python _unquote requires length >= 2.
The harness is fragile, exactly as described
assignment.test.cjs:7 recovers the shipped script by splitting the workflow text on a literal 10-space-indented "script: |" line and on the exact downstream step name "Publish reviewer history manifest", then stripping 12 leading spaces per line. Verified: assign-reviewers.yml contains exactly ONE "script: |" (line 166) and the anchor step is at line 710, so it works today -- but it is load-bearing on there never being a second "script: |" at that indentation, on that step name never changing, and on the indentation staying at 12. Any of those would silently capture the wrong span rather than fail.
The unification half is correctly dropped
Grepping assign-reviewers.yml for actions/checkout or workflows_ref returns NOTHING -- this workflow deliberately has no checkout at all, so moving the JS to a file would add a workflows_ref pin to every existing caller, a breaking contract change for a cosmetic gain. And the Python genuinely computes something the JS does not: parse_reviewer_config returns a (config, locations) pair recording flow/block line positions so the drift generator can rewrite only those bytes. They are not the same function. Do NOT collapse them.
Scope (test-only)
Value and risk
The config format is a contract read by the runtime and REWRITTEN by the drift generator, so a divergence could mean the generator edits lists that the runtime reads differently -- nothing today could catch that. Risk is low: test-only, no shipped code changes. Not marked security: this decides who is ASSIGNED to review, not who may approve or what may execute.
@mattmillerai commented on GitHub (Sep 18, 2026):
Triage: still valid, tracked internally. Leaving this open.
Re-verified every claim against
origin/main@cf7b8d9c2614ad9f8ee41acf245381ad76fcdc8b. All five hold, and the line numbers in the body are still exact:parseReviewerConfigatassign-reviewers.yml:424andparse_reviewer_configatgenerate.py:172are both present, with the "parity with parseReviewerConfig" banner still atgenerate.py:131and the "byte-for-byte semantics-equal" docstring atgenerate.py:99-101.git ls-tree -r origin/main .github/assign-reviewers .github/refresh-reviewersreturns only the two READMEs,generate.py,assignment.test.cjs,test_generate.pyandtest_inputs_docs.py. Each suite carries its own inline literals with no overlap.unquotedivergence is live.assign-reviewers.yml:436-440has no length guard;generate.py:152-156requireslen(s) >= 2. For a one-character", JS returns''and Python returns".assignment.test.cjs:7still splits on the 10-spacescript: |and the step namePublish reviewer history manifest. Those are still unique (:166and:710respectively), which is exactly why it works today and why it would silently capture the wrong span if either changed.actions/checkoutand zeroworkflows_refinassign-reviewers.yml, so the reasoning for not unifying the two implementations stands.Nothing has fixed this since filing: the only commits touching these paths since 2026-09-14 are
a8ecb81and0501c01, both adding the unrelated workflow-inputs-vs-docs drift test.Two additions from the sweep, now carried into the tracked work:
assign-reviewers.yml:449splits lines on/\r?\n/,generate.py:180on a bare"\n". Latent rather than live — Python's.strip()absorbs the\rat every consumer traced — but worth a corpus case.test-assign-reviewers.ymlwatches only.github/assign-reviewers/**+assign-reviewers.yml;test-refresh-reviewers.ymlwatches only.github/refresh-reviewers/**+ its own workflow + its caller guide. A corpus added under one directory would run only on the surface you edited, defeating the point — so both filters need the corpus path.#270 describes the same defect from the other anchor file and has been closed as a duplicate of this one, with its path-filter requirement folded into the tracked work.
This is being tracked internally and the issue stays open until the fix lands. Reopen or comment if you can still reproduce something here that this misses.
Created by Claude Code