Refined Canonical IR Validation Contract
Routed Finding
Hygiene design route: hr-8a8c092d9a61f101
- Rule: DESIGN-18 (validate, do not merely check and forward the raw value).
- Severity: Major.
- Evidence:
ori_canon::validateaccepts&CanonResult, asserts its invariants, returns(), and leaves the same rawCanonResultavailable to every downstream consumer. The canonicalization boundary therefore does not carry proof of validation in its output type. - Why this is not DESIGN-07: the problem is not merely an untyped identifier or primitive field; it is specifically a validation boundary that discards the established proof and forwards the unrefined representation.
- No within-budget cure: introducing the refined carrier alone is insufficient because canonical lowering, evaluator entry, realization, test fixtures, and every backend-facing consumer must migrate together without an unchecked escape hatch.
Goal
Make invalid or merely unchecked canonical IR unrepresentable beyond the canonicalization boundary. Validation must consume or wrap the raw result and return a refined type whose construction is controlled by ori_canon.
Required Design
- Introduce an opaque validated canonical-program/result carrier with read-only access to the canonical arena and associated roots, constants, decision trees, and dispatch metadata.
- Make canonical lowering return the refined carrier only after release-active invariant validation succeeds; keep raw construction private to the owning phase and focused malformed-input tests.
- Migrate evaluator, realization, VM preparation, LLVM/native preparation, and test helpers to accept the refined carrier rather than
CanonResult. - Delete public validate-and-continue entry points and any conversion that can manufacture the refined carrier without running the complete invariant suite.
- Preserve typed failure attribution at the canonicalization boundary; no downstream phase may re-assume, partially repeat, or bypass the proof.
Verification
- Compile-fail/API tests prove downstream crates cannot construct the refined carrier from raw parts.
- Malformed arena IDs, ranges, unresolved types, constants, and decision-tree references are rejected before a carrier is produced.
- Evaluator, realization, VM, LLVM, and native consumers all accept the same refined type.
- Existing canonical corpus behavior remains unchanged and canonical hashing/provenance remains deterministic.
Closeout
This section closes only after its owned criterion is satisfied, code-side TPR is clean, and a source-fingerprint-current canonical test-all run is full green.
Work Items
- Replace validate-and-forward CanonResult with a refined validated canonical-program type and migrate every downstream consumer