From 60a118c1a4c52220f0a2106a968a72864d3f2562 Mon Sep 17 00:00:00 2001 From: Shay Date: Mon, 22 Jun 2026 17:18:09 -0700 Subject: [PATCH] docs(kernel): define sealed practice trace boundary Adds ADR-0230 defining the immutable SealedPracticeTrace evidence envelope after the Contract/Proof Replay Adapter in the residual-gated practice loop. Docs-only; authorizes the inert shell implementation PR. --- ...ADR-0230-sealed-practice-trace-boundary.md | 930 ++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 docs/adr/ADR-0230-sealed-practice-trace-boundary.md diff --git a/docs/adr/ADR-0230-sealed-practice-trace-boundary.md b/docs/adr/ADR-0230-sealed-practice-trace-boundary.md new file mode 100644 index 00000000..f98e76c7 --- /dev/null +++ b/docs/adr/ADR-0230-sealed-practice-trace-boundary.md @@ -0,0 +1,930 @@ +# ADR-0230: SealedPracticeTrace Boundary + +**Status:** Proposed + +**Date:** 2026-06-22 + +**Scope:** Kernel diagnostics, immutable practice evidence, residual-gated practice loop + +**Depends on:** + +- ADR-0225 ContractResidual read model +- ADR-0226 Residual-Gated Practice Loop v1 +- ADR-0227 ComputeBudgetPolicy envelope +- ADR-0228 GeometricSearchRun envelope +- ADR-0229 Contract/Proof Replay Adapter boundary +- PR #872 diagnostic replay adapter shell + +## 1. Summary + +`SealedPracticeTrace` is an immutable diagnostic evidence envelope. It is the +first boundary after the Contract/Proof Replay Adapter that may bind a complete +residual-gated practice episode into one replay-stable, audit-native artifact. + +The trace consumes immutable identities for the original `ProblemFrame`, the +original refused `ContractAssessment`, projected `ContractResidual` records, the +`SearchGateDecision`, the `ComputeBudgetDecision`, the `GeometricSearchRun`, +every `CandidateAttempt`, every `ReplayAdapterResult`, every +`ReplayAdapterRefusal`, and the governing policy/schema versions. It emits +either a sealed trace or a trace refusal. + +A sealed trace records: + +```text +trace_id +trace_policy_version +input_digest +upstream_identity_chain +practice_disposition +trace_records / record_refs +evidence_spans +explanation +``` + +It does not emit or imply: + +```text +answer +final_answer +served_output +promotion +mutation +teaching_update +pack_update +policy_update +identity_update +workbench_state +runtime_effect +confidence +score +rank +priority +selected_candidate +best_candidate +serving_allowed +runnable +``` + +The trace is evidence only. It does not decide truth, answerability, serving, +promotion, or learning. + +This ADR defines the boundary before any sealed-trace implementation exists. It +adds no code, trace persistence, candidate generation, search execution, +operator implementation, repair, replay execution, answer production, serving +behavior, Workbench behavior, or mutation path. + +## 2. Why this exists + +PR #872 implemented the diagnostic Contract/Proof Replay Adapter shell +authorized by ADR-0229. CORE can now represent per-candidate replay +classifications and adapter refusals, but there is not yet a single sealed +artifact that binds the complete practice episode: + +```text +original refused assessment +→ residuals +→ gate +→ budget +→ run +→ candidate attempts +→ replay results/refusals +→ final practice disposition +``` + +Without a sealed trace, future candidate generation would produce local +diagnostic records but no durable, replay-stable evidence package that a +reviewer, Workbench projection, or promotion authority could inspect as one +unit. + +The sealed trace is the bridge from: + +```text +bounded practice attempt +``` + +to: + +```text +reviewable learning evidence +``` + +It is not learning itself. It is not promotion. It is not serving. It is not +Workbench behavior. It is the immutable evidence envelope future +review/promotion/Workbench systems may read. + +The intrinsic state space is not a final verdict. It is a typed binding between +already-produced upstream records and a practice disposition that summarizes +what happened without collapsing exploration into truth. + +## 3. Architectural directions considered + +### 3.1 Monolithic trace, answer, and promotion controller + +A single controller could seal the episode, select an answer, and emit a +promotion proposal. This would combine evidence packaging, answer production, +and durable mutation authority. A local replay closure could silently become a +user-facing assertion or reviewed promotion. Rejected. + +### 3.2 Trace inferred from mutable run state + +The trace could be derived by mutating `GeometricSearchRun`, +`CandidateAttempt.replay_status`, or upstream gate/budget records after replay. +This would destroy the immutability of exploration evidence and create reverse +dependencies from sealing into search and replay. Rejected. + +### 3.3 Partial trace on best-effort assembly + +A malformed or incomplete episode could still produce a partial sealed trace with +soft defaults for missing replay records or orphan attempts. This would let +incomplete evidence masquerade as a complete practice episode. Rejected. + +### 3.4 Immutable evidence envelope with explicit refusal + +The trace validates the full upstream identity chain, binds every replay +outcome by identity, preserves exact evidence spans, emits a closed practice +disposition, and fails closed into `PracticeTraceRefusal` when sealing is not +lawful. Answer production, serving, promotion, and Workbench remain later +boundaries. Selected. + +This direction makes trace failure distinct from candidate refusal and makes +illegal authority transitions visible in the output type. + +## 4. Decision + +The v1 policy identity is conceptually: + +```text +SEALED_PRACTICE_TRACE_POLICY_VERSION = "sealed_practice_trace.v1" +``` + +The public conceptual outcome is a discriminated union: + +```text +PracticeTraceOutcome = SealedPracticeTrace | PracticeTraceRefusal +``` + +`SealedPracticeTrace` exists only when the complete upstream identity chain was +validated and the episode can be sealed as immutable diagnostic evidence. + +`PracticeTraceRefusal` exists when the trace cannot lawfully seal the episode +because input, identity, policy, schema, upstream completeness, or evidence-span +validation failed. A refusal is not a partial sealed trace and must not +masquerade as a practice success disposition. + +The trace may decide only: + +```text +whether a complete practice episode can be sealed as immutable diagnostic evidence +``` + +It does not decide that the problem is solved. It does not select an answer. It +does not alter any upstream authority record. It is evidence packaging, not +authority beyond trace integrity. + +## 5. Position in the loop + +Dependency and authority remain one-way: + +```text +ContractAssessment +→ ContractResidual +→ SearchGateDecision +→ ComputeBudgetDecision +→ GeometricSearchRun +→ Contract/Proof Replay Adapter +→ SealedPracticeTrace +→ future Workbench read-only projection +→ future reviewed promotion path +``` + +There is no reverse dependency. In particular: + +- the trace does not create or alter any upstream record; +- assessment, residual, gate, budget, run, and replay-adapter modules do not + import the sealed-trace module; +- Workbench may later display a persisted trace but may not invoke, repair, or + override sealing; and +- no stage in this chain gains serving authority from its position in the + chain. + +The trace is episode-in and one-outcome-out. Multi-episode orchestration belongs +to a later boundary if separately authorized. + +## 6. Inputs + +### 6.1 PracticeTraceInput + +The conceptual trace input is: + +```python +@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, ...] + replay_result_ids: tuple[str, ...] + replay_refusal_ids: tuple[str, ...] + schema_versions: tuple[tuple[str, str], ...] + policy_versions: tuple[tuple[str, str], ...] +``` + +The input is accompanied by immutable values for the identified original +`ProblemFrame`, refused original `ContractAssessment`, residual records, gate +decision, budget decision, `GeometricSearchRun` or lawful `SearchRunRefusal`, +every bound `CandidateAttempt`, every supplied `ReplayAdapterResult`, and every +supplied `ReplayAdapterRefusal`. An implementation may consume validated +identity-bearing projections when those projections contain every field required +to reproduce the identity and cross-chain checks. + +The input binds to one complete practice episode. It cannot contain a preferred +candidate, a hidden answer, a serving decision, or a promotion target. + +The following validations are mandatory before sealing: + +1. `problem_frame_digest` reproduces from the supplied immutable frame. +2. `original_contract_assessment_id` reproduces, its `runnable` state is + refused, and it assesses the supplied frame identity. +3. Every `residual_id` reproduces and binds to that refused assessment. +4. `search_gate_decision_id` reproduces and binds to the supplied residual + context. +5. `compute_budget_id` reproduces and binds to the allowed gate decision. +6. `geometric_search_run_id` reproduces from the supplied run or lawful run + refusal envelope required by the episode shape. +7. Every `candidate_attempt_id` reproduces, belongs to the run, and appears in + canonical `GeometricSearchRun.candidate_attempts` order when a run exists. +8. Every `replay_result_id` and `replay_refusal_id` reproduces and binds to an + identified run, attempt, and candidate identity. +9. No orphan replay result, orphan replay refusal, orphan attempt, orphan + budget, orphan gate, or residual from a different assessment is accepted. +10. Every schema and policy version is supported explicitly. +11. `schema_versions` and `policy_versions` contain unique names in ascending + lexical order; missing, duplicate, or reordered entries are invalid. +12. Evidence spans required by the trace policy are exact, ordered, and + malformed spans fail closed. +13. `input_digest` reproduces from the complete structural payload defined in + Section 12. + +Any failed validation produces `PracticeTraceRefusal`; no sealed trace is +emitted. + +### 6.2 Upstream record binding + +The trace consumes upstream records by identity. It does not re-execute +contract assessment, residual projection, gate evaluation, budget allocation, +search, or replay classification. + +When the episode includes a `SearchRunRefusal` instead of a +`GeometricSearchRun`, the trace may still seal only if the refusal identity, +gate/budget bindings, and episode shape are lawful under this ADR. Such an +episode cannot claim candidate attempts or replay outcomes that were never +produced. + +## 7. Outputs + +### 7.1 SealedPracticeTrace + +```python +@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, ...] + 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 +``` + +`upstream_identity_chain` is the ordered, canonical list of load-bearing +upstream identities validated during sealing. It exists so a reviewer can verify +the binding without re-deriving it from scattered fields. + +`trace_records` holds content identities for the sealed upstream and replay +records referenced by the trace. It is evidence reference, not mutation. + +`created_by_policy` is a static policy identifier, not a user, model, or process +identity. + +`evidence_spans` copies the exact ordered spans required by the trace policy from +upstream records. The trace does not merge, widen, synthesize, sort, or dedupe +spans. + +### 7.2 PracticeTraceRefusal + +```python +@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 +``` + +`input_digest` is populated only when it can be validated without guessing. A +malformed input may therefore produce a refusal with `None` input digest. + +### 7.3 Forbidden output fields + +Neither output type may emit or contain: + +```text +answer +final_answer +served_output +promotion +mutation +teaching_update +pack_update +policy_update +identity_update +workbench_state +runtime_effect +confidence +score +rank +priority +selected_candidate +best_candidate +serving_allowed +runnable +``` + +Generated prose is explanatory only and excluded from identity. + +## 8. PracticeDisposition vocabulary + +`PracticeDisposition` is closed. + +Sealed-trace dispositions: + +```text +sealed_original_refusal +sealed_exhausted_no_candidate +sealed_all_candidates_refused +sealed_replay_unavailable +sealed_contract_closed_proof_refused +sealed_candidate_replay_closed +``` + +Trace-refusal dispositions: + +```text +trace_invalid_input +trace_identity_mismatch +trace_policy_unsupported +trace_upstream_incomplete +``` + +The output type constrains the vocabulary: + +| Output type | Permitted dispositions | +|---|---| +| `SealedPracticeTrace` | `sealed_original_refusal`, `sealed_exhausted_no_candidate`, `sealed_all_candidates_refused`, `sealed_replay_unavailable`, `sealed_contract_closed_proof_refused`, `sealed_candidate_replay_closed` | +| `PracticeTraceRefusal` | `trace_invalid_input`, `trace_identity_mismatch`, `trace_policy_unsupported`, `trace_upstream_incomplete` | + +### 8.1 Sealed disposition semantics + +The trace derives practice disposition only from validated upstream and replay +records. It does not invent new semantic meaning for replay outcomes. + +```text +Gate denied or lawful run refusal before candidate exploration +→ sealed_original_refusal + +No candidate attempts and run exhausted/no candidate +→ sealed_exhausted_no_candidate + +Candidate attempts exist but every lawful replay result is contract_refused +→ sealed_all_candidates_refused + +Replay adapter refusals only, with no lawful candidate replay result +→ sealed_replay_unavailable + +At least one contract_closed_but_proof_refused and no contract_and_proof_closed +→ sealed_contract_closed_proof_refused + +At least one contract_and_proof_closed +→ sealed_candidate_replay_closed +``` + +`sealed_original_refusal` means the episode never advanced beyond the original +refused assessment in a way that produced candidate exploration or replay +evidence. It preserves the original refusal posture; it does not authorize +answer production, serving, or promotion. + +`sealed_exhausted_no_candidate` means exploration ran under a lawful budget but +produced no candidate attempts before exhaustion. Budget or operator exhaustion +is not correctness. + +`sealed_all_candidates_refused` means every lawful replay result reported +`contract_refused`. Adapter refusals do not count as lawful candidate replay +results. + +`sealed_replay_unavailable` means candidate attempts exist, but every supplied +replay record is an adapter refusal and no lawful `ReplayAdapterResult` exists. + +`sealed_contract_closed_proof_refused` means at least one lawful replay result +reported `contract_closed_but_proof_refused` and none reported +`contract_and_proof_closed`. + +`sealed_candidate_replay_closed` means at least one lawful replay result reported +`contract_and_proof_closed` under ADR-0229. It does not mean answer production, +serving eligibility, promotion, or global uniqueness. It is replay evidence only +and is input to a future answer-realization/result stage that must be separately +authorized. + +If multiple candidates report `contract_and_proof_closed` and disagree, the +sealed trace preserves every replay result and may record a future +disagreement flag when that schema is separately authorized. It must not select +a winner, rank candidates, or collapse disagreement into an answer field. + +## 9. Identity-chain binding requirements + +The trace must verify the complete chain: + +```text +residuals bind to original refused ContractAssessment +SearchGateDecision binds to residual context +ComputeBudgetDecision binds to SearchGateDecision +GeometricSearchRun binds to SearchGateDecision and ComputeBudgetDecision +CandidateAttempt records bind to GeometricSearchRun +ReplayAdapterResult / ReplayAdapterRefusal records bind to CandidateAttempt / run / candidate identity +SealedPracticeTrace binds all of the above +``` + +The trace must fail closed if any required identity does not match. + +The trace must not accept: + +```text +orphan replay results +orphan replay refusals +orphan attempts +orphan budgets +orphan gates +residuals from a different assessment +replay results from a different run +attempts out of canonical run order when order is load-bearing +``` + +Identities must be recomputed independently; equality of user-supplied strings +alone is insufficient. + +## 10. Replay result/refusal binding + +The trace must preserve the ADR-0229 distinction between: + +```text +ReplayAdapterResult +``` + +and: + +```text +ReplayAdapterRefusal +``` + +A replay refusal means the adapter could not lawfully classify the candidate. It +is not candidate semantic refusal. + +A replay result with `contract_refused` means the existing contract authority +ran and refused the candidate. + +A replay result with `contract_closed_but_proof_refused` means contract closure +did not satisfy the applicable proof obligations. + +A replay result with `contract_and_proof_closed` is replay evidence only. + +The sealed trace may summarize these outcomes in `practice_disposition`, but may +not change their meaning, reorder proof obligations, discard failed candidates, +or convert adapter failure into semantic refusal. + +Every replay result or refusal bound into the trace must identify: + +```text +run_id +attempt_id +candidate_digest +replay_policy_version +replay disposition or refusal disposition +``` + +A replay record that cannot bind to a supplied run, attempt, and candidate +identity yields `PracticeTraceRefusal(trace_identity_mismatch)`. + +When candidate attempts exist and replay records are required by the episode +shape, absence of every required replay record yields +`PracticeTraceRefusal(trace_upstream_incomplete)`. + +## 11. Evidence and source-span preservation + +The trace must: + +```text +preserve ordered evidence spans +preserve duplicate spans +preserve source text references +preserve upstream record order where semantically meaningful +``` + +The trace must not: + +```text +synthesize spans +dedupe spans +sort spans independently unless the ordering rule is explicitly canonical and non-semantic +add provenance not already present +``` + +Malformed evidence spans must fail closed into +`PracticeTraceRefusal(trace_invalid_input)`. + +Evidence spans that participate in trace identity must change `trace_id` when +reordered. Duplicate spans remain distinct entries when upstream records +preserved them as distinct entries. + +The trace copies spans from upstream frame, assessment, residual, attempt, and +replay records as required by policy. It does not read raw source text again to +infer missing roles. + +## 12. Immutability and canonical identity + +All load-bearing identities use canonical JSON: + +```python +json.dumps( + payload, + ensure_ascii=False, + sort_keys=True, + separators=(",", ":"), +) +``` + +The serialized string is encoded as UTF-8 and hashed with SHA-256. The digest is +the full lowercase hexadecimal encoding. Floats, NaN, Infinity, implicit object +serialization, locale-dependent values, and unordered iteration are forbidden +in identity payloads. + +### 12.1 Input digest + +`input_digest` hashes exactly the structural `PracticeTraceInput` fields other +than `input_digest` itself: + +```text +trace_policy_version +problem_frame_digest +original_contract_assessment_id +ordered residual_ids +search_gate_decision_id +compute_budget_id +geometric_search_run_id +ordered candidate_attempt_ids +ordered replay_result_ids +ordered replay_refusal_ids +canonical schema_versions +canonical policy_versions +``` + +### 12.2 Trace and refusal identities + +`trace_id` self-seals the structural sealed-trace payload with its own field +blanked. It includes: + +```text +trace_policy_version +input_digest +problem_frame_digest +original_contract_assessment_id +ordered residual_ids +search_gate_decision_id +compute_budget_id +geometric_search_run_id +ordered candidate_attempt_ids +ordered replay_result_ids +ordered replay_refusal_ids +ordered upstream_identity_chain +practice_disposition +ordered trace_records +exact ordered evidence_spans +created_by_policy +``` + +`trace_refusal_id` self-seals the structural refusal payload with its own field +blanked. It includes the trace policy version, available input digest, refusal +disposition, and ordered reason codes. + +`explanation` is excluded from every identity. IDs also exclude: + +```text +wall-clock time +timestamps +random values +UUIDs +environment variables +hostname +OS details +CI metadata +file paths +generated prose +memory addresses +thread or process identifiers +filesystem order +hash-map iteration order unless canonicalized +user identity +model identity +machine identity +``` + +The trace may include static policy identifiers and schema versions, but not +runtime process identity. + +### 12.3 Immutability rule + +Once constructed, a `SealedPracticeTrace` is immutable. + +Future systems may reference it, compare it, display it, or submit it for +review, but may not mutate it in place. + +If a correction is needed, create a new trace that references the prior trace by +ID and explains the correction path. Do not edit the old trace. + +Sealing byte-equivalent inputs, upstream records, replay outcomes, and policy +versions must reproduce the same outcome type, disposition, reason codes, +evidence ordering, references, and IDs byte-for-byte. + +## 13. Trace refusal semantics + +| Failure or outcome | Required trace outcome | +|---|---| +| Malformed trace input | `PracticeTraceRefusal(trace_invalid_input)` | +| Unsupported trace policy version | `PracticeTraceRefusal(trace_policy_unsupported)` | +| Missing required upstream record | `PracticeTraceRefusal(trace_upstream_incomplete)` | +| Upstream identity mismatch | `PracticeTraceRefusal(trace_identity_mismatch)` | +| Replay result/refusal does not bind to run/attempt/candidate | `PracticeTraceRefusal(trace_identity_mismatch)` | +| Malformed evidence spans | `PracticeTraceRefusal(trace_invalid_input)` | +| No replay records where replay records are required | `PracticeTraceRefusal(trace_upstream_incomplete)` | + +A malformed or inconsistent trace input must produce a trace refusal record, +not a partial sealed trace. + +No trace refusal may become: + +```text +best guess +partial answer +soft proof +confidence score +rank +priority +serving fallback +proposal promotion +Unknown == False +``` + +## 14. Authority boundary + +The trace may decide only whether a complete practice episode can be sealed as +immutable diagnostic evidence. + +| Concern | Authority owner | SealedPracticeTrace authority | +|---|---|---| +| Original organ runnable/refused state | Existing `ContractAssessment` organ | None; preserves original record identity | +| Residual projection | `ContractResidual` | None; binds identities only | +| Search eligibility | `SearchGateDecision` | None | +| Compute allocation | `ComputeBudgetDecision` | None | +| Candidate generation/order | `GeometricSearchRun` and future authorized operators | None | +| Replay classification | Contract/Proof Replay Adapter | None; binds replay outcomes only | +| Cross-candidate uniqueness | Existing organ-specific disagreement authority | None | +| Answer production/selection | Future separately authorized result stage | None | +| Trace integrity | `SealedPracticeTrace` | Seals immutable evidence only | +| Durable promotion | Existing review/certificate paths | None | +| Workbench | Read-only future projection | None | + +The trace has no authority to: + +```text +generate candidates +execute search +execute operators +repair inputs +run contract replay +run proof replay +classify replay results +rank candidates +select final answers +serve output +mutate upstream records +allocate budget +change search eligibility +promote findings +edit packs +edit teaching data +edit policy +edit identity +edit eval reports +change Workbench state +write files/artifacts +``` + +No practice disposition changes durable epistemic standing. Source kind +(`search`, `replay`, or `practice`) grants no promotion authority. + +## 15. Forbidden imports/calls/effects + +### 15.1 Allowed dependency surface + +A future boundary implementation may import only: + +- standard-library immutable value, enum, canonical JSON, and SHA-256 + facilities; +- `SourceSpan` and existing identity-bearing `ProblemFrame` values; +- `ContractAssessment` as a value type; +- `ContractResidual` as a value type; +- `SearchGateDecision` as a value type; +- `ComputeBudgetDecision` as a value type; +- `GeometricSearchRun`, `SearchRunRefusal`, `CandidateAttempt`, and their value + enums/types; +- `ReplayAdapterResult`, `ReplayAdapterRefusal`, and replay-adapter value + enums/types; and +- local sealed-trace immutable value types and static policy manifests. + +The implementation consumes upstream records for identity binding and trace +construction only. It does not invoke contract replay, proof replay, search, +operators, serving, teaching, Vault, or Workbench. + +### 15.2 Forbidden calls and effects + +The sealed-trace module may not import or call: + +```text +candidate generation +search execution +operator execution +repair +contract replay execution +proof replay execution +serving/runtime +teaching or proposal mutation +pack, policy, or identity mutation +eval or report mutation +Workbench mutation +Vault or recall mutation +filesystem or network I/O +subprocess or shell execution +clock or timestamp APIs +randomness or UUID generation +environment or hostname inspection +dynamic import or plugin discovery +external model or tool invocation +``` + +No reverse import from assessment, residual, gate, budget, run, or replay-adapter +modules into the sealed-trace module is permitted. + +No hidden fallback is permitted. Missing upstream evidence, unsupported policy, +identity mismatch, or malformed spans produce a typed trace refusal. + +## 16. Failure modes and fail-closed behavior + +| Failure or outcome | Required trace outcome | +|---|---| +| Malformed trace input | `PracticeTraceRefusal(trace_invalid_input)` | +| Unsupported trace policy version | `PracticeTraceRefusal(trace_policy_unsupported)` | +| Missing upstream record | `PracticeTraceRefusal(trace_upstream_incomplete)` | +| Upstream identity mismatch | `PracticeTraceRefusal(trace_identity_mismatch)` | +| Replay result orphaned from run/attempt/candidate | `PracticeTraceRefusal(trace_identity_mismatch)` | +| Evidence span mismatch/malformed evidence | `PracticeTraceRefusal(trace_invalid_input)` | +| No replay records where replay records are required | `PracticeTraceRefusal(trace_upstream_incomplete)` | + +No failure may become: + +```text +answer +best guess +soft proof +confidence score +rank +priority +serving fallback +reviewed promotion +teaching mutation +Unknown == False +``` + +Search or budget exhaustion has no special sealing meaning beyond the sealed +dispositions defined in Section 8. It cannot create an answer field and cannot +change the original refusal into truth. + +## 17. Test obligations for future implementation PR + +The future implementation must add executing tests that meaningfully fail for +each prohibited state: + +1. Public API exports are exact. +2. Valid full practice chain seals a deterministic trace. +3. Original refusal-only/no-candidate episode seals as + `sealed_exhausted_no_candidate` or `sealed_original_refusal` as applicable. +4. All candidate contract refusals seal as `sealed_all_candidates_refused`. +5. Replay refusals only seal as `sealed_replay_unavailable` or fail closed, per + this ADR. +6. Contract-closed/proof-refused results seal as + `sealed_contract_closed_proof_refused`. +7. Contract-and-proof-closed result seals as `sealed_candidate_replay_closed` + without answer fields. +8. Missing upstream record returns `PracticeTraceRefusal`. +9. Gate/budget/run/replay identity mismatch returns `PracticeTraceRefusal`. +10. Orphan replay result/refusal fails closed. +11. Candidate disagreement is preserved and not resolved. +12. Duplicate evidence spans are preserved. +13. Evidence span reorder changes trace identity if spans participate in + identity. +14. Trace IDs are canonical and exclude prose/time/env/path/random. +15. Explanation changes do not affect IDs. +16. No answer/proof-as-answer/serving/promotion fields exist. +17. No candidate generation, search execution, repair, replay execution, or + proof engine call is reachable. +18. No runtime/serving/Workbench/teaching/eval/report mutation is reachable. +19. No reverse dependency from upstream modules into sealed trace module. +20. No filesystem/network/time/random/subprocess/env/UUID/hostname/path identity + is reachable. +21. Focused tests and the repository smoke lane pass. + +Additional required controls: + +- tests independently recompute input, trace, and refusal hashes rather than + calling the implementation's private hashing helper; +- static coupling tests parse the sealed-trace module and enforce the allowed + import/call surface; +- disagreement tests construct at least two independently closed, conflicting + replay results and prove the trace provides no selection API; and +- tests prove `sealed_candidate_replay_closed` does not create answer, + serving, or promotion fields. + +## 18. Authorized next PR + +This ADR authorizes exactly one next implementation PR: + +```text +feat(kernel): implement inert SealedPracticeTrace shell +``` + +That PR may only: + +- add sealed-practice-trace frozen dataclasses, closed enums, canonical hashing + helpers, and a discriminated outcome type; +- consume existing upstream diagnostic records produced by the residual-gated + practice loop shells; +- validate the complete upstream identity chain; +- represent `PracticeTraceRefusal` and `SealedPracticeTrace` records; +- derive closed `practice_disposition` values without changing replay meaning; +- produce deterministic input, trace, and refusal IDs; and +- add tests only for the boundary and isolation obligations in Section 17. + +That PR explicitly excludes: + +```text +candidate generation +operator implementation +search execution +repair +contract replay execution +proof replay execution +answer production +Workbench +runtime/serving +teaching/proposal/report/eval mutation +pack/policy/identity mutation +promotion +filesystem persistence +artifact writing +new proof engine +``` + +The shell may prove the state machine with constructed upstream fixtures, but it +cannot claim live practice capture, Workbench display, answer production, +serving integration, or durable promotion until separately reviewed PRs authorize +those boundaries. + +No other implementation PR is authorized by this ADR. Candidate-producing +operators, production replay wiring, multi-episode orchestration, Workbench +display, answer production, serving, evaluation, and promotion each remain +separately gated. \ No newline at end of file