pub struct RoleExtension {
pub bound_to_role_lct: Uuid,
pub affordances: Vec<Affordance>,
pub responsibilities: Vec<Responsibility>,
pub scope: Scope,
pub default_verdict: ExtensionVerdict,
pub folds_under: Vec<String>,
pub authored_under: Option<String>,
pub lint_verdict: Option<LintVerdict>,
}Expand description
The role:Extension — a role’s own law layer, composed under inherited society
∧ constellation law via strictest-wins fold (eval-time, in hestia). Affordances,
responsibilities, scope, plus the authoring-validity witness (§2.3).
Fields§
§bound_to_role_lct: Uuidrole:boundToRoleLct — the Role LCT this extension is the law of.
affordances: Vec<Affordance>role:hasAffordance.
responsibilities: Vec<Responsibility>role:hasResponsibility.
scope: Scoperole:hasScope.
default_verdict: ExtensionVerdictrole:defaultVerdict — REQUIRED. Absence is a deserialize error, never a
silent permissive default: “the field was omitted” must not be
indistinguishable from “the author chose Allow” (F1, CBP 2026-07-08).
folds_under: Vec<String>role:foldsUnder — the parent law level(s) this composes under. REQUIRED
and must be non-empty: an extension folding under NO parent has nothing to
be strictest against, so its overlay becomes the only law — the fail-open
worst case. Absence is a deserialize error; emptiness is rejected at use.
role:authoredUnder — the parent-law snapshot the write-time linter checked
this extension against. None = no witness → drift:unattributed on deny.
lint_verdict: Option<LintVerdict>role:lintVerdict — the linter’s persisted verdict. Paired with
authored_under it records whether the extension was EVER valid.
Implementations§
Source§impl RoleExtension
impl RoleExtension
Sourcepub fn drift_mark(&self) -> DriftMark
pub fn drift_mark(&self) -> DriftMark
The §2.3 attribution: given an eval-time base-deny on a role-permissive
action, the cause is read from the authoring witness — never guessed from
the fold. Fail ⇒ author violated parent at authoring; Pass ⇒ parent
tightened under a once-valid extension; no witness ⇒ unattributed.
Sourcepub fn affords(&self, wanted: &Affordance) -> bool
pub fn affords(&self, wanted: &Affordance) -> bool
Does this extension grant exactly this affordance? Fail-closed helper for
the launcher: a grant not present is refused. Kind-aware — the five
role:Affordance subclasses are distinct namespaces, so a Repo("x") does
NOT satisfy a query about a Channel("x"). (F3, CBP 2026-07-08: the old
token-only check unioned the namespaces — fail-open across kinds.)
Sourcepub fn validate(&self) -> Result<(), &'static str>
pub fn validate(&self) -> Result<(), &'static str>
Validate the fail-closed invariants that the type system can’t express.
Callers MUST call this before evaluating an extension: making a field
REQUIRED stops it being absent, but an explicitly-empty folds_under
([]) still deserializes and would leave the overlay as the only law with
nothing to be strictest against — the fail-open worst case CBP flagged (F1,
“emptiness is rejected at use”). Rejected here.