[PR #189] [MERGED] feat(linear-ticket): rename the status context to "Linear ticket" and drop the slug from its description #197

Closed
opened 2026-10-26 22:37:16 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Comfy-Org/github-workflows/pull/189
Author: @mattmillerai
Created: 8/20/2026
Status: ✅ Merged
Merged: 8/20/2026
Merged by: @mattmillerai

Base: main ← Head: matt/linear-ticket-pretty-context


📝 Commits (4)

  • a1f9aa2 feat(linear-ticket): rename the status context to "Linear ticket" and drop the slug from its description
  • 12f1029 fix(linear-ticket): keep the two link-failure categories distinguishable, and correct the rename callout
  • acdef01 docs(linear-ticket): drop the leading space inside the / validate code span
  • cf4d468 Merge origin/main into matt/linear-ticket-pretty-context

📊 Changes

7 files changed (+148 additions, -48 deletions)

View changed files

📝 .github/workflows/linear-ticket.yml (+6 -6)
📝 README.md (+1 -1)
📝 docs/callers/linear-ticket.md (+57 -19)
📝 scripts/linear-ticket/README.md (+3 -3)
📝 scripts/linear-ticket/lib.py (+25 -9)
📝 scripts/linear-ticket/tests/test_lib.py (+52 -6)
📝 scripts/linear-ticket/validate.py (+4 -4)

📄 Description

Before / after

GitHub renders the commit-status context verbatim as the check's name, so linear-ticket was putting a machine slug where a reader expects prose:

✗  linear-ticket   — Warn-only: no linked Linear issue (no_candidate)     ← before
✗  Linear ticket   — Warn-only: no linked Linear issue                    ← after

All four categories, in enforce mode:

category rendered row
no_candidate ✗ Linear ticket — No linked Linear issue
exists_not_linked ✗ Linear ticket — Referenced Linear issue is not linked yet
policy_mismatch ✗ Linear ticket — Linked Linear issue fails this repo's policy
infra_error ✗ Linear ticket — Could not verify — Linear could not be queried

And the same headline across the reporting modes:

mode rendered row
enforce ✗ Linear ticket — No linked Linear issue
warn + soft-fail ✗ Linear ticket — Warn-only: no linked Linear issue
warn, silent ✓ Linear ticket — Warn-only (would fail): no linked Linear issue

The category slug leaves the one-liner. It stays in the marker comment and job summary — ### Linear ticket check — ❌ fail (no_candidate) — warn-only — which is where triage actually happens. Beside the check name it was noise, and for infra_error it was the second slug in a line that already had one.

exists_not_linked gained its own headline in review (see Guardrails): dropping the slug had collapsed it onto no_candidate's string, and the two remedies are opposite — one means add a link at all, the other means Linear already knows the issue and has not attached it yet (the async-link race that rollout step 3 calls the common case, where the fix is a re-run, not an edit).

Timing is the whole point

The context is the exact string a consumer lists in its ruleset's required checks. Renaming it is free only while no caller requires it — after that it silently retires the required check: the new context is never satisfied, the old one is never reported again, and merges hang pending forever.

I checked all three callers before touching it, and re-verified live against the API during review:

caller requires the context?
caller 1 no
caller 2 no (no required checks at all)
caller 3 no (two rulesets, neither requires it)

Caller repos are private and this repo is public, so they are referred to by index — see vars.LINEAR_TICKET_CALLERS for the roster.

This is the last cheap moment. Once the pilot flips to enforce: true and repos start requiring the context, the same change becomes a coordinated multi-repo migration.

Guardrails added

A test now pins CONTEXT, so a future rename fails loudly and forces that same caller audit rather than shipping quietly. A second test pins MARKER as independent of it — the comment marker (<!-- linear-ticket-check -->) is not the status context, and "tidying" it to match a context rename would make the gate stop finding its own comment and start posting duplicates on every run.

A third asserts the status description carries no raw category slug and no underscore, so the slug can't creep back into the one-liner.

A fourth — test_each_category_gets_a_distinct_description — pins all four categories' descriptions pairwise-distinct in every reporting mode, so a future headline edit cannot silently re-collapse two categories onto one string the way dropping the slug did.

Docs

A migration callout where the context is introduced, covering the three things that bite when a caller takes the bump:

  • If your ruleset already requires linear-ticket, update it in the same change. The old context is never reported again, so a required check nobody publishes leaves every PR pending — which blocks merges exactly as a failure would.
  • Already-open PRs do not gain the new status on their own. The signal workflow fires on pull_request, so moving the pin publishes nothing for a PR already open: until it takes a new commit or someone re-runs its validate workflow, it carries the old context alone — there is no new Linear ticket beside it. Requiring the new context before those PRs are re-validated leaves every one of them pending, so backfill deliberately rather than waiting for head SHAs to turn over.
  • The stale linear-ticket status survives, and it is not inert. Statuses are last-write-wins per context, so whatever value the old context last held stays on that head SHA — and it is frequently success, not red (any pass, any exemption, and every outcome under soft-fail: false). While linear-ticket is still required, that stale green keeps satisfying the requirement even after the verdict changed underneath it (issue canceled, attachment removed, exempt label pulled, team-keys tightened); and either value counts toward the commit's combined status and statusCheckRollup, which tooling reads — this repo's own grade-pr-risk.sh does.

The enforce: false upgrade guide got the same treatment: where it describes pre-bump state it now names the old context, because a caller that has not taken the rename bump does not publish the new one — following the old instruction literally finds nothing and reports safe while the old requirement is live.

The job-vs-status gotcha is now a table, because the two names have become confusably similar in the ruleset's check picker — they differ only by capitalisation and a suffix:

pick name
✅ Linear ticket — the commit status
❌ Linear Ticket / validate — the job, which runs on the default branch

That collision is the one real cost of this name, and it's worth knowing about: requiring the job instead of the status is the classic mistake, and it just got easier to make. The alternative was a context that shares no words with the workflow name.

docs/callers/README.md is deliberately untouched — its three linear-ticket mentions name the reusable workflow, not the status context.

Tests

python3 -m unittest discover -s scripts/linear-ticket/tests -p 'test_*.py'   # 68 passed (63 on main)
python3 -m py_compile scripts/linear-ticket/{lib,validate}.py                # ok
python3 .github/workflow-pins/check_workflow_pins.py                         # 10 workflows, 0 defaults

Rename scoped mechanically (`linear-ticket` → `Linear ticket`, closing-backtick anchored so linear-ticket.yml, linear-ticket-validate.yml, linear-ticket-check, bump-linear-ticket-callers and scripts/linear-ticket/ can't match), with an assertion pass afterwards confirming no collateral renames.

After merge

The bump fleet rolls all three callers. Their caller files carry # publish the `linear-ticket` commit status in a permissions comment — cosmetic, not functional, and I'll clean it up in the same follow-up as the stale caller header if you want.

Provenance

Authored by: agent-work loop
Verified: Re-verified after merging current main (f8eec04) into this branch and resolving the three doc conflicts: scripts/linear-ticket/tests 74 passed, .github/cursor-review/tests 194, .github/groom/tests 365, .github/workflow-pins/tests 102, .github/refresh-reviewers/tests 48, .github/agents-md-integrity/tests 46 — all green on the merged tree. The PR is now MERGEABLE / CLEAN against main, and no merge-queue run on gh-readonly-queue/main/pr-189-* exists or has failed. (coderabbit-config tests need the pinned jsonschema dependency and are unrunnable in this local env — they fail identically on clean main, and this PR touches none of their path-filtered files.)
Deviations: One review thread is answered but deliberately left unresolved — whether this rename ships under the existing v1 tag or bumps the major is a call for whoever moves the tag, not for this PR. The live ruleset audit in that thread confirms no caller currently requires the old linear-ticket context, so nothing is stranded today; the open thread is the record of that decision, not an outstanding defect. The conflict resolution kept BOTH intents: main's new protected-branch-gating prose is preserved verbatim, and this branch's context rename was applied to the status references main introduced (README.md, docs/callers/linear-ticket.md, scripts/linear-ticket/README.md). References to the old linear-ticket spelling inside the rename/migration callout are left deliberately — they describe pre-bump state, where the old name is the correct one. No test coverage from main was removed or weakened.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Comfy-Org/github-workflows/pull/189 **Author:** [@mattmillerai](https://github.com/mattmillerai) **Created:** 8/20/2026 **Status:** ✅ Merged **Merged:** 8/20/2026 **Merged by:** [@mattmillerai](https://github.com/mattmillerai) **Base:** `main` ← **Head:** `matt/linear-ticket-pretty-context` --- ### 📝 Commits (4) - [`a1f9aa2`](https://github.com/Comfy-Org/github-workflows/commit/a1f9aa2eca72b78661acc53cc02cc6c73aa01b31) feat(linear-ticket): rename the status context to "Linear ticket" and drop the slug from its description - [`12f1029`](https://github.com/Comfy-Org/github-workflows/commit/12f10295ded59e1129935a7c39f35fafa770f6f9) fix(linear-ticket): keep the two link-failure categories distinguishable, and correct the rename callout - [`acdef01`](https://github.com/Comfy-Org/github-workflows/commit/acdef018ffdfdebead0c59aa82612903ea6b571d) docs(linear-ticket): drop the leading space inside the `/ validate` code span - [`cf4d468`](https://github.com/Comfy-Org/github-workflows/commit/cf4d4684dd8b510d1083cad9e08aa3ab3c4f73bb) Merge origin/main into matt/linear-ticket-pretty-context ### 📊 Changes **7 files changed** (+148 additions, -48 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/linear-ticket.yml` (+6 -6) 📝 `README.md` (+1 -1) 📝 `docs/callers/linear-ticket.md` (+57 -19) 📝 `scripts/linear-ticket/README.md` (+3 -3) 📝 `scripts/linear-ticket/lib.py` (+25 -9) 📝 `scripts/linear-ticket/tests/test_lib.py` (+52 -6) 📝 `scripts/linear-ticket/validate.py` (+4 -4) </details> ### 📄 Description ## Before / after GitHub renders the commit-status context **verbatim** as the check's name, so `linear-ticket` was putting a machine slug where a reader expects prose: ``` ✗ linear-ticket — Warn-only: no linked Linear issue (no_candidate) ← before ✗ Linear ticket — Warn-only: no linked Linear issue ← after ``` All four categories, in `enforce` mode: | category | rendered row | |---|---| | `no_candidate` | `✗ Linear ticket — No linked Linear issue` | | `exists_not_linked` | `✗ Linear ticket — Referenced Linear issue is not linked yet` | | `policy_mismatch` | `✗ Linear ticket — Linked Linear issue fails this repo's policy` | | `infra_error` | `✗ Linear ticket — Could not verify — Linear could not be queried` | And the same headline across the reporting modes: | mode | rendered row | |---|---| | enforce | `✗ Linear ticket — No linked Linear issue` | | warn + soft-fail | `✗ Linear ticket — Warn-only: no linked Linear issue` | | warn, silent | `✓ Linear ticket — Warn-only (would fail): no linked Linear issue` | The category slug leaves the one-liner. It stays in the marker comment and job summary — `### Linear ticket check — ❌ fail (no_candidate) — warn-only` — which is where triage actually happens. Beside the check name it was noise, and for `infra_error` it was the *second* slug in a line that already had one. `exists_not_linked` gained its own headline in review (see [Guardrails](#guardrails-added)): dropping the slug had collapsed it onto `no_candidate`'s string, and the two remedies are opposite — one means add a link at all, the other means Linear already knows the issue and has not attached it yet (the async-link race that rollout step 3 calls the common case, where the fix is a re-run, not an edit). ## Timing is the whole point The context is the exact string a consumer lists in its ruleset's required checks. Renaming it is free **only** while no caller requires it — after that it silently retires the required check: the new context is never satisfied, the old one is never reported again, and merges hang pending forever. I checked all three callers before touching it, and re-verified live against the API during review: | caller | requires the context? | |---|---| | caller 1 | no | | caller 2 | no (no required checks at all) | | caller 3 | no (two rulesets, neither requires it) | <sub>Caller repos are private and this repo is public, so they are referred to by index — see `vars.LINEAR_TICKET_CALLERS` for the roster.</sub> This is the last cheap moment. Once the pilot flips to `enforce: true` and repos start requiring the context, the same change becomes a coordinated multi-repo migration. ## Guardrails added A test now **pins `CONTEXT`**, so a future rename fails loudly and forces that same caller audit rather than shipping quietly. A second test pins **`MARKER` as independent of it** — the comment marker (`<!-- linear-ticket-check -->`) is not the status context, and "tidying" it to match a context rename would make the gate stop finding its own comment and start posting duplicates on every run. A third asserts the status description carries **no raw category slug and no underscore**, so the slug can't creep back into the one-liner. A fourth — `test_each_category_gets_a_distinct_description` — pins all four categories' descriptions **pairwise-distinct in every reporting mode**, so a future headline edit cannot silently re-collapse two categories onto one string the way dropping the slug did. ## Docs A migration callout where the context is introduced, covering the three things that bite when a caller takes the bump: - **If your ruleset already requires `linear-ticket`, update it in the same change.** The old context is never reported again, so a required check nobody publishes leaves every PR pending — which blocks merges exactly as a failure would. - **Already-open PRs do not gain the new status on their own.** The signal workflow fires on `pull_request`, so moving the pin publishes nothing for a PR already open: until it takes a new commit or someone re-runs its validate workflow, it carries the old context *alone* — there is no new `Linear ticket` beside it. Requiring the new context before those PRs are re-validated leaves every one of them pending, so backfill deliberately rather than waiting for head SHAs to turn over. - **The stale `linear-ticket` status survives, and it is not inert.** Statuses are last-write-wins per context, so whatever value the old context last held stays on that head SHA — and it is frequently `success`, not red (any pass, any exemption, and *every* outcome under `soft-fail: false`). While `linear-ticket` is still required, that stale green keeps satisfying the requirement even after the verdict changed underneath it (issue canceled, attachment removed, exempt label pulled, `team-keys` tightened); and either value counts toward the commit's combined status and `statusCheckRollup`, which tooling reads — this repo's own `grade-pr-risk.sh` does. The `enforce: false` upgrade guide got the same treatment: where it describes **pre-bump** state it now names the **old** context, because a caller that has not taken the rename bump does not publish the new one — following the old instruction literally finds nothing and reports safe while the old requirement is live. The job-vs-status gotcha is now a table, because the two names have become confusably similar in the ruleset's check picker — they differ only by capitalisation and a suffix: | pick | name | |---|---| | ✅ | `Linear ticket` — the commit status | | ❌ | `Linear Ticket / validate` — the job, which runs on the default branch | That collision is the one real cost of this name, and it's worth knowing about: requiring the job instead of the status is the classic mistake, and it just got easier to make. The alternative was a context that shares no words with the workflow name. `docs/callers/README.md` is deliberately **untouched** — its three `linear-ticket` mentions name the reusable workflow, not the status context. ## Tests ``` python3 -m unittest discover -s scripts/linear-ticket/tests -p 'test_*.py' # 68 passed (63 on main) python3 -m py_compile scripts/linear-ticket/{lib,validate}.py # ok python3 .github/workflow-pins/check_workflow_pins.py # 10 workflows, 0 defaults ``` Rename scoped mechanically (`` `linear-ticket` `` → `` `Linear ticket` ``, closing-backtick anchored so `linear-ticket.yml`, `linear-ticket-validate.yml`, `linear-ticket-check`, `bump-linear-ticket-callers` and `scripts/linear-ticket/` can't match), with an assertion pass afterwards confirming no collateral renames. ## After merge The bump fleet rolls all three callers. Their caller files carry ``# publish the `linear-ticket` commit status`` in a permissions comment — cosmetic, not functional, and I'll clean it up in the same follow-up as the stale caller header if you want. ## Provenance **Authored by:** agent-work loop **Verified:** Re-verified after merging current `main` (`f8eec04`) into this branch and resolving the three doc conflicts: `scripts/linear-ticket/tests` 74 passed, `.github/cursor-review/tests` 194, `.github/groom/tests` 365, `.github/workflow-pins/tests` 102, `.github/refresh-reviewers/tests` 48, `.github/agents-md-integrity/tests` 46 — all green on the merged tree. The PR is now `MERGEABLE` / `CLEAN` against `main`, and no merge-queue run on `gh-readonly-queue/main/pr-189-*` exists or has failed. (`coderabbit-config` tests need the pinned `jsonschema` dependency and are unrunnable in this local env — they fail identically on clean `main`, and this PR touches none of their path-filtered files.) **Deviations:** One review thread is answered but deliberately left **unresolved** — whether this rename ships under the existing `v1` tag or bumps the major is a call for whoever moves the tag, not for this PR. The live ruleset audit in that thread confirms no caller currently requires the old `linear-ticket` context, so nothing is stranded today; the open thread is the record of that decision, not an outstanding defect. The conflict resolution kept BOTH intents: `main`'s new protected-branch-gating prose is preserved verbatim, and this branch's context rename was applied to the status references `main` introduced (`README.md`, `docs/callers/linear-ticket.md`, `scripts/linear-ticket/README.md`). References to the old `linear-ticket` spelling inside the rename/migration callout are left deliberately — they describe pre-bump state, where the old name is the correct one. No test coverage from `main` was removed or weakened. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-26 22:37:16 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/github-workflows#197
No description provided.