WARDEN-WP-0044-T03: original-intent lookup/context for owner reconciliation
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Durably record the original run Invocation, pins, adapter source and
tenant/realm provenance before dispatch; expose Journal.original_intent and
Adapter.reconcile_original(ReconcileContext) for NK-WP-0048-T15. Missing or
mismatched intent refuses and leaves the step uncertain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 903097@bnt-lap001
Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
This commit is contained in:
tegwick 2026-10-17 04:32:50 +02:00
parent d97652a3bb
commit a45cf475bc
4 changed files with 191 additions and 7 deletions

View file

@ -629,3 +629,72 @@ def test_secret_sensitivity_parameter_cannot_reach_admission_or_journal(rig):
)
with pytest.raises(Refused, match="secret-sensitivity"):
executor.admit(sources[0], source, sources[2], sources[3], **kwargs)
def _lose_result(executor, args, calls):
old = executor.adapters[args[0].adapter]
def lost(inv):
calls.append(inv)
raise TimeoutError("lost")
seen = []
def by_original(ctx):
seen.append(ctx)
return old.reconcile(ctx.attempt)
executor.adapters[old.reference] = replace(
old, invoke=lost, reconcile=None, reconcile_original=by_original
)
assert executor.run(*args).last.outcome is Outcome.UNCERTAIN
return seen
def test_original_intent_survives_restart_separate_from_reconcile_attempt(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal = Journal(executor.journal.directory) # restart: fresh handle
assert executor.reconcile(*args).last.outcome is Outcome.NO_CHANGE
(ctx,) = seen
original = ctx.original.invocation
assert original.attempt_id == calls[0].attempt_id
assert original.operation == "run" and ctx.attempt.operation == "reconcile"
assert ctx.attempt.attempt_id != original.attempt_id
assert original.pins == args[1].pins
assert (original.principal, original.tenant, original.realm) == (
args[1].principal,
args[1].tenant,
args[1].realm,
)
assert ctx.original.source == executor.adapters[args[0].adapter].source
def test_missing_original_intent_refuses_and_stays_uncertain(rig):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
executor.journal.db.execute("DELETE FROM intents")
with pytest.raises(Refused, match="original intent record missing"):
executor.reconcile(*args)
assert seen == []
binding = f"{args[1].step}:{args[1].target}"
assert executor.journal.load(binding, args[2]).last.outcome is Outcome.UNCERTAIN
@pytest.mark.parametrize(
"change", [{"tenant": "other-tenant"}, {"realm": "other-realm"}, {"lane": "x"}]
)
def test_original_intent_mismatch_refuses(rig, change):
executor, args, calls, _, _ = rig
seen = _lose_result(executor, args, calls)
with pytest.raises(Refused):
executor.reconcile(args[0], replace(args[1], **change), args[2])
assert seen == []
def test_original_intent_source_mismatch_refuses(rig):
executor, args, calls, _, _ = rig
_lose_result(executor, args, calls)
binding = f"{args[1].step}:{args[1].target}"
with pytest.raises(Refused, match="source mismatch"):
executor.journal.original_intent(binding, calls[0], "other-source")