mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #186] [MERGED] feat(linear-ticket): make the warn-only pilot fail the check without blocking the merge #195
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#195
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/186
Author: @mattmillerai
Created: 8/20/2026
Status: ✅ Merged
Merged: 8/20/2026
Merged by: @mattmillerai
Base:
main← Head:matt/linear-ticket-soft-fail📝 Commits (2)
26339cdfeat(linear-ticket): make the warn-only pilot fail the check without blocking the mergefeca179fix(linear-ticket): make the soft-fail copy true in every caller configuration📊 Changes
7 files changed (+418 additions, -29 deletions)
View changed files
📝
.github/workflows/linear-ticket.yml(+35 -3)📝
README.md(+1 -1)📝
docs/callers/linear-ticket.md(+53 -5)📝
scripts/linear-ticket/README.md(+19 -3)📝
scripts/linear-ticket/lib.py(+139 -0)📝
scripts/linear-ticket/tests/test_lib.py(+144 -0)📝
scripts/linear-ticket/validate.py(+27 -17)📄 Description
Why
On Comfy-Org/cloud#6690 the gate worked perfectly — it found three referenced-but-unlinked identifiers (
PILOT-449, BE-7081, BE-3033) and explained exactly how to fix them. Nobody noticed. In warn-only the status publishes green, so the verdict lives only in a marker comment sitting among a dozen other bot comments on a busy PR.A pilot exists to be observed. A passing check is a check nobody reads.
What changes
New
soft-failinput (boolean, defaulttrue), read only whenenforce: false:enforce: truefailureenforce: false,soft-fail: true(new default)failureenforce: false,soft-fail: falsesuccessNothing becomes a blocker. Blocking is branch protection requiring the
linear-ticketstatus context — never this workflow's call. I checked both live callers before writing this: neitherComfy-Org/cloud's "Requirements to Merge to Main" ruleset norComfy-Org/comfy-infra'smainruleset listslinear-ticketamong its required contexts, so the red status is advisory on both today. A non-required failing check leaves the merge button live.The marker comment now says so, so a red X is never misread as a merge block. The wording is
deliberately hedged — the validator never reads the caller's ruleset, so it cannot assert
that nothing is blocked (see the review round below):
…plus one category-aware sentence: link the ticket, or — for
infra_error— there is nothing tofix on the PR at all. The headline becomes
❌ fail (exists_not_linked) — warn-only.Two deliberate calls
The job stays green in warn-only. This validator runs on the default branch off
workflow_run, so its run is never attached to the PR — the commit status is the only PR-visible signal. A red default-branch run for a check that is deliberately not gating would read as "main is broken" in the Actions tab: louder, in the wrong place. Onlyenforce: trueexits nonzero.Default
true, so the SHA bump alone delivers it.bump-callers.shmoves pins, not inputs; defaulting off would mean hand-editing every caller. The one thing this makes possible is a footgun, documented at the input, in the docs table, and as a gotcha:enforce: false+soft-fail: true+ the context already required would block merges. Don't require the context before flippingenforce: true— which was already the documented rollout order (step 6, after step 5).Rollout ladder, restated
enforce: true, still not required → PR-visible result unchanged; the validator's own run now also goes red, so systemic breakage shows in the Actions tab.linear-ticketto the ruleset. Only now does anything block.Implementation
The mode decision moves out of
validate.pyinto a purelib.failure_outcome()returning(verdict, state, description, exit_code, advisory)—lib.py's stated contract is that every decision is testable with no network call, and this was the last one inline in the orchestrator.New tests pin the invariants worth pinning: only enforce ever exits nonzero, the advisory note never rides along with a gating verdict, enforce ignores
soft-failentirely, and every mode's status description fits GitHub's 140-char truncation (a description that only survives truncation would silently lose the category).One behaviour deliberately unchanged: a failed terminal status write is still exit 1 even in warn-only. Soft-fail's whole point is that the red status lands; a missing write leaves the previous status standing as this commit's answer.
Tests
Review round (cursor-review panel, all 7 threads)
Four fixes landed in
feca179; three findings answered on the thread without a code change.claim about the caller's ruleset, which this validator never reads — and it is false in
exactly the footgun this PR documents. Rewritten to state only what is knowable, and to name
the misconfiguration to report if the merge button really is blocked.
infra_errormeans Linear could not bequeried, so
no linked Linear issue (infra_error)was a diagnosis the run never made; thenote likewise no longer tells an author to link a ticket to fix a broken credential. (This
string predates the PR — soft-fail just promoted it to a louder surface.)
SOFT_FAILenv now means the silent variant. The workflow always passes it,so absent can only mean the
uses:andworkflows_refpins skewed apart — and a caller thatcannot even express the input must not be silently upgraded from green to red. Pin skew is
now inert in the safe direction, matching
ENFORCE's fail-closed default.nonzero" across the input description, both READMEs, the caller doc and the
validate.pycontract — warn-only still exits 1 on a failed terminal status write, a missing token/repo,
malformed
team-keys, or a non-pull_requestevent.enforce: falsecaller" doc section, plus a BEHAVIOUR CHANGEparagraph on the input itself, so the green→red flip is documented at the callers it changes
along with the one-line
soft-fail: falseopt-out. The default staystrue— see below.Answered without a change: the
soft-failname (the polarity matches Buildkite'ssoft_fail— a real failure that does not fail the build; happy to rename while no caller setsit yet), the comment-before-status write order (reversing it trades an unexplained red check
for an unlanded one — pre-existing since #183), and the default
trueitself.Follow-up (not in this PR)
The auto-bump PR into
Comfy-Org/cloudwill move the SHA only, leavinglinear-ticket-validate.yml's header comment saying "WARN-ONLY pilot (enforce: false): every outcome is green" — true before this change, stale after. Happy to open a one-line comment fix there; say the word.Provenance
Authored by: agent-work loop
Verified:
python3 -m unittest discover -s scripts/linear-ticket/tests -p 'test_*.py'— 63 passed;python3 -m py_compile scripts/linear-ticket/{lib,validate}.py— ok. All PR checks green on the pre-review-round commit; the review-round commit re-runs them.Deviations: Three of the seven panel findings were answered on the thread rather than fixed — the
soft-failinput name, the comment-before-status write order, and thedefault: truebehaviour change (mitigated by documentation rather than by flipping the default). Rationale on each thread.AGENTS.mdfails the repo's own 200-line integrity ceiling at 273 lines, but that is pre-existing onmain, is not a check on this PR, and was left untouched.🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
ref:through a step output so the never-fail idiom is linted (BE-8130) #203if:spellings (BE-8130) #204