Skip to main content

Declarative lifecycle state-machine specs: one enforcement path, policy identity digests, semantic diffs

Project description

statespec

Declarative lifecycle policy for entities whose status moves through reviewable steps. A spec is plain data — states, named transitions (roles + guards), invariants — and the same artifact is human-readable (Mermaid / plain-English table), machine-checkable (validate), enforced through a single interpreter (apply / fire), and identified by content digests (identity) so that behavioural change is mechanically distinguishable from wording change.

  • statespec.core — the engine: StateSpec, Transition, Invariant, apply, fire, validate.
  • statespec.expr — closed guard/invariant expression grammar (compare + boolean), with a versioned Opaque escape hatch whose body is hashed into the policy identity.
  • statespec.identitycanonical(), semantic_digest / presentation_digest, change_kind, diff, and policy_record() (the versioned .policy.json envelope — see docs/policy-artifact-contract.md, the authoritative copy of the contract).
  • statespec.render — Mermaid, tables, and the generated lifecycle doc.

Pure Python, stdlib-only, no dependencies.

Quick start

pip install statespec
from statespec import StateSpec, Transition, apply, validate
from statespec.expr import field

spec = StateSpec(
    name="review", title="Review",
    states={"draft": "Being written", "submitted": "Awaiting review",
            "approved": "Done"},
    fields={"amount": "int"},
    initial="draft", terminal=frozenset({"approved"}),
    transitions=(
        Transition("submit", ("draft",), "submitted",
                   roles=frozenset({"author"})),
        Transition("approve", ("submitted",), "approved",
                   roles=frozenset({"reviewer"}),
                   guard=field("amount").le(100)),
    ),
)

assert validate(spec, known_roles=frozenset({"author", "reviewer"})) == []
apply(spec, "approve", "submitted", frozenset({"reviewer"}), {"amount": 40})
# -> "approved". Wrong role -> PermissionDenied; amount 500 -> GuardRejected;
# fire() returns the same decision plus structured evidence per condition.

Every claim above is exercised by the test suite: the refusal taxonomy and its precedence in tests/test_core.py, the expression grammar and typechecking in tests/test_expr.py, digests/diff in tests/test_identity.py, and canonicalisation byte-stability against a golden artifact in tests/test_contract_golden.py.

Boundaries (what this does not do)

statespec sits above concurrency and persistence. It decides whether a transition is legal; it does not make the write atomic or durable. It will not stop a race between two concurrent transitions (pair it with optimistic locking or a version column at the persistence layer), a forgotten lock, an out-of-band mutation that sets status around the interpreter, or a cross-system inconsistency. The "single enforcement path" property holds only if every status write in the application routes through apply/fire — enforce that with a repo-level convention or CI gate, not by trust. The digests identify policy change; they do not verify that deployed code matches the artifact — that check belongs to CI or a control plane.

Provenance

Extracted from ConceptPending/baseplate branch example/state-machine at tag statespec-v0.3.0 (commit 2aca24e, 2026-06-10), where the kernel was developed and frozen. The only changes at extraction were the import rename app.statespecstatespec and doc-path adjustments. This repository is the kernel's authoritative home from statespec-v0.4.0 onward; the in-tree copy in baseplate remains frozen at v0.3.0 as part of the reference example.

Versioning and freeze discipline

Kernel tags form their own series (statespec-vX.Y.Z), separate from any consuming product's versions. The canonicalisation and digest rules are a frozen contract: any change to the policy-artifact envelope bumps schema_version and the kernel tag together, and is recorded in docs/policy-artifact-contract.md's changelog. Changes that alter existing digests are breaking and require explicit re-binding by consumers (e.g. approval planes). Exceptions to the freeze: genuine bugs, security issues, or contract defects.

Known consumers: baseplate (reference example, v0.3.0), baseplate-control (approval plane; vendors this kernel byte-identically and verifies digests independently).

Development

python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/ruff check src tests

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

statespec-0.4.1.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

statespec-0.4.1-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file statespec-0.4.1.tar.gz.

File metadata

  • Download URL: statespec-0.4.1.tar.gz
  • Upload date:
  • Size: 34.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for statespec-0.4.1.tar.gz
Algorithm Hash digest
SHA256 4055cfb4577f324ddfc7aa3c7d6619b2aef88ba8533bc284a21f138d68804a01
MD5 4659aa5d2500b8536b5590f254da47da
BLAKE2b-256 c2e397bb84eaa7955ba4e904db0e869dbd66b6b495ee0fb5e31f536a330346b2

See more details on using hashes here.

File details

Details for the file statespec-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: statespec-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for statespec-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d85cd920e95d29cfe5ff9d73b571c7b120eba1363308d1ab03a4205c8607fa6e
MD5 8ed05836725c4288a89d5f540a138e0c
BLAKE2b-256 b5a5e6324f5c87367cb82730470357a987281f424d39ab413d539e71fb121f57

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page