Skip to content

packs

Discipline Packs: loading, validation and signing.

coalitionkit_packs

Discipline Packs: load, validate, sign and verify packs without touching the core.

CompareQuestion

Bases: _Strict

The question each seat is asked. choice lets a person pick any of the options.

PackError

Bases: Exception

A pack failed validation or verification and does not load.

Pack dataclass

validate_schema
validate_schema(kind: str, instance: Any) -> None

Validate against the closed, in-memory snapshot registry.

ScopeWidenError

Bases: ValueError

A pack scope reaches someone the scope it narrows does not, or that cannot be shown.

EvalOutcome dataclass

What a run of a scenario produced, to compare with its expect.

EvalScenario

Bases: _Strict

check
check(outcome: EvalOutcome) -> list[str]

Differences between the scripted expectation and an observed outcome.

inspect_pack

inspect_pack(
    root: Path | str,
    *,
    core_catalog: Catalog | None = None,
    core_version: str | None = None,
) -> Pack

Validate a pack folder without checking its signature.

Raises PackError listing every rule broken. Use load_pack to load for real.

load_pack

load_pack(
    root: Path | str,
    *,
    trusted_keys: Mapping[str, Ed25519PublicKey],
    core_catalog: Catalog | None = None,
    core_version: str | None = None,
) -> Pack

Verify the author signature against trusted_keys, then validate and load.

The folder is read once into a snapshot; the signature is checked on those bytes and the same bytes are parsed. A pack that fails either step raises PackError.

check_not_wider

check_not_wider(
    base: Scope,
    candidate: Scope,
    *,
    owner: str | None = None,
    membership: Membership | None = None,
) -> None

Raise ScopeWidenError unless candidate provably reaches no one base does not.

With owner (the sender's owner) and membership the two scopes are resolved to recipient sets and compared. Without them only conversions whose subset relation holds for every possible membership are accepted: anything to host, coalition to anything, equal audiences with subset lists, and self to self. Converting participants or roles to self (or between roles and participants) needs the resolved sets, so it is refused. The candidate must also keep every redaction path of base.

narrow

narrow(
    base: Scope,
    candidate: Scope,
    *,
    owner: str | None = None,
    membership: Membership | None = None,
) -> Scope

candidate if it is provably no wider than base; otherwise ScopeWidenError.

sign_pack

sign_pack(
    root: Path, private_key: Ed25519PrivateKey, kid: str
) -> Path

Write pack.sig for the folder and return its path.

verify_pack_embedded

verify_pack_embedded(root: Path) -> PackSignature

Check integrity against the public key inside pack.sig.

This proves the files are those the key holder signed, not who the author is: the caller must compare the kid with a key it already trusts. A pack never loads on this alone.

extend_catalog

extend_catalog(
    core: Catalog,
    packs: Iterable[Mapping[str, ComponentSpec]],
) -> Catalog

The core catalog plus the components of the active packs, as a new catalog.

The core catalog itself is never changed, so a tree that uses a pack component validates only against a catalog built from the packs that are active. Two active packs may not define the same component.