Host the Type-Specific Tasks and Retire the Date Badge - #761
Conversation
There was a problem hiding this comment.
Pull request overview
Stages “Type-Specific Tasks” reusable-workflow rollout by moving additional task workflows into the hub (via hook-based extensibility), updating the documented/audited contracts for downstream caller stubs, and retiring the date-badge task and related catalog snippets.
Changes:
- Add hub-hosted reusable workflows for Docker Hub readme publishing and update existing hub tasks (upstream-version tracker, deploy-site, codegen) to use required hooks and updated contracts.
- Retire date-badge and multiple catalog snippet workflows; update rollout/adoption docs and skill references accordingly.
- Update spec/audit selftests and divergence dispositions to reflect the new hub-hosted vs retired workflow surfaces.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| WORKFLOW.md | Updates workflow guarantees/docs to reflect hub-hosted type-specific tasks and date-badge retirement. |
| TODO.md | Updates backlog items and references to point at hub-hosted tasks and retired badge work. |
| spec/files.json | Updates interface contract expectations for deploy-site caller now that task is hub-hosted (explicit secret mapping). |
| spec/divergences.json | Adds retire dispositions for workflows moving to hub-hosted tasks and for date-badge retirement. |
| spec/audit.py | Adds check_interface selftest cases for new/updated caller-stub contracts. |
| scripts/prose_lint.py | Expands HUB_HOSTED allowlist to prevent dead-path linting for hub-hosted/retired workflow paths. |
| docs/reusable-workflows.md | Documents “Adopting the Type-Specific Tasks” including stubs, hooks, and rollout proof items. |
| catalog/snippets/workflows/run-periodic-codegen-pull-request.yml | Removes snippet (retired/migrated to hub-hosted contract). |
| catalog/snippets/workflows/README.md | Updates catalog README to reflect hub-hosted task set and snippet sequencing rules. |
| catalog/snippets/workflows/publish-docker-readme-task.yml | Removes snippet (task now hub-hosted). |
| catalog/snippets/workflows/deploy-site.yml | Removes snippet (caller now documented as stub; task hub-hosted). |
| catalog/snippets/workflows/build-datebadge-task.yml | Removes snippet (task retired). |
| .github/workflows/run-codegen-pull-request-task.yml | Updates codegen task to require a repo-owned codegen hook and makes NINJA_API_KEY optional. |
| .github/workflows/publish-docker-readme-task.yml | Adds new hub-hosted Docker Hub readme publish task with hook/default-hook behavior. |
| .github/workflows/deploy-site-task.yml | Refactors deploy-site task to require a single deploy hook (build/prune/verify modes) while keeping hub-owned upload/flip. |
| .github/workflows/check-upstream-version-task.yml | Replaces resolver-command input with required resolve-upstream hook and adds auto-merge control. |
| .github/actions/docker-readme-transform-default/action.yml | Adds hub default implementation for docker readme transform hook. |
| .github/actionlint.yaml | Adds scoped actionlint ignores for job context properties used by publish-docker-readme default-hook checkout. |
| .claude-plugin/fleet-skills/skills/operational-vs-release-workflow/references/release-publish-mechanics.md | Updates generated skill reference docs for new hub-hosted task behavior/retirements. |
| .claude-plugin/fleet-skills/.source-digest | Updates generated plugin digest for the regenerated skill payload. |
| .agents/skills/operational-vs-release-workflow/references/release-publish-mechanics.md | Updates source skill reference docs to match new hub-hosted task behavior/retirements. |
Suppressed comments (1)
.github/workflows/run-codegen-pull-request-task.yml:64
NINJA_API_KEYis declared as an optionalworkflow_callsecret and the comment says it’s consumed by the codegen hook, but the hook step doesn’t pass it viaenv/inputs. Composite actions don’t get thesecretscontext implicitly, so the hook won’t be able to read the key even when the caller maps it.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.
Suppressed comments (2)
.github/workflows/run-codegen-pull-request-task.yml:65
NINJA_API_KEYis declared as an optionalworkflow_callsecret, but it is never passed into the required./.github/actions/codegenhook. Composite actions generally can’t readsecrets.*directly, so the hook won’t be able to use the key even when a caller maps it.
TODO.md:62- This line says the task is hub-hosted, but the
[workflows]reference points to./catalog/snippets/workflows/(where the snippet was removed). Link directly to the hub-hosted workflow file so the reference doesn’t send readers to the wrong location.
- **Checked** - `develop` on 2026-08-08, where `repo-config/configure.sh` sets every other repository setting and carries no `description` handling, and the hub-hosted [`publish-docker-readme-task.yml`][workflows] pushes `github.event.repository.description` to Docker Hub.
|
Answering two suppressed (low-confidence) Copilot findings from the review on 0ad91d7, since a suppressed finding opens no thread to resolve.
Correct, fixed in fe0ab34. GitHub Actions restricts the
Correct, fixed in fe0ab34. Added a |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (5)
.github/workflows/check-upstream-version-task.yml:6
- The header comment says the resolve-upstream hook "prints" versions, but the workflow actually reads them from
steps.resolve-upstream.outputs.versions(it does not capture stdout). This can mislead adopters implementing the hook; it should explicitly document that the hook must set an action output namedversions(single-line JSON) via$GITHUB_OUTPUT.
docs/reusable-workflows.md:251 - This section introduces the
docker-readme-transformhook but doesn’t state the required contract (the workflow consumesreadme-filepathvia action outputs). Without documenting the required output name, adopters may implement a hook that only writes to stdout and the publish step will fail with an empty path.
**Docker Hub readme.** A repo publishing an image replaces its `publish-docker-readme-task.yml` job body with a caller stub reaching the hub task. A `docker-readme-transform` hook, `.github/actions/docker-readme-transform/action.yml`, is needed only to render the readme first or to override the hub default, which publishes `Docker/README.md` if present else `README.md` as-is.
docs/reusable-workflows.md:267
- The adoption text says the
resolve-upstreamhook "prints" versions, but the hub task reads versions from an action output (steps.resolve-upstream.outputs.versions). The docs should specify that the hook must set an output namedversions(single-line JSON) via$GITHUB_OUTPUT.
**Upstream-version tracker.** A repo tracking an upstream release replaces `check-upstream-version-task.yml`'s job body with a caller stub, and carries a required `resolve-upstream` hook, `.github/actions/resolve-upstream/action.yml`, printing the upstream version(s) as a JSON object of name -> version.
.github/workflows/publish-docker-readme-task.yml:9
- The comment describes the docker-readme-transform hook behavior but doesn’t state the concrete interface the workflow relies on. Since the workflow consumes
steps.<hook>.outputs.readme-filepath, the comment should explicitly mention the requiredreadme-filepathoutput (set via$GITHUB_OUTPUT) to avoid adopters implementing a hook that only writes to stdout.
# A docker-readme-transform hook resolves which file to push, defaulting to Docker/README.md when present, else README.md as-is.
# A repo needs a hook only to override that choice or to render the file first, an m4 template, for example.
.agents/skills/operational-vs-release-workflow/references/release-publish-mechanics.md:130
- This guidance says the
resolve-upstreamhook "prints" versions, but the hub task consumes an action output (steps.resolve-upstream.outputs.versions). Clarify in the skill reference that the hook must set an output namedversions(single-line JSON) via$GITHUB_OUTPUT(and regenerate the .claude-plugin copy accordingly).
A repo wrapping an upstream release uses the hub-hosted `check-upstream-version-task.yml`: a
required `resolve-upstream` hook prints the upstream version(s) as a **JSON object of
`name -> version`**, written to a committed state file at the **repo root beside `version.json`**
(default `upstream-version.json`, since it is a build-input version source, not GitHub-platform
config, so it does not belong under `.github/`), and opens a rolling App-signed bump PR per branch
Stage 5 of the hub-hosted reusable-workflow rollout: hosts publish-docker-readme-task.yml (docker-readme-transform hook, with a hub default), check-upstream-version-task.yml (resolve-upstream hook, an auto-merge input), deploy-site-task.yml (deploy hook covering build, prune, and verify), and run-codegen-pull-request-task.yml (codegen hook). build-datebadge-task.yml is retired outright rather than hosted, since the badge service it depended on is already tracked as retired. Retires the corresponding catalog snippets, updates the catalog README, adds retire gap dispositions in spec/divergences.json naming carriers, updates spec/files.json's deploy-site.yml/deploy-site-task.yml entries for the new hub-hosted contract, adds check_interface self-test cases in spec/audit.py, and fixes prose across WORKFLOW.md and the operational-vs-release-workflow skill that named the retired snippets or the old secrets: inherit shape. Adds the Adopting the Type-Specific Tasks section to docs/reusable-workflows.md and ticks the stage 5 tracker entries.
Copilot review on 0ad91d7: publish-docker-readme-task.yml's get-repos and publish-readme jobs check out code with no declared permissions, which fails against a caller that sets permissions: {} per the fleet convention. Grants contents: read on both, matching deploy-site-task.yml's existing precedent. run-codegen-pull-request-task.yml declared NINJA_API_KEY as an optional secret but never passed it to the codegen hook. A composite action never sees the secrets context directly (GitHub Actions restricts it for security), so the hub task now passes it as a ninja-api-key input, documented in docs/reusable-workflows.md's codegen adoption section. Also points TODO.md's publish-docker-readme-task.yml mention at the hub-hosted file directly instead of the retired catalog snippet path.
Copilot review on fe0ab34: the header comments and adoption doc said a resolve-upstream or docker-readme-transform hook prints its result, which could be read as writing to stdout. Both hooks actually communicate through a named composite-action step output (versions, readme-filepath) that the hub task reads via steps.<hook>.outputs.*, so an adopter following prints literally would implement a hook the task can never read. Names the output explicitly everywhere the hook contract is described: both hub task files, the Adopting the Type-Specific Tasks doc section, and the operational-vs-release-workflow skill reference.
fe0ab34 to
6d38066
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (1)
spec/files.json:35
- The deploy-site.yml interface contract doesn’t currently require an
environment:binding on thedeployjob. That binding is essential for the cross-repo deploy adoption described in docs/reusable-workflows.md (the DEPLOY_SSH_PRIVATE_KEY is intended to resolve from the GitHub Environment store at the call site). As-is, the audit could accept a caller stub that maps DEPLOY_SSH_PRIVATE_KEY but forgetsenvironment:, and the deploy would fail at runtime.
{ "path": ".github/workflows/deploy-site.yml", "fidelity": "interface", "contract": { "requiredJobKeys": ["assert-ref", "validate", "deploy"], "requireTokensInJob": { "deploy": ["deploy-site-task.yml", "DEPLOY_SSH_PRIVATE_KEY"] } }, "intentRef": "docs/reusable-workflows.md#adopting-the-type-specific-tasks", "appliesTo": ["hugo"] },
Copilot review on 6d38066: the deploy-site.yml interface contract required the crossing DEPLOY_SSH_PRIVATE_KEY secret but not the environment: binding on the caller's deploy job that makes it resolve from the GitHub Environment store. A caller stub could map the secret and still fail at runtime by omitting the binding, and the audit would not catch it. Adds environment: to the required tokens and a self-test case for the omission.
|
Answering the remaining suppressed (low-confidence) Copilot findings, since a suppressed finding opens no thread to resolve. From the review on fe0ab34 (5 findings, all the same shape: the hook contract said a hook "prints" its result, which reads as stdout rather than a step output):
Correct, fixed in 8d17ed6. Every place describing the two hooks now names the step output by name ( From the review on 6d38066:
Correct, fixed in fe59f1a. Added |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/workflows/publish-docker-readme-task.yml:145
actions/checkoutis using${{ job.workflow_repository }}/${{ job.workflow_sha }}to resolve the hub revision. These context fields are not reliably available in reusable workflows (and the actionlint ignore only silences lint, not runtime), so the default-hook path can fail at runtime for callers that don’t carry adocker-readme-transformhook.
if: ${{ hashFiles('.github/actions/docker-readme-transform/action.yml') == '' }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
|
Answering a suppressed (low-confidence) finding from the latest round.
Disproved. The actionlint ignore entry in This is genuinely unverified by a live run in this PR, since the hub has no downstream caller of its own docker-readme task to trigger it, which the tracker in |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
docs/reusable-workflows.md:312
- This paragraph says the hub task passes
NINJA_API_KEYto the hook as aninja-api-keyinput and that existing adopters’ hooks won’t declare that input. That combination would make the workflow fail with an unexpected input error. Update the docs to match the workflow contract (e.g., passing the optional key viaenv: NINJA_API_KEY, or requiring all hooks to declare the input).
The hub task passes `NINJA_API_KEY` to the hook as a `ninja-api-key` input, since a composite action never sees the `secrets` context directly and a hook whose generator calls a metered API needs the key handed to it explicitly. Neither LanguageTags nor NxWitness calls a metered API from its generator today, so neither maps `NINJA_API_KEY` and neither hook declares the input. Both add `dotnet husky install` ahead of the `dotnet csharpier format` step in their present copies, which the hub task carries verbatim, so a hook needs only the generator invocation itself (`dotnet run --project ...`).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
scripts/prose_lint.py:356
HUB_HOSTEDincludesrun-periodic-codegen-pull-request.yml, but this workflow is described in this PR as a per-repo caller stub (not hub-hosted or retired). Including it here suppresses dead-path findings for downstream repos that should continue carrying the scheduler.
".github/workflows/run-codegen-pull-request-task.yml",
".github/workflows/run-periodic-codegen-pull-request.yml",
".github/workflows/build-datebadge-task.yml",
scripts/prose_lint.py:338
- This comment says
run-periodic-codegen-pull-request.ymlis “retired outright with no hub replacement”, but the rollout doc in this PR explicitly says the scheduler stays as a per-repo caller stub. Keeping it listed here would exempt stale references to a file that should still exist downstream.
This issue also appears on line 354 of the same file.
# Paths retired per a `retire` disposition in `spec/divergences.json`, per GOVERNANCE.md "Hub-Hosted Tooling".
# Most are hub-hosted, so a mention names the hub's copy rather than a file this tree lost.
# A minority are retired outright with no hub replacement (`run-periodic-codegen-pull-request.yml`, `build-datebadge-task.yml`): the mention still names a real, intentional deletion rather than a stale reference, so the same exemption applies.
Copilot review on 86630e9: spec/divergences.json marked run-periodic-codegen-pull-request.yml retire, but the rollout doc already says it stays a per-repo caller stub with only its uses: line changing, the same shape as merge-bot-pull-request.yml and deploy-site.yml. Retire means the hub hosts the file and a downstream copy is deleted, which is wrong here and would have told a carrier to delete a file it still needs. Removed the gap entry and the matching HUB_HOSTED dead-path exemption, since a persisting caller stub needs neither.
|
Answering the suppressed (low-confidence) findings from the review on 86630e9, the same underlying issue as the open thread on spec/divergences.json.
Both correct, fixed in 17fc7e0. Removed |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (2)
.github/workflows/publish-docker-readme-task.yml:121
- After making
get-reposalways run,publish-readmeshould be explicitly main-only to preserve the intended behavior (no Docker Hub push from develop/other branches).
publish-readme:
name: Publish Docker Hub readme job
runs-on: ubuntu-latest
needs: get-repos
permissions:
.github/workflows/publish-docker-readme-task.yml:56
get-reposis skipped wheninputs.branch != 'main', which makesneeds.get-repos.outputs.repositoriesundefined/empty forpublish-readme's matrix. That commonly breaksfromJSON(...)evaluation (instead of cleanly no-op’ing on non-main). Keepget-reposrunning so it always produces a validrepositoriesoutput, and put the main-only gate on the publishing job instead.
This issue also appears on line 117 of the same file.
get-repos:
name: Get repository list job
runs-on: ubuntu-latest
if: ${{ inputs.branch == 'main' }}
permissions:
contents: read
Copilot review on 17fc7e0: publish-readme relies on the needs: skip-cascade from get-repos's own branch gate to stay main-only, which is correct today but leaves the guarantee implicit. States the same if: inputs.branch == 'main' condition on publish-readme directly, so the main-only guarantee does not depend on the needs relationship alone.
…fic-tasks # Conflicts: # .github/actionlint.yaml # TODO.md # docs/reusable-workflows.md # scripts/prose_lint.py # spec/divergences.json
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (2)
spec/files.json:34
- In this interface contract, requiring the token
environment:won’t actually prove the deploy job binds a GitHub Environment, because the job’swith:block also containsenvironment:. If a caller accidentally drops the job-levelenvironment:binding, the contract can still pass due to thewith.environmentline. Tighten the token to match the job-level binding (indent-sensitive) so the audit catches the real failure mode your self-test describes.
{ "path": ".github/workflows/deploy-site.yml", "fidelity": "interface", "contract": { "requiredJobKeys": ["assert-ref", "validate", "deploy"], "requireTokensInJob": { "deploy": ["deploy-site-task.yml", "environment:", "contents: read", "DEPLOY_SSH_PRIVATE_KEY"] } }, "intentRef": "docs/reusable-workflows.md#adopting-the-type-specific-tasks", "appliesTo": ["hugo"] },
spec/audit.py:2270
- The self-test case for “missing the environment binding” (deploy_stub without the job-level
environment:) won’t be reliably detected if the contract only requires the substringenvironment:, because the deploy job still containswith:\n environment:. Require an indent-anchored token so the check specifically proves the job-level environment binding is present.
"environment:",
Copilot review on ecdbd7a: requiring the bare substring environment: in deploy-site.yml's contract does not prove the deploy job binds a GitHub Environment, since the job's with: block also contains an environment: input for the task. A caller stub that drops only the job-level binding while keeping the with: input would still pass. Anchors the token to \n environment: (4-space indent), which the with:-nested input's 6-space indent cannot satisfy, and rewrites the self-test case to remove only the job-level line so it actually exercises this ambiguity instead of coincidentally clearing both.
|
Answering the suppressed (low-confidence) findings from the review on ecdbd7a.
Both correct, fixed in cd78cae. Anchored the token to |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (2)
.github/workflows/deploy-site-task.yml:10
- The header comment says the deploy hook is invoked only with a
modeinput, but the workflow actually passes additionalwith:inputs (bundle-path,release-id, and laterenvironment). Since composite actions reject undeclared inputs, the comment should reflect the full hook input contract so adopters implement a compatible.github/actions/deploy/action.yml.
docs/reusable-workflows.md:453 - The Deploy-site adoption guidance says the
deployhook is invoked only with amodeinput, but the hub task actually passes additionalwith:inputs (bundle-path,release-id, andenvironment). Because composite actions fail when given undeclared inputs, the docs should spell out the full set of inputs adopters must declare in.github/actions/deploy/action.yml.
**Deploy-site.** A site repo keeps `deploy-site.yml` as a per-repo caller (it has no manifest-wide catalog snippet either, since its `uses:` now names the hub, and it still carries the dispatch, the ref gate, and the shared validation call), but its `deploy` job reaches the hub-hosted `deploy-site-task.yml` and binds the same `environment:` the task binds, which is what lets the one crossing secret, `DEPLOY_SSH_PRIVATE_KEY`, resolve from the GitHub Environment store at the call site rather than through `secrets: inherit`, unusable across repositories. The three scripts `deploy/make-release.sh`, `deploy/prune-releases.sh`, and `checks/check-live-urls.sh` fold into one required `deploy` hook, `.github/actions/deploy/action.yml`, invoked three times with a `mode` input (`build`, `prune`, `verify`) so the site keeps its own generator, precompression, and URL contract while the upload-then-flip sequence stays hub-owned. Blog's own copy already carries more than three clean scripts, an `install-hugo` composite action, a git-mtime restore step, and PANGOLIN tokens for its staging auth check, which is why a hook, not a path convention, is the better contract here: it gives a site exactly this freedom instead of constraining it to fixed script names.
Copilot review on cd78cae: both the hub task's header comment and the adoption doc said the deploy hook runs three times with a mode input, but the three invocations also pass bundle-path, release-id, and environment between them, and a composite action rejects an invocation supplying an input it does not declare. States the full four-input contract (mode, bundle-path, release-id, environment) in both places, so an adopter's .github/actions/deploy/action.yml declares what every invocation actually needs.
|
Answering the suppressed (low-confidence) findings from the review on cd78cae.
Both correct, fixed in ac94267. Both the hub task's header comment and the adoption doc now state the full four-input contract ( |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (3)
.github/workflows/deploy-site-task.yml:130
- The deploy hook is invoked as a composite action, but no GitHub Environment vars are exported to it. Composite actions can’t read the
varscontext directly, so the hook can’t reliably use SITE_BASE_URL / DEPLOY_SSH_* without hardcoding unless the workflow passes them viaenv:(or inputs).
This issue also appears in the following locations of the same file:
- line 207
- line 217
.github/workflows/deploy-site-task.yml:221
- The verify hook is a composite action call but doesn’t receive SITE_BASE_URL (or other GitHub Environment vars) as env vars. Because composite actions can’t read the
varscontext directly, the hook won’t be able to verify against the live site without hardcoding unless these values are passed in.
.github/workflows/deploy-site-task.yml:211 - The prune hook is a composite action call, but it isn’t given the environment-derived connection details as env vars. Since composite actions can’t access the
varscontext directly, prune can’t use DEPLOY_SSH_HOST / DEPLOY_SSH_USER (or SITE_BASE_URL if needed) unless they’re passed from the workflow.
Copilot review on ac94267: the build, prune, and verify hook invocations relied on the hook reading SITE_BASE_URL and DEPLOY_SSH_USER/HOST through the vars context directly, but a composite action's own steps are not guaranteed to see the caller's vars context, the same class of restriction already established for secrets. Passes each mode the values it needs as plain env vars instead, the same mechanism the hub-owned upload and flip steps already use, and documents the handoff in both the header comment and the adoption doc.
|
Answering the suppressed (low-confidence) findings from the review on ac94267, all the same underlying issue across the three hook invocations.
Correct, fixed in 0081e59. I could not find a documented statement either confirming or ruling out |
… Default (#768) Promote `develop` to `main`, carrying the remaining stages of the hub-hosted reusable-workflow rollout and the changes that landed beside them: - #759 Host Get-Version and Publish-Plan as Hub Reusable Tasks - #760 Host the Validate Task and Reshape the Test Pull Request Stub (settles #729 by design: the hub's validate task runs `uvx <tool>@latest`, since Dependabot tracks the action pins and not a uvx version) - #761 Host the Type-Specific Tasks and Retire the Date Badge - #762 Host the Release Chain and the Docker Core in the Hub - #748 and #752, the staged rollout tracker and the PhotoCleaner merge-bot pilot record - #758 Flip the Fleet Line-Ending Default from CRLF to LF - #753, #755, #756, #764, host-setup and test-collection changes The release that follows this promotion is the first tag carrying every hub task, so it is the pin the stage 2 to 5 adoptions and their catalog snippets use. It is also the first run of the hub's own `publish-release.yml` through `build-release-task.yml` with every target disabled, which is the live proof that `github-release` runs when its build needs are skipped. Closes #729. Refs #521 (hub half shipped, the merge-bot adoption sweep is what remains).
What
Stage 5 of the hub-hosted reusable-workflow rollout (
docs/reusable-workflows.md"Rollout"). Hosts four more reusable tasks in the hub and retires one:
publish-docker-readme-task.yml: thetransform-run/transform-artifactstringinputs become a
docker-readme-transformhook, with a hub default that publishesDocker/README.mdif present elseREADME.mdas-is. ExplicitDOCKER_HUB_USERNAME/DOCKER_HUB_ACCESS_TOKENsecrets (the namesspec/secrets.jsonalready declares).A
branchinput keeps the readme push main-only inside the task itself.check-upstream-version-task.yml: theresolver-commandstring input becomes arequired
resolve-upstreamhook. Adds anauto-mergeboolean input (default true);false prefixes the bump PR's head so no merge-bot rule matches it, routing the bump
to a human. ESPHome-NonRoot's second tracker,
check-upstream-dependency.yml, foldsinto this same task with
auto-merge: falseon adoption.deploy-site-task.yml: the three path-conventioned scripts(
deploy/make-release.sh,deploy/prune-releases.sh,checks/check-live-urls.sh)fold into one required
deployhook, invoked three times with amodeinput(
build,prune,verify), while the environment binding and the atomicupload-then-flip sequence stay hub-owned.
deploy-site.ymlstays a per-repo caller,documented as a stub in
docs/reusable-workflows.md.run-codegen-pull-request-task.yml: a requiredcodegenhook for the generationstep; the App-token, setup, format, and PR-opening machinery stay hub-owned since
both current carriers (LanguageTags, NxWitness) run it identically.
NINJA_API_KEYbecomes an optional secret, since neither carrier maps it today.build-datebadge-task.ymlis retired rather than hosted:TODO.mdalready tracksdeleting the retired
byob.yarr.isbadge from its remaining carrier (KiCadLibrary).Retires the corresponding catalog snippets and updates the catalog README, adds
retiregap dispositions inspec/divergences.jsonnaming carriers, updatesspec/files.json'sdeploy-site.yml/deploy-site-task.ymlentries for the newhub-hosted contract (dropping
secrets: inherit, requiring the mappedDEPLOY_SSH_PRIVATE_KEYsecret name instead), and addscheck_interfaceself-testcases in
spec/audit.pyfor every new stub contract. Fixes prose inWORKFLOW.mdand the
operational-vs-release-workflowskill that named the retired snippets, theold
secrets: inheritshape, or the retired date-badge job. Adds "Adopting theType-Specific Tasks" to
docs/reusable-workflows.mdwith the calleruses:linesand hook names (pins as placeholders), ticks stage 5's hub PR item, and lists
adoption checkboxes per carrier.
Rebased onto
developafter #758 (the fleet's CRLF -> LF line-ending flip), so everynew/edited file already follows the new LF default.
Design choices where the brief left room
job.workflow_repository/job.workflow_sha(notgithub.job_workflow_sha, whichdoes not exist) resolve the hub checkout in
publish-docker-readme-task.yml'sdefault-hook path. actionlint's context schema has not caught up to these
documented GitHub Actions
jobcontext properties yet, so a scoped.github/actionlint.yamlignore entry covers the false finding until it does.deployhook is a single composite action taking amodeinput(
build/prune/verify) rather than three separate hooks, so a site repo ownsthe whole per-repo half in one file. Blog's live copy already carries more than
three clean scripts (its own
install-hugoaction, a git-mtime restore step,PANGOLIN tokens for its staging auth check), which argues for hook flexibility
over a path convention, not against it.
deploy-site-task.ymlreusable-workflow boundary,DEPLOY_SSH_PRIVATE_KEY, is a GitHub Environment secret. The caller's owndeployjob binds the same
environment:the task binds, which is what lets that secretresolve at the call site for explicit mapping instead of
secrets: inherit(forbidden here, and unusable cross-repository on a personal account regardless).
check-upstream-version-task.ymlbytreating its apt-package snapshot as a one-key name -> version object
(
{"docker_base_packages": "<sorted, comma-joined list>"}). This loses today'sbespoke "packages added/removed" title wording in favor of the shared task's
generic title, a documented tradeoff.
Could not prove
DEPLOY_SSH_PRIVATE_KEYenvironment-secret handoff across a cross-repositoryuses:(the caller job'senvironment:binding resolving it for explicit mapping)is correct per GitHub's documented behavior, but only Blog's first live deploy run
after adoption proves it. Tracked as a proof item in the rollout tracker.
job.workflow_repository/job.workflow_sharesolving to the hub at the caller'spinned commit is documented GitHub behavior, unverified by a live run in this PR
(the hub has no downstream caller of its own docker-readme task to trigger it).
Conflicts with sibling work
None encountered. Stage 4 (
build-release-task.ymletc.) has not merged as of thisPR, so the
operational-vs-release-workflowskill's "until that phase ships the liststays per repo" sentence is left as-is per the brief's instruction.
🤖 Generated with Claude Code