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: object

Scoped authorization issued by a named principal for one immutable version.

This record carries no proof of who issued it. issued_by is 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 write issued_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. provenance records whether the object was issued in this process, merely deserialized, or checked by an embedder against a real authority, and allows() 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:
  • decision_id (str)

  • capability (CapabilityIdentity)

  • outcome (AuthorizationOutcome)

  • issued_by (str)

  • scopes (frozenset[str])

  • decided_at (datetime)

  • expires_at (datetime | None)

  • reason (str)

  • revoked_at (datetime | None)

  • revoked_by (str | None)

  • revocation_reason (str)

  • provenance (AuthorizationProvenance)

  • verified_by (str)

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 scope at at.

A LOADED decision – one reconstructed from serialized content – returns False here 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 claiming issued_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=True restores 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.

Parameters:
Return type:

bool

mark_verified(*, by)[source]

Return a copy marked as checked by by against 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.

Parameters:
Return type:

AuthorizationDecision

classmethod from_dict(value)[source]

Parse an unauthenticated record; see the class docstring.

The result always carries LOADED provenance, whatever the content claims, so allows() refuses it until an embedder checks it and calls mark_verified().

Parameters:

value (Mapping[str, Any])

Return type:

AuthorizationDecision

class AuthorizationOutcome(*values)[source]

Bases: StrEnum

The outcome recorded by an authorization authority.

class AuthorizationProvenance(*values)[source]

Bases: StrEnum

Where an AuthorizationDecision came from – NOT a statement about who issued it.

ISSUED means the object was constructed in this process by code that was already trusted to issue it. LOADED means it was reconstructed from serialized content (from_dict()), whose issued_by is just a string the content claimed. VERIFIED means an embedder checked that content against whatever authority it actually trusts and said so via mark_verified().

class AuthorizationStatus(*values)[source]

Bases: StrEnum

Effective status of a decision at a point in time.

class CapabilityIdentity(capability_id, version, digest=None)[source]

Bases: object

Immutable identity of one capability version.

digest is optional for a purely semantic capability and must be the integrity digest of a concrete artifact when one exists. It is stored canonically as algorithm:hexdigest so that a holder of the artifact bytes can actually recompute it; a bare SHA-256 hex string is accepted and labelled.

Parameters:
  • capability_id (str)

  • version (str)

  • digest (str | None)

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: object

An immutable, replayable snapshot of every independent lifecycle dimension.

Parameters:
  • capability (CapabilityIdentity)

  • maturity (CapabilityMaturity)

  • operational (OperationalState)

  • evaluation (EvaluationState)

  • epistemic (EpistemicStanding)

  • authorization (AuthorizationDecision | None)

  • revision (int)

  • updated_at (datetime)

allows(scope, *, at=None)[source]

Return whether the current decision authorizes scope; maturity is intentionally separate.

Parameters:
Return type:

bool

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=None clears a decision; omitting it keeps the current decision. Maturity promotion never happens automatically: a transition into validated or supported explicitly requires the evaluation dimension to be passed in 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

classmethod from_dict(value)[source]

Parse an unauthenticated record; see the module docstring.

Parameters:

value (Mapping[str, Any])

Return type:

CapabilityLifecycle

class CapabilityMaturity(*values)[source]

Bases: StrEnum

Product maturity; this is distinct from API stability in mixle.maturity.

class EpistemicStanding(*values)[source]

Bases: StrEnum

Standing of the claims supporting a capability.

class EvaluationState(*values)[source]

Bases: StrEnum

State of the current evaluation, not a maturity or deployment verdict.

exception LifecycleTransitionError[source]

Bases: ValueError

Raised when a lifecycle transition would erase or contradict evidence.

class OperationalState(*values)[source]

Bases: StrEnum

Whether an implementation can currently accept work.