RuntimeStore
scripts/goal-runner/runtime_store.py defines the canonical RuntimeStore API. Every persistent mutation in ASF50 flows through it.
Construction
from pathlib import Path
from runtime_store import RuntimeStore
store = RuntimeStore(Path("scripts/goal-runner/local/runtime"))
store.migrate() # idempotent schema migration
migrate() reads schema_migrations and applies any pending migrations. It is safe to call on every orchestrator startup.
CRUD API
The store exposes a narrow API:
store.insert(table: str, row: dict) -> None
store.upsert(table: str, predicate: dict, row: dict) -> None
store.get(table: str, key: str, value: str) -> dict | None
store.list(table: str, **filters) -> list[dict]
store.delete(table: str, **filters) -> None # restricted to repair paths
There is no general "execute SQL" method.
Schema migrations
schema_migrations is a small table:
version INTEGER PRIMARY KEY,
applied_at TEXT NOT NULL,
description TEXT
A new migration is added by appending to runtime_store.MIGRATIONS and incrementing the version. The orchestrator refuses to start if the DB schema is older than the lowest migration.
Transaction semantics
Each insert/upsert/delete runs inside a transaction. The transaction is committed before the function returns. If the function raises, the transaction is rolled back.
Closing
Always close the store:
store.close()
In the orchestrator, this is done in a finally block.