Skip to content
Draft
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
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.

## Current Scope

The current runtime scope includes:
Expand Down
15 changes: 14 additions & 1 deletion docs/requirements/API-404/requirement.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type: FUNCTIONAL
priority: MUST
wave: 1
created_at: 2026-04-03T05:55:58.825305Z
updated_at: 2026-04-05T06:33:22.964497Z
updated_at: 2026-08-12T00:00:00.000000Z
---

# API-404 — Secure, Durable, And Idempotent Control-Plane Semantics
Expand All @@ -22,7 +22,20 @@ Requirement inventory phase. Status audit deferred until the full canonical grap
## Traceability

- IMPLEMENTS → GITHUB_ISSUE `8` (API-404: Secure, Durable, And Idempotent Control-Plane Semantics)
- IMPLEMENTS → GITHUB_ISSUE `1092` (Make the local control plane crash-consistent and explicitly single-process)
- IMPLEMENTS → SPEC `contracts/schemas/control-plane/operation-receipt-v1.json` (Operation receipt JSON Schema — submission acknowledgment contract)
- IMPLEMENTS → SPEC `contracts/schemas/control-plane/operation-status-v1.json` (Operation status JSON Schema — durable operation state contract)
- 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_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_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 @@ -76,6 +77,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 @@ -170,6 +175,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 @@ -461,6 +478,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 @@ -368,6 +368,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
Loading