Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: fruwehq/determa-state-conformance
ref: 600523ca08c3b8a6ee790439a32dc4ce47f71b95
ref: 86cb08a98267371b96b8f4908409aee022e4b4fe
path: .pinned/determa-state-conformance
- name: Check out pinned specification
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: fruwehq/determa-state-spec
ref: c1635d74e6a216301a8986d37be8ce7e7111dfd7
ref: 318ef1f16ae024770090bd338c8b70056df2855b
path: .pinned/determa-state-spec
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
Expand All @@ -55,3 +55,32 @@ jobs:
DETERMA_CONFORMANCE_DIR: ${{ github.workspace }}/.pinned/determa-state-conformance
DETERMA_SPEC_DIR: ${{ github.workspace }}/.pinned/determa-state-spec
run: pytest conformance -q

postgresql:
runs-on: ubuntu-24.04
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: determa_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d determa_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
cache: pip
- name: Install
run: pip install -e '.[dev,postgresql]'
- name: PostgreSQL adapter tests
env:
DETERMA_POSTGRESQL_DSN: postgresql://postgres:postgres@localhost:5432/determa_test
run: pytest tests/test_postgresql_store.py -q
30 changes: 22 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,31 @@ package so it can coexist with the umbrella `determa` launcher.
The implementation is conformant only when it passes the language-neutral suite.
The synchronized 0.1.0 release uses these immutable inputs:

- specification: `c1635d74e6a216301a8986d37be8ce7e7111dfd7`;
- conformance: `600523ca08c3b8a6ee790439a32dc4ce47f71b95` (110 core cases plus
persistence profiles).
- specification: `318ef1f16ae024770090bd338c8b70056df2855b`;
- conformance: `86cb08a98267371b96b8f4908409aee022e4b4fe` (110 core cases,
persistence profiles, and the 85-vector execution-checkpoint profile).

The package metadata is `0.1.0` for the next synchronized release; the specification,
conformance suite, Python engine, and Rust engine version together.

## Boundaries

The implemented public API is `load_bundle`, `create`, and `dispatch`, plus validation
and error types exported by `determa.state`. It implements the exact `format: 1`
The pure public API remains `load_bundle`, `create`, and `dispatch`, plus validation
and error types exported by `determa.state`. The optional synchronous `ExecutionHost`
and execution-store APIs wrap that core without changing its exact `format: 1`
grammar. Do not restore abandoned draft field names or compatibility aliases.

The core is a pure foreground transform over one root ownership aggregate. It has no
hidden queues, timers, stores, snapshots, migration, enabled-event inspection, or
standardized execution CLI. Snapshot portability, machine definition migration or
hot-swap, package imports, and living tutorials are separate initiatives.
hidden queues, timers, stores, or standardized execution CLI. Portable aggregate
migration remains pure. The optional host owns checkpoint transactions, accepted
pending delivery, receipts, outbox state, retention, and tombstones. The CLI remains
validation-only.

Layout:

- `src/determa/state/` — loader, validator, CEL profile, model, and engine;
- `src/determa/state/checkpoint.py`, `host.py`, and `stores/` — optional portable
checkpoint validation, synchronous host orchestration, registry, and adapters;
- `src/determa/state/data/machine.schema.json` — exact pinned normative schema;
- `tests/` — hermetic implementation tests;
- `conformance/` — black-box format-1 harness and immutable pins;
Expand All @@ -49,6 +53,13 @@ Layout:
- Keep JSON/public identifiers unabbreviated and use only exact normative grammar.
- Unit tests remain hermetic and offline. Conformance may use its immutable checkouts.
- Preserve lazy CEL and JSON Schema imports where practical.
- Preserve lazy Psycopg import and explicit file/database schema setup. Never add
checkpoint or root-marker deletion.
- Every execution-store transaction is root-bound. Shared application transactions
use the host-owned callback API; never expose raw native/store transaction injection
on portable host operations or return committed/pending responses before commit.
- Durable and retention profile checks use the configured store instance. SQLite and
PostgreSQL schema health requires the exact explicit schema version and shape.

## Gates

Expand All @@ -60,6 +71,9 @@ pytest -q
DETERMA_CONFORMANCE_DIR=/path/to/conformance \
DETERMA_SPEC_DIR=/path/to/spec \
pytest conformance -q

# Optional, only with a configured service and installed postgresql extra
DETERMA_POSTGRESQL_DSN=postgresql://... pytest tests/test_postgresql_store.py -q
```

`make check` runs lint, type checking, and unit tests. `make conformance` fetches or
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test conformance lint typecheck check all sync-schema
.PHONY: test conformance postgresql-test lint typecheck check all sync-schema

# Unit tests — the implementation's own suite. Hermetic and offline.
test:
Expand All @@ -10,6 +10,10 @@ test:
conformance:
pytest conformance -q

# Optional live adapter test. Requires DETERMA_POSTGRESQL_DSN and the postgresql extra.
postgresql-test:
pytest tests/test_postgresql_store.py -q

# Refresh the bundled JSON Schema from the immutable format-1 specification pin
# (or DETERMA_SPEC_DIR=/path/to/determa-state-spec).
sync-schema:
Expand Down
105 changes: 94 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Python implementation of [Determa State](https://github.com/fruwehq/determa-stat
a language-agnostic statechart engine with a shared normative conformance suite.

This release implements Determa State `format: 1` at the synchronized specification
commit `c1635d74e6a216301a8986d37be8ce7e7111dfd7`. Correctness is determined by the
110-case core suite and persistence profiles at conformance commit
`600523ca08c3b8a6ee790439a32dc4ce47f71b95`.
commit `318ef1f16ae024770090bd338c8b70056df2855b`. Correctness is determined by the
110-case core suite, persistence profiles, and 85-vector execution-checkpoint profile
at conformance commit `86cb08a98267371b96b8f4908409aee022e4b4fe`.

The package metadata is `0.1.0` for the next synchronized release of the specification,
conformance suite, Python engine, and Rust engine.
Expand All @@ -26,6 +26,12 @@ python -m pip install -e .
The distribution is `determa-state`; the import is `determa.state`. It also installs
`determa-state` and `determa-state-python` commands.

PostgreSQL support is optional and imports Psycopg only when that adapter is used:

```sh
python -m pip install -e '.[postgresql]'
```

## Define A Bundle

Format 1 uses one self-contained bundle containing one or more machines:
Expand Down Expand Up @@ -141,11 +147,83 @@ migrations return a deterministic `MigrationFailure` and do not mutate the suppl
artifact or resolver.

Definition and descriptor resolvers are protocols, so applications can back them with
an immutable registry or a transaction-local cache. Database schemas, broker
acknowledgement, retries, and quarantine remain host responsibilities; the conformance
persistence profile verifies the required transaction ordering.
an immutable registry or a transaction-local cache.

## Run A Checkpoint Host

`ExecutionHost` is an optional synchronous durable-host layer. It stores one strict
portable checkpoint per root and implements durable acceptance, committed receipts,
pending delivery, outbox lifecycle, keyed migration, bounded replay retention, CAS,
and terminal tombstones. Direct store injection does not require a registry:

```python
store = ds.SQLiteExecutionStore("state.db")
store.setup_schema() # always explicit
resolver = ds.MemoryArtifactResolver(definitions={bundle.fingerprint: bundle})
host = ds.ExecutionHost(store, resolver)

created = host.create(
bundle,
machine_id="counter",
root_instance_id="counter-42",
creation_id="create-counter-42",
bindings={},
)
checkpoint = host.read_checkpoint("counter-42").document
```

`MemoryExecutionStore` is ephemeral. `FileExecutionStore` provides locked atomic
replacement and restart persistence only. SQLite advertises durable single-writer
storage only with its verified transaction, journal, and synchronization settings.
The optional PostgreSQL adapter provides concurrent CAS and host-owned shared
application transactions. Every store transaction is bound to one exact root.

SQLite and PostgreSQL accept explicit `replay_retention="permanent"` and
`outbox_retention="strict" | "compact"` configuration. These settings add only the
retention capabilities they actually enforce. Database setup records that policy
immutably; reopening with a different policy is rejected, and database guards reject
native root-checkpoint deletion or policy mutation. `ExecutionHost` validates required
capabilities and composed profiles against the injected store. Strong retention
capabilities are withheld before schema setup and whenever policy or guard validation
fails:

```python
store = ds.SQLiteExecutionStore(
"bank.db",
replay_retention="permanent",
outbox_retention="strict",
)
store.setup_schema()
host = ds.ExecutionHost(
store,
resolver,
required_capabilities={
ds.DURABLE_SINGLE_WRITER,
ds.ROOT_IDENTITY_RETENTION,
ds.PERMANENT_RECEIPT_RETENTION,
},
profile="exactly_once_committed_processing",
)
```

For PostgreSQL application composition, `run_shared_transaction` opens and owns one
native transaction. Its callback receives the Psycopg connection plus a root-bound
staging surface for exactly one host operation. That operation returns only
`StagedExecutionResult`; the portable committed or pending response is returned by
`run_shared_transaction` after the native transaction commits. Callback failure rolls
back both application writes and checkpoint work.

## Implemented Core
File and database schema setup is never implicit. SQLite and PostgreSQL validate an
explicit schema version and the exact required tables, columns, types, nullability,
primary keys, indexes, immutable policy rows, and deletion-protection triggers before
checkpoint use.

`ExecutionStoreRegistry` starts empty. `register_bundled_execution_stores` registers
`memory`, `file`, `sqlite`, and `postgresql` through the same public operation used by
third-party factories. URI resolution extracts only the scheme; each factory owns its
configuration. Root checkpoint deletion is unsupported.

## Implemented Surface

- strict format-1 loading, default materialization, bundle fingerprinting, and exact
source-level scalar handling;
Expand All @@ -161,10 +239,15 @@ persistence profile verifies the required transaction ordering.
- canonical aggregate serialization/restoration, portable typed values, package
attachments, exact definition resolution, trusted lazy migration, deterministic
audits, resource limits, and atomic migrate-and-dispatch results.

Format 1 deliberately does not define native queues, timers, deferral, dead letters,
database schemas, package imports, standardized enabled-event inspection, or a
standardized execution CLI.
- strict portable execution-checkpoint parsing, canonical digests, semantic
validation, synchronous transaction/CAS/replay orchestration, receipts, pending
delivery, outbox lifecycle, replay retention, and root tombstones;
- public direct execution-store injection and explicit registration for memory, file,
SQLite, optional PostgreSQL, and third-party adapters.

Format 1 deliberately does not define timers, a broker implementation, package
imports, standardized enabled-event inspection, or a standardized execution CLI.
Adapter storage schemas are implementation-owned and require explicit setup.

The implementation-local CLI only validates a bundle:

Expand Down
Loading