mixle.capability_lifecycle module¶
Governed lifecycle records for capabilities shared across Mixle projects.
Capability lifecycle state is deliberately factored into independent dimensions.
An evaluation result is not a maturity promotion, an available service is not an
authorized service, and a corroborated claim is not proof that an implementation
is operational. CapabilityLifecycle keeps those facts together without
collapsing them into one ambiguous status.
All records are frozen, JSON-compatible value objects carrying an explicit
schema_version. A change creates a new snapshot with a monotonically
increasing revision, which makes transitions safe to persist, audit, replay, and
exchange between projects.
These records are unauthenticated data, never bearer credentials. An
AuthorizationDecision records that a named principal decided
something; it carries no signature or MAC, so nothing in the record itself
distinguishes a decision this process issued from one an attacker wrote into the
store. from_dict() therefore parses untrusted
input: whoever persists or transports these records is responsible for
authenticating them before their contents are given any authority.
- class AuthorizationDecision(decision_id, capability, outcome, issued_by, scopes, decided_at, expires_at=None, reason='', revoked_at=None, revoked_by=None, revocation_reason='', provenance=AuthorizationProvenance.ISSUED, verified_by='')[source]
Bases:
objectScoped authorization issued by a named principal for one immutable version.
This record carries no proof of who issued it.
issued_byis a self-asserted string, and this library has no key, trust domain, or signature scheme with which to check it – so anyone who can supply the persisted content can writeissued_by="root",outcome="granted"and the scopes they want (MXR-080-1725). Adding an unkeyed digest here would not change that: whoever writes the record can write the digest too. The gap is real and cannot be closed inside a library that never sees a key.What is closed is the silent part.
provenancerecords whether the object was issued in this process, merely deserialized, or checked by an embedder against a real authority, andallows()refuses a merely-deserialized grant by default. Reaching for the record over an untrusted channel is the whole attack, so that is the direction the default has to fail.- Parameters:
- status_at(at)[source]
Return the decision’s effective status at
at.- Parameters:
at (datetime)
- Return type:
AuthorizationStatus
- allows(scope, *, at, trust_unverified=False)[source]
Return whether this decision authorizes
scopeatat.A
LOADEDdecision – one reconstructed from serialized content – returnsFalsehere regardless of what the content says. Deserializing cleanly is not evidence that anyone authorized anything, and the persisted bytes are exactly what an attacker controls, so hand-built JSON claimingissued_by="root"no longer authorizes through the ordinary public call (MXR-080-1725).Making verification opt-in was the earlier mistake: every caller that did not know to ask for it stayed vulnerable, which is the wrong default for the one method whose answer gates access. ISSUED (constructed in-process by code already trusted to issue it) and VERIFIED (checked by an embedder via
mark_verified()) both pass.trust_unverified=Truerestores the old behaviour for a caller that has decided, knowingly and locally, to act on an unverified record – an offline audit tool reading an archive, say. It is deliberately explicit and deliberately ugly to read at a call site.
- mark_verified(*, by)[source]
Return a copy marked as checked by
byagainst a trust authority outside this library.Call this only after actually verifying the record – a signature, a registry lookup, an operator confirmation. The library performs no check of its own here and cannot: it is recording your verdict so a later
allows()stops refusing the record.- Parameters:
by (str)
- Return type:
AuthorizationDecision
- revoke(*, by, at, reason='')[source]
Return a revoked copy; the original audit record remains unchanged.
- classmethod from_dict(value)[source]
Parse an unauthenticated record; see the class docstring.
The result always carries
LOADEDprovenance, whatever the content claims, soallows()refuses it until an embedder checks it and callsmark_verified().
- class AuthorizationOutcome(*values)[source]
Bases:
StrEnumThe outcome recorded by an authorization authority.
- class AuthorizationProvenance(*values)[source]
Bases:
StrEnumWhere an
AuthorizationDecisioncame from – NOT a statement about who issued it.ISSUEDmeans the object was constructed in this process by code that was already trusted to issue it.LOADEDmeans it was reconstructed from serialized content (from_dict()), whoseissued_byis just a string the content claimed.VERIFIEDmeans an embedder checked that content against whatever authority it actually trusts and said so viamark_verified().
- class AuthorizationStatus(*values)[source]
Bases:
StrEnumEffective status of a decision at a point in time.
- class CapabilityIdentity(capability_id, version, digest=None)[source]
Bases:
objectImmutable identity of one capability version.
digestis optional for a purely semantic capability and must be the integrity digest of a concrete artifact when one exists. It is stored canonically asalgorithm:hexdigestso that a holder of the artifact bytes can actually recompute it; a bare SHA-256 hex string is accepted and labelled.
- class CapabilityLifecycle(capability, maturity=CapabilityMaturity.CONCEPT, operational=OperationalState.UNAVAILABLE, evaluation=EvaluationState.UNEVALUATED, epistemic=EpistemicStanding.UNASSESSED, authorization=None, revision=0, updated_at=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc))[source]
Bases:
objectAn immutable, replayable snapshot of every independent lifecycle dimension.
- Parameters:
- allows(scope, *, at=None)[source]
Return whether the current decision authorizes
scope; maturity is intentionally separate.
- evolve(*, maturity=None, operational=None, evaluation=None, epistemic=None, authorization=_KEEP_AUTHORIZATION, at)[source]
Create the next snapshot after validating every requested transition.
Passing
authorization=Noneclears a decision; omitting it keeps the current decision. Maturity promotion never happens automatically: a transition intovalidatedorsupportedexplicitly requires the evaluation dimension to bepassedin the resulting snapshot.- Parameters:
maturity (CapabilityMaturity | None)
operational (OperationalState | None)
evaluation (EvaluationState | None)
epistemic (EpistemicStanding | None)
authorization (AuthorizationDecision | None | _KeepAuthorization)
at (datetime)
- Return type:
CapabilityLifecycle
- class CapabilityMaturity(*values)[source]
Bases:
StrEnumProduct maturity; this is distinct from API stability in
mixle.maturity.
- class EpistemicStanding(*values)[source]
Bases:
StrEnumStanding of the claims supporting a capability.
- class EvaluationState(*values)[source]
Bases:
StrEnumState of the current evaluation, not a maturity or deployment verdict.
- exception LifecycleTransitionError[source]
Bases:
ValueErrorRaised when a lifecycle transition would erase or contradict evidence.