"""Inert, diagnostic-only missing-role candidate operator shell.""" from __future__ import annotations import hashlib import json from dataclasses import dataclass from enum import Enum, unique from generate.compute_budget import ComputeBudgetDecision, ComputeBudgetStatus from generate.geometric_search_run import ( BudgetCharge, CandidateAttempt, CandidateReplayStatus, GeometricSearchRun, ) from generate.kernel_facts import SourceSpan from generate.search_gate import SearchGateDecision, SearchGateStatus CANDIDATE_OPERATOR_POLICY_VERSION = "candidate_operator.v1" CANDIDATE_OPERATOR_SET_VERSION = "candidate_operators.v2" MISSING_ROLE_CANDIDATE_OPERATOR_NAME = "missing_role_candidate" MISSING_ROLE_CANDIDATE_OPERATOR_VERSION = "missing_role_candidate.v1" MISSING_ROLE_RESIDUAL_KIND = "missing_role" MISSING_ROLE_RESIDUAL_CODE = "direction_unbound" MISSING_ROLE_CANDIDATE_ORGAN = "unary_delta_transition" QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME = "quantity_entity_binding_candidate" QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION = "quantity_entity_binding_candidate.v1" QUANTITY_ENTITY_BINDING_RESIDUAL_KIND = "missing_relation" QUANTITY_ENTITY_BINDING_RESIDUAL_CODE = "local_binding_relation_unbound" QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN = "quantity_entity_binding" _OPERATOR_FAMILY = "residual_missing_role" _SUPPORTED_DIRECTIONS = frozenset({"increase", "decrease"}) _FIXED_BUDGET_CHARGE = BudgetCharge(candidates=1, steps=1) _OPERATOR_DEPTH = 1 _OPERATOR_MAX_PARALLELISM = 1 _DETERMINISM_REQUIREMENTS = ( "canonical_json_sha256", "static_operator_table", "no_source_reread", "no_stochastic_generation", ) _FORBIDDEN_AUTHORITY_PATHS = ( "answer_production", "contract_replay", "proof_replay", "sealed_trace", "serving", "mutation", "promotion", "workbench", "repair", "open_ended_search", ) @unique class CandidateOperatorRefusalReason(str, Enum): UNSUPPORTED_OPERATOR_POLICY = "unsupported_operator_policy" UNSUPPORTED_OPERATOR = "unsupported_operator" UNSUPPORTED_RESIDUAL_KIND = "unsupported_residual_kind" UNSUPPORTED_RESIDUAL_CODE = "unsupported_residual_code" UNSUPPORTED_CANDIDATE_ORGAN = "unsupported_candidate_organ" INELIGIBLE_SEARCH_GATE = "ineligible_search_gate" NON_ALLOWED_BUDGET = "non_allowed_budget" GATE_BUDGET_MISMATCH = "gate_budget_mismatch" RUN_GATE_MISMATCH = "run_gate_mismatch" RUN_BUDGET_MISMATCH = "run_budget_mismatch" OPERATOR_SET_MISMATCH = "operator_set_mismatch" ATTEMPT_INDEX_EXCEEDS_BUDGET = "attempt_index_exceeds_budget" ATTEMPT_INDEX_EXCEEDS_OPERATOR_POLICY = "attempt_index_exceeds_operator_policy" BUDGET_CHARGE_EXCEEDS_BUDGET = "budget_charge_exceeds_budget" NON_SERIAL_BUDGET = "non_serial_budget" MISSING_TYPED_CUE = "missing_typed_cue" AMBIGUOUS_TYPED_CUE = "ambiguous_typed_cue" UNSUPPORTED_TYPED_CUE = "unsupported_typed_cue" MALFORMED_EVIDENCE_SPAN = "malformed_evidence_span" INVALID_OPERATOR_INPUT = "invalid_operator_input" UNSUPPORTED_SCHEMA_VERSION = "unsupported_schema_version" INVALID_QUANTITY_ENTITY_CUE_TYPE = "invalid_quantity_entity_cue_type" QUANTITY_ENTITY_CUE_COUNT_MISMATCH = "quantity_entity_cue_count_mismatch" EMPTY_QUANTITY_MENTION_ID = "empty_quantity_mention_id" EMPTY_ENTITY_MENTION_ID = "empty_entity_mention_id" EMPTY_QUANTITY_KIND = "empty_quantity_kind" EMPTY_UNIT_MENTION_ID = "empty_unit_mention_id" MISSING_EVIDENCE_SPANS = "missing_evidence_spans" @dataclass(frozen=True, slots=True) class CandidateOperatorPolicy: operator_policy_version: str operator_family: str operator_name: str operator_version: str allowed_residual_kinds: tuple[str, ...] allowed_residual_codes: tuple[str, ...] allowed_candidate_organs: tuple[str, ...] max_attempts_per_run: int budget_charge: BudgetCharge depth: int max_parallelism: int determinism_requirements: tuple[str, ...] forbidden_authority_paths: tuple[str, ...] MISSING_ROLE_OPERATOR_POLICY = CandidateOperatorPolicy( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, operator_family=_OPERATOR_FAMILY, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, allowed_residual_kinds=(MISSING_ROLE_RESIDUAL_KIND,), allowed_residual_codes=(MISSING_ROLE_RESIDUAL_CODE,), allowed_candidate_organs=(MISSING_ROLE_CANDIDATE_ORGAN,), max_attempts_per_run=1, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, max_parallelism=_OPERATOR_MAX_PARALLELISM, determinism_requirements=_DETERMINISM_REQUIREMENTS, forbidden_authority_paths=_FORBIDDEN_AUTHORITY_PATHS, ) QUANTITY_ENTITY_BINDING_OPERATOR_POLICY = CandidateOperatorPolicy( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, operator_family="residual_missing_relation", operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, allowed_residual_kinds=(QUANTITY_ENTITY_BINDING_RESIDUAL_KIND,), allowed_residual_codes=(QUANTITY_ENTITY_BINDING_RESIDUAL_CODE,), allowed_candidate_organs=(QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN,), max_attempts_per_run=1, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, max_parallelism=_OPERATOR_MAX_PARALLELISM, determinism_requirements=_DETERMINISM_REQUIREMENTS, forbidden_authority_paths=_FORBIDDEN_AUTHORITY_PATHS, ) @dataclass(frozen=True, slots=True) class GroundedUnaryDeltaCue: direction: str evidence_spans: tuple[SourceSpan, ...] @dataclass(frozen=True, slots=True) class GroundedQuantityEntityCue: quantity_mention_id: str entity_mention_id: str quantity_kind: str evidence_spans: tuple[SourceSpan, ...] unit_mention_id: str | None = None @dataclass(frozen=True, slots=True) class CandidateOperatorInput: input_digest: str operator_policy_version: str operator_name: str operator_version: str problem_frame_digest: str original_contract_assessment_id: str residual_id: str residual_kind: str residual_code: str candidate_organ: str search_gate_decision_id: str compute_budget_id: str geometric_search_run_id: str operator_set_id: str operator_set_version: str attempt_index: int schema_versions: tuple[tuple[str, str], ...] policy_versions: tuple[tuple[str, str], ...] @dataclass(frozen=True, slots=True) class CandidateReconstruction: candidate_digest: str candidate_reconstruction_digest: str candidate_organ: str candidate_payload: tuple[tuple[str, str], ...] evidence_spans: tuple[SourceSpan, ...] operator_name: str operator_version: str operator_provenance: tuple[tuple[str, str], ...] source_residual_id: str problem_frame_digest: str original_contract_assessment_id: str @dataclass(frozen=True, slots=True) class CandidateOperatorResult: operator_result_id: str operator_policy_version: str input_digest: str geometric_search_run_id: str attempt_id: str attempt_index: int candidate_digest: str candidate_reconstruction_digest: str candidate_organ: str operator_name: str operator_version: str candidate_attempt: CandidateAttempt candidate_reconstruction: CandidateReconstruction reason_codes: tuple[str, ...] evidence_spans: tuple[SourceSpan, ...] explanation: str @dataclass(frozen=True, slots=True) class CandidateOperatorRefusal: operator_refusal_id: str operator_policy_version: str input_digest: str | None geometric_search_run_id: str | None residual_id: str | None operator_name: str reason_codes: tuple[str, ...] explanation: str CandidateOperatorOutcome = CandidateOperatorResult | CandidateOperatorRefusal 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 _safe_getattr(value: object, name: str) -> object: try: return getattr(value, name, None) except Exception: return None 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 _text_or_none(value: object) -> str | None: return value if isinstance(value, str) and value else None def _enum_value(value: object) -> object: return getattr(value, "value", 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 if not value: return True 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) if len(names) != len(set(names)): return False return names == sorted(names) def _operator_set_table_payload() -> dict[str, object]: return { "operator_set_version": CANDIDATE_OPERATOR_SET_VERSION, "operators": [ { "operator_family": MISSING_ROLE_OPERATOR_POLICY.operator_family, "operator_name": MISSING_ROLE_OPERATOR_POLICY.operator_name, "operator_version": MISSING_ROLE_OPERATOR_POLICY.operator_version, "allowed_residual_kinds": list( MISSING_ROLE_OPERATOR_POLICY.allowed_residual_kinds ), "allowed_residual_codes": list( MISSING_ROLE_OPERATOR_POLICY.allowed_residual_codes ), "allowed_candidate_organs": list( MISSING_ROLE_OPERATOR_POLICY.allowed_candidate_organs ), "max_attempts_per_run": MISSING_ROLE_OPERATOR_POLICY.max_attempts_per_run, "budget_charge": { "candidates": MISSING_ROLE_OPERATOR_POLICY.budget_charge.candidates, "steps": MISSING_ROLE_OPERATOR_POLICY.budget_charge.steps, }, "depth": MISSING_ROLE_OPERATOR_POLICY.depth, "max_parallelism": MISSING_ROLE_OPERATOR_POLICY.max_parallelism, }, { "operator_family": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.operator_family, "operator_name": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.operator_name, "operator_version": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.operator_version, "allowed_residual_kinds": list( QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.allowed_residual_kinds ), "allowed_residual_codes": list( QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.allowed_residual_codes ), "allowed_candidate_organs": list( QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.allowed_candidate_organs ), "max_attempts_per_run": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.max_attempts_per_run, "budget_charge": { "candidates": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.budget_charge.candidates, "steps": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.budget_charge.steps, }, "depth": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.depth, "max_parallelism": QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.max_parallelism, }, ], "schema_versions": [], "policy_versions": [], } def candidate_operator_set_id() -> str: """Return the canonical digest of the closed one-row operator table.""" return _canonical_digest(_operator_set_table_payload()) def _candidate_payload(direction: str) -> tuple[tuple[str, str], ...]: return ( ("candidate_organ", MISSING_ROLE_CANDIDATE_ORGAN), ("direction", direction), ("kind", "role_binding_delta"), ("relation_type", "state_change.unary_delta"), ("role", "direction"), ("source", "GroundedUnaryDeltaCue.direction"), ) def _quantity_entity_binding_candidate_payload( cue: GroundedQuantityEntityCue, ) -> tuple[tuple[str, str], ...]: return ( ("binding_type", "quantity_entity"), ("candidate_organ", QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN), ("entity_mention_id", cue.entity_mention_id), ("kind", "mention_binding"), ("quantity_kind", cue.quantity_kind), ("quantity_mention_id", cue.quantity_mention_id), ("relation_type", "quantity_entity"), ("source", "GroundedQuantityEntityCue"), ("unit_mention_id", cue.unit_mention_id or ""), ) def _candidate_payload_dict( payload: tuple[tuple[str, str], ...], ) -> list[list[str]]: return [[key, value] for key, value in payload] def _candidate_digest_payload( *, problem_frame_digest: str, candidate_organ: str, candidate_payload: tuple[tuple[str, str], ...], evidence_spans: tuple[SourceSpan, ...], ) -> dict[str, object]: return { "problem_frame_digest": problem_frame_digest, "candidate_organ": candidate_organ, "candidate_payload": _candidate_payload_dict(candidate_payload), "evidence_spans": [_span_payload(span) for span in evidence_spans], } def _input_digest_payload( *, operator_policy_version: str, operator_name: str, operator_version: str, problem_frame_digest: str, original_contract_assessment_id: str, residual_id: str, residual_kind: str, residual_code: str, candidate_organ: str, search_gate_decision_id: str, compute_budget_id: str, geometric_search_run_id: str, operator_set_id: str, operator_set_version: str, attempt_index: int, schema_versions: tuple[tuple[str, str], ...], policy_versions: tuple[tuple[str, str], ...], ) -> dict[str, object]: return { "operator_policy_version": operator_policy_version, "operator_name": operator_name, "operator_version": operator_version, "problem_frame_digest": problem_frame_digest, "original_contract_assessment_id": original_contract_assessment_id, "residual_id": residual_id, "residual_kind": residual_kind, "residual_code": residual_code, "candidate_organ": candidate_organ, "search_gate_decision_id": search_gate_decision_id, "compute_budget_id": compute_budget_id, "geometric_search_run_id": geometric_search_run_id, "operator_set_id": operator_set_id, "operator_set_version": operator_set_version, "attempt_index": attempt_index, "schema_versions": _version_pairs_payload(schema_versions), "policy_versions": _version_pairs_payload(policy_versions), } def _attempt_id_payload( *, attempt_index: int, parent_attempt_id: str | None, operator_id: str, operator_version: str, input_digest: str, candidate_digest: str, budget_charge: BudgetCharge, depth: int, step_index: int, replay_status: CandidateReplayStatus, replay_blockers: tuple[str, ...], evidence_spans: tuple[SourceSpan, ...], ) -> dict[str, object]: return { "attempt_id": "", "attempt_index": attempt_index, "parent_attempt_id": parent_attempt_id, "operator_id": operator_id, "operator_version": operator_version, "input_digest": input_digest, "candidate_digest": candidate_digest, "budget_charge": { "candidates": budget_charge.candidates, "steps": budget_charge.steps, }, "depth": depth, "step_index": step_index, "replay_status": replay_status.value, "replay_blockers": list(replay_blockers), "evidence_spans": [_span_payload(span) for span in evidence_spans], } def _reconstruction_digest_payload( *, geometric_search_run_id: str, attempt_id: str, attempt_index: int, operator_set_id: str, operator_set_version: str, operator_name: str, operator_version: str, residual_id: str, residual_kind: str, residual_code: str, candidate_digest: str, evidence_spans: tuple[SourceSpan, ...], schema_versions: tuple[tuple[str, str], ...], policy_versions: tuple[tuple[str, str], ...], ) -> dict[str, object]: return { "candidate_reconstruction_digest": "", "geometric_search_run_id": geometric_search_run_id, "attempt_id": attempt_id, "attempt_index": attempt_index, "operator_set_id": operator_set_id, "operator_set_version": operator_set_version, "operator_name": operator_name, "operator_version": operator_version, "residual_id": residual_id, "residual_kind": residual_kind, "residual_code": residual_code, "candidate_digest": candidate_digest, "evidence_spans": [_span_payload(span) for span in evidence_spans], "schema_versions": _version_pairs_payload(schema_versions), "policy_versions": _version_pairs_payload(policy_versions), } def _operator_result_id_payload( *, operator_policy_version: str, input_digest: str, geometric_search_run_id: str, attempt_id: str, attempt_index: int, candidate_digest: str, candidate_reconstruction_digest: str, candidate_organ: str, operator_name: str, operator_version: str, reason_codes: tuple[str, ...], evidence_spans: tuple[SourceSpan, ...], ) -> dict[str, object]: return { "operator_result_id": "", "operator_policy_version": operator_policy_version, "input_digest": input_digest, "geometric_search_run_id": geometric_search_run_id, "attempt_id": attempt_id, "attempt_index": attempt_index, "candidate_digest": candidate_digest, "candidate_reconstruction_digest": candidate_reconstruction_digest, "candidate_organ": candidate_organ, "operator_name": operator_name, "operator_version": operator_version, "reason_codes": list(reason_codes), "evidence_spans": [_span_payload(span) for span in evidence_spans], } def _operator_refusal_id_payload( *, operator_policy_version: str, input_digest: str | None, geometric_search_run_id: str | None, residual_id: str | None, operator_name: str, reason_codes: tuple[str, ...], ) -> dict[str, object]: return { "operator_refusal_id": "", "operator_policy_version": operator_policy_version, "input_digest": input_digest, "geometric_search_run_id": geometric_search_run_id, "residual_id": residual_id, "operator_name": operator_name, "reason_codes": list(reason_codes), } def _refusal( *, input_digest: str | None, geometric_search_run_id: str | None, residual_id: str | None, reason_codes: tuple[str, ...], ) -> CandidateOperatorRefusal: operator_refusal_id = _canonical_digest( _operator_refusal_id_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=geometric_search_run_id, residual_id=residual_id, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, reason_codes=reason_codes, ) ) return CandidateOperatorRefusal( operator_refusal_id=operator_refusal_id, operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=geometric_search_run_id, residual_id=residual_id, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, reason_codes=reason_codes, explanation="Candidate operator refused: " + ", ".join(reason_codes) + ".", ) def _spans_grounded_in_residual( cue_spans: tuple[SourceSpan, ...], residual_spans: tuple[SourceSpan, ...], ) -> bool: if not cue_spans: return False for cue_span in cue_spans: if cue_span not in residual_spans: return False return True def _valid_residual_record(residual: object) -> bool: required = ( "residual_id", "candidate_organ", "residual_kind", "residual_code", "evidence_spans", ) return all(_safe_getattr(residual, name) is not None for name in required) def build_missing_role_candidate( *, residual: object, search_gate: SearchGateDecision, compute_budget: ComputeBudgetDecision, run: GeometricSearchRun, problem_frame_digest: str, original_contract_assessment_id: str, grounded_unary_delta_cues: tuple[GroundedUnaryDeltaCue, ...], attempt_index: int = 0, schema_versions: tuple[tuple[str, str], ...] = (), policy_versions: tuple[tuple[str, str], ...] = (), explanation: str = "", ) -> CandidateOperatorOutcome: """Construct one missing-role candidate or return a typed refusal.""" operator_set_id = candidate_operator_set_id() reasons: list[str] = [] residual_id = _safe_getattr(residual, "residual_id") residual_kind = _enum_value(_safe_getattr(residual, "residual_kind")) residual_code = _safe_getattr(residual, "residual_code") candidate_organ = _safe_getattr(residual, "candidate_organ") residual_spans = _safe_getattr(residual, "evidence_spans") gate_id = _safe_getattr(search_gate, "decision_id") gate_status = _safe_getattr(search_gate, "status") gate_reason = _safe_getattr(search_gate, "reason_code") gate_residual_ids = _safe_getattr(search_gate, "residual_ids") gate_candidate_organ = _safe_getattr(search_gate, "candidate_organ") budget_id = _safe_getattr(compute_budget, "budget_id") budget_status = _safe_getattr(compute_budget, "status") budget_reason = _safe_getattr(compute_budget, "reason_code") budget_gate_id = _safe_getattr(compute_budget, "gate_decision_id") max_candidates = _safe_getattr(compute_budget, "max_candidates") max_depth = _safe_getattr(compute_budget, "max_depth") max_steps = _safe_getattr(compute_budget, "max_steps") max_parallelism = _safe_getattr(compute_budget, "max_parallelism") run_id = _safe_getattr(run, "run_id") run_gate_id = _safe_getattr(run, "gate_decision_id") run_budget_id = _safe_getattr(run, "budget_id") run_operator_set_id = _safe_getattr(run, "operator_set_id") run_operator_set_version = _safe_getattr(run, "operator_set_version") run_problem_frame_digest = _safe_getattr(run, "problem_frame_digest") run_assessment_id = _safe_getattr(run, "contract_assessment_id") run_residual_ids = _safe_getattr(run, "residual_ids") if not _valid_residual_record(residual): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(search_gate, SearchGateDecision): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(compute_budget, ComputeBudgetDecision): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(run, GeometricSearchRun): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _nonempty_text(residual_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if residual_kind != MISSING_ROLE_RESIDUAL_KIND: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_RESIDUAL_KIND.value) if residual_code != MISSING_ROLE_RESIDUAL_CODE: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_RESIDUAL_CODE.value) if candidate_organ != MISSING_ROLE_CANDIDATE_ORGAN: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_CANDIDATE_ORGAN.value) if not _valid_spans(residual_spans): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) if gate_status is not SearchGateStatus.ELIGIBLE: reasons.append(CandidateOperatorRefusalReason.INELIGIBLE_SEARCH_GATE.value) if gate_reason != "eligible_missing_role": reasons.append(CandidateOperatorRefusalReason.INELIGIBLE_SEARCH_GATE.value) if gate_candidate_organ != MISSING_ROLE_CANDIDATE_ORGAN: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_CANDIDATE_ORGAN.value) if budget_status is not ComputeBudgetStatus.BUDGET_ALLOWED: reasons.append(CandidateOperatorRefusalReason.NON_ALLOWED_BUDGET.value) if budget_reason != "budget_allowed_missing_role": reasons.append(CandidateOperatorRefusalReason.NON_ALLOWED_BUDGET.value) if not _nonempty_text(budget_gate_id) or not _nonempty_text(gate_id): reasons.append(CandidateOperatorRefusalReason.GATE_BUDGET_MISMATCH.value) elif budget_gate_id != gate_id: reasons.append(CandidateOperatorRefusalReason.GATE_BUDGET_MISMATCH.value) if not _nonempty_text(run_gate_id) or not _nonempty_text(gate_id): reasons.append(CandidateOperatorRefusalReason.RUN_GATE_MISMATCH.value) elif run_gate_id != gate_id: reasons.append(CandidateOperatorRefusalReason.RUN_GATE_MISMATCH.value) if not _nonempty_text(run_budget_id) or not _nonempty_text(budget_id): reasons.append(CandidateOperatorRefusalReason.RUN_BUDGET_MISMATCH.value) elif run_budget_id != budget_id: reasons.append(CandidateOperatorRefusalReason.RUN_BUDGET_MISMATCH.value) if run_operator_set_id != operator_set_id: reasons.append(CandidateOperatorRefusalReason.OPERATOR_SET_MISMATCH.value) if run_operator_set_version != CANDIDATE_OPERATOR_SET_VERSION: reasons.append(CandidateOperatorRefusalReason.OPERATOR_SET_MISMATCH.value) if type(attempt_index) is not int or attempt_index < 0: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if type(max_candidates) is not int: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) elif attempt_index >= max_candidates: reasons.append( CandidateOperatorRefusalReason.ATTEMPT_INDEX_EXCEEDS_BUDGET.value ) if attempt_index >= MISSING_ROLE_OPERATOR_POLICY.max_attempts_per_run: reasons.append( CandidateOperatorRefusalReason.ATTEMPT_INDEX_EXCEEDS_OPERATOR_POLICY.value ) if type(max_depth) is not int or type(max_steps) is not int: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) else: charge = MISSING_ROLE_OPERATOR_POLICY.budget_charge if charge.candidates > max_candidates: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if charge.steps > max_steps: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if MISSING_ROLE_OPERATOR_POLICY.depth > max_depth: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if type(max_parallelism) is not int or max_parallelism != 1: reasons.append(CandidateOperatorRefusalReason.NON_SERIAL_BUDGET.value) if not _valid_version_pairs(schema_versions): reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_SCHEMA_VERSION.value) if not _valid_version_pairs(policy_versions): reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_SCHEMA_VERSION.value) if not _sha256_text(problem_frame_digest): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _nonempty_text(original_contract_assessment_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _sha256_text(run_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(residual_id, str) and isinstance(gate_residual_ids, tuple) and residual_id not in gate_residual_ids ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(residual_id, str) and isinstance(run_residual_ids, tuple) and residual_id not in run_residual_ids ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(problem_frame_digest, str) and isinstance(run_problem_frame_digest, str) and problem_frame_digest != run_problem_frame_digest ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(original_contract_assessment_id, str) and isinstance(run_assessment_id, str) and original_contract_assessment_id != run_assessment_id ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if len(grounded_unary_delta_cues) == 0: reasons.append(CandidateOperatorRefusalReason.MISSING_TYPED_CUE.value) elif len(grounded_unary_delta_cues) > 1: reasons.append(CandidateOperatorRefusalReason.AMBIGUOUS_TYPED_CUE.value) cue: GroundedUnaryDeltaCue | None = None if len(grounded_unary_delta_cues) == 1: cue = grounded_unary_delta_cues[0] if not _nonempty_text(cue.direction): reasons.append(CandidateOperatorRefusalReason.MISSING_TYPED_CUE.value) elif cue.direction not in _SUPPORTED_DIRECTIONS: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_TYPED_CUE.value) if not _valid_spans(cue.evidence_spans): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) elif isinstance(residual_spans, tuple) and not _spans_grounded_in_residual( cue.evidence_spans, residual_spans ): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) input_digest: str | None = None if ( not reasons and isinstance(residual_id, str) and isinstance(run_id, str) and isinstance(gate_id, str) and isinstance(budget_id, str) and type(attempt_index) is int ): input_digest = _canonical_digest( _input_digest_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, problem_frame_digest=problem_frame_digest, original_contract_assessment_id=original_contract_assessment_id, residual_id=residual_id, residual_kind=MISSING_ROLE_RESIDUAL_KIND, residual_code=MISSING_ROLE_RESIDUAL_CODE, candidate_organ=MISSING_ROLE_CANDIDATE_ORGAN, search_gate_decision_id=gate_id, compute_budget_id=budget_id, geometric_search_run_id=run_id, operator_set_id=operator_set_id, operator_set_version=CANDIDATE_OPERATOR_SET_VERSION, attempt_index=attempt_index, schema_versions=schema_versions, policy_versions=policy_versions, ) ) if reasons: return _refusal( input_digest=input_digest, geometric_search_run_id=_text_or_none(run_id), residual_id=_text_or_none(residual_id), reason_codes=tuple(dict.fromkeys(reasons)), ) assert cue is not None assert input_digest is not None assert isinstance(residual_id, str) assert isinstance(run_id, str) evidence_spans = cue.evidence_spans payload = _candidate_payload(cue.direction) candidate_digest = _canonical_digest( _candidate_digest_payload( problem_frame_digest=problem_frame_digest, candidate_organ=MISSING_ROLE_CANDIDATE_ORGAN, candidate_payload=payload, evidence_spans=evidence_spans, ) ) attempt_id = _canonical_digest( _attempt_id_payload( attempt_index=attempt_index, parent_attempt_id=None, operator_id=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, input_digest=input_digest, candidate_digest=candidate_digest, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, step_index=attempt_index, replay_status=CandidateReplayStatus.REPLAY_PENDING, replay_blockers=(), evidence_spans=evidence_spans, ) ) candidate_reconstruction_digest = _canonical_digest( _reconstruction_digest_payload( geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, operator_set_id=operator_set_id, operator_set_version=CANDIDATE_OPERATOR_SET_VERSION, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, residual_id=residual_id, residual_kind=MISSING_ROLE_RESIDUAL_KIND, residual_code=MISSING_ROLE_RESIDUAL_CODE, candidate_digest=candidate_digest, evidence_spans=evidence_spans, schema_versions=schema_versions, policy_versions=policy_versions, ) ) operator_provenance = ( ("operator_family", _OPERATOR_FAMILY), ("operator_name", MISSING_ROLE_CANDIDATE_OPERATOR_NAME), ("operator_version", MISSING_ROLE_CANDIDATE_OPERATOR_VERSION), ("operator_set_id", operator_set_id), ("operator_set_version", CANDIDATE_OPERATOR_SET_VERSION), ) candidate_reconstruction = CandidateReconstruction( candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=MISSING_ROLE_CANDIDATE_ORGAN, candidate_payload=payload, evidence_spans=evidence_spans, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, operator_provenance=operator_provenance, source_residual_id=residual_id, problem_frame_digest=problem_frame_digest, original_contract_assessment_id=original_contract_assessment_id, ) candidate_attempt = CandidateAttempt( attempt_id=attempt_id, attempt_index=attempt_index, parent_attempt_id=None, operator_id=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, input_digest=input_digest, candidate_digest=candidate_digest, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, step_index=attempt_index, replay_status=CandidateReplayStatus.REPLAY_PENDING, replay_blockers=(), evidence_spans=evidence_spans, explanation="", ) reason_codes: tuple[str, ...] = () operator_result_id = _canonical_digest( _operator_result_id_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=MISSING_ROLE_CANDIDATE_ORGAN, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, reason_codes=reason_codes, evidence_spans=evidence_spans, ) ) safe_explanation = explanation or ( "Missing-role candidate constructed for residual " + residual_id + " with direction " + cue.direction + "." ) return CandidateOperatorResult( operator_result_id=operator_result_id, operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=MISSING_ROLE_CANDIDATE_ORGAN, operator_name=MISSING_ROLE_CANDIDATE_OPERATOR_NAME, operator_version=MISSING_ROLE_CANDIDATE_OPERATOR_VERSION, candidate_attempt=candidate_attempt, candidate_reconstruction=candidate_reconstruction, reason_codes=reason_codes, evidence_spans=evidence_spans, explanation=safe_explanation, ) def build_quantity_entity_binding_candidate( *, residual: object, search_gate: SearchGateDecision, compute_budget: ComputeBudgetDecision, run: GeometricSearchRun, problem_frame_digest: str, original_contract_assessment_id: str, grounded_quantity_entity_cues: tuple[GroundedQuantityEntityCue, ...], attempt_index: int = 0, schema_versions: tuple[tuple[str, str], ...] = (), policy_versions: tuple[tuple[str, str], ...] = (), explanation: str = "", ) -> CandidateOperatorOutcome: """Construct one quantity-entity binding candidate or return a typed refusal.""" operator_set_id = candidate_operator_set_id() reasons: list[str] = [] residual_id = _safe_getattr(residual, "residual_id") residual_kind = _enum_value(_safe_getattr(residual, "residual_kind")) residual_code = _safe_getattr(residual, "residual_code") candidate_organ = _safe_getattr(residual, "candidate_organ") residual_spans = _safe_getattr(residual, "evidence_spans") gate_id = _safe_getattr(search_gate, "decision_id") gate_status = _safe_getattr(search_gate, "status") gate_reason = _safe_getattr(search_gate, "reason_code") gate_residual_ids = _safe_getattr(search_gate, "residual_ids") gate_candidate_organ = _safe_getattr(search_gate, "candidate_organ") budget_id = _safe_getattr(compute_budget, "budget_id") budget_status = _safe_getattr(compute_budget, "status") budget_reason = _safe_getattr(compute_budget, "reason_code") budget_gate_id = _safe_getattr(compute_budget, "gate_decision_id") max_candidates = _safe_getattr(compute_budget, "max_candidates") max_depth = _safe_getattr(compute_budget, "max_depth") max_steps = _safe_getattr(compute_budget, "max_steps") max_parallelism = _safe_getattr(compute_budget, "max_parallelism") run_id = _safe_getattr(run, "run_id") run_gate_id = _safe_getattr(run, "gate_decision_id") run_budget_id = _safe_getattr(run, "budget_id") run_operator_set_id = _safe_getattr(run, "operator_set_id") run_operator_set_version = _safe_getattr(run, "operator_set_version") run_problem_frame_digest = _safe_getattr(run, "problem_frame_digest") run_assessment_id = _safe_getattr(run, "contract_assessment_id") run_residual_ids = _safe_getattr(run, "residual_ids") if not _valid_residual_record(residual): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(search_gate, SearchGateDecision): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(compute_budget, ComputeBudgetDecision): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(run, GeometricSearchRun): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _nonempty_text(residual_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if residual_kind != QUANTITY_ENTITY_BINDING_RESIDUAL_KIND: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_RESIDUAL_KIND.value) if residual_code != QUANTITY_ENTITY_BINDING_RESIDUAL_CODE: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_RESIDUAL_CODE.value) if candidate_organ != QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_CANDIDATE_ORGAN.value) if not _valid_spans(residual_spans): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) if gate_status is not SearchGateStatus.ELIGIBLE: reasons.append(CandidateOperatorRefusalReason.INELIGIBLE_SEARCH_GATE.value) if gate_reason != "eligible_missing_relation": reasons.append(CandidateOperatorRefusalReason.INELIGIBLE_SEARCH_GATE.value) if gate_candidate_organ != QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN: reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_CANDIDATE_ORGAN.value) if budget_status is not ComputeBudgetStatus.BUDGET_ALLOWED: reasons.append(CandidateOperatorRefusalReason.NON_ALLOWED_BUDGET.value) if budget_reason != "budget_allowed_missing_relation": reasons.append(CandidateOperatorRefusalReason.NON_ALLOWED_BUDGET.value) if not _nonempty_text(budget_gate_id) or not _nonempty_text(gate_id): reasons.append(CandidateOperatorRefusalReason.GATE_BUDGET_MISMATCH.value) elif budget_gate_id != gate_id: reasons.append(CandidateOperatorRefusalReason.GATE_BUDGET_MISMATCH.value) if not _nonempty_text(run_gate_id) or not _nonempty_text(gate_id): reasons.append(CandidateOperatorRefusalReason.RUN_GATE_MISMATCH.value) elif run_gate_id != gate_id: reasons.append(CandidateOperatorRefusalReason.RUN_GATE_MISMATCH.value) if not _nonempty_text(run_budget_id) or not _nonempty_text(budget_id): reasons.append(CandidateOperatorRefusalReason.RUN_BUDGET_MISMATCH.value) elif run_budget_id != budget_id: reasons.append(CandidateOperatorRefusalReason.RUN_BUDGET_MISMATCH.value) if run_operator_set_id != operator_set_id: reasons.append(CandidateOperatorRefusalReason.OPERATOR_SET_MISMATCH.value) if run_operator_set_version != CANDIDATE_OPERATOR_SET_VERSION: reasons.append(CandidateOperatorRefusalReason.OPERATOR_SET_MISMATCH.value) if type(attempt_index) is not int or attempt_index < 0: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) elif attempt_index != 0: reasons.append(CandidateOperatorRefusalReason.ATTEMPT_INDEX_EXCEEDS_BUDGET.value) if type(max_candidates) is not int: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) elif max_candidates < 1: reasons.append(CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value) if attempt_index >= QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.max_attempts_per_run: reasons.append( CandidateOperatorRefusalReason.ATTEMPT_INDEX_EXCEEDS_OPERATOR_POLICY.value ) if type(max_depth) is not int or type(max_steps) is not int: reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) else: charge = QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.budget_charge if charge.candidates > max_candidates: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if charge.steps > max_steps: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.depth > max_depth: reasons.append( CandidateOperatorRefusalReason.BUDGET_CHARGE_EXCEEDS_BUDGET.value ) if type(max_parallelism) is not int or max_parallelism != 1: reasons.append(CandidateOperatorRefusalReason.NON_SERIAL_BUDGET.value) if not _valid_version_pairs(schema_versions): reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_SCHEMA_VERSION.value) if not _valid_version_pairs(policy_versions): reasons.append(CandidateOperatorRefusalReason.UNSUPPORTED_SCHEMA_VERSION.value) if not _sha256_text(problem_frame_digest): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _nonempty_text(original_contract_assessment_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not _sha256_text(run_id): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(residual_id, str) and isinstance(gate_residual_ids, tuple) and residual_id not in gate_residual_ids ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(residual_id, str) and isinstance(run_residual_ids, tuple) and residual_id not in run_residual_ids ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(problem_frame_digest, str) and isinstance(run_problem_frame_digest, str) and problem_frame_digest != run_problem_frame_digest ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if ( isinstance(original_contract_assessment_id, str) and isinstance(run_assessment_id, str) and original_contract_assessment_id != run_assessment_id ): reasons.append(CandidateOperatorRefusalReason.INVALID_OPERATOR_INPUT.value) if not isinstance(grounded_quantity_entity_cues, tuple): reasons.append(CandidateOperatorRefusalReason.INVALID_QUANTITY_ENTITY_CUE_TYPE.value) elif len(grounded_quantity_entity_cues) == 0: reasons.append(CandidateOperatorRefusalReason.MISSING_TYPED_CUE.value) elif len(grounded_quantity_entity_cues) > 1: reasons.append(CandidateOperatorRefusalReason.QUANTITY_ENTITY_CUE_COUNT_MISMATCH.value) cue: GroundedQuantityEntityCue | None = None if isinstance(grounded_quantity_entity_cues, tuple) and len(grounded_quantity_entity_cues) == 1: cue = grounded_quantity_entity_cues[0] if not isinstance(cue, GroundedQuantityEntityCue): reasons.append(CandidateOperatorRefusalReason.INVALID_QUANTITY_ENTITY_CUE_TYPE.value) else: if not _nonempty_text(cue.quantity_mention_id): reasons.append(CandidateOperatorRefusalReason.EMPTY_QUANTITY_MENTION_ID.value) if not _nonempty_text(cue.entity_mention_id): reasons.append(CandidateOperatorRefusalReason.EMPTY_ENTITY_MENTION_ID.value) if not _nonempty_text(cue.quantity_kind): reasons.append(CandidateOperatorRefusalReason.EMPTY_QUANTITY_KIND.value) if cue.unit_mention_id is not None and not _nonempty_text(cue.unit_mention_id): reasons.append(CandidateOperatorRefusalReason.EMPTY_UNIT_MENTION_ID.value) if not _valid_spans(cue.evidence_spans): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) elif not cue.evidence_spans: reasons.append(CandidateOperatorRefusalReason.MISSING_EVIDENCE_SPANS.value) elif isinstance(residual_spans, tuple) and not _spans_grounded_in_residual( cue.evidence_spans, residual_spans ): reasons.append(CandidateOperatorRefusalReason.MALFORMED_EVIDENCE_SPAN.value) input_digest: str | None = None if ( not reasons and isinstance(residual_id, str) and isinstance(run_id, str) and isinstance(gate_id, str) and isinstance(budget_id, str) and type(attempt_index) is int ): input_digest = _canonical_digest( _input_digest_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, problem_frame_digest=problem_frame_digest, original_contract_assessment_id=original_contract_assessment_id, residual_id=residual_id, residual_kind=QUANTITY_ENTITY_BINDING_RESIDUAL_KIND, residual_code=QUANTITY_ENTITY_BINDING_RESIDUAL_CODE, candidate_organ=QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN, search_gate_decision_id=gate_id, compute_budget_id=budget_id, geometric_search_run_id=run_id, operator_set_id=operator_set_id, operator_set_version=CANDIDATE_OPERATOR_SET_VERSION, attempt_index=attempt_index, schema_versions=schema_versions, policy_versions=policy_versions, ) ) if reasons: operator_refusal_id = _canonical_digest( _operator_refusal_id_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=_text_or_none(run_id), residual_id=_text_or_none(residual_id), operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, reason_codes=tuple(dict.fromkeys(reasons)), ) ) return CandidateOperatorRefusal( operator_refusal_id=operator_refusal_id, operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=_text_or_none(run_id), residual_id=_text_or_none(residual_id), operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, reason_codes=tuple(dict.fromkeys(reasons)), explanation="Candidate operator refused: " + ", ".join(dict.fromkeys(reasons)) + ".", ) assert cue is not None assert input_digest is not None assert isinstance(residual_id, str) assert isinstance(run_id, str) evidence_spans = cue.evidence_spans payload = _quantity_entity_binding_candidate_payload(cue) candidate_digest = _canonical_digest( _candidate_digest_payload( problem_frame_digest=problem_frame_digest, candidate_organ=QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN, candidate_payload=payload, evidence_spans=evidence_spans, ) ) attempt_id = _canonical_digest( _attempt_id_payload( attempt_index=attempt_index, parent_attempt_id=None, operator_id=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, input_digest=input_digest, candidate_digest=candidate_digest, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, step_index=attempt_index, replay_status=CandidateReplayStatus.REPLAY_PENDING, replay_blockers=(), evidence_spans=evidence_spans, ) ) candidate_reconstruction_digest = _canonical_digest( _reconstruction_digest_payload( geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, operator_set_id=operator_set_id, operator_set_version=CANDIDATE_OPERATOR_SET_VERSION, operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, residual_id=residual_id, residual_kind=QUANTITY_ENTITY_BINDING_RESIDUAL_KIND, residual_code=QUANTITY_ENTITY_BINDING_RESIDUAL_CODE, candidate_digest=candidate_digest, evidence_spans=evidence_spans, schema_versions=schema_versions, policy_versions=policy_versions, ) ) operator_provenance = ( ("operator_family", QUANTITY_ENTITY_BINDING_OPERATOR_POLICY.operator_family), ("operator_name", QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME), ("operator_version", QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION), ("operator_set_id", operator_set_id), ("operator_set_version", CANDIDATE_OPERATOR_SET_VERSION), ) candidate_reconstruction = CandidateReconstruction( candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN, candidate_payload=payload, evidence_spans=evidence_spans, operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, operator_provenance=operator_provenance, source_residual_id=residual_id, problem_frame_digest=problem_frame_digest, original_contract_assessment_id=original_contract_assessment_id, ) candidate_attempt = CandidateAttempt( attempt_id=attempt_id, attempt_index=attempt_index, parent_attempt_id=None, operator_id=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, input_digest=input_digest, candidate_digest=candidate_digest, budget_charge=_FIXED_BUDGET_CHARGE, depth=_OPERATOR_DEPTH, step_index=attempt_index, replay_status=CandidateReplayStatus.REPLAY_PENDING, replay_blockers=(), evidence_spans=evidence_spans, explanation="", ) reason_codes: tuple[str, ...] = () operator_result_id = _canonical_digest( _operator_result_id_payload( operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN, operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, reason_codes=reason_codes, evidence_spans=evidence_spans, ) ) safe_explanation = explanation or ( "Quantity-entity binding candidate constructed for residual " + residual_id + " linking " + cue.quantity_mention_id + " and " + cue.entity_mention_id + "." ) return CandidateOperatorResult( operator_result_id=operator_result_id, operator_policy_version=CANDIDATE_OPERATOR_POLICY_VERSION, input_digest=input_digest, geometric_search_run_id=run_id, attempt_id=attempt_id, attempt_index=attempt_index, candidate_digest=candidate_digest, candidate_reconstruction_digest=candidate_reconstruction_digest, candidate_organ=QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN, operator_name=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME, operator_version=QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION, candidate_attempt=candidate_attempt, candidate_reconstruction=candidate_reconstruction, reason_codes=reason_codes, evidence_spans=evidence_spans, explanation=safe_explanation, ) __all__ = [ "CANDIDATE_OPERATOR_POLICY_VERSION", "CANDIDATE_OPERATOR_SET_VERSION", "MISSING_ROLE_CANDIDATE_OPERATOR_NAME", "MISSING_ROLE_CANDIDATE_OPERATOR_VERSION", "MISSING_ROLE_RESIDUAL_KIND", "MISSING_ROLE_RESIDUAL_CODE", "MISSING_ROLE_CANDIDATE_ORGAN", "QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_NAME", "QUANTITY_ENTITY_BINDING_CANDIDATE_OPERATOR_VERSION", "QUANTITY_ENTITY_BINDING_RESIDUAL_KIND", "QUANTITY_ENTITY_BINDING_RESIDUAL_CODE", "QUANTITY_ENTITY_BINDING_CANDIDATE_ORGAN", "CandidateOperatorRefusalReason", "CandidateOperatorPolicy", "GroundedUnaryDeltaCue", "GroundedQuantityEntityCue", "CandidateOperatorInput", "CandidateReconstruction", "CandidateOperatorResult", "CandidateOperatorRefusal", "CandidateOperatorOutcome", "candidate_operator_set_id", "build_missing_role_candidate", "build_quantity_entity_binding_candidate", ]