Skip to content
6 changes: 3 additions & 3 deletions contracts/schema-publication/entries/runtime-snapshot-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"contract_id": "runtime-snapshot-v1",
"schema_path": "contracts/schemas/snapshots/runtime-snapshot-v1.json",
"stability": "draft",
"content_hash": "4388410c8e7536fef3f1251b7649b7d2cefef3764bf9da31d221430c92935879",
"content_hash": "90ca4bb76c8ff2e46ba7facec0d5199bdd682f379a63686e03b4cbf8b261304d",
"last_change": {
"summary": "Added typed guest-observed operating-system identity bound to operation, envelope, configuration, observer, and sequence for issue #1077.",
"content_hash": "4388410c8e7536fef3f1251b7649b7d2cefef3764bf9da31d221430c92935879"
"summary": "Published participant episode closure records for issue #1092.",
"content_hash": "90ca4bb76c8ff2e46ba7facec0d5199bdd682f379a63686e03b4cbf8b261304d"
}
}
11 changes: 11 additions & 0 deletions contracts/schemas/snapshots/runtime-snapshot-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -11558,6 +11558,17 @@
"title": "Participant Crossing History",
"type": "object"
},
"participant_episode_closure_records": {
"additionalProperties": {
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"title": "Participant Episode Closure Records",
"type": "object"
},
"participant_episode_history": {
"additionalProperties": {
"items": {
Expand Down
287 changes: 287 additions & 0 deletions docs/decisions/issue-1092-local-control-plane-durability-preflight.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/explain/reference/shared-semantic-integrity.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ so they are tracked by their own requirements, not here.
| Planner dependency, ordering, refresh, and applicability semantics | RUN-303 | planning | `implementations/python/packages/raes_processor/semantics/planner.py`, `implementations/python/packages/raes_processor/planner/__init__.py`, `specs/formal/planner/README.md`, `specs/formal/planner/dependency-ordering.md`, `implementations/python/tests/test_semantics_planner.py`, `implementations/python/tests/test_runtime_planner.py` | active |
| Live execution state and lifecycle (snapshots, results, history) | RUN-304, API-402 | execution, observation | `implementations/python/packages/raes_runtime/manager.py`, `implementations/python/packages/raes_runtime/result_contracts.py`, `implementations/python/packages/raes_processor/models/`, `implementations/python/tests/test_runtime_manager.py`, `implementations/python/tests/test_runtime_models.py` | active |
| Runtime result and evaluator-result contracts | ASR-503, API-402 | execution, observation | `implementations/python/packages/raes_runtime/result_contracts.py`, `specs/formal/runtime-contracts/README.md`, `specs/formal/runtime-contracts/workflow-results.md`, `specs/formal/runtime-contracts/evaluator-results.md`, `implementations/python/tests/test_runtime_contracts.py`, `implementations/python/tests/test_run_311_participant_episode_lifecycle.py` | active |
| Control-plane semantics (auth, durable state, idempotency, audit) | API-403, API-404 | execution, observation | `implementations/python/packages/raes_runtime/control_plane_api/__init__.py`, `implementations/python/packages/raes_runtime/control_plane_security.py`, `implementations/python/packages/raes_runtime/control_plane_store.py`, `implementations/python/tests/test_runtime_control_plane.py`, `implementations/python/tests/test_runtime_control_plane_api.py` | active |
| Control-plane semantics (auth, durable state, idempotency, audit) | API-403, API-404 | execution, observation | `implementations/python/packages/raes_runtime/control_plane_api/__init__.py`, `implementations/python/packages/raes_runtime/control_plane_security.py`, `implementations/python/packages/raes_runtime/control_plane_store.py`, `implementations/python/packages/raes_runtime/control_plane_store_local.py`, `implementations/python/packages/raes_runtime/control_plane_store_paths.py`, `docs/decisions/issue-1092-local-control-plane-durability-preflight.md`, `implementations/python/tests/test_runtime_control_plane.py`, `implementations/python/tests/test_runtime_control_plane_api.py`, `implementations/python/tests/test_issue_1092_control_plane_crash_consistency.py` | active |
| Backend and processor identity, capability, and compatibility manifests | API-401, API-412 | planning, execution | `implementations/python/packages/raes_processor/manifest.py`, `implementations/python/packages/raes_processor/capabilities.py`, `implementations/python/packages/raes_contracts/apparatus.py`, `implementations/python/packages/raes_contracts/manifest_authority.py`, `implementations/python/tests/test_backend_manifest.py`, `implementations/python/tests/test_processor_manifest.py` | active |
| Concept authority, controlled vocabularies, reference models, and semantic profiles (meta-layer) | GOV-920 | authoring, validation, compilation, planning, execution | `specs/concept-authority/concept-authority.md`, `specs/concept-authority/semantic-profiles.md`, `implementations/python/packages/raes_contracts/semantic_profiles.py`, `implementations/python/packages/raes_contracts/controlled_vocabularies.py`, `implementations/python/packages/raes_contracts/reference_models.py`, `docs/explain/reference/shared-concept-model.md`, `implementations/python/tests/test_concept_authority.py`, `implementations/python/tests/test_semantic_profiles.py` | active |
| Participant episode lifecycle boundaries and authored episode structure (initialization, reset, completion, timeout, truncation, interruption) | RUN-311, SEM-222, DSL-120, ACT-623 | authoring, validation, execution, observation | `docs/decisions/adrs/adr-013-participant-episode-lifecycle-boundaries.md`, `docs/decisions/adrs/adr-054-participant-runtime-observable-lifecycle.md`, `specs/formal/participant-episode-model/README.md`, `docs/decisions/issue-122-sem-222-episode-budget-model-preflight.md`, `implementations/python/packages/raes_contracts/participant_episode_closure.py`, `implementations/python/packages/raes_runtime/participant_result_contracts.py`, `implementations/python/tests/test_run_311_participant_episode_lifecycle.py`, `implementations/python/tests/test_sem_222_episode_termination_semantics.py`, `implementations/python/tests/test_sem_222_episode_termination_oracle.py` | partial |
Expand Down
43 changes: 43 additions & 0 deletions docs/explain/sdl/runtime-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,49 @@ header identity must pass an explicit `ControlPlaneSecurityConfig`, set
`trust_proxy_identity_headers=True`, and only trust those headers behind an
authenticated proxy that strips caller-supplied identity headers.

The local control-plane store persists snapshots, operations, idempotency
claims, and audit events in a single SQLite WAL database. Full synchronous
transactions and a unique idempotency index make concurrent same-host writers
and participant transition commits atomic. A backend claim is stored before
execution, and its resulting snapshot and terminal operation record commit in
one transaction. Startup marks an orphaned non-terminal record `FAILED` with
an explicit indeterminate-outcome diagnostic and never replays it; retaining
the idempotency claim prevents a retry from blindly repeating backend effects.
On first use, legacy JSON state is imported without deleting its source and is
copied to a timestamped backup. Payload digests and SQLite integrity checks
detect accidental durable-state corruption. Owned POSIX store directories are
created or migrated to `0700` and the main SQLite database to `0600`. SQLite
alone owns descriptors for the main database, WAL, shared-memory, and rollback
journal. OpenRÆ uses descriptor-free metadata inspection and path-based mode
tightening for type, owner, private-mode, and main-database same-file checks,
so an independent `close()` cannot cancel SQLite's POSIX locks. Existing opens
use URI `mode=rw`; only first creation uses
`mode=rwc`, preventing a disappeared database from being silently recreated.
The initialized database identity remains pinned for the store lifetime, and
hard-linked aliases are rejected. Unsafe symlink, reparse, type, owner, mode, or
identity changes fail closed. If a commit reports an error after its outcome is
uncertain, the runtime reloads both durable caches; a failed reload poisons the
runtime until restart rather than allowing another mutation from stale state.

Built-in stores use the complete crash-atomic commit capability. Existing 3.x
custom `ControlPlaneStore` adapters remain accepted when they implement the
pre-atomic structural contract: a centralized compatibility seam warns once per
runtime and uses lookup-then-save claims, ordered snapshot/record writes, and
per-record recovery. This mode preserves legacy behavior but has documented
claim and terminal-write race/crash windows and is scheduled for removal in
version 4; custom adapters should implement `claim_record` and both atomic
terminal/recovery methods before upgrading.

The local runtime is deliberately single-process. Its cached snapshot does not
yet implement cross-process compare-and-swap, so a non-blocking filesystem
lease admits one `RuntimeControlPlane` owner and rejects another, including
inherited post-fork use. POSIX runtimes also hold a store-directory guard so
unlinking or replacing the owner-file path cannot admit a second owner. Close
drains admitted composite calls, including their nested guarded work, before it
releases authority. Run one ASGI worker with reload disabled. This is a
single-host reference boundary, not a distributed queue, replication, or
multi-host availability claim.

Bearer and verified-proxy authentication require the same exact target binding.
An identity with no target, and an explicitly supplied bearer that is unknown,
revoked, or scoped to another target, is rejected; a rejected bearer never
Expand Down
13 changes: 13 additions & 0 deletions docs/requirements/API-404/requirement.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,16 @@ Requirement inventory phase. Status audit deferred until the full canonical grap
- TESTS → TEST `implementations/python/tests/test_runtime_control_plane.py` (Core control-plane unit tests)
- TESTS → TEST `implementations/python/tests/test_runtime_control_plane_api.py` (HTTP/JSON control-plane API tests — auth, idempotency, durability, audit)
- TESTS → TEST `implementations/python/tests/test_issue_1093_request_rejection_offload.py` (Non-blocking, saturation-bounded, fail-closed request rejection audit tests)
- IMPLEMENTS → GITHUB_ISSUE `1092` (Make the local control plane crash-consistent and explicitly single-process)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store.py` (Atomic terminal commits and interrupted-operation reconciliation contract)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_recovery.py` (Conservative startup recovery policy for interrupted operations)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_durability.py` (Commit-outcome cache publication, reconciliation, and poison-on-unknown behavior)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_lifecycle.py` (Draining close, nested-call admission, and durability-poison boundary)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_lease.py` (Secure single-process local runtime ownership)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_snapshots.py` (Compatibility-preserving portable snapshot serialization split)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_local.py` (Required WAL admission, pinned database identity, durable legacy backup copies, and atomic transactions)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_legacy.py` (Complexity-bounded legacy JSON import readers)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_paths.py` (Descriptor-verified private directories, fail-closed durability synchronization, and metadata-only SQLite path validation)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/control_plane_store_compatibility.py` (Deprecated 3.x custom-store fallback and optional atomic capability adapter)
- DOCUMENTS → DOCUMENTATION `docs/decisions/issue-1092-local-control-plane-durability-preflight.md` (Crash recovery and supported process topology)
- TESTS → TEST `implementations/python/tests/test_issue_1092_control_plane_crash_consistency.py` (Atomic and legacy terminal commit, WAL admission, backup file/directory synchronization, interrupted-operation recovery, descriptor-free SQLite paths, URI no-recreation, multiprocess stress, retry, and runtime-owner tests)
2 changes: 2 additions & 0 deletions docs/requirements/SEM-222/requirement.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ Primary-source refresh shows that episode lifecycle meaning must be explicit if
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/participant_result_contracts.py` (SEM-222 runtime episode-closure validation diagnostics seam (EBM-10 enforcement point))
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/result_contracts.py` (SEM-222 public re-export of participant_episode_closure_contract_diagnostics)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/runtime_state.py` (SEM-222 RuntimeSnapshot participant_episode_closure_records carrier (canonical closure-validation wiring))
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/contracts/realization_plans.py` (Published runtime-snapshot-v1 participant episode closure-record carrier)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_conformance/conformance/snapshot_semantics.py` (Published runtime snapshot closure-record preservation and semantic validation)
- IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/_snapshot_updates.py` (RuntimeSnapshot update-builder module split out to admit the SEM-222 closure-records field under the source-size cap)
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from raes_contracts.participant_concurrency import iter_participant_concurrency_snapshot_violations
from raes_contracts.participant_episode import iter_participant_episode_snapshot_violations
from raes_contracts.participant_episode_closure import iter_participant_episode_closure_violations
from raes_contracts.participant_information_state_history import (
iter_participant_information_state_snapshot_violations,
)
Expand Down Expand Up @@ -111,6 +112,10 @@ def _snapshot_from_envelope(payload: dict[str, Any]) -> RuntimeSnapshot:
participant_address: [event.model_dump(mode="json") for event in history]
for participant_address, history in validated.participant_episode_history.items()
},
participant_episode_closure_records={
participant_address: [dict(record) for record in records]
for participant_address, records in validated.participant_episode_closure_records.items()
},
participant_behavior_history={
participant_address: [event.model_dump(mode="json") for event in history]
for participant_address, history in validated.participant_behavior_history.items()
Expand Down Expand Up @@ -179,6 +184,18 @@ def _participant_episode_snapshot_diagnostics(
]


def _participant_episode_closure_snapshot_diagnostics(
snapshot: RuntimeSnapshot,
) -> list[Diagnostic]:
return [
_diagnostic(_SEMANTIC_INVALID_DIAGNOSTIC_CODE, address, message)
for address, message in iter_participant_episode_closure_violations(
snapshot.participant_episode_closure_records,
snapshot.participant_episode_history,
)
]


def _participant_behavior_snapshot_references(
snapshot: RuntimeSnapshot,
) -> tuple[
Expand Down Expand Up @@ -470,6 +487,7 @@ def _runtime_snapshot_semantic_diagnostics(
*workflow_result_contract_diagnostics(snapshot),
*evaluation_result_contract_diagnostics(snapshot),
*_participant_episode_snapshot_diagnostics(snapshot),
*_participant_episode_closure_snapshot_diagnostics(snapshot),
*_participant_behavior_snapshot_diagnostics(snapshot),
*_shared_state_snapshot_diagnostics(snapshot),
*_participant_concurrency_snapshot_diagnostics(snapshot),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ class RuntimeSnapshotEnvelopeModel(ContractModel):
proposition_truth_results: dict[str, PropositionTruthResultModel] = Field(default_factory=dict)
participant_episode_results: dict[str, ParticipantEpisodeStateModel] = Field(default_factory=dict)
participant_episode_history: dict[str, list[ParticipantEpisodeHistoryEventModel]] = Field(default_factory=dict)
participant_episode_closure_records: dict[str, list[dict[str, Any]]] = Field(default_factory=dict)
participant_behavior_history: dict[str, list[ParticipantBehaviorHistoryEventModel]] = Field(default_factory=dict)
participant_control_history: dict[str, list[ParticipantControlOccurrenceModel]] = Field(default_factory=dict)
participant_crossing_history: dict[str, list[ParticipantCrossingOccurrenceModel]] = Field(default_factory=dict)
Expand Down
Loading