Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .machine_readable/6a2/META.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
# META.a2ml — Standards meta-level information
[metadata]
version = "1.0.0"
last-updated = "2026-04-11"
last-updated = "2026-05-15"

[project-info]
license = "PMPL-1.0-or-later"
author = "Jonathan D.A. Jewell (hyperpolymath)"

[architecture-decisions]
decisions = [
# No ADRs recorded
{ id = "ADR-001", date = "2026-05-15", title = "CODEOWNERS policy for hyperpolymath repos", status = "accepted", ref = "CODEOWNERS-POLICY.adoc", issue = "standards#55", summary = "Solo-owned repos carry no catch-all `*` or `/.github/workflows/` CODEOWNERS lines (silences Dependabot review_requested flood); path lines kept only for genuine co-owners; co-owner removal needs explicit confirmation." }
]

[development-practices]
Expand Down
152 changes: 152 additions & 0 deletions CODEOWNERS-POLICY.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: PMPL-1.0-or-later
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
= Hyperpolymath CODEOWNERS Policy
Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
:revnumber: 1.0.0
:revdate: 2026-05-15
:toc:
:toc-placement: preamble

Canonical `CODEOWNERS` policy for all `hyperpolymath/*` repositories.
All maintainers and AI agents must follow this document. It resolves
link:https://github.com/hyperpolymath/standards/issues/55[standards#55].

== Problem

GitHub auto-requests review from every matching `CODEOWNERS` entry on
*every* pull request — including Dependabot PRs. On solo-owned repos the
only matching owner is the sole maintainer, so every dependency bump
fires a `reason:review_requested` notification that conveys no
information (the sole maintainer is going to review their own repo
anyway). Across ~18 active `hyperpolymath/*` repos this produced a
recurring notification flood.

Two `CODEOWNERS` line shapes cause this:

* the catch-all `* @owner` line — triggered by *all* Dependabot
ecosystems (cargo, mix, nix, npm, …);
* the `/.github/workflows/` path line — triggered specifically by the
Dependabot `github-actions` ecosystem, which bumps action versions by
editing workflow files.

== The Standard

=== Rule 1 — Solo-owned repos carry no functional CODEOWNERS lines

For a repository whose only code owner would be the sole maintainer,
`CODEOWNERS` MUST NOT contain a catch-all (`*`) line *or* a
`/.github/workflows/` (or `.github/workflows/`) line.

Such a repo SHOULD either omit `CODEOWNERS` entirely or keep only a
comment header (SPDX + a one-line note). Sole-maintainer review gating is
moot, and attribution is already carried by the SPDX header on every
file, so the lines provide neither security nor attribution value — only
noise.

=== Rule 2 — Path lines are kept only for real co-owners

A path-specific `CODEOWNERS` line is justified *only* when it maps to a
collaborator other than the sole maintainer who genuinely should be
auto-pinged for changes under that path. When such a co-owner exists,
keep the path line but scope it to the co-owner and drop any redundant
self-ping of the sole maintainer.

=== Rule 3 — Co-owner removal requires explicit confirmation

Dropping or narrowing a path line that currently auto-requests review
from a co-owner removes that co-owner's review gate. This MUST NOT be
done without the co-owner's (or repo lead's) explicit confirmation.

== Canonical Templates

=== Solo-owned repo (`CODEOWNERS`)

[source]
----
# SPDX-License-Identifier: PMPL-1.0-or-later
# Solo-maintained hyperpolymath repo: no owner lines by policy.
# See hyperpolymath/standards CODEOWNERS-POLICY.adoc (Rule 1).
# Sole-maintainer review is moot; SPDX headers carry attribution.
----

(An absent `CODEOWNERS` file is equally compliant.)

=== Multi-owner repo (`CODEOWNERS`)

[source]
----
# SPDX-License-Identifier: PMPL-1.0-or-later
# Path lines map ONLY to genuine co-owners (Rule 2).
# Do not add a catch-all `*` line.
/.github/workflows/ @co-owner-handle
----

== Decision Matrix — standards#55 remaining repos

The 2026-05-14 batch already opened 18 PRs dropping the catch-all
`* @hyperpolymath` line (cargo/mix/nix/npm noise). This matrix resolves
the remaining `github-actions`-ecosystem `.github/workflows/` line.

[cols="2,1,3", options="header"]
|===
| Repo | Resolution | Basis

| gitbot-fleet | Drop line | Solo-owned (Rule 1)
| hypatia | Drop line | Solo-owned (Rule 1)
| boj-server | Drop line | Solo-owned (Rule 1)
| bofig | Drop line | Solo-owned (Rule 1)
| idaptik | Keep, scope to `@JoshuaJewell` | Co-owned (Rule 2); self-ping of `@hyperpolymath` dropped, `@JoshuaJewell` gate retained per Rule 3
| proof-of-work | Drop line | Solo-owned (Rule 1)
| InvestigativeJournalist.jl | Drop line | Solo-owned (Rule 1)
| TradeUnionist.jl | Drop line | Solo-owned (Rule 1)
| echidna | Drop line | Solo-owned (Rule 1)
| coq-jr | Drop line | Solo-owned (Rule 1)
| cloudguard-server | Drop line | Solo-owned (Rule 1)
| cloudguard-cli | Drop line | Solo-owned (Rule 1)
| snifs | Drop line | Solo-owned (Rule 1)
| somethings-fishy | Drop line | Solo-owned (Rule 1)
| affinescript-vite | Drop line | Solo-owned (Rule 1)
|===

idaptik is the sole Rule 3 case: `@JoshuaJewell` is a genuine co-owner,
so its `.github/workflows/` gate is retained (narrowed to
`@JoshuaJewell` only). All other 14 are solo-owned and take the Rule 1
drop.

=== Rollout tracking

Per-repo `CODEOWNERS` edits land in each target repository, not in this
standards repo (which has no `CODEOWNERS` lines of its own and is already
compliant). This document is the canonical reference those PRs cite.

[cols="3,2", options="header"]
|===
| Batch | Status

| 18 PRs dropping catch-all `*` line (cargo/mix/nix/npm) | Opened 2026-05-14 (see standards#55 body)
| 14 solo-owned repos dropping `.github/workflows/` line | Authorised by Rule 1 — execute per-repo
| idaptik — narrow `.github/workflows/` to `@JoshuaJewell` | Authorised by Rule 2/3 — execute on co-owner confirmation
|===

== Enforcement

* New repos: the RSR repo template ships no catch-all `CODEOWNERS` line;
a `CODEOWNERS` file, if present, follows the canonical templates above.
* Audit: a repo is non-compliant if `CODEOWNERS` contains a `*` line, or
a `/.github/workflows/` line whose owners are limited to the sole
maintainer. Grep check:
+
[source,bash]
----
grep -nE '^\s*\*\s|^\s*/?\.github/workflows/' CODEOWNERS 2>/dev/null
----
+
Any catch-all match is a violation; a workflow-path match is a violation
unless every listed owner is a genuine co-owner (Rule 2).

== See Also

* link:https://github.com/hyperpolymath/standards/issues/55[standards#55] — originating decision
* `LICENCE-POLICY.adoc` (this directory) — companion canonical policy; SPDX headers cover attribution
* `MAINTAINERS.adoc` (this directory) — maintainer-of-record (separate from CODEOWNERS auto-ping)
* link:https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners[GitHub: About code owners]
1 change: 1 addition & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This repository serves as the canonical source for policies, templates, and spec
* **Session Management Standards** -- link:session-management-standards/README.adoc[canonical continuity, verify, and handover protocols]
* **Contractiles / K9** -- link:contractiles/CANONICAL-TEMPLATES.adoc[canonical Must/Trust/Dust/Intent semantics] and Kennel/Yard/Hunt guidance
* **Governance Templates** -- Reusable CODE_OF_CONDUCT, CONTRIBUTING, and SECURITY documents
* **CODEOWNERS Policy** -- link:CODEOWNERS-POLICY.adoc[canonical `CODEOWNERS` rules] (no catch-all/workflow lines on solo-owned repos)
* **Licensing Framework** -- PMPL-1.0-or-later with Palimpsest philosophical principles
* **Enforcement** -- CI/CD workflows and pre-commit hooks

Expand Down
4 changes: 2 additions & 2 deletions a2ml/docs/CONTRACTILES-A2ML-V1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,6 @@ The validator and emitter support explicit types:

[source,bash]
----
python3 scripts/contractiles-a2ml-tool.py validate --type mustfile tests/contractiles/fixtures/invalid-mustfile.a2ml
python3 scripts/contractiles-a2ml-tool.py emit --type trustfile contractiles/trust/Trustfile.a2ml /tmp/trustfile.json
deno run --allow-read --allow-write scripts/contractiles-a2ml-tool.js validate --type mustfile tests/contractiles/fixtures/invalid-mustfile.a2ml
deno run --allow-read --allow-write scripts/contractiles-a2ml-tool.js emit --type trustfile contractiles/trust/Trustfile.a2ml /tmp/trustfile.json
----
2 changes: 1 addition & 1 deletion a2ml/docs/RELEASE-CHECKLIST-CONTRACTILES-A2ML-V1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
== Pre-Release

- [ ] Specs updated: `docs/CONTRACTILES-A2ML-V1.adoc` and `contractiles/spec/contractiles-v1.json`
- [ ] Validator/emitter tool updated: `scripts/contractiles-a2ml-tool.py`
- [ ] Validator/emitter tool updated: `scripts/contractiles-a2ml-tool.js`
- [ ] Fixtures updated: `tests/contractiles/fixtures/*`
- [ ] Expected outputs updated: `tests/contractiles/expected/*`
- [ ] CI workflow present: `.github/workflows/contractiles-a2ml.yml`
Expand Down
2 changes: 1 addition & 1 deletion a2ml/docs/RELEASE-NOTES-CONTRACTILES-A2ML-V1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ just contractiles-k9-validate

* `docs/CONTRACTILES-A2ML-V1.adoc`
* `contractiles/spec/contractiles-v1.json`
* `scripts/contractiles-a2ml-tool.py`
* `scripts/contractiles-a2ml-tool.js`
* `tests/contractiles/fixtures/*`
* `.github/workflows/contractiles-a2ml.yml`

Expand Down
11 changes: 6 additions & 5 deletions a2ml/scripts/contractiles-a2ml-emit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
out_dir="${1:-$root/build/contractiles}"
mkdir -p "$out_dir"

tool="$root/scripts/contractiles-a2ml-tool.py"
tool="$root/scripts/contractiles-a2ml-tool.js"
runtool() { deno run --quiet --allow-read --allow-write "$tool" "$@"; }

python3 "$tool" emit "$root/contractiles/must/Mustfile.a2ml" "$out_dir/mustfile.json"
python3 "$tool" emit "$root/contractiles/trust/Trustfile.a2ml" "$out_dir/trustfile.json"
python3 "$tool" emit "$root/contractiles/dust/Dustfile.a2ml" "$out_dir/dustfile.json"
python3 "$tool" emit "$root/contractiles/lust/Intentfile.a2ml" "$out_dir/intentfile.json"
runtool emit "$root/contractiles/must/Mustfile.a2ml" "$out_dir/mustfile.json"
runtool emit "$root/contractiles/trust/Trustfile.a2ml" "$out_dir/trustfile.json"
runtool emit "$root/contractiles/dust/Dustfile.a2ml" "$out_dir/dustfile.json"
runtool emit "$root/contractiles/lust/Intentfile.a2ml" "$out_dir/intentfile.json"

echo "Wrote: $out_dir/mustfile.json"
echo "Wrote: $out_dir/trustfile.json"
Expand Down
18 changes: 10 additions & 8 deletions a2ml/scripts/contractiles-a2ml-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ set -euo pipefail

root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)

tool="$root/scripts/contractiles-a2ml-tool.py"
tool="$root/scripts/contractiles-a2ml-tool.js"
fixtures="$root/tests/contractiles/fixtures"
expected="$root/tests/contractiles/expected"

python3 "$tool" validate \
runtool() { deno run --quiet --allow-read --allow-write "$tool" "$@"; }

runtool validate \
"$fixtures/Mustfile.a2ml" \
"$fixtures/Trustfile.a2ml" \
"$fixtures/Dustfile.a2ml" \
"$fixtures/Intentfile.a2ml"

python3 "$tool" emit "$fixtures/Mustfile.a2ml" "$expected/mustfile.json.tmp"
python3 "$tool" emit "$fixtures/Trustfile.a2ml" "$expected/trustfile.json.tmp"
python3 "$tool" emit "$fixtures/Dustfile.a2ml" "$expected/dustfile.json.tmp"
python3 "$tool" emit "$fixtures/Intentfile.a2ml" "$expected/intentfile.json.tmp"
runtool emit "$fixtures/Mustfile.a2ml" "$expected/mustfile.json.tmp"
runtool emit "$fixtures/Trustfile.a2ml" "$expected/trustfile.json.tmp"
runtool emit "$fixtures/Dustfile.a2ml" "$expected/dustfile.json.tmp"
runtool emit "$fixtures/Intentfile.a2ml" "$expected/intentfile.json.tmp"

diff -u "$expected/mustfile.json" "$expected/mustfile.json.tmp"
diff -u "$expected/trustfile.json" "$expected/trustfile.json.tmp"
Expand All @@ -25,7 +27,7 @@ diff -u "$expected/intentfile.json" "$expected/intentfile.json.tmp"

expect_fail() {
local file="$1"
if python3 "$tool" validate "$file"; then
if runtool validate "$file"; then
echo "Expected validation failure: $file" >&2
exit 1
fi
Expand All @@ -34,7 +36,7 @@ expect_fail() {
expect_fail_type() {
local file="$1"
local type="$2"
if python3 "$tool" validate --type "$type" "$file"; then
if runtool validate --type "$type" "$file"; then
echo "Expected validation failure: $file ($type)" >&2
exit 1
fi
Expand Down
Loading
Loading