Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .machine_readable/template-capability-gates.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ paths = ["README.adoc", "EXPLAINME.adoc", "LICENSE", "SECURITY.md", "CONTRIBUTIN
"MAINTAINERS.adoc" = "governance-tier"

[presets]
# OPTIONAL shorthands. A profile may declare `capabilities = [...]` directly
# instead of a preset; presets are pure sugar that expands to a capability set.
# preset name = [ base capabilities ]
rust-cli = ["rust", "cli", "library"]
rust-ffi-lib = ["rust", "zig", "ffi", "abi", "library"]
Expand Down
51 changes: 33 additions & 18 deletions TEMPLATE-APPLICABILITY-POLICY.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ makes "carry it only if you need it" a *rule with a test*, not a judgement call.

== Model

Three layers:

. *Universal baseline* — modules every repo carries unconditionally (identity,
community-health, machine-readable state, the licence invariant).
. *Capability gates* — every other template module is tagged with the
*capability* it serves. A repo carries the module **iff** it declares that
capability.
. *Presets* — named capability bundles (`rust-cli`, `rust-ffi-lib`,
`rust-service`, `formal-proof-lib`, `docs-site`, …) a repo adopts as its base,
then adjusts with explicit per-capability `add` / `remove`. (The "hybrid"
layer: presets for ergonomics, gates for precision.)

A repo's *profile* (`.machine_readable/rsr-profile.a2ml`) declares its preset
and any adjustments. Its effective capability set drives everything else.
. *Capability gates (the model)* — every other template module is tagged with
the *capability* it serves. A repo *declares its capabilities* and carries a
module **iff** it declares that module's gating capability.
. *Presets (optional sugar)* — named capability bundles (`rust-cli`,
`rust-ffi-lib`, `rust-service`, `formal-proof-lib`, `docs-site`, …). A repo
*may* adopt a preset as a shorthand for its base capabilities instead of
listing them, then adjust with `add` / `remove`. Presets are pure ergonomics
over the gate model — never required.

A repo's *profile* (`.machine_readable/rsr-profile.a2ml`) declares its
capabilities (directly, or via a preset + adjustments). Its effective
capability set drives everything else.

== Capability taxonomy

Expand Down Expand Up @@ -114,7 +114,10 @@ and the SPDX licence invariant (`LICENCE-POLICY.adoc`).
| `.github/workflows/release.yml`, registry metadata | `published-package`
|===

== Presets
== Presets (optional)

Presets are optional shorthands — a repo can always declare `capabilities`
directly instead. Each expands to a base capability set:

[cols="1,3"]
|===
Expand Down Expand Up @@ -153,21 +156,33 @@ that justifies it. That is the thing this policy removes.

== Per-repo profile

`.machine_readable/rsr-profile.a2ml` (A2ML, TOML-like; SPDX `MPL-2.0`):
`.machine_readable/rsr-profile.a2ml` (A2ML, TOML-like; SPDX `MPL-2.0`). Declare
capabilities directly (primary form):

[source,toml]
----
[profile]
preset = "rust-cli"
add = [] # extra capabilities beyond the preset
remove = [] # preset capabilities this repo does NOT have
capabilities = ["rust", "cli", "library"]

[rationale]
# One line per non-obvious add/remove or declined capability.
# One line per non-obvious capability or declined module.
no-abi = "language-agnostic engine; no C-ABI seam, no Idris2 ABI proofs"
no-formal-proofs = "consumes Agda (shells out); contains no in-tree proofs"
----

Or, equivalently, adopt a preset (optional shorthand) and adjust:

[source,toml]
----
[profile]
preset = "rust-cli" # = ["rust", "cli", "library"]
add = ["published-package"] # extra capabilities beyond the preset
remove = [] # preset capabilities this repo does NOT have
----

`preset`, `capabilities`, `add`, and `remove` all union (then `remove`
subtracts); at least one of `capabilities` / `preset` is required.

== Enforcement (how this evolves the existing machinery)

`root-allow.txt` becomes *derived*, not hand-maintained as one shape:
Expand Down
21 changes: 14 additions & 7 deletions scripts/check-rsr-profile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,25 @@ section() { awk -v s="[$1]" '$0==s{f=1;next} /^\[/{f=0} f && !/^[[:space:]]*#/ &
quoted_on_key() { grep -E "^[[:space:]]*$1[[:space:]]*=" | grep -oE '"[^"]+"' | tr -d '"' || true; }

# --- target profile ---
# Capability declaration is primary: a profile may list `capabilities = [...]`
# directly. `preset` is optional sugar — a named bundle expanded from the gate
# data. A profile must provide at least one of the two.
PBODY="$(section profile "$PROFILE")"
PRESET="$(printf '%s\n' "$PBODY" | quoted_on_key preset | sed -n 1p)"
DIRECT="$(printf '%s\n' "$PBODY" | quoted_on_key capabilities)"
ADD="$(printf '%s\n' "$PBODY" | quoted_on_key add)"
REMOVE="$(printf '%s\n' "$PBODY" | quoted_on_key remove)"
[ -n "$PRESET" ] || { echo "ERROR: profile declares no preset" >&2; exit 2; }
[ -n "$PRESET$DIRECT" ] || { echo "ERROR: profile declares neither 'capabilities' nor 'preset'" >&2; exit 2; }

# --- preset's base capabilities (from the gate data) ---
PRESETCAPS="$(section presets "$GATES" | quoted_on_key "$PRESET")"
[ -n "$PRESETCAPS" ] || { echo "ERROR: unknown preset '$PRESET' (not in $GATES [presets])" >&2; exit 2; }
# --- preset's base capabilities, if a preset is named ---
PRESETCAPS=""
if [ -n "$PRESET" ]; then
PRESETCAPS="$(section presets "$GATES" | quoted_on_key "$PRESET")"
[ -n "$PRESETCAPS" ] || { echo "ERROR: unknown preset '$PRESET' (not in $GATES [presets])" >&2; exit 2; }
fi

# --- effective capabilities = presetcaps + add - remove ---
EFFECTIVE="$(printf '%s\n%s\n' "$PRESETCAPS" "$ADD" | sort -u | sed '/^$/d')"
# --- effective capabilities = capabilities + presetcaps + add - remove ---
EFFECTIVE="$(printf '%s\n%s\n%s\n' "$DIRECT" "$PRESETCAPS" "$ADD" | sort -u | sed '/^$/d')"
if [ -n "$REMOVE" ]; then
EFFECTIVE="$(comm -23 <(printf '%s\n' "$EFFECTIVE") <(printf '%s\n' "$REMOVE" | sort -u))"
fi
Expand All @@ -58,7 +65,7 @@ present() {
}

echo "repo: $REPO"
echo "preset: $PRESET"
echo "profile: ${PRESET:+preset=$PRESET }${DIRECT:+direct-capabilities}"
echo "effective capabilities: $(printf '%s ' $EFFECTIVE)"
echo

Expand Down
Loading