fix(history): bound persisted identifier bytes before restore reads

This commit is contained in:
Vito Sansevero
2026-10-17 18:10:37 -07:00
parent 8b922c6b64
commit 8e014c0ebe
4 changed files with 221 additions and 8 deletions
+10 -4
View File
@@ -79,11 +79,16 @@ TABLE_COLUMNS = {
def _digest_check(column: str, nullable: bool = False) -> str:
check = (
f"typeof({column}) = 'text' AND length({column}) = 64 "
f"AND length(CAST({column} AS BLOB)) = 64 "
f"AND {column} NOT GLOB '*[^0-9a-f]*'"
)
return f"{column} IS NULL OR ({check})" if nullable else check
def _bounded_uuid_check(column: str) -> str:
return f"{_uuid_check(column)} AND length(CAST({column} AS BLOB)) = 36"
def _enum_check(column: str, values: frozenset[str]) -> str:
return (
f"typeof({column}) = 'text' AND {column} IN ("
@@ -108,8 +113,9 @@ TABLE_CHECKS = {
"positive_snapshot_id IS NOT NULL OR negative_snapshot_id IS NOT NULL",
),
"execution_run_contexts": (
_uuid_check("run_id"),
"typeof(anchor_id) = 'text' AND length(anchor_id) BETWEEN 1 AND 128",
_bounded_uuid_check("run_id"),
"typeof(anchor_id) = 'text' AND length(anchor_id) BETWEEN 1 AND 128 "
"AND length(CAST(anchor_id AS BLOB)) <= 512",
_digest_check("context_id"),
"typeof(evidence_json) = 'text' AND length(CAST(evidence_json AS "
"BLOB)) <= 8192",
@@ -117,11 +123,11 @@ TABLE_CHECKS = {
f"{column} IS NULL OR (typeof({column}) = 'integer' AND {column} > 0)"
for column in ("positive_prompt_id", "negative_prompt_id", "pair_id")
),
f"reference_epoch IS NULL OR ({_uuid_check('reference_epoch')})",
f"reference_epoch IS NULL OR ({_bounded_uuid_check('reference_epoch')})",
"typeof(capture_version) = 'integer' AND capture_version = 1",
),
"execution_context_capture": (
_uuid_check("run_id"),
_bounded_uuid_check("run_id"),
_enum_check("state", BUNDLE_STATES),
_enum_check("reason", CAPTURE_REASONS),
"length(CAST(reason AS BLOB)) <= 64",
+31 -4
View File
@@ -92,6 +92,30 @@ _TABLE_CHECKS = {
"execution_history_metadata": _METADATA_CHECKS,
"execution_runs": _RUN_CHECKS,
}
# Row-only guards preserve the supported v1 DDL fingerprint while bounding reads.
_ROW_BYTE_CHECKS = {
"execution_history_metadata": ("length(CAST(storage_epoch AS BLOB)) = 36",),
"execution_runs": (
*(
f"length(CAST({column} AS BLOB)) = 36"
for column in (
"run_id",
"session_id",
"job_id",
"storage_epoch",
)
),
*(
f"{column} IS NULL OR length(CAST({column} AS BLOB)) <= {limit}"
for column, limit in (
("node_id", 512),
("node_type", 512),
("exception_type", 1024),
)
),
),
}
_INDEXES = {
"idx_execution_runs_identity": (True, ("session_id", "queue_item_id")),
"idx_execution_runs_observed": (False, ("observed_dequeue_at", "run_id")),
@@ -127,11 +151,12 @@ def history_schema_error(
if tables.keys() != _TABLE_COLUMNS.keys():
return "Incomplete execution history schema"
metadata = conn.execute(
"SELECT * FROM execution_history_metadata LIMIT 2"
"SELECT CASE WHEN typeof(schema_version) = 'integer' "
"THEN schema_version ELSE NULL END FROM execution_history_metadata LIMIT 2"
).fetchall()
if len(metadata) != 1 or len(metadata[0]) != 3 or metadata[0][1] not in (1, 2):
if len(metadata) != 1 or len(metadata[0]) != 1 or metadata[0][0] not in (1, 2):
return "Unsupported execution history metadata/version"
version = metadata[0][1]
version = metadata[0][0]
if version == 1 and context_present:
return "Unexpected execution contexts for history v1"
if not allow_missing and version != SCHEMA_VERSION:
@@ -173,7 +198,9 @@ def history_schema_error(
or any(key[3] or key[4] != "BINARY" for key in keys)
):
return f"{table} has unexpected execution history uniqueness"
predicate = " AND ".join(f"({check})" for check in checks)
predicate = " AND ".join(
f"({check})" for check in (*checks, *_ROW_BYTE_CHECKS[table])
)
if conn.execute(
f"SELECT 1 FROM {table} WHERE NOT ({predicate}) LIMIT 1"
).fetchone():