91 lines
4.2 KiB
Text
91 lines
4.2 KiB
Text
# schemas/lib/radicle.ncl — Radicle Heartwood governance substrate types (ADR-038)
|
|
#
|
|
# Three repo families per workspace: policy, desired, state — each with a distinct
|
|
# delegation profile. Used by the audit-mirror crate and governance domain commands.
|
|
#
|
|
# Usage:
|
|
# let rad = import "schemas/lib/radicle.ncl" in
|
|
# { repos | rad.WorkspaceRepos = rad.make_workspace_repos "libre-wuji" & { ... } }
|
|
|
|
let _RepoRole = [| 'policy, 'desired, 'state |] in
|
|
|
|
let _PatchStatus = [| 'open, 'merged, 'rejected |] in
|
|
|
|
# M-of-N delegation profile attached to a Radicle repo.
|
|
# threshold <= length(signers) is a business invariant enforced by the Rust caller.
|
|
let _DelegationProfile = {
|
|
threshold | Number | doc "Minimum signatures required to merge a patch (M in M-of-N)",
|
|
signers | Array String | doc "Key IDs of authorized delegates (Radicle DID or human-readable alias)",
|
|
} in
|
|
|
|
# A Radicle repo descriptor: RID + role + delegation profile.
|
|
# rid is empty string until the repo is initialised via 'rad init'.
|
|
let _RadicleRepo = {
|
|
name | String | doc "Human-readable name (e.g., 'policy-libre-wuji')",
|
|
rid | String | doc "Radicle Identifier assigned by 'rad init' (rad:...); empty before init" | default = "",
|
|
role | _RepoRole | doc "Functional role in the three-repo split",
|
|
delegates | _DelegationProfile | doc "M-of-N delegation profile for patches to this repo",
|
|
} in
|
|
|
|
# A proposed change patch — governance domain commands surface these for operator review.
|
|
let _Patch = {
|
|
id | String | doc "Radicle patch ID",
|
|
proposed_by | String | doc "Key ID or alias of the patch author",
|
|
status | _PatchStatus | doc "Current lifecycle state" | default = 'open,
|
|
signatures | Array String | doc "Key IDs that have signed this patch" | default = [],
|
|
payload | String | doc "Short human-readable description of what this patch changes",
|
|
} in
|
|
|
|
# Snapshot of signature satisfaction for a pending patch.
|
|
let _SignatureSet = {
|
|
required | Number | doc "Threshold from the repo's DelegationProfile (M)",
|
|
present | Array String | doc "Key IDs that have already signed",
|
|
satisfied | Bool | doc "True when length(present) >= required",
|
|
} in
|
|
|
|
# The three repos belonging to one workspace — the canonical three-repo split.
|
|
let _WorkspaceRepos = {
|
|
policy | _RadicleRepo | doc "policy-<workspace>: keeper auto-sign policy + authorized-signers set; M-of-N operator delegates",
|
|
desired | _RadicleRepo | doc "<workspace>-desired: version-controlled workspace declaration; M-of-N operators + CI keys",
|
|
state | _RadicleRepo | doc "<workspace>-state: immutable applied-ops ledger; exactly one delegate (ops-controller key)",
|
|
} in
|
|
|
|
{
|
|
RepoRole = _RepoRole,
|
|
PatchStatus = _PatchStatus,
|
|
DelegationProfile = _DelegationProfile,
|
|
RadicleRepo = _RadicleRepo,
|
|
Patch = _Patch,
|
|
SignatureSet = _SignatureSet,
|
|
WorkspaceRepos = _WorkspaceRepos,
|
|
|
|
# Returns a _WorkspaceRepos template with empty RIDs and placeholder signer lists.
|
|
# `rid` and `delegates` fields carry `| default` priority so callers can override via merge:
|
|
# (rad.make_workspace_repos "libre-wuji") & {
|
|
# policy.rid = "rad:abc",
|
|
# policy.delegates = { threshold = 2, signers = ["jpl-yubikey", "alice-key"] },
|
|
# state.rid = "rad:ghi",
|
|
# state.delegates = { threshold = 1, signers = ["ops-controller-wuji-key"] },
|
|
# }
|
|
# Alternatively, use `{ ... } | rad.WorkspaceRepos` directly with all fields populated.
|
|
make_workspace_repos | not_exported = fun workspace => {
|
|
policy = {
|
|
name = "policy-%{workspace}",
|
|
rid | default = "",
|
|
role = 'policy,
|
|
delegates | default = { threshold = 1, signers = [] },
|
|
},
|
|
desired = {
|
|
name = "%{workspace}-desired",
|
|
rid | default = "",
|
|
role = 'desired,
|
|
delegates | default = { threshold = 1, signers = [] },
|
|
},
|
|
state = {
|
|
name = "%{workspace}-state",
|
|
rid | default = "",
|
|
role = 'state,
|
|
delegates | default = { threshold = 1, signers = [] },
|
|
},
|
|
},
|
|
}
|