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.0.tar.gz (33.4 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.0-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: statespec-0.4.0.tar.gz
  • Upload date:
  • Size: 33.4 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.0.tar.gz
Algorithm Hash digest
SHA256 a1866b4ea5d51c59446866ab1aef24f30289b4aff87d7e9592565bdf9b4858ce
MD5 94f8dc935a763d643419103e8a2743da
BLAKE2b-256 4ef0a5e0fb5bac218ea865436d5022de9d3413b6f3cd005dccacecb2b2c62a4a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: statespec-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 20.6 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1c6a3e0d4c5ac4b18e1087f40a8e664d782a5ff68d0f0e56971b218b5076aff1
MD5 84c6b1f10d929a3be176ea83937c9993
BLAKE2b-256 6cff6e53c015a2e96fa9d90e59537891484a01056c34166750c849019377405a

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