mirror of
https://github.com/Comfy-Org/comfy-typescript-sdk.git
synced 2026-11-04 23:47:27 +00:00
[PR #172] [MERGED] ci(cursor-review): lint the bump PR's caller before counting it delivered #172
Labels
No labels
audit:ai-readiness
audit:community
audit:github
audit:health-scoring
audit:policy
audit:release
audit:supply-chain
bug
cursor-review-pin
effort:medium
effort:small
effort:trivial
priority:nice-to-have
priority:recommended
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-typescript-sdk#172
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/comfy-typescript-sdk/pull/172
Author: @mattmillerai
Created: 9/21/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @mattmillerai
Base:
matt/be-16336-check-workflow-pins-fail-closed← Head:matt/be-16377-bump-pr-lint-before-delivered📝 Commits (4)
10d6279ci(cursor-review): lint the bump PR's caller before counting it deliveredcb4e5b7ci(cursor-review): measure both delivery facts, and lint the whole workflow dirf93d443Merge the fail-closed base into the lint-before-delivered branch7b85e1cci(cursor-review): gate lint-fault on a read pin, and harden the bump-head reads📊 Changes
1 file changed (+355 additions, -57 deletions)
View changed files
📝
.github/workflows/ci.yml(+355 -57)📄 Description
STACKED — merging lands on
matt/be-16336-check-workflow-pins-fail-closed(owned by @mattmillerai), NOTmain. This branches off the top of the #153 ← #169 ← #170 stack, because the code it edits exists only there. Land the stack first; do not treat a green check list here as a merge signal (ci.ymlisbranches: [main]-scoped, so the real gates do not run on a stacked head — everything below was run locally instead).ELI-5
The daily pin watchdog asks "is anyone moving this pin?" and goes quiet for a week if it sees an open bump PR that carries the commit we owe. It checked that by reading ONE of the bump PR's two pins. If the other pin was left behind, the PR could not actually work — but the watchdog counted it as delivered and shut up anyway. Now it also runs the repo's own pin lint against that PR's file, so it only shuts up for a bump PR that would be green.
What changed
All in
.github/workflows/ci.yml, in thebump_deliversblock of thecursor-review-pin-freshnessjob and the two places downstream that report its verdict.--print-pinread and thecat-file -egate (see round 10 below — it was originally sequenced after them).ROOTinscripts/check-workflow-pins.mjscomes fromimport.meta.url, so the copy already placed in$scratch/scriptsscans$scratch/.github/workflows— which is materialised fromrefs/bump-head. It judges that PR's workflows, not this branch's.bump_no_reasonoutput islintwhen the pair is inconsistent,ancestrywhen the pin is consistent but does not carry the oldest owed commit, andlint-faultwhen the lint could not be run at all but the pin was read and does carry the owed commit (round 10, narrowed in round 11). A lint fault together with an unreadable pin falls through to the genericunknown. A newbump_lint_firstoutput carries the lint's own first problem line (--stripped, with the problem count appended), and a newbump_carries_notecarries the ancestry fact as a sentence. All are emitted alongsidebump_pr/bump_age_days/bump_delivers.::error::in thestate=stalebranch ofassess, and thecause=chain in "Open or update the stale-pin issue". The lint's line is quoted, not paraphrased: exit 1 covers a non-40-hexuses:, a stale trailing version comment, a missingworkflows_ref, aworkflows_refthat disagrees withuses:, and a caller spelling the scanner cannot read — only one of which is literally a split pair, so asserting "split pin" in prose would be wrong most of the time.$BUMP_LINT_FIRSTis passed as aprintfargument, never in a format string, and is%-escaped before reaching any::error::(round 10).bump_delivers=unknownnow says the pin is read through--print-pinand the pair is checked through the lint, soyesmeans "a caller that would also be green onworkflow-pins".Judgment call: the exit-1 test is not keyed on the exit code alone
The obvious mapping is
rc == 1 → no/lint, and it is wrong. Measured here on node 26:node /nonexistent.mjsexits 1, an uncaughtthrowexits 1, and only a bad CLI flag gives 9. Keyed on the code alone, this job's own crash would publish a stack-trace line as "the lint says your caller is broken" and open a sticky issue blaming the fleet for it — the fault-as-verdict conflation the rest of this step is built to avoid. All three of the script's exit-1 paths (fail(),reportUnreadable(), the lint-error report) open their stderr withcheck-workflow-pins:, and nothing node emits on its own does, so the classifier requires that marker too. Anything else lands onunknownwith the existing "could NOT VERIFY" wording.Two smaller deviations from the plan as written: the stderr capture now goes to
$gwtmp/bump-lint.err(it was/tmp/bump-lint.erruntil the base branch introduced the per-run$gwtmpdirectory — see the merge note below); and the lint line is threaded as a new$GITHUB_OUTPUToutput rather than re-derived, which the plan allowed either way.Falsification of the new deny path
This diff adds a path that withholds a
deliveredverdict, so the affirmative capability was exercised first rather than assumed: fixture caserealbelow runs a fully consistent caller through the unchanged--print-pinread, the new lint, and the ancestry test, and still reachesbump_delivers=yes. The denial fires only on a caller the repo's own lint actually rejects at run time — it is decided by running the tool, not by an authored premise.Round 10 review (commit
cb4e5b7)Nine cursor-review findings, all one shape: the
lintcause was wired as a short-circuit, so it suppressed facts the job had already paid for and then asserted things it had never measured. All nine are fixed and their threads resolved..github/workflows/*.y*mlis now materialised fromrefs/bump-head(git ls-tree+git show, non-recursive and.y*ml-filtered, matching the scanner's ownreaddirSync). The realworkflow-pinsjob scans the whole directory, so a bump PR that broke or added a caller in any other file read asdelivers=yeshere and muted the watchdog for the full bump-PR window while being red on merge — which falsified item 4's "yesmeans it would also be green onworkflow-pins" claim. Demonstrated in the sandbox: with a cleanci-cursor-review.ymland a broken caller inother.yml, the old code answeredyesand the new code answersno/lintnaming.github/workflows/other.yml:5.stale, reddening the schedule and refreshing the public issue daily. Both facts are now reported, so the reader learns whether a fixup commit or a whole fresh bump is owed. Precedence (lint>ancestry>lint-fault) is decided in one place with its rationale.workflows_ref, an unreadable caller spelling or a non-40-hexuses:takes--print-pindown too, so those permanent, actionable defects surfaced as the transient "could not verify". The deterministic verdict now wins.lint-faultis its own cause. A lint that could not run was routed to text saying the job "could NOT VERIFY which commit its caller pin carries" — false on that path, where the pin was read, asserted 40-hex and confirmed upstream. It now points at this job, and its step 1 says to re-run rather than audit the PR.%escaping. The runner percent-decodes%25/%0A/%0Din workflow-command message data, so a lint line quoting a ref or path containing one forged extra annotation lines.%is escaped first (so it cannot re-encode the escapes that follow), then CR.$GITHUB_OUTPUThardening. The two free-text fields now cross in the heredoc/delimiter form and are newline/CR-flattened at the boundary, rather than relying on the producer's current message shapes. In the plainname=valueform a newline forges further outputs — includingoldest_shaandbehind_count, written earlier in the same block and never overwritten.(+N more problem(s))), so a caller with several defects is not fixed one round-trip per day.Round 11 review (commit
7b85e1c)Five inline cursor-review findings, all fixed and their threads resolved:
lint-faultis now gated oncarries = yes. Both message sites for that cause say "its pin reads fine", and that was false when the same fault also took--print-pindown. That double fault now reports as the genericunknown.lint-faultgets its own ancestry sentence. It now states the bare fact ("Its pin does carry the oldest owed commit"). Before, it reused the lint-fail note, which bills a fixup commit for a defect nobody had established.git ls-tree -zwithread -r -d ''. Without-z, git C-quotes a name containing non-ASCII bytes,"or\, and that file silently dropped out of the scratch root.$GITHUB_OUTPUTheredoc delimiter instead of the fixed__BUMP_FIELD_EOF__.The panel's two unanchored findings (
.github/dependabot.yml:97, and the$clone_err/$pr_err/$reason::error::sinks) are about code from #153 at the bottom of the stack (thedependabot.ymlnarrowing is commita8c02efon #153's branch), not this diff. There is a comment on this PR saying so; it names #170, which is wrong, and this sentence corrects it. The High finding's premise also does not hold against currentdependabot-core:github_actions/lib/dependabot/github_actions/file_parser.rb(github_dependency) names a dependency whose path matches/.github/workflows/*.y(a)mlasowner/repoplus that path, so theComfy-Org/github-workflows/.github/workflows/*glob does match these callers.Merge of the base branch (commit
f93d443)The base (
matt/be-16336-check-workflow-pins-fail-closed) had moved on and conflicted in threeci.ymlhunks. Resolved keeping both intents:carries/carries_whyshape, adopting the base's whole-value[[ =~ ]]40-hex match and its per-run"$gwtmp/gw"clone path.::error::lines: this branch'slint/lint-faultbranches, all now using the base's future-dated-aware$landedwording.step1(chosen alongside$cause, covering the lint causes, and already naming$OLDEST_SHAonunknown) is kept; the base's later, narrowerstep1block is dropped rather than left to overwrite it.Also moved the lint stderr capture from
/tmp/bump-lint.errto"$gwtmp/bump-lint.err", per the base's rule that every scratch path in that step lives in the per-run directory.Verification
cursor-review-pin-freshnessisif: github.event_name == 'schedule', so no PR CI can run it. Thebump_deliversblock was extracted verbatim into a/tmpfixture (real local git repo for the upstream clone, socat-file -eandmerge-base --is-ancestorrun for real; only the branch fetch/show is stubbed to supply the caller), and each case's$GITHUB_OUTPUTwas read back:bump_deliversbump_no_reasonyesworkflows_refadvanced,uses:left behindnolintnolintnoancestryunknownunknownlint-fault(round 10; was (empty))The two quoted lint lines came back intact and single-line through
$GITHUB_OUTPUT(theworkflows_refvsuses:message and the stale-comment message). Both downstream chains were then exercised across all four reachable states —no+lint,no+ancestry,unknown, no-PR — and each selected its own branch; a%planted in the lint value survived thecause=printf, confirming it never reaches a format position.Worth stating plainly about the missing-script row: it reaches
unknownvia the pre-existing--print-pinguard higher up, not via the new classifier, because a missing script takes--print-pindown first. The new fault path is exercised by the throwing-script row instead.Also run:
actionlint(0 issues; confirmed it invokes shellcheck onrun:bodies by planting a deliberate SC2086 in a probe workflow),node scripts/check-workflow-pins.mjs(1 caller, pins agree),pnpm lint,pnpm format:check(86 files),pnpm typecheck,pnpm test(27 files, 652 passed, 0 failed; 654 after the base merge),node scripts/check-public-repo-hygiene.mjs,node scripts/check-spec-drift.mjs.Scope swept, including the part not changed
Comfy-Org/github-workflowscaller under.github/workflowsis now covered by both the--print-pinread and the pair lint. There is no second caller left uncovered.bump_delivers. The 2 that branch on= nowere threaded withbump_no_reason; the third is thedeliveredmute, which branches only on= yesand needs no reason.Comfy-Org/github-workflows's.github/bump-callers/bump-callers.sh(public, read via the API at 1273 lines) does rewrite both pins in one pass and re-read them in a post-rewrite assertion that fails the repo on a mismatch. So this bites a hand-pushedci/bump-cursor-reviewhead or a producer regression, not the fleet's normal output — severity low, as scoped.Residual
The stale-pin issue body's step 1 still reads wrong for everyFixed in round 10 — reviewers raised it independently, so it was pulled into scope. Step 1 is now chosen in the same branch asnoverdict.cause, so the checklist can no longer contradict the paragraph above it.workflow-pinsis not a required status check onmain(only the two Test jobs,build-checkandpublic-repo-hygieneare), so a hand-pushed split-pin bump PR is red but still mergeable. That is a repo-admin setting, not a repo-content change, and is unfixable from this PR.run:block, so the/tmpfixture above is a one-shot harness and is not committed; nothing inpnpm testwill catch a future regression in this block. Extracting thebump_deliversblock into a testable script is the durable fix and is its own piece of work.cursor-review.ymlitself was not run — no scheduled orworkflow_dispatchexecution ofcursor-review-pin-freshnesshas been performed from this branch, since adding that trigger is an operator change.Provenance
/tmpfixture of the extractedbump_deliversblock: 6/6 cases matched the expectedbump_delivers/bump_no_reasonpairs; both downstream message chains: 4/4 branches selected correctly. (round 10, commitcb4e5b7)actionlint .github/workflows/ci.yml: 0 issues;shellcheck -S warningon the extractedassessand issue-steprun:bodies: clean; sandbox harness driving the extracted block against real local git repos — clean+carries →yes, clean+behind →no/ancestry, split pin →no/lint, broken sibling caller →no/lint, node fault →unknown/lint-fault, three-problem tree →(+2 more problem(s)); injection probes against$GITHUB_OUTPUTand::error::with a hostile value carrying an embeddedoldest_sha=line, a CR and a%0Asequence — no forged output keys, no forged annotation lines; issue body rendered under all six causes, each selecting its own step 1;npm test: 27 files, 652 passed, 0 failed;npm run lint,format:check(86 files),typecheck: clean;node scripts/check-workflow-pins.mjs: 1 caller, pins agree;check-public-repo-hygiene.mjs: clean. (base merge, commitf93d443)pnpm lint,format:check,typecheck: clean;pnpm test: 27 files, 654 passed;check-workflow-pins.mjs: 1 caller, pins agree;check-spec-drift,check-public-repo-hygiene.mjs: OK;bash -non everyrun:body andshellcheck -S warningon theassessand issue-step bodies: clean. The/tmpfixture harness was not re-run after the merge. (round 11, commit7b85e1c) The extracted precedence block was run over all 8 combinations of lint (pass/fail/fault) and carries (yes/no/unknown), and each produced the expectedbump_delivers/bump_no_reason. Fault with unknown carries now givesunknownwith no reason. Thels-tree -zloop was run in a scratch repo holdinga"b.yml,é.yamlandREADME.md: both YAML files were kept unquoted and the README was skipped.bash -non everyrun:body andshellcheck -S warningon the pin-freshness job's bodies were clean, as werecheck-workflow-pins.mjs(1 caller, pins agree),pnpm lint,pnpm format:checkandcheck-public-repo-hygiene.mjs.actionlintis not installed on this host and was not run this round.pnpm testwas not re-run: the change touches onlyci.yml. (reviews pass, no new commit) Readdependabot-core'sfile_parser.rbon its default branch to check the round-11 High finding's naming premise (see above); no code changed./tmp/bump-lint.errwhile$gwtmpdid not exist, and moved to$gwtmp/bump-lint.erronce the base introduced it (base merge); the exit-1 classifier additionally requires the script'scheck-workflow-pins:stderr marker, because node's exit code alone cannot separate a lint verdict from a crash (see above). (round 10) Scope was widened beyond the original plan to take all nine review findings, including the issue-body step 1 that the original PR had deliberately left as a Residual — reviewers raised it independently and it is two lines beside thecausechain it contradicts. Thelint-faulttext is truncated to 300 characters because a node stack trace is bound for a public issue body; the full text stays in the step log.Note on CI:
ci.ymlisbranches: [main]-scoped andcursor-review-pin-freshnessisif: github.event_name == 'schedule', so neither this job nor the repo's gates run on a stacked head. Everything above was run locally; no CI run on this PR exercises the changed code.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.