Consolidate shared workflows into a single generated automation.yml entry point#88
Consolidate shared workflows into a single generated automation.yml entry point#88akolson wants to merge 1 commit into
Conversation
…ntry point Replace the per-feature call-*.yml callers and the pull-request-target.yml dispatcher with one reusable automation.yml plus a single generated caller template, driven by automation-registry.yml as the source of truth. A pre-commit hook regenerates and fails on drift between the registry and the generated files. Closes #86 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔵 Review postedLast updated: 2026-07-05 05:15 UTC |
rtibblesbot
left a comment
There was a problem hiding this comment.
Solid generator/registry design and correctly-scoped permission narrowing, but the branch was forked before recent changes landed on main that this registry doesn't account for.
CI passing. No UI files in scope, Phase 3 skipped.
Blocking:
automation-registry.yml:79— stale/too-broadmanage-issue-headerdispatch condition, and a whole new automation (good-first-issue-comment) missing from the registry entirely (inline comment).
Suggestion:
- PR body —
Closes #86will auto-close the tracking issue despite the acknowledged-incomplete migration checklist; considerPart of #86instead, or open a follow-up tracking issue for the remaining per-repo migrations.
Nitpick:
package.json:10—js-yamlis only used by the build-time codegen script; considerdevDependenciesinstead.
@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
Ran a phased review pipeline over the pull request diff:
- Classified the diff to select review passes (core, frontend, backend) and whether manual QA was required
- Core review pass checked correctness, design, architecture, testing, completeness, and DRY/SRP/Rule-of-Three principles
- Specialized frontend/backend review passes applied framework-specific lenses where those files changed
- For UI changes: manual QA and an accessibility audit against a live dev server, when available
- Checked CI status and linked issue acceptance criteria
- Synthesized one review from those passes and chose the verdict from the findings, CI status, and QA evidence
| on: | ||
| issues: | ||
| types: [opened, reopened, labeled, unlabeled] | ||
| if: "github.event_name == 'issues' && contains(fromJSON('[\"opened\",\"reopened\",\"labeled\",\"unlabeled\"]'), github.event.action)" |
There was a problem hiding this comment.
blocking: This branch's merge-base with upstream/main (5512260) is stale — main has since merged #62/#90, which refactored issue-header dispatch:
manage-issue-header.yml's own leaf-levelif:filter (opened/reopened/labeled+help wanted/unlabeled+help wanted) was removed and pushed up into two new callers,issue-open.yml(unconditional for opened/reopened) andissue-label.yml(labeled/unlabeled gated tolabel.name == 'help wanted'only).- This registry entry's
if:fires on any labeled/unlabeled action regardless of label name, and since the leaf no longer self-filters, merging as-is meansmanage-issue-header.jsruns on every label add/remove on every issue — a real behavior regression, not just missed parity. issue-label.ymlalso adds a second job,good-first-issue-comment(gated onlabel.name in ['good first issue', 'help wanted']), calling a brand-new leafgood-first-issue-comment.yml. This automation has no entry anywhere in the registry, so it's silently dropped from the generatedautomation.yml.
Please rebase onto current upstream/main, add a good-first-issue-comment registry entry, and split this entry's if: to match issue-label.yml's help wanted-only gating.
| "axios": "^1.13.6", | ||
| "dotenv": "^17.3.1", | ||
| "googleapis": "^142.0.0", | ||
| "js-yaml": "^4.1.0", |
There was a problem hiding this comment.
nitpick: js-yaml is only consumed by scripts/generate-automation.js (a build-time tool), not by any runtime workflow script — consider moving it to devDependencies.
Summary
Replaces the ~7 per-feature
call-*.ymlcallers (and thepull-request-target.ymldispatcher) that every consumer repo copies with a single reusableautomation.yml, driven byautomation-registry.ymlas the source of truth, plus one generatedautomation-template.ymlevery consumer copies once.automation-registry.ymldeclares each automation's leaf workflow, trigger events/types (or schedule), dispatchif:condition, and required/optional secrets.scripts/generate-automation.jsregenerates.github/workflows/automation.yml(the reusable workflow, one job per automation),automation-template.yml(the file consumers copy, with the exhaustive unionon:block), and.github/workflows/automation-caller.yml(this repo dogfooding the same template against itself).pull-request-label/review-requested/dependabot-reviewerrouting, previously done bypull-request-target.yml, is now direct jobs inautomation.yml- keeping the deepest chain (caller → automation.yml → leaf → is-contributor.yml) at exactly GitHub's 4-level nesting cap.resolve-bot-pr-threadsandholiday-messageget their first-ever caller wiring here (previously undeployed anywhere).pre-commithook (generate-automation) fails the commit if the registry and generated files drift; a new.github/workflows/pre-commit.ymlCI workflow runsprek(the repo had.pre-commit-config.yamlbut no CI lint check before).resolve-bot-pr-threads's leaf job needscontents: write+pull-requests: writevia the defaultGITHUB_TOKEN(every other automation uses its own scoped bot-app token instead). Since reusable-workflow permissions can only be narrowed downstream of the root caller,automation-template.ymlgrantscontents: write/pull-requests: writeat the top level, and every job inautomation.ymlother thanresolve-bot-pr-threadsexplicitly narrows back tocontents: read- so only that one job actually gets write capability, matching today's read-only default everywhere else.No leaf workflow's internal logic changed - this is a routing/packaging consolidation only.
References
Closes #86
Reviewer guidance
if:inautomation.ymlagainst theon:/types:of thecall-*.ymlfile it replaces (andpull-request-target.yml's action routing) - functional parity confirmed, see the registry comments for the mapping.node scripts/generate-automation.js --checkand the fullpre-commit run --all-filessuite locally (viapre-commit, prek's predecessor, sinceprekisn't installable in this sandbox) - all hooks pass, including drift detection (verified it fails when the registry is edited without regenerating, then passes again after regenerating).actionlintpasses onautomation.ymlandautomation-template.yml(tested the template in a scratch.github/workflows/dir since it lives at repo root here, pending each consumer copying it into their own.github/workflows/).automation.yml(contents: readjob-level override on every job exceptresolve-bot-pr-threads) is the one piece of new authorization logic in this PR - worth a careful look.AI usage
Implemented end-to-end with Claude Code (Sonnet 4.6) from the architecture already laid out in issue #86 (which was itself drafted with Claude Code per its own AI-usage note). I directed the registry/generator design, reviewed the generated
automation.yml/automation-template.ymloutput, and specifically caught and directed the fix for a permissions-scoping gap (resolve-bot-pr-threadsneeding write access that the rest of the automations shouldn't inherit) before it became a security issue. Claude traced trigger parity against the originalcall-*.ymlfiles, ran the pre-commit/actionlint validation, and verified the generator's drift detection actually works rather than just asserting it does.