Finding
A repository ruleset named Immutable-Tags that carries the creation rule with an empty bypass_actors list means no tag can ever be created in that repository by anyone — the owner included. The repo can never ship a release, and there is no workaround: gh release create creates the same ref and is rejected identically.
Surfaced by a real rejection while cutting launch-scaffolder v0.1.0:
remote: error: GH013: Repository rule violations found for refs/tags/v0.1.0.
remote: - Cannot create ref due to creations being restricted.
! [remote rejected] v0.1.0 -> v0.1.0
"Immutable tags" means a tag cannot be changed or deleted once cut — that is update + deletion + non_fast_forward. creation does not belong to that intent, and with an empty bypass list it authorises nobody, so the rule can only ever refuse.
Measured (8 repos sampled — NOT a census)
8 of 8 restricted tag creation. The difference was entirely the bypass list:
| repo |
bypass |
current_user_can_bypass |
tags |
hyperpolymath/standards |
2 |
always |
7 |
metadatastician/* (org EstateTagging) |
3 |
always |
0 |
hyperpolymath/hypatia |
0 |
never |
14 |
hyperpolymath/launch-scaffolder |
0 |
never |
0 |
hyperpolymath/rsr-template-repo |
0 |
never |
0 |
hyperpolymath/trigger |
0 |
never |
0 |
⚠ Existing tags do not prove a repo can tag. hypatia held 14 tags and was still refused a new one — every one predated the ruleset (created 2026-06-25). The count of existing tags is not a probe for tag-creation capability; current_user_can_bypass is.
The blocking rulesets are substantively identical to standards' working one — same five rules; only the name casing and the rule array order differ. The sole real difference is bypass_actors. This is the same skipped-apply-step class as the marid F25 finding, not a policy decision.
Already cured (owner-ruled 2026-09-23)
Four repos had the standards bypass list mirrored onto them — repository-admin role + the Integration app standards already trusts — applied as a full reconstructed body, one call each:
hyperpolymath/launch-scaffolder → v0.1.0 cut and released
hyperpolymath/rsr-template-repo
hyperpolymath/trigger
hyperpolymath/hypatia
All four now read bypass=2 / can=always, with the full ruleset shape diffed before-vs-after and unchanged apart from bypass_actors.
What remains — the reason this issue exists
The other ~160 hyperpolymath repos are unmeasured. It is already recorded that 167 of 170 "no rules" repos carry an active tag ruleset. If those also carry creation with no bypass, none of them can ever ship a release, and nobody will discover it until someone tries to tag.
Acceptance criteria
- A census over every
hyperpolymath repo recording, per repo: whether an active tag-target ruleset exists, whether its rules include creation, its bypass_actors length, and current_user_can_bypass. Throttled to avoid the REST secondary limit.
- The census output names the set where
creation is restricted and bypass_actors is empty — the set that cannot release.
- A ruling on that set: mirror the
standards bypass list, or drop creation from the ruleset. One decision applied uniformly, not per repo.
- A positive control carried in the same run:
hyperpolymath/standards must read bypass=2 / can=always, so a reported zero is provably real absence rather than an auth artefact.
- The check is written against the applied ruleset via
repos/O/R/rulesets/{id}, never against a committed .github/rulesets/*.json — committing the JSON does not create the ruleset.
Two traps worth recording in whatever does the sweep
- A ruleset
PUT returned HTTP/2.0 200 OK with an empty body and had not applied. Three sibling repos succeeded in the same minute, so it was not permissions. An unchanged retry applied it. A 200 is not evidence a ruleset write landed — re-read it.
- Verify the whole shape, not the field you expected to move. Diff the ruleset before and after with
bypass_actors and the volatile fields deleted, and require the result empty, so a silently dropped rules entry cannot pass as success.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo
Finding
A repository ruleset named
Immutable-Tagsthat carries thecreationrule with an emptybypass_actorslist means no tag can ever be created in that repository by anyone — the owner included. The repo can never ship a release, and there is no workaround:gh release createcreates the same ref and is rejected identically.Surfaced by a real rejection while cutting
launch-scaffolderv0.1.0:"Immutable tags" means a tag cannot be changed or deleted once cut — that is
update+deletion+non_fast_forward.creationdoes not belong to that intent, and with an empty bypass list it authorises nobody, so the rule can only ever refuse.Measured (8 repos sampled — NOT a census)
8 of 8 restricted tag
creation. The difference was entirely the bypass list:current_user_can_bypasshyperpolymath/standardsmetadatastician/*(orgEstateTagging)hyperpolymath/hypatiahyperpolymath/launch-scaffolderhyperpolymath/rsr-template-repohyperpolymath/trigger⚠ Existing tags do not prove a repo can tag.
hypatiaheld 14 tags and was still refused a new one — every one predated the ruleset (created 2026-06-25). The count of existing tags is not a probe for tag-creation capability;current_user_can_bypassis.The blocking rulesets are substantively identical to
standards' working one — same five rules; only the name casing and the rule array order differ. The sole real difference isbypass_actors. This is the same skipped-apply-step class as themaridF25 finding, not a policy decision.Already cured (owner-ruled 2026-09-23)
Four repos had the
standardsbypass list mirrored onto them — repository-admin role + the Integration appstandardsalready trusts — applied as a full reconstructed body, one call each:hyperpolymath/launch-scaffolder→v0.1.0cut and releasedhyperpolymath/rsr-template-repohyperpolymath/triggerhyperpolymath/hypatiaAll four now read
bypass=2 / can=always, with the full ruleset shape diffed before-vs-after and unchanged apart frombypass_actors.What remains — the reason this issue exists
The other ~160
hyperpolymathrepos are unmeasured. It is already recorded that 167 of 170 "no rules" repos carry an active tag ruleset. If those also carrycreationwith no bypass, none of them can ever ship a release, and nobody will discover it until someone tries to tag.Acceptance criteria
hyperpolymathrepo recording, per repo: whether an active tag-target ruleset exists, whether its rules includecreation, itsbypass_actorslength, andcurrent_user_can_bypass. Throttled to avoid the REST secondary limit.creationis restricted andbypass_actorsis empty — the set that cannot release.standardsbypass list, or dropcreationfrom the ruleset. One decision applied uniformly, not per repo.hyperpolymath/standardsmust readbypass=2 / can=always, so a reported zero is provably real absence rather than an auth artefact.repos/O/R/rulesets/{id}, never against a committed.github/rulesets/*.json— committing the JSON does not create the ruleset.Two traps worth recording in whatever does the sweep
PUTreturnedHTTP/2.0 200 OKwith an empty body and had not applied. Three sibling repos succeeded in the same minute, so it was not permissions. An unchanged retry applied it. A 200 is not evidence a ruleset write landed — re-read it.bypass_actorsand the volatile fields deleted, and require the result empty, so a silently droppedrulesentry cannot pass as success.🤖 Generated with Claude Code
https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo