fix(policy): make the Bun-over-Deno ruling actually effective - #592
Conversation
LANGUAGE-POLICY.adoc section 1 has ruled Bun > Deno > pnpm > npm since 2026-07-29, and section 1.2 retired the "use ReScript instead" rule because ReScript is no longer used in this estate. The ruling was recorded. It was not in force: every surface that ACTS still encoded its predecessor. WHAT WAS ACTUALLY HAPPENING .github/workflows/governance-reusable.yml Failed any repository carrying bun.lockb -- "Use Deno instead" -- and any package.json declaring runtime dependencies. Bun's model IS an npm-compatible package.json plus a Bun lockfile, so this gate did not merely discourage the tier-1 runtime, it made adopting it impossible. This reusable is called estate-wide. docs/JS-RUNTIME-POLICY.adoc Stated the hierarchy as Deno > Bun > pnpm > npm -- the exact inverse of LANGUAGE-POLICY section 1 -- and rule 2 required that bun.lockb MUST NOT be tracked. This is the document governance-reusable.yml cites for remediation, so a repository following the error message was directed further from the policy. .claude/CLAUDE.md Listed Bun in the BANNED table with Deno as its replacement, and described Deno as "replaces Node/npm/bun". This is the file agents read first, so recorded policy and agent behaviour had diverged: agents were being instructed to migrate away from the estate's first-choice runtime. CHANGES governance-reusable.yml bun.lock / bun.lockb accepted and reported as tier 1. package.json runtime dependencies accepted when a Bun lockfile is present, still flagged otherwise. yarn.lock and .npmrc still fail; remediation text now names Bun rather than Deno. The package-lock.json rule (standards#67) is UNCHANGED in behaviour -- only its message was corrected. JS-RUNTIME-POLICY.adoc Hierarchy table inverted to match LANGUAGE-POLICY, with a note recording that LANGUAGE-POLICY is authoritative if the two ever disagree again. Rule 2 split: yarn.lock and .npmrc still banned, Bun lockfiles explicitly permitted and expected. .claude/CLAUDE.md Bun promoted to a tier-1 row; the banned rows for Node.js/npm/Bun/pnpm-yarn replaced with accurate ones. npm is described as tier 4 -- permitted, never preferred -- which is what the policy says, rather than "banned". Also corrected: docs/migrations/npm-to-deno-template/MIGRATION.md, meta-a2ml/.claude/CLAUDE.md, rhodium-standard-repositories/PROJECT-STATUS.md and rhodium-standard-repositories/.github/workflows/language-policy.yml. DELIBERATELY NOT CHANGED - The package-lock.json prohibition. LANGUAGE-POLICY calls npm "permitted, never preferred" while standards#67 hard-fails a tracked lockfile. That tension predates this change and deserves its own decision. - .claude/CLAUDE.md bans TypeScript in favour of AffineScript, while LANGUAGE-POLICY section 1.2 says TypeScript is "permitted under Bun". Both cannot be right. The AffineScript direction is a substantive architectural position, not an oversight, so it is flagged in the file for an owner ruling rather than changed here. - consent-aware-http/.claude/CLAUDE.md carries the same stale table but that directory is being extracted to metadatastician/consent-aware-web in a separate PR, so it is left alone here to avoid a conflict. STILL BROKEN ELSEWHERE (cannot be fixed from this repository) - The metadatastician organisation Actions allowlist has patterns_allowed containing 'denoland/*' but not 'oven-sh/*'. Any workflow referencing oven-sh/setup-bun is rejected with startup_failure, zero jobs, and no explanatory log. Adding the pattern per-repo returns 409 Conflict -- it is set at organisation level. Needs an org admin. - hyperpolymath/rsr-template-repo ships .cursorrules, .clinerules, .windsurfrules and .github/copilot-instructions.md all instructing "TypeScript -> use ReScript" and "Node.js / npm / bun -> use Deno". These propagate to every mint. Corrected wording exists in metadatastician/consent-aware-web and can be lifted verbatim; a separate PR is needed against the template. Found while extracting consent-aware-http into its own repository, where the manifest validator had to be written dependency-free specifically to avoid tripping the gate this commit fixes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
hyperpolymath
commented
Aug 7, 2026
Correction to the last paragraph of the description, which said the That was incomplete. Fixing the allowlist did not unblock it. A probe branch on
Proven working afterwards; probe branch deleted. Two further things worth knowing for anyone adopting Bun:
Method note, since it nearly went the other way: the API accepting the allowlist PUT, and reading the pattern back at both org and repo level, was not evidence that a workflow would start. Only running one was. This PR's substance is unaffected — |
'Registry + topology in sync' failed with 'REGISTRY.a2ml is stale'. This PR edits two files under rhodium-standard-repositories/, which is a spec home in the registry, and the registry records a source_hash per spec. Editing anything under a spec's home directory invalidates that hash, and nothing warns at edit time — the only signal is this gate, after push. Regenerated; build-registry.sh --check now reports in sync. Rule of thumb worth writing down: 'just registry' (== bash scripts/build-registry.sh) must be the LAST thing run before committing any change that touches a spec home. Running it first, then making further edits, produces exactly this failure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
All four agent-instruction files, plus the arrival-pack source that generates `CLAUDE.md`, instructed agents: ``` TypeScript -> use ReScript Node.js / npm / bun -> use Deno ``` Both have been wrong since 2026-07-29. `standards/LANGUAGE-POLICY.adoc` §1 rules **Bun > Deno > pnpm > npm**. §1.2 retires the ReScript rule outright, because ReScript is no longer used in this estate — so that rule pointed agents at a dead alternative. **These files propagate to every mint.** Every repository created from this template is born instructing its agents to migrate away from the estate's first-choice runtime and toward a language nobody uses. A ruling that lives only in the document a human reads, while the files that steer behaviour encode its predecessor, is recorded rather than in force. ## Changed | File | Why it matters | |---|---| | `.machine_readable/ai/.cursorrules` | read by Cursor | | `.machine_readable/ai/.clinerules` | read by Cline | | `.machine_readable/ai/.windsurfrules` | read by Windsurf | | `.github/copilot-instructions.md` | read by Copilot | | `.machine_readable/arrival-pack/arrival-pack.ncl` | generates `CLAUDE.md` — without this the correction is undone on the next `just claude-md` | npm is now described as **tier 4 — permitted, never preferred**, which is what the policy says, rather than banned. Go and Python remain banned; those rows are untouched. ## Verification `metadatastician/consent-aware-web` was minted from this template at `c250e661`, carries this exact wording, and its regenerated `CLAUDE.md` renders correctly. ## Related - hyperpolymath/standards#592 — same inversion in `governance-reusable.yml`, `docs/JS-RUNTIME-POLICY.adoc` and `.claude/CLAUDE.md`. That one matters most: the gate **failed any repo carrying `bun.lockb`**, and Bun's model is `package.json` + `bun.lock`, so adopting tier 1 was impossible rather than merely awkward. - Not fixable from either repo: the `metadatastician` org Actions allowlist permits `denoland/*` but not `oven-sh/*`, so any workflow using `oven-sh/setup-bun` is rejected with `startup_failure` and zero jobs. Needs an org admin. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
REGISTRY.a2ml conflicted on rebase. It is a GENERATED file, so the resolution is to regenerate from the source spec table in scripts/build-registry.sh rather than hand-merge two machine outputs. build-registry.sh --check reports in sync. Verified after rebase: consent-aware-http/ is still removed, the external pointer for metadatastician/consent-aware-web is present, and #592's Bun changes to .claude/CLAUDE.md are preserved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#593) Removes **189 files** across two divergent copies and retires a phantom submodule. Full reasoning in `docs/decisions/ADR-005-extract-consent-aware-web.adoc`. New home: **https://github.com/metadatastician/consent-aware-web** (public, live, CI green). ## Why this was more than a directory move | | | |---|---| | **Rated 1 of 5 MUSTs** | by this repo's own scorecard (2026-07-03), while shipping an `RSR-COMPLIANCE.md` claiming *"RSR Gold, 100% compliant"* — asserting PASS for `LICENSE.txt`, `MAINTAINERS.md`, `CHANGELOG.md`, `flake.nix` and a whole `.well-known/` tree, none of which existed | | **Phantom submodule** | `.gitmodules` declared `satellites/consent-aware-http` as a submodule of `hyperpolymath/consent-aware-http` — a repo that has **never existed**. Materialised as 81 ordinary tracked files, 26 behind the live copy | | **The flagship draft existed twice** | with different normative text. The root copy is byte-identical to the satellite copy (the retired ancestor); the `drafts/` copy is the later edit and the only valid RFC-XML v3. They disagreed on `category`: `std` vs `info` | ## Registry — regenerated, not hand-edited `AGENTS.md` says `REGISTRY.a2ml` and `TOPOLOGY.md` are generated and must never be edited directly. The source of truth is the spec table inside `scripts/build-registry.sh`; the entry moved from the **in-tree** table to the **EXTERNAL** table, so this repo now holds a verified pointer rather than a copy — the pattern already used for the AffineScript specs. Same for `COMPLIANCE-DASHBOARD.md` via `build-scorecards.sh`. `bash scripts/build-registry.sh --check` → *OK: registry + topology are in sync with the file tree.*⚠️ `spec_kind` is recorded as `service-coupled`. The enum is `language-coupled | service-coupled`, and a protocol specification is honestly neither — `service-coupled` is the closer reading rather than a good one. **Worth a third value.** ## Salvaged before deletion The satellite carried a **418-line `GOVERNANCE.adoc`** — Tri-Perimeter Contribution Framework, decision authority by perimeter, funding model, IETF coordination — that exists nowhere else. The live copy's `docs/governance.md` is an unrelated essay on consent in institutions; the two share a name and nothing else. Copied into the new repository first. This is the failure mode `AGENTS.md` warns about: cold is not disposable. A de-duplication by filename would have destroyed it. ## Licence references — kept, not removed Those in `LICENCE-POLICY.adoc`, `PALIMPSEST.adoc`, `README.adoc`, `.claude/CLAUDE.md` and `.machine_readable/licensing-policy.toml` are statements about a **repository**, not a directory. They remain correct and now name the new location. The PMPL prospective carve-out and the IETF-mandated MIT carve-out both still apply. **No licence file was edited.** ## Also repointed Seven dangling relative links under `docs/UX-standards/` and `docs/wikis/developers/`, `.well-known/humans.txt`, and one `.hypatia-baseline.json` finding whose file no longer exists here. ## Left open The two drafts name **different author organisations** (`NUJ Ethics Council` vs `National Union of Journalists`). Normatively visible in a published Internet-Draft. Recorded as a blocker in the new repo's `STATE.a2ml`; not decided here. ## Related - #592 — Bun-over-Deno ruling made effective - hyperpolymath/rsr-template-repo#25 — agent rule files said Bun was banned - hyperpolymath/rsr-template-repo#26 — `repo-init.just:305` self-name guard 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
#599) ## The deadlock `.github/CODEOWNERS` made `@hyperpolymath` the **sole** owner of every path, and the Base ruleset sets `require_code_owner_review: true`. GitHub will not let a pull request's author satisfy the code-owner requirement themselves. With one owner who is also always the author, **the rule could not be satisfied by anybody** — every maintainer-authored PR sat permanently `BLOCKED`. The evidence is in the merge history: #592, #593 and #597 all merged with `DISMISSED` / `CHANGES_REQUESTED` and **zero approving reviews**, via the admin bypass (`RepositoryRole id=2, mode=always`). A rule that can never pass doesn't gate anything. It just makes bypass the normal path — and once bypass is routine it stops carrying information, which is how three *other* broken rules in this same ruleset went unnoticed for months. ## The fix `@JoshuaJewell` (repo admin, the only other org member) is named co-owner, so either maintainer can approve the other's work and the requirement becomes satisfiable for the first time. **On every line, not just `*`.** In CODEOWNERS the last matching rule wins, and a specific path line *replaces* the default rather than adding to it. Co-owning only the `*` default would leave `SECURITY.md`, `.github/workflows/`, `.machine_readable/`, `LICENSE`, `*.sh` and the rest single-owned — and any PR touching them still deadlocked. ## Bootstrapping The ruleset reads CODEOWNERS from the **base** branch, so this change only takes effect once it is on `main`. This PR itself therefore still needs one admin-bypass merge. After that, code-owner review works normally. ## Context This is the fourth of four independent deadlocks found in this ruleset on 2026-08-07: 1. `code_quality` / `code_coverage` / `copilot_code_review` — features producing no PR result — **removed** 2. `required_deployments: github-pages` — Pages deploys on `push` only, so no PR head can ever have one — **removed** (18 other repos still affected; see `scripts/clear-pages-deployment-deadlock.sh`) 3. `code_scanning` @ error threshold — 13 alerts from May–July, all already excused in `.hypatia-baseline.json` — **resolved**, 12 dismissed 4. `require_code_owner_review` — **this PR** 🤖 Generated with [Claude Code](https://claude.com/claude-code)



LANGUAGE-POLICY.adoc section 1 has ruled Bun > Deno > pnpm > npm since
2026-07-29, and section 1.2 retired the "use ReScript instead" rule because
ReScript is no longer used in this estate. The ruling was recorded. It was not
in force: every surface that ACTS still encoded its predecessor.
WHAT WAS ACTUALLY HAPPENING
.github/workflows/governance-reusable.yml
Failed any repository carrying bun.lockb -- "Use Deno instead" -- and any
package.json declaring runtime dependencies. Bun's model IS an
npm-compatible package.json plus a Bun lockfile, so this gate did not
merely discourage the tier-1 runtime, it made adopting it impossible.
This reusable is called estate-wide.
docs/JS-RUNTIME-POLICY.adoc
Stated the hierarchy as Deno > Bun > pnpm > npm -- the exact inverse of
LANGUAGE-POLICY section 1 -- and rule 2 required that bun.lockb MUST NOT
be tracked. This is the document governance-reusable.yml cites for
remediation, so a repository following the error message was directed
further from the policy.
.claude/CLAUDE.md
Listed Bun in the BANNED table with Deno as its replacement, and
described Deno as "replaces Node/npm/bun". This is the file agents read
first, so recorded policy and agent behaviour had diverged: agents were
being instructed to migrate away from the estate's first-choice runtime.
CHANGES
governance-reusable.yml bun.lock / bun.lockb accepted and reported as tier
1. package.json runtime dependencies accepted when
a Bun lockfile is present, still flagged otherwise.
yarn.lock and .npmrc still fail; remediation text
now names Bun rather than Deno. The
package-lock.json rule (standards#67) is UNCHANGED
in behaviour -- only its message was corrected.
JS-RUNTIME-POLICY.adoc Hierarchy table inverted to match LANGUAGE-POLICY,
with a note recording that LANGUAGE-POLICY is
authoritative if the two ever disagree again.
Rule 2 split: yarn.lock and .npmrc still banned,
Bun lockfiles explicitly permitted and expected.
.claude/CLAUDE.md Bun promoted to a tier-1 row; the banned rows for
Node.js/npm/Bun/pnpm-yarn replaced with accurate
ones. npm is described as tier 4 -- permitted,
never preferred -- which is what the policy says,
rather than "banned".
Also corrected: docs/migrations/npm-to-deno-template/MIGRATION.md,
meta-a2ml/.claude/CLAUDE.md, rhodium-standard-repositories/PROJECT-STATUS.md
and rhodium-standard-repositories/.github/workflows/language-policy.yml.
DELIBERATELY NOT CHANGED
The package-lock.json prohibition. LANGUAGE-POLICY calls npm "permitted,
never preferred" while standards#67 hard-fails a tracked lockfile. That
tension predates this change and deserves its own decision.
.claude/CLAUDE.md bans TypeScript in favour of AffineScript, while
LANGUAGE-POLICY section 1.2 says TypeScript is "permitted under Bun".
Both cannot be right. The AffineScript direction is a substantive
architectural position, not an oversight, so it is flagged in the file for
an owner ruling rather than changed here.
consent-aware-http/.claude/CLAUDE.md carries the same stale table but that
directory is being extracted to metadatastician/consent-aware-web in a
separate PR, so it is left alone here to avoid a conflict.
STILL BROKEN ELSEWHERE (cannot be fixed from this repository)
The metadatastician organisation Actions allowlist has patterns_allowed
containing 'denoland/' but not 'oven-sh/'. Any workflow referencing
oven-sh/setup-bun is rejected with startup_failure, zero jobs, and no
explanatory log. Adding the pattern per-repo returns 409 Conflict --
it is set at organisation level. Needs an org admin.
hyperpolymath/rsr-template-repo ships .cursorrules, .clinerules,
.windsurfrules and .github/copilot-instructions.md all instructing
"TypeScript -> use ReScript" and "Node.js / npm / bun -> use Deno". These
propagate to every mint. Corrected wording exists in
metadatastician/consent-aware-web and can be lifted verbatim; a separate PR
is needed against the template.
Found while extracting consent-aware-http into its own repository, where the
manifest validator had to be written dependency-free specifically to avoid
tripping the gate this commit fixes.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
🤖 Generated with Claude Code