the-custodian/docs/changes/netkingdom-target-2026-10-17/original-context-compare-r2/minimal-integration.patch
codex 1fc8eed19c
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Reject generated-only commits / generated-commit-guard (push) Successful in 12s
docs: preserve reviewed NetKingdom session artifacts
2026-11-01 23:32:07 +01:00

427 lines
16 KiB
Diff

--- a/src/warden/case_run.py
+++ b/src/warden/case_run.py
@@ -189,7 +189,66 @@
invocation: Invocation
source: str
+ def validate(self) -> None:
+ """Fixed bounded metadata only; tenant/realm are not authority claims.
+
+ Current admit leaves tenant/realm empty. Nonempty future coordinates need
+ separate owner provenance; serializability alone must never supply it.
+ """
+ if (
+ type(self.invocation) is not Invocation
+ or type(self.invocation.pins) is not Pins
+ ):
+ raise Refused("exact original invocation required")
+ i = self.invocation
+ fields = (i.step, i.owner, i.target, i.principal, i.lane, i.attempt_id)
+ if (
+ not all(
+ type(value) is str and IDENTIFIER.fullmatch(value) for value in fields
+ )
+ or type(i.actor) is not str
+ or i.actor not in ("human", "agent")
+ or type(i.operation) is not str
+ or i.operation not in ("run", "rollback")
+ or not all(
+ type(value) is str and (not value or IDENTIFIER.fullmatch(value))
+ for value in (i.tenant, i.realm)
+ )
+ or type(self.source) is not str
+ or not DIGEST.fullmatch(self.source)
+ or type(self.binding) is not str
+ or self.binding != f"{i.step}:{i.target}"
+ ):
+ raise Refused("invalid original intent metadata")
+ if set(Invocation.__dataclass_fields__) != {
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "pins",
+ "attempt_id",
+ "operation",
+ "tenant",
+ "realm",
+ }:
+ raise Refused("original invocation field contract changed")
+ if not all(
+ type(v) is str and DIGEST.fullmatch(v)
+ for v in (
+ i.pins.case,
+ i.pins.case_type,
+ i.pins.adapter,
+ i.pins.catalog,
+ i.pins.acceptance,
+ i.pins.run_sheet,
+ )
+ ):
+ raise Refused("invalid original intent pins")
+
def payload(self) -> str:
+ self.validate()
return json.dumps(
{"schema": INTENT_SCHEMA, "binding": self.binding, "source": self.source}
| asdict(self.invocation),
@@ -199,13 +258,44 @@
@classmethod
def decode(cls, raw: str) -> OriginalIntent:
- obj = json.loads(raw)
- fields = {f for f in Invocation.__dataclass_fields__}
- if set(obj) != fields | {"schema", "binding", "source"} or obj["schema"] != INTENT_SCHEMA:
- raise Refused("unknown original intent schema")
- inv = {k: obj[k] for k in fields}
- inv["pins"] = Pins(**inv["pins"])
- return cls(obj["binding"], Invocation(**inv), obj["source"])
+ def unique(pairs):
+ result = {}
+ for key, value in pairs:
+ if key in result:
+ raise Refused("duplicate original intent field")
+ result[key] = value
+ return result
+
+ try:
+ if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
+ raise Refused("original intent input exceeds bound")
+ obj = json.loads(raw, object_pairs_hook=unique)
+ fields = {
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "pins",
+ "attempt_id",
+ "operation",
+ "tenant",
+ "realm",
+ }
+ if (
+ type(obj) is not dict
+ or set(obj) != fields | {"schema", "binding", "source"}
+ or obj["schema"] != INTENT_SCHEMA
+ ):
+ raise Refused("unknown original intent schema")
+ inv = {k: obj[k] for k in fields}
+ inv["pins"] = Pins(**inv["pins"])
+ result = cls(obj["binding"], Invocation(**inv), obj["source"])
+ result.validate()
+ return result
+ except (TypeError, ValueError, KeyError):
+ raise Refused("invalid original intent record") from None
@dataclass(frozen=True, slots=True)
@@ -256,28 +346,76 @@
"CREATE TABLE IF NOT EXISTS intents (seq INTEGER PRIMARY KEY, attempt_id TEXT NOT NULL UNIQUE, binding TEXT NOT NULL, payload TEXT NOT NULL)"
)
- def original_intent(self, binding: str, current: Invocation, source: str) -> OriginalIntent:
+ def original_intent(
+ self, binding: str, current: Invocation, source: str
+ ) -> OriginalIntent:
"""Latest original run intent for binding, refused unless it matches exactly.
Missing or mismatched records refuse; the step stays uncertain.
"""
row = self.db.execute(
- "SELECT payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
+ "SELECT attempt_id,payload FROM intents WHERE binding=? ORDER BY seq DESC LIMIT 1",
(binding,),
).fetchone()
if row is None:
raise Refused("original intent record missing; step stays uncertain")
- intent = OriginalIntent.decode(row[0])
+ intent = OriginalIntent.decode(row[1])
o = intent.invocation
+ if row[0] != o.attempt_id:
+ raise Refused("original intent attempt identity differs")
if intent.binding != binding or o.operation != "run":
raise Refused("original intent binding mismatch")
if o.pins != current.pins:
raise Refused("original intent pins mismatch")
if intent.source != source:
raise Refused("original intent source mismatch")
- for name in ("step", "owner", "target", "principal", "lane", "tenant", "realm"):
+ for name in (
+ "step",
+ "owner",
+ "target",
+ "actor",
+ "principal",
+ "lane",
+ "tenant",
+ "realm",
+ ):
if getattr(o, name) != getattr(current, name):
raise Refused(f"original intent {name} mismatch")
+ # Match the persisted original running receipt. An orphan context or a
+ # payload from another attempt cannot become the current lookup key.
+ receipts = self.db.execute(
+ "SELECT payload FROM receipts WHERE binding=? ORDER BY seq DESC LIMIT ?",
+ (binding, MAX_HISTORY + 1),
+ ).fetchall()
+ if len(receipts) > MAX_HISTORY:
+ raise Refused("original intent receipt history exceeds bound")
+ matched = False
+ try:
+ for (raw,) in receipts:
+ if type(raw) is not str or len(raw.encode()) > MAX_SOURCE_BYTES:
+ raise Refused("original receipt input exceeds bound")
+ payload = json.loads(raw)
+ if (
+ payload.get("attempt_id") != o.attempt_id
+ or payload.get("operation") != "run"
+ ):
+ continue
+ last = payload.get("receipts", [])[-1]
+ if last.get("outcome") != "running":
+ continue
+ if (
+ payload.get("journal_schema") != "warden.case.step-journal.v1"
+ or payload.get("step_id") != o.step
+ or payload.get("owner") != o.owner
+ or payload.get("pins") != asdict(o.pins)
+ ):
+ raise Refused("original running receipt binding differs")
+ matched = True
+ break
+ except (TypeError, ValueError, KeyError, IndexError, AttributeError):
+ raise Refused("invalid original running receipt") from None
+ if not matched:
+ raise Refused("original running receipt missing; no backfill")
return intent
@contextmanager
@@ -355,6 +493,23 @@
invocation: Invocation | None = None,
intent: OriginalIntent | None = None,
):
+ if intent is not None:
+ if type(intent) is not OriginalIntent:
+ raise Refused("exact original intent required")
+ intent.validate()
+ expected = (
+ Outcome.RUNNING
+ if intent.invocation.operation == "run"
+ else Outcome.ROLLBACK_RUNNING
+ )
+ if (
+ intent.binding != binding
+ or intent.invocation != invocation
+ or intent.invocation.pins != state.pins
+ or not state.last
+ or state.last.outcome is not expected
+ ):
+ raise Refused("original intent and running receipt differ")
self.db.execute("BEGIN IMMEDIATE")
try:
if intent is not None:
--- /dev/null
+++ b/tests/test_case_original_context_consistency.py
@@ -0,0 +1,198 @@
+"""Original-intent consistency checks with generated metadata only.
+
+Reuse the existing synthetic owner rig. These checks do not provide a native
+holder or independently authenticate original creation from local SQL/JSON.
+"""
+
+from dataclasses import asdict, replace
+import json
+from pathlib import Path
+import sqlite3
+import subprocess
+import sys
+import pytest
+from test_case_run import rig as rig
+from warden.case_receipt_state import Outcome, Refused
+from warden.case_run import OriginalIntent
+
+
+def interrupted(rig):
+ executor, args, calls, sources, kwargs = rig
+ old = executor.adapters[args[0].adapter]
+ seen = []
+
+ def lost(inv):
+ calls.append(inv)
+ raise TimeoutError("generated lost response")
+
+ def original(ctx):
+ seen.append(ctx)
+ return old.reconcile(ctx.attempt)
+
+ executor.adapters[old.reference] = replace(
+ old, invoke=lost, reconcile=None, reconcile_original=original
+ )
+ assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
+ return executor, args, calls, old, seen
+
+
+def alter_payload(executor, **changes):
+ row = executor.journal.db.execute(
+ "SELECT seq,payload FROM intents ORDER BY seq DESC LIMIT 1"
+ ).fetchone()
+ obj = json.loads(row[1])
+ obj.update(changes)
+ executor.journal.db.execute(
+ "UPDATE intents SET payload=? WHERE seq=?", (json.dumps(obj), row[0])
+ )
+
+
+def test_original_actor_mismatch_is_refused(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ alter_payload(executor, actor="agent")
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_payload_attempt_id_must_match_sql_column_and_original_receipt(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ actual = calls[0].attempt_id
+ alter_payload(executor, attempt_id="attempt-unrelated")
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+ assert (
+ executor.journal.db.execute("SELECT attempt_id FROM intents").fetchone()[0]
+ == actual
+ )
+
+
+def test_orphan_intent_without_original_running_receipt_is_refused(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ executor.journal.db.execute(
+ "DELETE FROM receipts WHERE seq=(SELECT MIN(seq) FROM receipts)"
+ )
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_serializer_refuses_arbitrary_values_outside_normal_admit(rig):
+ _, args, _, _, _ = rig
+ inv = replace(
+ args[1],
+ target={"unexpected": "synthetic-owner-payload"},
+ operation="run",
+ attempt_id="attempt-fixture",
+ )
+ record = OriginalIntent("mint-secret:fixture-client", inv, "sha256:" + "1" * 64)
+ with pytest.raises(Refused):
+ OriginalIntent.decode(record.payload())
+ # This is a direct serialization API gap, not an observed normal-admit leak.
+
+ # Owner trust is the existing synthetic fixture; this proves call shape only.
+
+
+@pytest.mark.parametrize(
+ "field,value",
+ [
+ ("principal", "another-person"),
+ ("tenant", "another-tenant"),
+ ("realm", "another-realm"),
+ ],
+)
+def test_existing_lookup_does_refuse_stored_principal_tenant_realm_mismatch(
+ rig, field, value
+):
+ executor, args, _, old, _ = interrupted(rig)
+ alter_payload(executor, **{field: value})
+ with pytest.raises(Refused):
+ executor.journal.original_intent(
+ "mint-secret:fixture-client", args[1], old.source
+ )
+
+
+def test_existing_atomic_insert_failure_prevents_dispatch_and_both_records(rig):
+ executor, args, calls, _, _ = rig
+ executor.journal.db.execute(
+ "CREATE TRIGGER fail_receipt BEFORE INSERT ON receipts BEGIN SELECT RAISE(ABORT,'fixture'); END"
+ )
+ with pytest.raises(sqlite3.IntegrityError):
+ executor.run(*args)
+ assert not calls
+ assert executor.journal.db.execute("SELECT COUNT(*) FROM intents").fetchone() == (
+ 0,
+ )
+ assert executor.journal.db.execute("SELECT COUNT(*) FROM receipts").fetchone() == (
+ 0,
+ )
+
+
+def test_existing_missing_original_refuses_before_callback(rig):
+ executor, args, _, _, seen = interrupted(rig)
+ executor.journal.db.execute("DELETE FROM intents")
+ with pytest.raises(Refused):
+ executor.reconcile(*args)
+ assert not seen
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+
+
+def test_existing_current_parent_revocation_remains_mandatory(rig):
+ executor, args, _, _, _ = interrupted(rig)
+ old = executor.evidence_verifier
+
+ def refuse_session(purpose, source, evidence):
+ return (
+ False
+ if purpose.startswith("session-revocation:")
+ else old(purpose, source, evidence)
+ )
+
+ executor.evidence_verifier = refuse_session
+ with pytest.raises(Refused):
+ executor.reconcile(*args)
+ assert (
+ executor.journal.load("mint-secret:fixture-client", args[2]).last.outcome
+ is Outcome.UNCERTAIN
+ )
+
+
+def test_existing_intent_survives_actual_distinct_interpreter(rig):
+ executor, args, calls, old, _ = interrupted(rig)
+ code = """import json,sys
+from pathlib import Path
+from warden.case_run import Journal,Invocation
+from warden.case_receipt_state import Pins
+obj=json.load(sys.stdin);obj['pins']=Pins(**obj['pins']);j=Journal(Path(sys.argv[1]))
+with j.locked():
+ i=j.original_intent('mint-secret:fixture-client',Invocation(**obj),sys.argv[2])
+ print(json.dumps({'attempt':i.invocation.attempt_id,'operation':i.invocation.operation}))
+"""
+ result = subprocess.run(
+ [sys.executable, "-B", "-c", code, str(executor.journal.directory), old.source],
+ input=json.dumps(asdict(args[1])),
+ text=True,
+ capture_output=True,
+ timeout=15,
+ env={
+ "PATH": "/usr/bin:/bin",
+ "PYTHONPATH": str(Path(__file__).parents[1] / "src"),
+ "PYTHONDONTWRITEBYTECODE": "1",
+ },
+ check=True,
+ )
+ assert json.loads(result.stdout) == {
+ "attempt": calls[0].attempt_id,
+ "operation": "run",
+ }