330 lines
13 KiB
Python
330 lines
13 KiB
Python
"""Immutable execution capture and exact, epoch-fenced library navigation hints."""
|
|
|
|
import json
|
|
import sqlite3
|
|
from typing import Iterator
|
|
|
|
from utils.execution_contexts import (
|
|
CAPTURE_REASONS,
|
|
ContextBundle,
|
|
content_digest,
|
|
validate_bundle,
|
|
)
|
|
|
|
FIELDS = ("raw", "effective", "prepend", "append")
|
|
ROLES = ("positive", "negative")
|
|
|
|
|
|
def _prepare(bundle: ContextBundle) -> list[dict]:
|
|
validate_bundle(bundle)
|
|
if bundle.reason not in CAPTURE_REASONS:
|
|
raise ValueError("Invalid capture reason")
|
|
prepared = []
|
|
complete = bool(bundle.contexts)
|
|
for context in bundle.contexts:
|
|
evidence = {"format_version": 1, "role_provenance": context.role_provenance}
|
|
snapshots = []
|
|
for role in ROLES:
|
|
snapshot = getattr(context, role)
|
|
if snapshot is None:
|
|
snapshots.append(None)
|
|
evidence[role] = None
|
|
complete = False
|
|
continue
|
|
values = tuple(getattr(snapshot, field).value for field in FIELDS)
|
|
complete = complete and all(value is not None for value in values)
|
|
snapshots.append((content_digest("snapshot", values), values))
|
|
evidence[role] = {
|
|
field: {
|
|
"provenance": getattr(snapshot, field).provenance,
|
|
"source": getattr(snapshot, field).source,
|
|
"reason": getattr(snapshot, field).reason,
|
|
}
|
|
for field in FIELDS
|
|
}
|
|
if all(snapshot is None for snapshot in snapshots):
|
|
raise ValueError("Context must contain a snapshot")
|
|
context_id = content_digest(
|
|
"context", tuple(s[0] if s else None for s in snapshots)
|
|
)
|
|
encoded = json.dumps(
|
|
evidence,
|
|
ensure_ascii=False,
|
|
allow_nan=False,
|
|
separators=(",", ":"),
|
|
sort_keys=True,
|
|
)
|
|
if len(encoded.encode("utf-8")) > 8192:
|
|
raise ValueError("Oversized context evidence")
|
|
prepared.append(
|
|
{
|
|
"anchor_id": context.anchor_id,
|
|
"context_id": context_id,
|
|
"snapshots": snapshots,
|
|
"evidence_json": encoded,
|
|
}
|
|
)
|
|
if bundle.state == "complete" and not complete:
|
|
raise ValueError("Incomplete scalar capture")
|
|
return sorted(prepared, key=lambda item: item["anchor_id"])
|
|
|
|
|
|
def _existing_row(
|
|
conn: sqlite3.Connection, table: str, columns: tuple[str, ...], values: tuple
|
|
) -> bool:
|
|
row = conn.execute(
|
|
f"SELECT {','.join(columns[1:])} FROM {table} WHERE {columns[0]}=?",
|
|
(values[0],),
|
|
).fetchone()
|
|
if row is None:
|
|
return False
|
|
if tuple(row) != values[1:]:
|
|
raise ValueError("Execution context digest collision")
|
|
return True
|
|
|
|
|
|
def _content_rows(item: dict) -> Iterator[tuple[str, tuple[str, ...], tuple]]:
|
|
snapshot_ids = []
|
|
for snapshot in item["snapshots"]:
|
|
if snapshot is None:
|
|
snapshot_ids.append(None)
|
|
continue
|
|
snapshot_id, values = snapshot
|
|
text_ids = []
|
|
for value in values:
|
|
text_id = None if value is None else content_digest("text", (value,))
|
|
if value is not None:
|
|
yield "execution_context_texts", ("text_id", "text_value"), (
|
|
text_id,
|
|
value,
|
|
)
|
|
text_ids.append(text_id)
|
|
yield "execution_prompt_snapshots", (
|
|
"snapshot_id",
|
|
*(f"{field}_text_id" for field in FIELDS),
|
|
), (snapshot_id, *text_ids)
|
|
snapshot_ids.append(snapshot_id)
|
|
yield "execution_contexts", (
|
|
"context_id",
|
|
"positive_snapshot_id",
|
|
"negative_snapshot_id",
|
|
), (item["context_id"], *snapshot_ids)
|
|
|
|
|
|
def _insert_exact(
|
|
conn: sqlite3.Connection, table: str, columns: tuple[str, ...], values: tuple
|
|
) -> None:
|
|
if not _existing_row(conn, table, columns, values):
|
|
names = ",".join(columns)
|
|
placeholders = ",".join("?" for _ in columns)
|
|
conn.execute(f"INSERT INTO {table} ({names}) VALUES ({placeholders})", values)
|
|
|
|
|
|
def _prompt_hint(conn: sqlite3.Connection, raw: str | None) -> int | None:
|
|
if raw is None:
|
|
return None
|
|
rows = conn.execute(
|
|
"SELECT id FROM prompts WHERE text=? COLLATE BINARY LIMIT 2", (raw,)
|
|
).fetchall()
|
|
return rows[0][0] if len(rows) == 1 else None
|
|
|
|
|
|
def _hints(
|
|
conn: sqlite3.Connection, positive: str | None, negative: str | None
|
|
) -> tuple:
|
|
pos_id, neg_id = _prompt_hint(conn, positive), _prompt_hint(conn, negative)
|
|
pair_id = None
|
|
negative_ambiguous = (
|
|
negative is not None
|
|
and neg_id is None
|
|
and conn.execute(
|
|
"SELECT 1 FROM prompts WHERE text=? COLLATE BINARY LIMIT 1", (negative,)
|
|
).fetchone()
|
|
is not None
|
|
)
|
|
if pos_id is not None and negative is not None and not negative_ambiguous:
|
|
rows = conn.execute(
|
|
"SELECT pp.id FROM prompt_pairs pp LEFT JOIN prompts n ON "
|
|
"n.id=pp.negative_prompt_id "
|
|
"WHERE pp.positive_prompt_id=? AND ((pp.negative_prompt_id IS NULL AND "
|
|
"?='') "
|
|
"OR (pp.negative_prompt_id=? AND n.text=? COLLATE BINARY)) LIMIT 2",
|
|
(pos_id, negative, neg_id, negative),
|
|
).fetchall()
|
|
if len(rows) == 1:
|
|
pair_id = rows[0][0]
|
|
return pos_id, neg_id, pair_id
|
|
|
|
|
|
def _values(conn: sqlite3.Connection, snapshot_id: str | None) -> dict | None:
|
|
if snapshot_id is None:
|
|
return None
|
|
row = conn.execute(
|
|
"SELECT r.text_value,e.text_value,p.text_value,a.text_value "
|
|
"FROM execution_prompt_snapshots s "
|
|
"LEFT JOIN execution_context_texts r ON r.text_id=s.raw_text_id "
|
|
"LEFT JOIN execution_context_texts e ON e.text_id=s.effective_text_id "
|
|
"LEFT JOIN execution_context_texts p ON p.text_id=s.prepend_text_id "
|
|
"LEFT JOIN execution_context_texts a ON a.text_id=s.append_text_id "
|
|
"WHERE s.snapshot_id=?",
|
|
(snapshot_id,),
|
|
).fetchone()
|
|
if row is None:
|
|
raise sqlite3.DatabaseError("Missing execution context snapshot")
|
|
return dict(zip(FIELDS, row))
|
|
|
|
|
|
class ExecutionContextOperations:
|
|
"""Compose with ExecutionHistoryOperations on PromptDatabase."""
|
|
|
|
def write_execution_contexts(
|
|
self, run_id: str, expected_epoch: str, bundle: ContextBundle
|
|
) -> bool:
|
|
prepared = _prepare(bundle)
|
|
with self._execution_transaction(expected_epoch) as conn:
|
|
if (
|
|
conn.execute(
|
|
"SELECT 1 FROM execution_runs WHERE run_id=? AND storage_epoch=?",
|
|
(run_id, expected_epoch),
|
|
).fetchone()
|
|
is None
|
|
):
|
|
return False
|
|
capture = conn.execute(
|
|
"SELECT state,reason,format_version FROM execution_context_capture "
|
|
"WHERE run_id=?",
|
|
(run_id,),
|
|
).fetchone()
|
|
if capture is not None:
|
|
for item in prepared:
|
|
for table, columns, values in _content_rows(item):
|
|
_existing_row(conn, table, columns, values)
|
|
links = conn.execute(
|
|
"SELECT anchor_id,context_id,evidence_json FROM "
|
|
"execution_run_contexts WHERE run_id=? ORDER BY anchor_id",
|
|
(run_id,),
|
|
).fetchall()
|
|
expected = [
|
|
(item["anchor_id"], item["context_id"], item["evidence_json"])
|
|
for item in prepared
|
|
]
|
|
# Compare JSON objects so serialization order never creates a conflict.
|
|
original = [(row[0], row[1], json.loads(row[2])) for row in links]
|
|
proposed = [
|
|
(anchor, context, json.loads(evidence))
|
|
for anchor, context, evidence in expected
|
|
]
|
|
if capture[0] != "conflicting" and (
|
|
tuple(capture)
|
|
!= (bundle.state, bundle.reason, bundle.format_version)
|
|
or original != proposed
|
|
):
|
|
conn.execute(
|
|
"UPDATE execution_context_capture SET "
|
|
"state='conflicting',reason='conflicting' WHERE run_id=?",
|
|
(run_id,),
|
|
)
|
|
return True
|
|
for item in prepared:
|
|
for table, columns, values in _content_rows(item):
|
|
_insert_exact(conn, table, columns, values)
|
|
raw = [
|
|
snapshot[1][0] if snapshot else None
|
|
for snapshot in item["snapshots"]
|
|
]
|
|
positive_id, negative_id, pair_id = _hints(conn, *raw)
|
|
conn.execute(
|
|
"INSERT INTO "
|
|
"execution_run_contexts(run_id,anchor_id,context_id,evidence_json,"
|
|
"positive_prompt_id,negative_prompt_id,pair_id,reference_epoch,"
|
|
"capture_version) VALUES(?,?,?,?,?,?,?,?,1)",
|
|
(
|
|
run_id,
|
|
item["anchor_id"],
|
|
item["context_id"],
|
|
item["evidence_json"],
|
|
positive_id,
|
|
negative_id,
|
|
pair_id,
|
|
expected_epoch,
|
|
),
|
|
)
|
|
conn.execute(
|
|
"INSERT INTO "
|
|
"execution_context_capture(run_id,state,reason,format_version) "
|
|
"VALUES(?,?,?,?)",
|
|
(run_id, bundle.state, bundle.reason, bundle.format_version),
|
|
)
|
|
return True
|
|
|
|
def get_execution_contexts(self, run_id: str) -> dict:
|
|
"""Return first-capture scalars; hints are None unless currently valid.
|
|
|
|
reference_epoch remains historical evidence even when hints are invalidated.
|
|
Reads never rebind a first-capture reference or alter stored capture data.
|
|
"""
|
|
conn = self.model.get_connection()
|
|
own_transaction = not conn.in_transaction
|
|
if own_transaction:
|
|
conn.execute("BEGIN")
|
|
try:
|
|
capture = conn.execute(
|
|
"SELECT state,reason,format_version FROM execution_context_capture "
|
|
"WHERE run_id=?",
|
|
(run_id,),
|
|
).fetchone()
|
|
if capture is None:
|
|
return {
|
|
"state": "not_captured",
|
|
"reason": "missing",
|
|
"format_version": None,
|
|
"contexts": [],
|
|
}
|
|
epoch = self.get_execution_epoch()
|
|
contexts = []
|
|
rows = conn.execute(
|
|
"SELECT r.*,c.positive_snapshot_id,c.negative_snapshot_id FROM "
|
|
"execution_run_contexts r JOIN execution_contexts c ON "
|
|
"c.context_id=r.context_id WHERE r.run_id=? ORDER BY r.anchor_id",
|
|
(run_id,),
|
|
)
|
|
for row in rows:
|
|
positive = _values(conn, row["positive_snapshot_id"])
|
|
negative = _values(conn, row["negative_snapshot_id"])
|
|
hints = (None, None, None)
|
|
if row["reference_epoch"] == epoch:
|
|
current = _hints(
|
|
conn,
|
|
positive["raw"] if positive else None,
|
|
negative["raw"] if negative else None,
|
|
)
|
|
hints = tuple(
|
|
row[key] if row[key] == value else None
|
|
for key, value in zip(
|
|
("positive_prompt_id", "negative_prompt_id", "pair_id"),
|
|
current,
|
|
)
|
|
)
|
|
contexts.append(
|
|
{
|
|
"anchor_id": row["anchor_id"],
|
|
"context_id": row["context_id"],
|
|
"positive": positive,
|
|
"negative": negative,
|
|
"evidence": json.loads(row["evidence_json"]),
|
|
"positive_prompt_id": hints[0],
|
|
"negative_prompt_id": hints[1],
|
|
"pair_id": hints[2],
|
|
"reference_epoch": row["reference_epoch"],
|
|
}
|
|
)
|
|
return {
|
|
"state": capture[0],
|
|
"reason": capture[1],
|
|
"format_version": capture[2],
|
|
"contexts": contexts,
|
|
}
|
|
finally:
|
|
if own_transaction:
|
|
conn.rollback()
|