Extends SealedPracticeTrace for externally bound candidate episodes per ADR-0233. Adds candidate_attempt_binding_ids to trace identity, bound trace input/seal entry points, and end-to-end bound episode tests without mutating GeometricSearchRun.candidate_attempts.
1314 lines
52 KiB
Python
1314 lines
52 KiB
Python
"""Inert, diagnostic-only sealed practice trace shell over upstream loop records."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from dataclasses import dataclass
|
|
from enum import Enum, unique
|
|
|
|
from generate.geometric_search_run import (
|
|
GeometricSearchRun,
|
|
SearchRunDisposition,
|
|
SearchRunRefusal,
|
|
)
|
|
from generate.kernel_facts import SourceSpan
|
|
from generate.replay_adapter import ReplayAdapterRefusal, ReplayAdapterResult, ReplayDisposition
|
|
|
|
SEALED_PRACTICE_TRACE_POLICY_VERSION = "sealed_practice_trace.v1"
|
|
CREATED_BY_POLICY = SEALED_PRACTICE_TRACE_POLICY_VERSION
|
|
|
|
|
|
@unique
|
|
class PracticeDisposition(str, Enum):
|
|
SEALED_ORIGINAL_REFUSAL = "sealed_original_refusal"
|
|
SEALED_EXHAUSTED_NO_CANDIDATE = "sealed_exhausted_no_candidate"
|
|
SEALED_ALL_CANDIDATES_REFUSED = "sealed_all_candidates_refused"
|
|
SEALED_REPLAY_UNAVAILABLE = "sealed_replay_unavailable"
|
|
SEALED_CONTRACT_CLOSED_PROOF_REFUSED = "sealed_contract_closed_proof_refused"
|
|
SEALED_CANDIDATE_REPLAY_CLOSED = "sealed_candidate_replay_closed"
|
|
TRACE_INVALID_INPUT = "trace_invalid_input"
|
|
TRACE_IDENTITY_MISMATCH = "trace_identity_mismatch"
|
|
TRACE_POLICY_UNSUPPORTED = "trace_policy_unsupported"
|
|
TRACE_UPSTREAM_INCOMPLETE = "trace_upstream_incomplete"
|
|
|
|
|
|
_SEALED_DISPOSITIONS = frozenset(
|
|
{
|
|
PracticeDisposition.SEALED_ORIGINAL_REFUSAL,
|
|
PracticeDisposition.SEALED_EXHAUSTED_NO_CANDIDATE,
|
|
PracticeDisposition.SEALED_ALL_CANDIDATES_REFUSED,
|
|
PracticeDisposition.SEALED_REPLAY_UNAVAILABLE,
|
|
PracticeDisposition.SEALED_CONTRACT_CLOSED_PROOF_REFUSED,
|
|
PracticeDisposition.SEALED_CANDIDATE_REPLAY_CLOSED,
|
|
}
|
|
)
|
|
|
|
_ORIGINAL_REFUSAL_RUN_DISPOSITIONS = frozenset(
|
|
{
|
|
SearchRunDisposition.BLOCKED_BY_GATE,
|
|
SearchRunDisposition.BLOCKED_BY_BUDGET,
|
|
SearchRunDisposition.NOT_STARTED,
|
|
SearchRunDisposition.INVALID_INPUT,
|
|
}
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class PracticeTraceInput:
|
|
input_digest: str
|
|
trace_policy_version: str
|
|
problem_frame_digest: str
|
|
original_contract_assessment_id: str
|
|
residual_ids: tuple[str, ...]
|
|
search_gate_decision_id: str
|
|
compute_budget_id: str
|
|
geometric_search_run_id: str
|
|
candidate_attempt_ids: tuple[str, ...]
|
|
candidate_attempt_binding_ids: tuple[str, ...]
|
|
replay_result_ids: tuple[str, ...]
|
|
replay_refusal_ids: tuple[str, ...]
|
|
schema_versions: tuple[tuple[str, str], ...]
|
|
policy_versions: tuple[tuple[str, str], ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SealedPracticeTrace:
|
|
trace_id: str
|
|
trace_policy_version: str
|
|
input_digest: str
|
|
problem_frame_digest: str
|
|
original_contract_assessment_id: str
|
|
residual_ids: tuple[str, ...]
|
|
search_gate_decision_id: str
|
|
compute_budget_id: str
|
|
geometric_search_run_id: str
|
|
candidate_attempt_ids: tuple[str, ...]
|
|
candidate_attempt_binding_ids: tuple[str, ...]
|
|
replay_result_ids: tuple[str, ...]
|
|
replay_refusal_ids: tuple[str, ...]
|
|
upstream_identity_chain: tuple[str, ...]
|
|
practice_disposition: PracticeDisposition
|
|
trace_records: tuple[str, ...]
|
|
evidence_spans: tuple[SourceSpan, ...]
|
|
created_by_policy: str
|
|
explanation: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class PracticeTraceRefusal:
|
|
trace_refusal_id: str
|
|
trace_policy_version: str
|
|
input_digest: str | None
|
|
practice_disposition: PracticeDisposition
|
|
reason_codes: tuple[str, ...]
|
|
explanation: str
|
|
|
|
|
|
PracticeTraceOutcome = SealedPracticeTrace | PracticeTraceRefusal
|
|
|
|
|
|
def _canonical_digest(payload: dict[str, object]) -> str:
|
|
encoded = json.dumps(
|
|
payload,
|
|
ensure_ascii=False,
|
|
sort_keys=True,
|
|
separators=(",", ":"),
|
|
).encode("utf-8")
|
|
return hashlib.sha256(encoded).hexdigest()
|
|
|
|
|
|
def _nonempty_text(value: object) -> bool:
|
|
return isinstance(value, str) and bool(value.strip())
|
|
|
|
|
|
def _sha256_text(value: object) -> bool:
|
|
return (
|
|
isinstance(value, str)
|
|
and len(value) == 64
|
|
and value == value.lower()
|
|
and all(character in "0123456789abcdef" for character in value)
|
|
)
|
|
|
|
|
|
def _valid_span(span: object) -> bool:
|
|
return (
|
|
isinstance(span, SourceSpan)
|
|
and isinstance(span.text, str)
|
|
and type(span.start) is int
|
|
and type(span.end) is int
|
|
and span.start >= 0
|
|
and span.end >= span.start
|
|
and (span.sentence_index is None or type(span.sentence_index) is int)
|
|
)
|
|
|
|
|
|
def _valid_spans(value: object) -> bool:
|
|
return isinstance(value, tuple) and all(_valid_span(span) for span in value)
|
|
|
|
|
|
def _span_payload(span: SourceSpan) -> dict[str, object]:
|
|
return {
|
|
"text": span.text,
|
|
"start": span.start,
|
|
"end": span.end,
|
|
"sentence_index": span.sentence_index,
|
|
}
|
|
|
|
|
|
def _version_pairs_payload(
|
|
versions: tuple[tuple[str, str], ...],
|
|
) -> list[list[str]]:
|
|
return [[name, version] for name, version in versions]
|
|
|
|
|
|
def _valid_version_pairs(value: object) -> bool:
|
|
if not isinstance(value, tuple):
|
|
return False
|
|
names: list[str] = []
|
|
for entry in value:
|
|
if not isinstance(entry, tuple) or len(entry) != 2:
|
|
return False
|
|
name, version = entry
|
|
if not _nonempty_text(name) or not _nonempty_text(version):
|
|
return False
|
|
names.append(name)
|
|
return len(names) == len(set(names)) and names == sorted(names)
|
|
|
|
|
|
def _input_digest_payload(
|
|
*,
|
|
trace_policy_version: str,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
geometric_search_run_id: str,
|
|
candidate_attempt_ids: tuple[str, ...],
|
|
candidate_attempt_binding_ids: tuple[str, ...],
|
|
replay_result_ids: tuple[str, ...],
|
|
replay_refusal_ids: tuple[str, ...],
|
|
schema_versions: tuple[tuple[str, str], ...],
|
|
policy_versions: tuple[tuple[str, str], ...],
|
|
) -> dict[str, object]:
|
|
return {
|
|
"trace_policy_version": trace_policy_version,
|
|
"problem_frame_digest": problem_frame_digest,
|
|
"original_contract_assessment_id": original_contract_assessment_id,
|
|
"residual_ids": list(residual_ids),
|
|
"search_gate_decision_id": search_gate_decision_id,
|
|
"compute_budget_id": compute_budget_id,
|
|
"geometric_search_run_id": geometric_search_run_id,
|
|
"candidate_attempt_ids": list(candidate_attempt_ids),
|
|
"candidate_attempt_binding_ids": list(candidate_attempt_binding_ids),
|
|
"replay_result_ids": list(replay_result_ids),
|
|
"replay_refusal_ids": list(replay_refusal_ids),
|
|
"schema_versions": _version_pairs_payload(schema_versions),
|
|
"policy_versions": _version_pairs_payload(policy_versions),
|
|
}
|
|
|
|
|
|
def _trace_id_payload(
|
|
*,
|
|
trace_policy_version: str,
|
|
input_digest: str,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
geometric_search_run_id: str,
|
|
candidate_attempt_ids: tuple[str, ...],
|
|
candidate_attempt_binding_ids: tuple[str, ...],
|
|
replay_result_ids: tuple[str, ...],
|
|
replay_refusal_ids: tuple[str, ...],
|
|
upstream_identity_chain: tuple[str, ...],
|
|
practice_disposition: PracticeDisposition,
|
|
trace_records: tuple[str, ...],
|
|
evidence_spans: tuple[SourceSpan, ...],
|
|
created_by_policy: str,
|
|
) -> dict[str, object]:
|
|
return {
|
|
"trace_id": "",
|
|
"trace_policy_version": trace_policy_version,
|
|
"input_digest": input_digest,
|
|
"problem_frame_digest": problem_frame_digest,
|
|
"original_contract_assessment_id": original_contract_assessment_id,
|
|
"residual_ids": list(residual_ids),
|
|
"search_gate_decision_id": search_gate_decision_id,
|
|
"compute_budget_id": compute_budget_id,
|
|
"geometric_search_run_id": geometric_search_run_id,
|
|
"candidate_attempt_ids": list(candidate_attempt_ids),
|
|
"candidate_attempt_binding_ids": list(candidate_attempt_binding_ids),
|
|
"replay_result_ids": list(replay_result_ids),
|
|
"replay_refusal_ids": list(replay_refusal_ids),
|
|
"upstream_identity_chain": list(upstream_identity_chain),
|
|
"practice_disposition": practice_disposition.value,
|
|
"trace_records": list(trace_records),
|
|
"evidence_spans": [_span_payload(span) for span in evidence_spans],
|
|
"created_by_policy": created_by_policy,
|
|
}
|
|
|
|
|
|
def _refusal(
|
|
*,
|
|
trace_policy_version: str = SEALED_PRACTICE_TRACE_POLICY_VERSION,
|
|
input_digest: str | None,
|
|
disposition: PracticeDisposition,
|
|
reason_codes: tuple[str, ...],
|
|
) -> PracticeTraceRefusal:
|
|
trace_refusal_id = _canonical_digest(
|
|
{
|
|
"trace_refusal_id": "",
|
|
"trace_policy_version": trace_policy_version,
|
|
"input_digest": input_digest,
|
|
"practice_disposition": disposition.value,
|
|
"reason_codes": list(reason_codes),
|
|
}
|
|
)
|
|
return PracticeTraceRefusal(
|
|
trace_refusal_id=trace_refusal_id,
|
|
trace_policy_version=trace_policy_version,
|
|
input_digest=input_digest,
|
|
practice_disposition=disposition,
|
|
reason_codes=reason_codes,
|
|
explanation="Practice trace refused: "
|
|
+ disposition.value
|
|
+ " ("
|
|
+ ", ".join(reason_codes)
|
|
+ ").",
|
|
)
|
|
|
|
|
|
def _run_identity(run: GeometricSearchRun | SearchRunRefusal) -> str:
|
|
if isinstance(run, GeometricSearchRun):
|
|
return run.run_id
|
|
if isinstance(run, SearchRunRefusal):
|
|
return run.outcome_id
|
|
return ""
|
|
|
|
|
|
def _validate_run_bindings(
|
|
*,
|
|
run: GeometricSearchRun | SearchRunRefusal,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
) -> list[str]:
|
|
reasons: list[str] = []
|
|
if isinstance(run, GeometricSearchRun):
|
|
if run.problem_frame_digest != problem_frame_digest:
|
|
reasons.append("problem_frame_digest_run_mismatch")
|
|
if run.contract_assessment_id != original_contract_assessment_id:
|
|
reasons.append("contract_assessment_id_run_mismatch")
|
|
if run.residual_ids != residual_ids:
|
|
reasons.append("residual_ids_run_mismatch")
|
|
if run.gate_decision_id != search_gate_decision_id:
|
|
reasons.append("gate_decision_id_run_mismatch")
|
|
if run.budget_id != compute_budget_id:
|
|
reasons.append("budget_id_run_mismatch")
|
|
elif isinstance(run, SearchRunRefusal):
|
|
if run.gate_decision_id != search_gate_decision_id:
|
|
reasons.append("gate_decision_id_refusal_mismatch")
|
|
if run.budget_id != compute_budget_id:
|
|
reasons.append("budget_id_refusal_mismatch")
|
|
else:
|
|
reasons.append("invalid_run_type")
|
|
return reasons
|
|
|
|
|
|
def _validate_replay_record_identity(
|
|
record: ReplayAdapterResult | ReplayAdapterRefusal,
|
|
) -> str | None:
|
|
if isinstance(record, ReplayAdapterResult):
|
|
return None if _sha256_text(record.replay_result_id) else "invalid_replay_result_id"
|
|
if isinstance(record, ReplayAdapterRefusal):
|
|
return None if _sha256_text(record.replay_refusal_id) else "invalid_replay_refusal_id"
|
|
return "invalid_replay_record_type"
|
|
|
|
|
|
def _validate_replay_bindings(
|
|
*,
|
|
run: GeometricSearchRun,
|
|
replay_results: tuple[ReplayAdapterResult, ...],
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...],
|
|
) -> list[str]:
|
|
reasons: list[str] = []
|
|
attempt_by_id = {attempt.attempt_id: attempt for attempt in run.candidate_attempts}
|
|
attempt_ids = {attempt.attempt_id for attempt in run.candidate_attempts}
|
|
digest_by_attempt = {
|
|
attempt.attempt_id: attempt.candidate_digest for attempt in run.candidate_attempts
|
|
}
|
|
|
|
for record in (*replay_results, *replay_refusals):
|
|
identity_reason = _validate_replay_record_identity(record)
|
|
if identity_reason is not None:
|
|
reasons.append(identity_reason)
|
|
run_id = record.run_id
|
|
attempt_id = record.attempt_id
|
|
candidate_digest = record.candidate_digest
|
|
if run_id != run.run_id:
|
|
reasons.append("replay_run_id_mismatch")
|
|
if attempt_id is None or not _nonempty_text(attempt_id):
|
|
reasons.append("replay_missing_attempt_id")
|
|
elif attempt_id not in attempt_ids:
|
|
reasons.append("replay_orphan_attempt_id")
|
|
if candidate_digest is not None and _nonempty_text(candidate_digest):
|
|
if attempt_id in digest_by_attempt and candidate_digest != digest_by_attempt[attempt_id]:
|
|
reasons.append("replay_candidate_digest_mismatch")
|
|
elif attempt_id in attempt_by_id:
|
|
reasons.append("replay_missing_candidate_digest")
|
|
|
|
return reasons
|
|
|
|
|
|
def _derive_disposition(
|
|
*,
|
|
run: GeometricSearchRun | SearchRunRefusal,
|
|
replay_results: tuple[ReplayAdapterResult, ...],
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...],
|
|
) -> PracticeDisposition | None:
|
|
if isinstance(run, SearchRunRefusal):
|
|
if run.run_disposition in _ORIGINAL_REFUSAL_RUN_DISPOSITIONS:
|
|
return PracticeDisposition.SEALED_ORIGINAL_REFUSAL
|
|
return None
|
|
|
|
if not run.candidate_attempts:
|
|
if run.run_disposition is SearchRunDisposition.EXHAUSTED_NO_CANDIDATE:
|
|
return PracticeDisposition.SEALED_EXHAUSTED_NO_CANDIDATE
|
|
if run.run_disposition in _ORIGINAL_REFUSAL_RUN_DISPOSITIONS:
|
|
return PracticeDisposition.SEALED_ORIGINAL_REFUSAL
|
|
return None
|
|
|
|
if not replay_results and not replay_refusals:
|
|
return None
|
|
|
|
if any(
|
|
result.replay_disposition is ReplayDisposition.CONTRACT_AND_PROOF_CLOSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_CANDIDATE_REPLAY_CLOSED
|
|
|
|
if any(
|
|
result.replay_disposition
|
|
is ReplayDisposition.CONTRACT_CLOSED_BUT_PROOF_REFUSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_CONTRACT_CLOSED_PROOF_REFUSED
|
|
|
|
if replay_results and all(
|
|
result.replay_disposition is ReplayDisposition.CONTRACT_REFUSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_ALL_CANDIDATES_REFUSED
|
|
|
|
if replay_refusals and not replay_results:
|
|
return PracticeDisposition.SEALED_REPLAY_UNAVAILABLE
|
|
|
|
return None
|
|
|
|
|
|
def _upstream_identity_chain(
|
|
*,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
geometric_search_run_id: str,
|
|
candidate_attempt_ids: tuple[str, ...],
|
|
candidate_attempt_binding_ids: tuple[str, ...],
|
|
replay_result_ids: tuple[str, ...],
|
|
replay_refusal_ids: tuple[str, ...],
|
|
) -> tuple[str, ...]:
|
|
return (
|
|
problem_frame_digest,
|
|
original_contract_assessment_id,
|
|
*residual_ids,
|
|
search_gate_decision_id,
|
|
compute_budget_id,
|
|
geometric_search_run_id,
|
|
*candidate_attempt_ids,
|
|
*candidate_attempt_binding_ids,
|
|
*replay_result_ids,
|
|
*replay_refusal_ids,
|
|
)
|
|
|
|
|
|
def _failure_disposition(reasons: list[str]) -> PracticeDisposition:
|
|
identity_mismatch_codes = {
|
|
"problem_frame_digest_run_mismatch",
|
|
"contract_assessment_id_run_mismatch",
|
|
"residual_ids_run_mismatch",
|
|
"gate_decision_id_run_mismatch",
|
|
"budget_id_run_mismatch",
|
|
"gate_decision_id_refusal_mismatch",
|
|
"budget_id_refusal_mismatch",
|
|
"geometric_search_run_id_mismatch",
|
|
"candidate_attempt_ids_mismatch",
|
|
"candidate_attempt_binding_ids_mismatch",
|
|
"invalid_binding_type",
|
|
"invalid_candidate_operator_result_type",
|
|
"binding_result_count_mismatch",
|
|
"binding_run_mismatch",
|
|
"binding_result_mismatch",
|
|
"binding_attempt_mismatch",
|
|
"binding_reconstruction_mismatch",
|
|
"binding_not_structurally_bound",
|
|
"binding_not_successful",
|
|
"binding_evidence_mismatch",
|
|
"operator_result_run_mismatch",
|
|
"operator_reconstruction_run_mismatch",
|
|
"duplicate_candidate_attempt_binding_id",
|
|
"duplicate_candidate_attempt_id",
|
|
"duplicate_candidate_digest",
|
|
"replay_run_id_mismatch",
|
|
"replay_orphan_attempt_id",
|
|
"replay_candidate_digest_mismatch",
|
|
"replay_result_ids_mismatch",
|
|
"replay_refusal_ids_mismatch",
|
|
"invalid_replay_result_id",
|
|
"invalid_replay_refusal_id",
|
|
}
|
|
if "unsupported_trace_policy_version" in reasons:
|
|
return PracticeDisposition.TRACE_POLICY_UNSUPPORTED
|
|
if any(reason in identity_mismatch_codes for reason in reasons):
|
|
return PracticeDisposition.TRACE_IDENTITY_MISMATCH
|
|
if "missing_replay_records" in reasons:
|
|
return PracticeDisposition.TRACE_UPSTREAM_INCOMPLETE
|
|
return PracticeDisposition.TRACE_INVALID_INPUT
|
|
|
|
|
|
def build_practice_trace_input(
|
|
*,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
run: GeometricSearchRun | SearchRunRefusal,
|
|
replay_results: tuple[ReplayAdapterResult, ...] = (),
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...] = (),
|
|
schema_versions: tuple[tuple[str, str], ...] = (),
|
|
policy_versions: tuple[tuple[str, str], ...] = (),
|
|
trace_policy_version: str = SEALED_PRACTICE_TRACE_POLICY_VERSION,
|
|
) -> PracticeTraceInput | PracticeTraceRefusal:
|
|
"""Validate upstream identities and emit a trace input or refusal."""
|
|
|
|
if trace_policy_version != SEALED_PRACTICE_TRACE_POLICY_VERSION:
|
|
return _refusal(
|
|
input_digest=None,
|
|
trace_policy_version=trace_policy_version,
|
|
disposition=PracticeDisposition.TRACE_POLICY_UNSUPPORTED,
|
|
reason_codes=("unsupported_trace_policy_version",),
|
|
)
|
|
|
|
reasons: list[str] = []
|
|
if not _sha256_text(problem_frame_digest):
|
|
reasons.append("invalid_problem_frame_digest")
|
|
if not _nonempty_text(original_contract_assessment_id):
|
|
reasons.append("missing_original_contract_assessment_id")
|
|
if not isinstance(residual_ids, tuple) or not all(
|
|
_nonempty_text(residual_id) for residual_id in residual_ids
|
|
):
|
|
reasons.append("invalid_residual_ids")
|
|
if not _sha256_text(search_gate_decision_id):
|
|
reasons.append("invalid_search_gate_decision_id")
|
|
if not _sha256_text(compute_budget_id):
|
|
reasons.append("invalid_compute_budget_id")
|
|
if not _valid_version_pairs(schema_versions):
|
|
reasons.append("invalid_schema_versions")
|
|
if not _valid_version_pairs(policy_versions):
|
|
reasons.append("invalid_policy_versions")
|
|
|
|
geometric_search_run_id = _run_identity(run)
|
|
if not _sha256_text(geometric_search_run_id):
|
|
reasons.append("invalid_geometric_search_run_id")
|
|
|
|
candidate_attempt_ids: tuple[str, ...] = ()
|
|
if isinstance(run, GeometricSearchRun):
|
|
attempts = run.candidate_attempts
|
|
if not isinstance(attempts, tuple):
|
|
reasons.append("invalid_candidate_attempts")
|
|
else:
|
|
candidate_attempt_ids = tuple(attempt.attempt_id for attempt in attempts)
|
|
if not all(_nonempty_text(attempt_id) for attempt_id in candidate_attempt_ids):
|
|
reasons.append("invalid_candidate_attempt_id")
|
|
elif isinstance(run, SearchRunRefusal):
|
|
if replay_results or replay_refusals:
|
|
reasons.append("replay_records_with_run_refusal")
|
|
else:
|
|
reasons.append("invalid_run_type")
|
|
|
|
if not reasons:
|
|
reasons.extend(
|
|
_validate_run_bindings(
|
|
run=run,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
)
|
|
)
|
|
|
|
replay_result_ids = tuple(result.replay_result_id for result in replay_results)
|
|
replay_refusal_ids = tuple(refusal.replay_refusal_id for refusal in replay_refusals)
|
|
|
|
if isinstance(run, GeometricSearchRun) and not reasons:
|
|
reasons.extend(
|
|
_validate_replay_bindings(
|
|
run=run,
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
)
|
|
|
|
if reasons:
|
|
return _refusal(
|
|
input_digest=None,
|
|
disposition=_failure_disposition(reasons),
|
|
reason_codes=tuple(reasons),
|
|
)
|
|
|
|
input_digest = _canonical_digest(
|
|
_input_digest_payload(
|
|
trace_policy_version=trace_policy_version,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
geometric_search_run_id=geometric_search_run_id,
|
|
candidate_attempt_ids=candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=(),
|
|
replay_result_ids=replay_result_ids,
|
|
replay_refusal_ids=replay_refusal_ids,
|
|
schema_versions=schema_versions,
|
|
policy_versions=policy_versions,
|
|
)
|
|
)
|
|
return PracticeTraceInput(
|
|
input_digest=input_digest,
|
|
trace_policy_version=trace_policy_version,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
geometric_search_run_id=geometric_search_run_id,
|
|
candidate_attempt_ids=candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=(),
|
|
replay_result_ids=replay_result_ids,
|
|
replay_refusal_ids=replay_refusal_ids,
|
|
schema_versions=schema_versions,
|
|
policy_versions=policy_versions,
|
|
)
|
|
|
|
|
|
def seal_practice_trace(
|
|
trace_input: PracticeTraceInput,
|
|
*,
|
|
run: GeometricSearchRun | SearchRunRefusal,
|
|
replay_results: tuple[ReplayAdapterResult, ...] = (),
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...] = (),
|
|
evidence_spans: tuple[SourceSpan, ...] = (),
|
|
explanation: str = "",
|
|
) -> SealedPracticeTrace | PracticeTraceRefusal:
|
|
"""Seal a validated practice episode as immutable diagnostic evidence."""
|
|
|
|
if not isinstance(trace_input, PracticeTraceInput):
|
|
return _refusal(
|
|
input_digest=None,
|
|
disposition=PracticeDisposition.TRACE_INVALID_INPUT,
|
|
reason_codes=("invalid_trace_input_type",),
|
|
)
|
|
if trace_input.trace_policy_version != SEALED_PRACTICE_TRACE_POLICY_VERSION:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
disposition=PracticeDisposition.TRACE_POLICY_UNSUPPORTED,
|
|
reason_codes=("unsupported_trace_policy_version",),
|
|
)
|
|
if not _valid_spans(evidence_spans):
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_INVALID_INPUT,
|
|
reason_codes=("invalid_evidence_spans",),
|
|
)
|
|
|
|
reasons: list[str] = []
|
|
geometric_search_run_id = _run_identity(run)
|
|
if geometric_search_run_id != trace_input.geometric_search_run_id:
|
|
reasons.append("geometric_search_run_id_mismatch")
|
|
|
|
replay_result_ids = tuple(result.replay_result_id for result in replay_results)
|
|
replay_refusal_ids = tuple(refusal.replay_refusal_id for refusal in replay_refusals)
|
|
if replay_result_ids != trace_input.replay_result_ids:
|
|
reasons.append("replay_result_ids_mismatch")
|
|
if replay_refusal_ids != trace_input.replay_refusal_ids:
|
|
reasons.append("replay_refusal_ids_mismatch")
|
|
|
|
if not reasons:
|
|
reasons.extend(
|
|
_validate_run_bindings(
|
|
run=run,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
)
|
|
)
|
|
|
|
if isinstance(run, GeometricSearchRun) and not reasons:
|
|
attempt_ids = tuple(attempt.attempt_id for attempt in run.candidate_attempts)
|
|
if attempt_ids != trace_input.candidate_attempt_ids:
|
|
reasons.append("candidate_attempt_ids_mismatch")
|
|
reasons.extend(
|
|
_validate_replay_bindings(
|
|
run=run,
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
)
|
|
if run.candidate_attempts and not replay_results and not replay_refusals:
|
|
reasons.append("missing_replay_records")
|
|
|
|
if reasons:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=_failure_disposition(reasons),
|
|
reason_codes=tuple(reasons),
|
|
)
|
|
|
|
recomputed_input_digest = _canonical_digest(
|
|
_input_digest_payload(
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
schema_versions=trace_input.schema_versions,
|
|
policy_versions=trace_input.policy_versions,
|
|
)
|
|
)
|
|
if recomputed_input_digest != trace_input.input_digest:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_IDENTITY_MISMATCH,
|
|
reason_codes=("input_digest_mismatch",),
|
|
)
|
|
|
|
practice_disposition = _derive_disposition(
|
|
run=run,
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
if practice_disposition is None or practice_disposition not in _SEALED_DISPOSITIONS:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_UPSTREAM_INCOMPLETE,
|
|
reason_codes=("unsupported_practice_disposition",),
|
|
)
|
|
|
|
identity_chain = _upstream_identity_chain(
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
)
|
|
trace_records = identity_chain
|
|
trace_id = _canonical_digest(
|
|
_trace_id_payload(
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
input_digest=trace_input.input_digest,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
upstream_identity_chain=identity_chain,
|
|
practice_disposition=practice_disposition,
|
|
trace_records=trace_records,
|
|
evidence_spans=evidence_spans,
|
|
created_by_policy=CREATED_BY_POLICY,
|
|
)
|
|
)
|
|
|
|
safe_explanation = explanation or (
|
|
"Sealed practice trace disposition: " + practice_disposition.value + "."
|
|
)
|
|
return SealedPracticeTrace(
|
|
trace_id=trace_id,
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
input_digest=trace_input.input_digest,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
upstream_identity_chain=identity_chain,
|
|
practice_disposition=practice_disposition,
|
|
trace_records=trace_records,
|
|
evidence_spans=evidence_spans,
|
|
created_by_policy=CREATED_BY_POLICY,
|
|
explanation=safe_explanation,
|
|
)
|
|
|
|
|
|
def _valid_binding_record(binding: object) -> bool:
|
|
required = (
|
|
"binding_id",
|
|
"original_run_id",
|
|
"operator_result_id",
|
|
"candidate_attempt_id",
|
|
"attempt_index",
|
|
"candidate_digest",
|
|
"candidate_reconstruction_digest",
|
|
"run_attempt_membership",
|
|
"reason_codes",
|
|
"evidence_spans",
|
|
)
|
|
return all(hasattr(binding, name) for name in required)
|
|
|
|
|
|
def _valid_operator_result_record(operator_result: object) -> bool:
|
|
required = (
|
|
"operator_result_id",
|
|
"attempt_id",
|
|
"attempt_index",
|
|
"candidate_digest",
|
|
"candidate_reconstruction_digest",
|
|
"geometric_search_run_id",
|
|
"evidence_spans",
|
|
"candidate_attempt",
|
|
"candidate_reconstruction",
|
|
)
|
|
return all(hasattr(operator_result, name) for name in required)
|
|
|
|
|
|
def _validate_bound_binding_pair(
|
|
*,
|
|
run: GeometricSearchRun,
|
|
binding: object,
|
|
operator_result: object,
|
|
) -> list[str]:
|
|
reasons: list[str] = []
|
|
attempt = operator_result.candidate_attempt
|
|
reconstruction = operator_result.candidate_reconstruction
|
|
|
|
if binding.original_run_id != run.run_id:
|
|
reasons.append("binding_run_mismatch")
|
|
if binding.operator_result_id != operator_result.operator_result_id:
|
|
reasons.append("binding_result_mismatch")
|
|
if binding.candidate_attempt_id != operator_result.attempt_id:
|
|
reasons.append("binding_attempt_mismatch")
|
|
if binding.candidate_attempt_id != attempt.attempt_id:
|
|
reasons.append("binding_attempt_mismatch")
|
|
if binding.attempt_index != operator_result.attempt_index:
|
|
reasons.append("binding_attempt_mismatch")
|
|
if binding.attempt_index != attempt.attempt_index:
|
|
reasons.append("binding_attempt_mismatch")
|
|
if binding.candidate_digest != operator_result.candidate_digest:
|
|
reasons.append("binding_reconstruction_mismatch")
|
|
if binding.candidate_digest != attempt.candidate_digest:
|
|
reasons.append("binding_reconstruction_mismatch")
|
|
if (
|
|
binding.candidate_reconstruction_digest
|
|
!= operator_result.candidate_reconstruction_digest
|
|
):
|
|
reasons.append("binding_reconstruction_mismatch")
|
|
if (
|
|
binding.candidate_reconstruction_digest
|
|
!= reconstruction.candidate_reconstruction_digest
|
|
):
|
|
reasons.append("binding_reconstruction_mismatch")
|
|
if binding.run_attempt_membership != "structurally_bound":
|
|
reasons.append("binding_not_structurally_bound")
|
|
if binding.reason_codes != ():
|
|
reasons.append("binding_not_successful")
|
|
if binding.evidence_spans != operator_result.evidence_spans:
|
|
reasons.append("binding_evidence_mismatch")
|
|
if binding.evidence_spans != attempt.evidence_spans:
|
|
reasons.append("binding_evidence_mismatch")
|
|
if binding.evidence_spans != reconstruction.evidence_spans:
|
|
reasons.append("binding_evidence_mismatch")
|
|
if operator_result.geometric_search_run_id != run.run_id:
|
|
reasons.append("operator_result_run_mismatch")
|
|
if reconstruction.problem_frame_digest != run.problem_frame_digest:
|
|
reasons.append("operator_reconstruction_run_mismatch")
|
|
if reconstruction.original_contract_assessment_id != run.contract_assessment_id:
|
|
reasons.append("operator_reconstruction_run_mismatch")
|
|
if reconstruction.source_residual_id not in run.residual_ids:
|
|
reasons.append("operator_reconstruction_run_mismatch")
|
|
return reasons
|
|
|
|
|
|
def _validate_bound_replay_bindings(
|
|
*,
|
|
run: GeometricSearchRun,
|
|
bindings: tuple[object, ...],
|
|
replay_results: tuple[ReplayAdapterResult, ...],
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...],
|
|
) -> list[str]:
|
|
reasons: list[str] = []
|
|
attempt_ids = {binding.candidate_attempt_id for binding in bindings} # type: ignore[attr-defined]
|
|
digest_by_attempt = {
|
|
binding.candidate_attempt_id: binding.candidate_digest # type: ignore[attr-defined]
|
|
for binding in bindings
|
|
}
|
|
|
|
for record in (*replay_results, *replay_refusals):
|
|
identity_reason = _validate_replay_record_identity(record)
|
|
if identity_reason is not None:
|
|
reasons.append(identity_reason)
|
|
run_id = record.run_id
|
|
attempt_id = record.attempt_id
|
|
candidate_digest = record.candidate_digest
|
|
if run_id != run.run_id:
|
|
reasons.append("replay_run_id_mismatch")
|
|
if attempt_id is None or not _nonempty_text(attempt_id):
|
|
reasons.append("replay_orphan_attempt_id")
|
|
elif attempt_id not in attempt_ids:
|
|
reasons.append("replay_orphan_attempt_id")
|
|
if candidate_digest is not None and _nonempty_text(candidate_digest):
|
|
if (
|
|
attempt_id in digest_by_attempt
|
|
and candidate_digest != digest_by_attempt[attempt_id]
|
|
):
|
|
reasons.append("replay_candidate_digest_mismatch")
|
|
elif attempt_id in digest_by_attempt:
|
|
reasons.append("replay_candidate_digest_mismatch")
|
|
|
|
return reasons
|
|
|
|
|
|
def _derive_bound_disposition(
|
|
*,
|
|
replay_results: tuple[ReplayAdapterResult, ...],
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...],
|
|
) -> PracticeDisposition | None:
|
|
if not replay_results and not replay_refusals:
|
|
return None
|
|
|
|
if any(
|
|
result.replay_disposition is ReplayDisposition.CONTRACT_AND_PROOF_CLOSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_CANDIDATE_REPLAY_CLOSED
|
|
|
|
if any(
|
|
result.replay_disposition
|
|
is ReplayDisposition.CONTRACT_CLOSED_BUT_PROOF_REFUSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_CONTRACT_CLOSED_PROOF_REFUSED
|
|
|
|
if replay_results and all(
|
|
result.replay_disposition is ReplayDisposition.CONTRACT_REFUSED
|
|
for result in replay_results
|
|
):
|
|
return PracticeDisposition.SEALED_ALL_CANDIDATES_REFUSED
|
|
|
|
if replay_refusals and not replay_results:
|
|
return PracticeDisposition.SEALED_REPLAY_UNAVAILABLE
|
|
|
|
return None
|
|
|
|
|
|
def build_bound_practice_trace_input(
|
|
*,
|
|
problem_frame_digest: str,
|
|
original_contract_assessment_id: str,
|
|
residual_ids: tuple[str, ...],
|
|
search_gate_decision_id: str,
|
|
compute_budget_id: str,
|
|
run: GeometricSearchRun,
|
|
bindings: tuple[object, ...],
|
|
candidate_operator_results: tuple[object, ...],
|
|
replay_results: tuple[ReplayAdapterResult, ...] = (),
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...] = (),
|
|
schema_versions: tuple[tuple[str, str], ...] = (),
|
|
policy_versions: tuple[tuple[str, str], ...] = (),
|
|
trace_policy_version: str = SEALED_PRACTICE_TRACE_POLICY_VERSION,
|
|
) -> PracticeTraceInput | PracticeTraceRefusal:
|
|
"""Validate bound episode identities and emit a trace input or refusal."""
|
|
|
|
if trace_policy_version != SEALED_PRACTICE_TRACE_POLICY_VERSION:
|
|
return _refusal(
|
|
input_digest=None,
|
|
trace_policy_version=trace_policy_version,
|
|
disposition=PracticeDisposition.TRACE_POLICY_UNSUPPORTED,
|
|
reason_codes=("unsupported_trace_policy_version",),
|
|
)
|
|
|
|
reasons: list[str] = []
|
|
if not isinstance(run, GeometricSearchRun):
|
|
reasons.append("invalid_run_type")
|
|
if not isinstance(bindings, tuple) or not all(
|
|
_valid_binding_record(binding) for binding in bindings
|
|
):
|
|
reasons.append("invalid_binding_type")
|
|
if not isinstance(candidate_operator_results, tuple) or not all(
|
|
_valid_operator_result_record(result) for result in candidate_operator_results
|
|
):
|
|
reasons.append("invalid_candidate_operator_result_type")
|
|
if not isinstance(replay_results, tuple) or not all(
|
|
isinstance(result, ReplayAdapterResult) for result in replay_results
|
|
):
|
|
reasons.append("invalid_replay_result_type")
|
|
if not isinstance(replay_refusals, tuple) or not all(
|
|
isinstance(refusal, ReplayAdapterRefusal) for refusal in replay_refusals
|
|
):
|
|
reasons.append("invalid_replay_refusal_type")
|
|
|
|
if not _sha256_text(problem_frame_digest):
|
|
reasons.append("invalid_problem_frame_digest")
|
|
if not _nonempty_text(original_contract_assessment_id):
|
|
reasons.append("missing_original_contract_assessment_id")
|
|
if not isinstance(residual_ids, tuple) or not all(
|
|
_nonempty_text(residual_id) for residual_id in residual_ids
|
|
):
|
|
reasons.append("invalid_residual_ids")
|
|
if not _sha256_text(search_gate_decision_id):
|
|
reasons.append("invalid_search_gate_decision_id")
|
|
if not _sha256_text(compute_budget_id):
|
|
reasons.append("invalid_compute_budget_id")
|
|
if not _valid_version_pairs(schema_versions):
|
|
reasons.append("invalid_schema_versions")
|
|
if not _valid_version_pairs(policy_versions):
|
|
reasons.append("invalid_policy_versions")
|
|
|
|
geometric_search_run_id = run.run_id if isinstance(run, GeometricSearchRun) else ""
|
|
if not _sha256_text(geometric_search_run_id):
|
|
reasons.append("invalid_geometric_search_run_id")
|
|
|
|
if len(bindings) != len(candidate_operator_results):
|
|
reasons.append("binding_result_count_mismatch")
|
|
|
|
if not reasons and isinstance(run, GeometricSearchRun):
|
|
reasons.extend(
|
|
_validate_run_bindings(
|
|
run=run,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
)
|
|
)
|
|
|
|
binding_ids: list[str] = []
|
|
attempt_ids: list[str] = []
|
|
candidate_digests: list[str] = []
|
|
for binding, operator_result in zip(bindings, candidate_operator_results, strict=True):
|
|
if not _sha256_text(binding.binding_id):
|
|
reasons.append("invalid_candidate_attempt_binding_id")
|
|
if binding.binding_id in binding_ids:
|
|
reasons.append("duplicate_candidate_attempt_binding_id")
|
|
binding_ids.append(binding.binding_id)
|
|
if binding.candidate_attempt_id in attempt_ids:
|
|
reasons.append("duplicate_candidate_attempt_id")
|
|
attempt_ids.append(binding.candidate_attempt_id)
|
|
if binding.candidate_digest in candidate_digests:
|
|
reasons.append("duplicate_candidate_digest")
|
|
candidate_digests.append(binding.candidate_digest)
|
|
reasons.extend(
|
|
_validate_bound_binding_pair(
|
|
run=run,
|
|
binding=binding,
|
|
operator_result=operator_result,
|
|
)
|
|
)
|
|
|
|
reasons.extend(
|
|
_validate_bound_replay_bindings(
|
|
run=run,
|
|
bindings=bindings,
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
)
|
|
|
|
candidate_attempt_ids = tuple(binding.candidate_attempt_id for binding in bindings)
|
|
candidate_attempt_binding_ids = tuple(binding.binding_id for binding in bindings)
|
|
replay_result_ids = tuple(result.replay_result_id for result in replay_results)
|
|
replay_refusal_ids = tuple(refusal.replay_refusal_id for refusal in replay_refusals)
|
|
|
|
if reasons:
|
|
return _refusal(
|
|
input_digest=None,
|
|
disposition=_failure_disposition(reasons),
|
|
reason_codes=tuple(dict.fromkeys(reasons)),
|
|
)
|
|
|
|
input_digest = _canonical_digest(
|
|
_input_digest_payload(
|
|
trace_policy_version=trace_policy_version,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
geometric_search_run_id=geometric_search_run_id,
|
|
candidate_attempt_ids=candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=candidate_attempt_binding_ids,
|
|
replay_result_ids=replay_result_ids,
|
|
replay_refusal_ids=replay_refusal_ids,
|
|
schema_versions=schema_versions,
|
|
policy_versions=policy_versions,
|
|
)
|
|
)
|
|
return PracticeTraceInput(
|
|
input_digest=input_digest,
|
|
trace_policy_version=trace_policy_version,
|
|
problem_frame_digest=problem_frame_digest,
|
|
original_contract_assessment_id=original_contract_assessment_id,
|
|
residual_ids=residual_ids,
|
|
search_gate_decision_id=search_gate_decision_id,
|
|
compute_budget_id=compute_budget_id,
|
|
geometric_search_run_id=geometric_search_run_id,
|
|
candidate_attempt_ids=candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=candidate_attempt_binding_ids,
|
|
replay_result_ids=replay_result_ids,
|
|
replay_refusal_ids=replay_refusal_ids,
|
|
schema_versions=schema_versions,
|
|
policy_versions=policy_versions,
|
|
)
|
|
|
|
|
|
def seal_bound_practice_trace(
|
|
trace_input: PracticeTraceInput,
|
|
*,
|
|
run: GeometricSearchRun,
|
|
bindings: tuple[object, ...],
|
|
candidate_operator_results: tuple[object, ...],
|
|
replay_results: tuple[ReplayAdapterResult, ...] = (),
|
|
replay_refusals: tuple[ReplayAdapterRefusal, ...] = (),
|
|
evidence_spans: tuple[SourceSpan, ...] = (),
|
|
explanation: str = "",
|
|
) -> SealedPracticeTrace | PracticeTraceRefusal:
|
|
"""Seal a validated bound practice episode as immutable diagnostic evidence."""
|
|
|
|
if not isinstance(trace_input, PracticeTraceInput):
|
|
return _refusal(
|
|
input_digest=None,
|
|
disposition=PracticeDisposition.TRACE_INVALID_INPUT,
|
|
reason_codes=("invalid_trace_input_type",),
|
|
)
|
|
if trace_input.trace_policy_version != SEALED_PRACTICE_TRACE_POLICY_VERSION:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
disposition=PracticeDisposition.TRACE_POLICY_UNSUPPORTED,
|
|
reason_codes=("unsupported_trace_policy_version",),
|
|
)
|
|
if not _valid_spans(evidence_spans):
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_INVALID_INPUT,
|
|
reason_codes=("invalid_evidence_spans",),
|
|
)
|
|
|
|
reasons: list[str] = []
|
|
if not isinstance(run, GeometricSearchRun):
|
|
reasons.append("invalid_run_type")
|
|
if not isinstance(bindings, tuple) or not all(
|
|
_valid_binding_record(binding) for binding in bindings
|
|
):
|
|
reasons.append("invalid_binding_type")
|
|
if not isinstance(candidate_operator_results, tuple) or not all(
|
|
_valid_operator_result_record(result) for result in candidate_operator_results
|
|
):
|
|
reasons.append("invalid_candidate_operator_result_type")
|
|
|
|
if run.run_id != trace_input.geometric_search_run_id:
|
|
reasons.append("geometric_search_run_id_mismatch")
|
|
|
|
replay_result_ids = tuple(result.replay_result_id for result in replay_results)
|
|
replay_refusal_ids = tuple(refusal.replay_refusal_id for refusal in replay_refusals)
|
|
if replay_result_ids != trace_input.replay_result_ids:
|
|
reasons.append("replay_result_ids_mismatch")
|
|
if replay_refusal_ids != trace_input.replay_refusal_ids:
|
|
reasons.append("replay_refusal_ids_mismatch")
|
|
|
|
binding_ids = tuple(binding.binding_id for binding in bindings)
|
|
attempt_ids = tuple(binding.candidate_attempt_id for binding in bindings)
|
|
if binding_ids != trace_input.candidate_attempt_binding_ids:
|
|
reasons.append("candidate_attempt_binding_ids_mismatch")
|
|
if attempt_ids != trace_input.candidate_attempt_ids:
|
|
reasons.append("candidate_attempt_ids_mismatch")
|
|
|
|
if not reasons:
|
|
reasons.extend(
|
|
_validate_run_bindings(
|
|
run=run,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
)
|
|
)
|
|
if len(bindings) != len(candidate_operator_results):
|
|
reasons.append("binding_result_count_mismatch")
|
|
for binding, operator_result in zip(bindings, candidate_operator_results, strict=True):
|
|
reasons.extend(
|
|
_validate_bound_binding_pair(
|
|
run=run,
|
|
binding=binding,
|
|
operator_result=operator_result,
|
|
)
|
|
)
|
|
reasons.extend(
|
|
_validate_bound_replay_bindings(
|
|
run=run,
|
|
bindings=bindings,
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
)
|
|
if bindings and not replay_results and not replay_refusals:
|
|
reasons.append("missing_replay_records")
|
|
|
|
if reasons:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=_failure_disposition(reasons),
|
|
reason_codes=tuple(dict.fromkeys(reasons)),
|
|
)
|
|
|
|
recomputed_input_digest = _canonical_digest(
|
|
_input_digest_payload(
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
schema_versions=trace_input.schema_versions,
|
|
policy_versions=trace_input.policy_versions,
|
|
)
|
|
)
|
|
if recomputed_input_digest != trace_input.input_digest:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_IDENTITY_MISMATCH,
|
|
reason_codes=("input_digest_mismatch",),
|
|
)
|
|
|
|
practice_disposition = _derive_bound_disposition(
|
|
replay_results=replay_results,
|
|
replay_refusals=replay_refusals,
|
|
)
|
|
if practice_disposition is None or practice_disposition not in _SEALED_DISPOSITIONS:
|
|
return _refusal(
|
|
input_digest=trace_input.input_digest,
|
|
disposition=PracticeDisposition.TRACE_UPSTREAM_INCOMPLETE,
|
|
reason_codes=("unsupported_bound_practice_disposition",),
|
|
)
|
|
|
|
identity_chain = _upstream_identity_chain(
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
)
|
|
trace_records = identity_chain
|
|
trace_id = _canonical_digest(
|
|
_trace_id_payload(
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
input_digest=trace_input.input_digest,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
upstream_identity_chain=identity_chain,
|
|
practice_disposition=practice_disposition,
|
|
trace_records=trace_records,
|
|
evidence_spans=evidence_spans,
|
|
created_by_policy=CREATED_BY_POLICY,
|
|
)
|
|
)
|
|
|
|
safe_explanation = explanation or (
|
|
"Sealed bound practice trace disposition: " + practice_disposition.value + "."
|
|
)
|
|
return SealedPracticeTrace(
|
|
trace_id=trace_id,
|
|
trace_policy_version=trace_input.trace_policy_version,
|
|
input_digest=trace_input.input_digest,
|
|
problem_frame_digest=trace_input.problem_frame_digest,
|
|
original_contract_assessment_id=trace_input.original_contract_assessment_id,
|
|
residual_ids=trace_input.residual_ids,
|
|
search_gate_decision_id=trace_input.search_gate_decision_id,
|
|
compute_budget_id=trace_input.compute_budget_id,
|
|
geometric_search_run_id=trace_input.geometric_search_run_id,
|
|
candidate_attempt_ids=trace_input.candidate_attempt_ids,
|
|
candidate_attempt_binding_ids=trace_input.candidate_attempt_binding_ids,
|
|
replay_result_ids=trace_input.replay_result_ids,
|
|
replay_refusal_ids=trace_input.replay_refusal_ids,
|
|
upstream_identity_chain=identity_chain,
|
|
practice_disposition=practice_disposition,
|
|
trace_records=trace_records,
|
|
evidence_spans=evidence_spans,
|
|
created_by_policy=CREATED_BY_POLICY,
|
|
explanation=safe_explanation,
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"SEALED_PRACTICE_TRACE_POLICY_VERSION",
|
|
"PracticeDisposition",
|
|
"PracticeTraceInput",
|
|
"SealedPracticeTrace",
|
|
"PracticeTraceRefusal",
|
|
"PracticeTraceOutcome",
|
|
"build_practice_trace_input",
|
|
"seal_practice_trace",
|
|
"build_bound_practice_trace_input",
|
|
"seal_bound_practice_trace",
|
|
]
|