mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #310] [MERGED] fix(reviewers): converge both glob translators on full-string anchoring, code-point ? and line-terminator-agnostic ** #311
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#311
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/310
Author: @mattmillerai
Created: 9/18/2026
Status: ✅ Merged
Merged: 9/19/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-15311-glob-translator-convergence📝 Commits (2)
f11b5adfix(reviewers): converge both glob translators on full-string anchoring, code-point?and line-terminator-agnostic**ef83485docs(reviewers): scope the?code-point claim to precomposed forms, and pin NFD in the corpus📊 Changes
5 files changed (+85 additions, -20 deletions)
View changed files
📝
.github/assign-reviewers/parser-corpus.json(+41 -3)📝
.github/refresh-reviewers/README.md(+1 -1)📝
.github/refresh-reviewers/generate.py(+9 -9)📝
.github/workflows/assign-reviewers.yml(+27 -5)📝
docs/callers/assign-reviewers.md(+7 -2)📄 Description
STACKED — merging lands on
matt/be-15247-shared-reviewers-parser-corpus(owned by @mattmillerai, PR #305), NOTmain. Review the net diff (4 files) rather than the two-dot diff, and do not merge this before #305.ELI-5
Two copies of the same "does this file path match this pattern?" code exist — one in JavaScript inside
assign-reviewers.yml(the thing that actually picks reviewers) and one in Python insiderefresh-reviewers/generate.py(the thing that proposes the reviewer map). They were supposed to behave identically. They didn't, in three small ways involving newlines and emoji. This makes them identical and adds test cases so they can't drift apart again.What changed
generate.pyglob_to_regexp:re.compile("^" + out + "$")→re.compile("^" + out + r"\Z", re.DOTALL). Python's$also matches just before a single trailing newline;\Zdoes not, so the anchoring is genuinely full-string and now matches the JSRegExp.re.DOTALLis the other half —**(the only construct that compiles to a bare.) spans line terminators. The docstring's "deliberately-unfixed divergence" paragraph is deleted and the full-string-anchored claim restored.assign-reviewers.ymlglobToRegExp:new RegExp('^' + re + '$')→new RegExp('^' + re + '$', 'su').smakes**span line terminators;umakes?one Unicode code point rather than one UTF-16 code unit, so an astral path character (an emoji) counts once instead of as its two surrogate halves. The comment above it now documents all three semantics and names the Python counterpart.parser-corpus.json: every formerly-divergent case pinned, so both suites enforce it from the one fixture. Four newglobs[]entries (src/a.js,src/**,src/*,**/x?) plus two cases on the existingdocs/?.md.docs/callers/assign-reviewers.md: one sentence under the glob-semantics paragraph stating?is one Unicode character.matchesAnyalso backsREVIEWER_SKIP_BASE_BRANCHES, and while git refnames cannot contain control characters (so no base-branch decision changes on thesflag), they can contain astral characters — which is exactly what theuflag changes, so the doc sentence is load-bearing there and not only for path rules.Non-vacuity by mutation
Each of the four edits reverted one at a time, with the corpus cases in place. Every revert reds the relevant suite on a specific new case:
\Z→$(DOTALL kept)test_generate.pyglob='src/a.js', path='src/a.js\n're.DOTALLdropped (\Zkept)test_generate.pyglob='src/**'on'src/a\nb'and'src/a/b\n'sdropped ('u')assignment.test.cjscorpus glob — src/**, first onglobToRegExp("src/**").test("src/a\rb")udropped ('s')assignment.test.cjscorpus glob — docs/?.mdon"docs/😀.md"andcorpus glob — **/x?on"a/b/x😀"Differential sweep — the half that is not being changed
Rather than assert parity, I measured it. 1,165 generated globs × 489 generated paths = 569,685 (glob, path) pairs, both translators run over the same space (the generator built the glob and path alphabets out of
*,**,**/,?,/,., every regex metacharacter the translator escapes,\n,\r, U+2028, U+2029,éand an astral emoji):uflag: 262,161 probe globs (every UTF-16 code unit as a lone glob character — lone surrogates included — each of those followed by and preceded by a literal, each adjacent to*/?, plus astral code points and realistic shapes). 0 patterns that compiled before and throw undersu, and 0 whose self-match verdict changed. That is the empirical check behind the "every escape is a legal identity escape underu" claim, not a restatement of it.Judgment calls
main— it arrives with #305, which is open, green and mergeable but unmerged. Since the blocker is an unmerged PR that already carries the foundation code on a branch, this stacks on that branch instead of waiting. GitHub retargets tomainwhen #305 merges.src/**cases were ambiguous in the source text. The list of expected paths carried two visually identical"src/a b"entries. I read them as U+2028 and U+2029 — the two line terminators a JSRegExphonours that Python's.does not, which is the only reading that makes them two distinct cases and makes them formerly-divergent in the direction the change fixes. Verified: both were JS-false / Python-true before, both true after.\u-escaped in the JSON whileéand the emoji are written raw, matching the file's existing style. They are invisible characters, and a raw one in a fixture is a review hazard — a raw U+2028 is also a line terminator to a JS parser. Thewhyfield says so.Skip-caller-bump. This is a behavioural change inside a watched surface, so the assign-reviewers fleet should bump.Residual
validPathmeans the cached-history path never exercises thesflag.assign-reviewers.yml:285rejects any path containing\x00-\x1fwhen validating a downloaded history manifest, so a cached record holding a newline in a filename throws and falls back to a live fetch rather than reachingglobToRegExp. Live PR file paths are not filtered that way and do reach it, so the change is not vacuous at runtime — but the two paths into the matcher now have different reachable input sets, and nothing tests that asymmetry. U+2028/U+2029 are outside\x00-\x1fand passvalidPath, so the cached path is only partly insulated. Worth its own look at whethervalidPathshould be the shared entry gate for both.docs/callers/refresh-reviewers.mdis watched by a two-way input/docs drift test and bytest-refresh-reviewers.yml's path filter;docs/callers/assign-reviewers.md— the file this PR edits — is watched by neither, so the sentence added here can rot silently.check_workflow_pins.py's docs cross-check coversworkflows_refrows only.?semantics are documented for base-branch globs but not corpus-pinned for them. The corpus drivesglobToRegExp/matchesAnydirectly, which is the same function the base-branch gate calls, so the semantics are covered; what is not covered is a case shaped like a refname (stack/…) going throughREVIEWER_SKIP_BASE_BRANCHESend to end. The stated reason is that refnames cannot hold control characters — true for control characters, but theu-flag half applies to refnames and is asserted only indirectly.Provenance
node --test .github/assign-reviewers/tests/*.test.cjs: 104 pass, 0 fail (100 before; +4 corpus glob entries);python3 -m unittest discover -s .github/refresh-reviewers/tests -p 'test_*.py': 56 tests, OK;python3 .github/workflow-pins/check_workflow_pins.py: OK, 11 workflows, 0 exempt;python3 .github/agents-md-integrity/check_agents_md.py --root .: passed (2 pre-existing warnings, untouched by this diff);yaml.safe_loadon the edited workflow: parses; 4/4 mutation reverts red the expected suite on the expected case; differential sweep 569,685 pairs 6,454 → 0 divergent;u-flag compile sweep 262,161 probes, 0 regressions.src/**path literals were resolved to U+2028/U+2029 as described under Judgment calls.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.