feat: add archive client foundation

This commit is contained in:
2026-07-22 14:55:02 +00:00
commit c11a7b5b5b
39 changed files with 2985 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
"""Durable command inbox and client recovery cursors."""
from __future__ import annotations
import hashlib
import json
import sqlite3
from dataclasses import dataclass
from pathlib import Path
class CommandConflict(RuntimeError):
pass
@dataclass(frozen=True)
class CommandAcceptance:
duplicate: bool
acknowledgement_json: str
class ClientStore:
def __init__(self, database: Path):
self.database = database
def initialize(self) -> None:
self.database.parent.mkdir(parents=True, exist_ok=True)
with self._connect() as connection:
version = connection.execute("PRAGMA user_version").fetchone()[0]
if version > 1:
raise RuntimeError(
f"client database schema {version} is newer than supported"
)
connection.executescript(_SCHEMA)
connection.execute("PRAGMA user_version = 1")
if connection.execute("PRAGMA foreign_key_check").fetchall():
raise RuntimeError("client database foreign-key check failed")
def accept_command(
self, command_id: str, command_json: str, acknowledgement_json: str
) -> CommandAcceptance:
payload = _canonical(json.loads(command_json))
acknowledgement = _canonical(json.loads(acknowledgement_json))
digest = hashlib.sha256(payload.encode()).hexdigest()
with self._connect() as connection:
connection.execute("BEGIN IMMEDIATE")
existing = connection.execute(
"SELECT payload_sha256, command_json, acknowledgement_json FROM commands WHERE command_id = ?",
(command_id,),
).fetchone()
if existing:
if existing["payload_sha256"] != digest or existing["command_json"] != payload:
raise CommandConflict("command ID was reused with different content")
return CommandAcceptance(True, existing["acknowledgement_json"])
connection.execute(
"""
INSERT INTO commands (
command_id, payload_sha256, command_json,
acknowledgement_json, state
) VALUES (?, ?, ?, ?, 'received')
""",
(command_id, digest, payload, acknowledgement),
)
return CommandAcceptance(False, acknowledgement)
def list_active_job_cursors(self) -> list[dict[str, object]]:
with self._connect() as connection:
rows = connection.execute(
"""
SELECT job_id, revision, last_event_sequence, state, committed
FROM jobs WHERE state NOT IN ('JOB_STATE_SUCCEEDED',
'JOB_STATE_FAILED', 'JOB_STATE_CANCELLED')
ORDER BY job_id
"""
).fetchall()
return [dict(row) for row in rows]
def _connect(self) -> sqlite3.Connection:
connection = sqlite3.connect(self.database, isolation_level=None, timeout=5)
connection.row_factory = sqlite3.Row
connection.execute("PRAGMA foreign_keys = ON")
connection.execute("PRAGMA journal_mode = WAL")
connection.execute("PRAGMA synchronous = FULL")
connection.execute("PRAGMA busy_timeout = 5000")
return connection
def _canonical(value: object) -> str:
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
_SCHEMA = """
CREATE TABLE IF NOT EXISTS commands (
command_id TEXT PRIMARY KEY,
payload_sha256 TEXT NOT NULL,
command_json TEXT NOT NULL,
acknowledgement_json TEXT NOT NULL,
state TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS jobs (
job_id TEXT PRIMARY KEY,
definition_json TEXT NOT NULL,
state TEXT NOT NULL,
revision INTEGER NOT NULL,
last_event_sequence INTEGER NOT NULL,
committed INTEGER NOT NULL CHECK(committed IN (0, 1))
);
CREATE TABLE IF NOT EXISTS events (
event_id TEXT PRIMARY KEY,
job_id TEXT NOT NULL REFERENCES jobs(job_id),
sequence INTEGER NOT NULL,
event_json TEXT NOT NULL,
UNIQUE(job_id, sequence)
);
CREATE TABLE IF NOT EXISTS file_journal (
operation_id TEXT PRIMARY KEY,
job_id TEXT NOT NULL,
intent_json TEXT NOT NULL,
result_json TEXT,
state TEXT NOT NULL
);
"""