From 6ab42b322b724918704c324d018e83f65ad3bb84 Mon Sep 17 00:00:00 2001 From: Christian-Manuel Butzke Date: Tue, 8 Sep 2026 22:24:36 +0900 Subject: [PATCH 1/2] Conform selected legacy artifact decoding --- AGENTS.md | 6 ++--- README.md | 8 +++---- conformance/persistence.py | 17 ++++++++++++++ conformance/pins.py | 4 ++-- conformance/test_conformance.py | 2 +- scripts/sync_schema.py | 2 +- src/determa/state/wire.py | 2 +- tests/test_persistence.py | 41 +++++++++++++++++++++++++++++++++ 8 files changed, 70 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c880c24..eaa56ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,10 +9,10 @@ This is the Python implementation of Determa State. The distribution is 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: +The current implementation uses these immutable inputs: -- specification: `318ef1f16ae024770090bd338c8b70056df2855b`; -- conformance: `86cb08a98267371b96b8f4908409aee022e4b4fe` (110 core cases, +- specification: `cc4b0d734aa1c5953de75fb53b63e390a3b72761`; +- conformance: `263644f951f342b0eeaa3aceef4877293d2d7c67` (111 core cases, persistence profiles, and the 85-vector execution-checkpoint profile). Version `0.1.0` is the published synchronized release. The specification, conformance diff --git a/README.md b/README.md index 475061e..5561916 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ Python implementation of [Determa State](https://github.com/fruwehq/determa-state-spec), a language-agnostic statechart engine with a shared normative conformance suite. -This release implements Determa State `format: 1` at the synchronized specification -commit `318ef1f16ae024770090bd338c8b70056df2855b`. Correctness is determined by the -110-case core suite, persistence profiles, and 85-vector execution-checkpoint profile -at conformance commit `86cb08a98267371b96b8f4908409aee022e4b4fe`. +This implementation supports Determa State `format: 1` at specification +commit `cc4b0d734aa1c5953de75fb53b63e390a3b72761`. Correctness is determined by the +111-case core suite, persistence profiles, and 85-vector execution-checkpoint profile +at conformance commit `263644f951f342b0eeaa3aceef4877293d2d7c67`. Version `0.1.0` is the published synchronized release of the specification, conformance suite, Python engine, and Rust engine. diff --git a/conformance/persistence.py b/conformance/persistence.py index 70924f4..65f569d 100644 --- a/conformance/persistence.py +++ b/conformance/persistence.py @@ -24,6 +24,7 @@ ) from determa.state.wire import ( canonical_bytes, + load_json_artifact, migration_descriptor_digest, strict_json, ) @@ -107,6 +108,14 @@ def _limits(path: Path, vector: dict[str, Any]) -> MigrationLimits | None: def _run_vector(path: Path, vector: dict[str, Any]) -> None: operation = vector["operation"] expected = vector["expect"] + descriptor_source = ( + (path / vector["migration_descriptor"]).read_bytes() + if operation == "decode_selected_migration_descriptor" + else None + ) + descriptor_snapshot = ( + bytes(descriptor_source) if descriptor_source is not None else None + ) source_key = ( "aggregate_state_package" if operation.startswith("restore_package") @@ -116,6 +125,12 @@ def _run_vector(path: Path, vector: dict[str, Any]) -> None: source_snapshot = bytes(source) if source is not None else None resolver = _resolver(path, vector) try: + if operation == "decode_selected_migration_descriptor": + assert descriptor_source is not None + load_json_artifact(descriptor_source, "migration_descriptor") + assert expected == {"result": "success"}, vector["name"] + assert descriptor_source == descriptor_snapshot + return if operation == "serialize_created_aggregate": bundle = load_bundle((path / vector["source_bundle"]).read_text(encoding="utf-8")) result = create(bundle, **vector["creation"]) @@ -233,6 +248,8 @@ def _run_vector(path: Path, vector: dict[str, Any]) -> None: except ArtifactError as error: assert expected["result"] == "failure", (vector["name"], error.code) assert error.code == expected["code"], (vector["name"], error.code) + if descriptor_source is not None: + assert descriptor_source == descriptor_snapshot if expected.get("caller_still_owns_aggregate"): assert source == source_snapshot if vector.get("repeat_count", 1) > 1: diff --git a/conformance/pins.py b/conformance/pins.py index d0ac803..4e3cbaf 100644 --- a/conformance/pins.py +++ b/conformance/pins.py @@ -4,8 +4,8 @@ from pathlib import Path -CONFORMANCE_COMMIT = "86cb08a98267371b96b8f4908409aee022e4b4fe" -SPEC_COMMIT = "318ef1f16ae024770090bd338c8b70056df2855b" +CONFORMANCE_COMMIT = "263644f951f342b0eeaa3aceef4877293d2d7c67" +SPEC_COMMIT = "cc4b0d734aa1c5953de75fb53b63e390a3b72761" ROOT = Path(__file__).resolve().parent.parent CONFORMANCE_CACHE = ROOT / ".cache" / f"determa-state-conformance-{CONFORMANCE_COMMIT[:12]}" diff --git a/conformance/test_conformance.py b/conformance/test_conformance.py index cf25110..71895bb 100644 --- a/conformance/test_conformance.py +++ b/conformance/test_conformance.py @@ -45,7 +45,7 @@ def _spec_root() -> Path | None: def test_suite_present() -> None: assert CORE_DIR.exists(), "pinned conformance suite is unavailable" - assert len(core_cases()) == 110 + assert len(core_cases()) == 111 assert len(execution_checkpoint_vectors()) == 85 diff --git a/scripts/sync_schema.py b/scripts/sync_schema.py index 85e4830..c4eab95 100644 --- a/scripts/sync_schema.py +++ b/scripts/sync_schema.py @@ -26,7 +26,7 @@ "aggregate-state-package.schema.json", "execution-checkpoint.schema.json", ) -SPEC_COMMIT = "318ef1f16ae024770090bd338c8b70056df2855b" +SPEC_COMMIT = "cc4b0d734aa1c5953de75fb53b63e390a3b72761" def _fetch(name: str) -> str: diff --git a/src/determa/state/wire.py b/src/determa/state/wire.py index 3b3a7f7..0a0690f 100644 --- a/src/determa/state/wire.py +++ b/src/determa/state/wire.py @@ -386,7 +386,7 @@ def _format_code(document: Any, kind: str) -> str | None: format_member, expected_format, version_member, expected_version, format_code, version_code = ( definitions[kind] ) - if format_member in document and document[format_member] != expected_format: + if format_member not in document or document[format_member] != expected_format: return format_code if version_member in document and document[version_member] != expected_version: return version_code diff --git a/tests/test_persistence.py b/tests/test_persistence.py index bd646a3..7856976 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -18,6 +18,7 @@ from determa.state.wire import ( aggregate_state_digest, canonical_bytes, + load_json_artifact, migration_descriptor_digest, strict_json, ) @@ -80,6 +81,46 @@ def _redigest(document): return canonical_bytes(document) +LEGACY_SNAPSHOT = b'''{ + "machine": { + "id": "legacy_job", + "version": "0.0.6" + }, + "configuration": ["idle"], + "extended_state_variables": { + "attempts": 1 + } +}\n''' + + +def test_selected_legacy_migration_descriptor_without_discriminator_is_unsupported() -> None: + source = bytes(LEGACY_SNAPSHOT) + resolver = MemoryArtifactResolver() + + with pytest.raises(ArtifactError) as raised: + resolver.put_migration_descriptor("sha256:" + "0" * 64, source) + + assert raised.value.code == "unsupported_migration_descriptor_format" + assert source == LEGACY_SNAPSHOT + + +@pytest.mark.parametrize( + ("kind", "code"), + [ + ("aggregate_state", "unsupported_aggregate_state_format"), + ("aggregate_state_package", "unsupported_aggregate_state_package_format"), + ("execution_checkpoint", "unsupported_execution_checkpoint_format"), + ], +) +def test_selected_legacy_artifact_decoder_uses_its_exact_format_code( + kind: str, code: str +) -> None: + with pytest.raises(ArtifactError) as raised: + load_json_artifact(LEGACY_SNAPSHOT, kind) + + assert raised.value.code == code + + def test_aggregate_round_trip_is_canonical_and_does_not_mutate_state() -> None: bundle = load_bundle(SOURCE) created = create(bundle, "job", "job-1", "create-1", {}) From 8030122ae2c796edea0f5acb3a69a75e3c927be1 Mon Sep 17 00:00:00 2001 From: Christian-Manuel Butzke Date: Tue, 8 Sep 2026 22:27:11 +0900 Subject: [PATCH 2/2] Align CI with pinned conformance inputs --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a793b93..6a171a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,13 +58,13 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: fruwehq/determa-state-conformance - ref: 86cb08a98267371b96b8f4908409aee022e4b4fe + ref: 263644f951f342b0eeaa3aceef4877293d2d7c67 path: .pinned/determa-state-conformance - name: Check out pinned specification uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: fruwehq/determa-state-spec - ref: 318ef1f16ae024770090bd338c8b70056df2855b + ref: cc4b0d734aa1c5953de75fb53b63e390a3b72761 path: .pinned/determa-state-spec - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: