Problem
docs/how-to/add-homebrew-and-scoop.md
tells adopters that a required check cannot be added until it has run once, and
routes them through a first publication against an unprotected destination:
GitHub may not offer the required check until it has run once. If necessary,
enable the publisher for one real release, wait for the new tap pull request
and its validation run, add that check to the ruleset, and only then merge the
pull request.
That is true of the UI picker, which only offers observed checks. It is not
true of the rulesets REST API, which accepts an arbitrary context string. The
destination can therefore be fully protected before the first publisher run.
Evidence
Both rulesets below were created on brand-new repositories with zero workflow
runs and zero check history, and were immediately active:
gh api -X POST repos/componere/homebrew-tap/rulesets --input - <<'JSON'
{
"name": "Default branch",
"target": "branch",
"enforcement": "active",
"bypass_actors": [{"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always"}],
"conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
"rules": [
{"type": "deletion"},
{"type": "non_fast_forward"},
{"type": "pull_request", "parameters": {
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": false,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": false,
"automatic_copilot_code_review_enabled": false,
"allowed_merge_methods": ["squash"]
}},
{"type": "required_status_checks", "parameters": {
"strict_required_status_checks_policy": false,
"do_not_enforce_on_create": false,
"required_status_checks": [
{"context": "casks / Homebrew cask validation", "integration_id": 15368}
]
}}
]
}
JSON
Result: ruleset 21201639 on componere/homebrew-tap and 21201641 on
componere/scoop-bucket, with contexts casks / Homebrew cask validation and
manifests / Scoop manifest validation.
The context string is <caller job id> / <reusable result job name>. Both halves
are fixed by this repository, so they are knowable in advance:
init homebrew-tap generates job id casks, and
homebrew-tap-ci.yml names its final job Homebrew cask validation.
init scoop-bucket generates job id manifests, and
scoop-bucket-ci.yml names its final job Scoop manifest validation.
integration_id: 15368 is the GitHub Actions app, matching what
meigma/homebrew-tap's own live protection already records for the identical
context.
Why this matters
The documented order enables a publisher against a destination whose main has
no PR requirement and no required check, for the duration of the first release.
The API order protects the destination first, so the first tap or bucket pull
request lands in an already-enforced repository.
Suggested change
- In
add-homebrew-and-scoop.md, make the API call the primary instruction for
both destinations, with the exact context strings, and keep the UI
"run it once" note as a fallback for adopters who prefer the picker.
- Consider having
release-cli init homebrew-tap / init scoop-bucket emit the
matching ruleset JSON (or a --print-ruleset flag) next to the scaffold, so
the context string is generated by the same code that generates the workflow
and cannot drift from it.
- If a
result job name ever changes, that is now a breaking change for every
adopter ruleset. Worth stating as a contract in
docs/reference/release-system.md.
Context
Found while onboarding componere at v0.1.17. First real publication will
confirm the contexts resolve; the strings are byte-identical to the ones
meigma/homebrew-tap already enforces.
Problem
docs/how-to/add-homebrew-and-scoop.mdtells adopters that a required check cannot be added until it has run once, and
routes them through a first publication against an unprotected destination:
That is true of the UI picker, which only offers observed checks. It is not
true of the rulesets REST API, which accepts an arbitrary context string. The
destination can therefore be fully protected before the first publisher run.
Evidence
Both rulesets below were created on brand-new repositories with zero workflow
runs and zero check history, and were immediately
active:Result: ruleset
21201639oncomponere/homebrew-tapand21201641oncomponere/scoop-bucket, with contextscasks / Homebrew cask validationandmanifests / Scoop manifest validation.The context string is
<caller job id> / <reusable result job name>. Both halvesare fixed by this repository, so they are knowable in advance:
init homebrew-tapgenerates job idcasks, andhomebrew-tap-ci.ymlnames its final jobHomebrew cask validation.init scoop-bucketgenerates job idmanifests, andscoop-bucket-ci.ymlnames its final jobScoop manifest validation.integration_id: 15368is the GitHub Actions app, matching whatmeigma/homebrew-tap's own live protection already records for the identicalcontext.
Why this matters
The documented order enables a publisher against a destination whose
mainhasno PR requirement and no required check, for the duration of the first release.
The API order protects the destination first, so the first tap or bucket pull
request lands in an already-enforced repository.
Suggested change
add-homebrew-and-scoop.md, make the API call the primary instruction forboth destinations, with the exact context strings, and keep the UI
"run it once" note as a fallback for adopters who prefer the picker.
release-cli init homebrew-tap/init scoop-bucketemit thematching ruleset JSON (or a
--print-rulesetflag) next to the scaffold, sothe context string is generated by the same code that generates the workflow
and cannot drift from it.
resultjob name ever changes, that is now a breaking change for everyadopter ruleset. Worth stating as a contract in
docs/reference/release-system.md.Context
Found while onboarding
componereat v0.1.17. First real publication willconfirm the contexts resolve; the strings are byte-identical to the ones
meigma/homebrew-tapalready enforces.