Section 01: Verifier Gates & Quick Wins
Status: Not Started
Goal: Make AIMS and LLVM verifier failures blocking gates under verification mode (ORI_VERIFY_ARC=1 / ORI_VERIFY_EACH=1), wire the existing verify_each plumbing to an env var registered in debug_flags.rs, add function-level IR verification after each function’s codegen at ALL emission sites, and integrate opt -lint into the codegen audit pipeline. This section ensures that all subsequent verification tooling (Sections 02-12) has enforceable failure semantics — a verifier that detects a problem but only logs a warning is not verification, it’s a suggestion.
Success Criteria:
-
run_verify()andrun_aims_verify()return errors (not warnings) whenORI_VERIFY_ARC=1— satisfies mission criterion: “Verifier failures become blocking gates” - Full error propagation chain from
run_verify()throughverify_and_merge()->run_aims_pipeline()->run_arc_pipeline()->FunctionCompiler::process_arc_function()-> compilation failure — errors must propagate, not be silently logged -
ORI_VERIFY_EACH=1registered indebug_flags.rsand wired throughOptimizationConfigin ALL entry points:compiler/oric/src/commands/build/mod.rs,compiler/oric/src/commands/run/mod.rs, and the JIT path incompiler/ori_llvm/src/evaluator/compile.rs -
fn_val.verify()called after each function in ALL LLVM emission sites (define phase, nounwind emit, impls, tests, derives, thunks, wrappers) -
opt -lintintegrated into codegen audit output usingfunction(lint)pipeline syntax (lint output via stderr; structured capture not feasible — LLVM lint usesdbgs()) -
test-all.shpasses withORI_VERIFY_EACH=1 ORI_VERIFY_ARC=1within the 150s non-negotiable timeout — measured 54s (36% of budget)
Context: Currently, run_verify() (compiler/ori_arc/src/pipeline/mod.rs:128) and run_aims_verify() (line 144) log warnings via tracing::warn! but never fail the compilation. FIP structural checks at compiler/ori_arc/src/pipeline/aims_pipeline/mod.rs:182 and compiler/ori_arc/src/pipeline/aims_pipeline/batch.rs:196 use debug_assert! which disappears in release builds. This violates .claude/rules/arc.md §Non-Negotiable Invariant #4: “Every active subsystem needs implementation + invariant enforcement + verification.” The verify_each field exists at compiler/ori_llvm/src/aot/passes/config.rs:210 with a builder at line 321, but it’s not wired to any env var or CLI flag — build_optimization_config in compiler/oric/src/commands/build/mod.rs:158 doesn’t read it. The run command at compiler/oric/src/commands/run/mod.rs:289 constructs OptimizationConfig::new(O2) directly without verify_each. The JIT path at compiler/ori_llvm/src/evaluator/compile.rs:259 hardcodes verify_arc: false. The codegen audit pipeline (compiler/ori_llvm/src/verify/mod.rs) runs RC balance, COW rules, ABI checks, and safety checks, but doesn’t run LLVM’s own opt -lint pass which catches UB patterns the custom checks miss.
BLOAT finding: compiler/ori_llvm/src/codegen/arc_emitter/mod.rs is 630 lines (over the 500-line limit per .claude/rules/impl-hygiene.md). This should be split during implementation if any changes touch that file. Tracked as a prerequisite awareness item — the split itself is not gated by this section but must not be deferred if implementation touches the file.
Reference implementations:
- Swift
lib/SIL/Verifier/SILVerifier.cpp: 7 verifiers that abort on failure (configurable viaverify-abort-on-failureflag). The-enable-sil-verify-allflag runs ALL verifiers on every compilation. - Lean4
src/Lean/Compiler/IR/Checker.lean: IR checker throws compilation errors on violation (not warnings). Runs before AND after optimization passes.
Depends on: Nothing — this is the foundation section.
01.1 Make ARC/AIMS Verifiers Blocking (with Full Error Propagation)
File(s):
compiler/ori_arc/src/pipeline/mod.rs—run_verify(),run_aims_verify()compiler/ori_arc/src/pipeline/aims_pipeline/mod.rs— FIP first-pass checks (step 5a)compiler/ori_arc/src/pipeline/aims_pipeline/batch.rs— FIP second-pass checkscompiler/ori_arc/src/pipeline/aims_pipeline/postprocess.rs—verify_and_merge(),emit_postprocess()compiler/ori_arc/src/verify/mod.rs—VerifyErrortypecompiler/ori_arc/src/lower/mod.rs—ArcProblemtypecompiler/ori_llvm/src/codegen/function_compiler/define_phase.rs— consumesrun_arc_pipeline()results
The ARC/AIMS verifiers currently log warnings but never fail. Under ORI_VERIFY_ARC=1, verification failures must become blocking errors that halt compilation with a clear diagnostic. Errors must propagate from verification through the entire pipeline up to compilation failure.
01.1.1 Make run_verify() and run_aims_verify() return Result
-
Write failing tests FIRST (TDD) — create
compiler/ori_arc/src/pipeline/tests.rs(new file; add#[cfg(test)] mod tests;topipeline/mod.rs):verify_returns_err_when_verify_true_and_errors_found— construct a malformedArcFunction, callrun_verify()withverify=true, assertErrreturnedverify_warns_only_when_debug_assertions_and_no_explicit_verify— same malformed input,verify=false, assertOk(())returned (warnings only)aims_verify_blocks_on_absent_param_has_uses— construct function whereCardinality::Absentparam has uses,verify=true, assertErr- Verify tests FAIL before implementation (proves understanding)
-
Modify
run_verify()(compiler/ori_arc/src/pipeline/mod.rs:128-138) to returnResult<(), Vec<crate::verify::VerifyError>>instead of(). Whenverifyis true and errors are found, returnErr(errors)instead of logging and continuing. Whenverifyis false (and onlydebug_assertionsis active), keep the current warning behavior — debug mode is diagnostic, explicit verification mode is blocking.// Current (warns only): pub(crate) fn run_verify(func: &ArcFunction, phase: &str, verify: bool) { let enabled = verify || cfg!(debug_assertions); if !enabled { return; } let errors = crate::verify::check_function(func); for e in &errors { tracing::warn!(phase, "ARC IR verification: {e}"); } } // Target (blocking under verify mode): pub(crate) fn run_verify(func: &ArcFunction, phase: &str, verify: bool) -> Result<(), Vec<crate::verify::VerifyError>> { let enabled = verify || cfg!(debug_assertions); if !enabled { return Ok(()); } let errors = crate::verify::check_function(func); if errors.is_empty() { return Ok(()); } if verify { // Explicit verification mode: hard error return Err(errors); } // debug_assertions only: warn but continue for e in &errors { tracing::warn!(phase, "ARC IR verification: {e}"); } Ok(()) } -
Apply the same pattern to
run_aims_verify()(compiler/ori_arc/src/pipeline/mod.rs:144-162) — returnResult<(), Vec<VerifyError>>, error under explicit verify mode.
01.1.2 Add VerifyError variant to ArcProblem for type mapping
Verification errors from the ARC IR verifier are Internal Compiler Errors (ICEs), fundamentally different from user-facing ArcProblems (like FBIP enforcement diagnostics). The pipeline must distinguish them:
-
AddN/A — chose the Result wrapper approach (Option B) below.ArcProblem::InternalVerificationError { phase: String, errors: Vec<crate::verify::VerifyError> }variant to theArcProblemenum incompiler/ori_arc/src/lower/mod.rs. This variant represents an ICE, not a user diagnostic —FunctionCompilershould treat it as a compilation abort. -
Alternatively, change both
run_arc_pipeline()andrun_arc_pipeline_all()(compiler/ori_arc/src/pipeline/mod.rs:36andcompiler/ori_arc/src/lib.rs:72) to returnResult<Vec<ArcProblem>, ArcVerificationError>whereArcVerificationErrorwraps the verification failures with phase/function context. TheVec<ArcProblem>remains for user-facing diagnostics (FBIP), whileErrmeans an ICE from verification. This is the cleaner approach since it uses the type system to enforce that ICEs cannot be silently iterated over. Both the single-function and batch APIs must adopt the same contract —arc_dumpandarc_dotcall the batch API (run_arc_pipeline_all), not the single-function API.- Implementation: used
Result<..., Vec<VerifyError>>as the error type sinceVerifyErroris already the canonical error type. AddedVerifyError::FipStructuralvariant for FIP structural violations.
- Implementation: used
01.1.3 Propagate errors through the full pipeline chain
Type semantics clarification: The current Vec<ArcProblem> return type from run_arc_pipeline() represents user-facing diagnostics — FBIP enforcement findings, optimization skips, and reuse misses that the user may need to act on. The Result wrapper introduced in §01.1.2 serves a different purpose: it separates blocking ICEs (internal compiler errors from IR invariant violations — things that should never happen and abort compilation immediately) from user diagnostics (things that may be warnings or fixable errors). The type Result<Vec<ArcProblem>, ArcVerificationError> reads as: “either a list of user-facing ARC diagnostics (Ok), or an ICE from verification that prevents codegen from continuing (Err).” Callers must treat Err as unrecoverable — they should emit an ICE diagnostic and halt, not continue compiling with a potentially corrupt IR.
Currently, errors from run_verify() are silently consumed at multiple call sites. The full propagation chain must be:
-
verify_and_merge()incompiler/ori_arc/src/pipeline/aims_pipeline/postprocess.rs:10— currently callsrun_verify()andrun_aims_verify()without checking returns. Must returnResultand propagate errors from both verification steps (steps 6-7). -
emit_postprocess()incompiler/ori_arc/src/pipeline/aims_pipeline/postprocess.rs:40— currently callsrun_verify()for step 11 without checking. Must returnResult<Vec<ArcProblem>, ArcVerificationError>. -
run_aims_pipeline()incompiler/ori_arc/src/pipeline/aims_pipeline/mod.rs— callsverify_and_merge()at line 193. Must propagate theResult. -
run_arc_pipeline()incompiler/ori_arc/src/pipeline/mod.rs:36— currently returnsVec<ArcProblem>. Must returnResult<Vec<ArcProblem>, ArcVerificationError>(or include ICEs via theArcProblem::InternalVerificationErrorvariant). -
FunctionCompiler::process_arc_function()incompiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:311— currently iteratesarc_problemswithdebug!(). Must check for verification errors and abort compilation (return an error to the caller or accumulate ICE diagnostics that block codegen). -
Lambda compilation in
compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:409— samerun_arc_pipeline()call, same propagation needed. -
compiler/oric/src/arc_dump/mod.rs:61— currently useslet _problems = run_arc_pipeline_all(...)(result intentionally discarded). Oncerun_arc_pipeline_all()returnsResult<Vec<ArcProblem>, ArcVerificationError>, this site must handle theErrbranch: propagate verification errors up to the caller or surface them as a compilation diagnostic. Do NOT leave_problemsdiscarding anErr. -
compiler/oric/src/arc_dot/mod.rs:53— samelet _problems = run_arc_pipeline_all(...)pattern asarc_dump. Must handle theErrbranch after the signature change. -
compiler/oric/src/problem/codegen/mod.rs:242-263—CodegenProblemmapping. TheArcProblem->CodegenProblemmapping must include a case forArcProblem::InternalVerificationError(or theArcVerificationErrorICE path). Currently this mapping has no catch-all for ICE variants. Add anInternalVerificationErrorarm that emits a compiler ICE diagnostic rather than a user-facingCodegenProblem. -
compiler/oric/src/problem/codegen/mod.rs:469-473—CodegenDiagnostics::add_arc_problems(). This method iteratesVec<ArcProblem>and maps each to aCodegenProblem. Once theInternalVerificationErrorvariant exists (point 9), this method must propagate it — either by returningResultor by accumulating ICEs in a separate list that causes compilation to abort.
- Implement each of the 10 propagation points above. Write a test that constructs a verification failure deep in the pipeline and asserts it surfaces as a compilation error (not a silent log message).
- Points 1-8: All propagation sites updated with
?operator andResultreturn types. Points 9-10 are N/A since we chose theResultwrapper approach (ICEs go throughErr, not throughArcProblem). Also fixedis_ok()→is_ok_and(|v| v != "0")inarc_dumpandarc_dot(bonus: addresses TPR-01-002-codex-i4 early).
- Points 1-8: All propagation sites updated with
01.1.4 Fix FIP debug_assert! — first-pass vs second-pass distinction
The FIP structural checks at compiler/ori_arc/src/pipeline/aims_pipeline/mod.rs:164-186 and compiler/ori_arc/src/pipeline/aims_pipeline/batch.rs:192-197 both use debug_assert!(false, ...) which disappears in release builds. These must be replaced with explicit error returns under verify_arc mode.
Critical distinction — do NOT break the two-pass FIP pattern:
-
First pass (step 5a,
compiler/ori_arc/src/pipeline/aims_pipeline/mod.rs:164-186):CertifiedButHasMissedReuseserrors are EXPECTED becausemay_deallocatefacts haven’t been updated yet (the contract has optimisticmay_deallocate=falsefrom interprocedural analysis). OnlyCertifiedButUnboundedStackandBoundedExceededare genuine structural violations that should be blocking errors. The existing code at lines 170-184 already implements this distinction correctly in its match arms — preserve this logic when replacingdebug_assert!with error returns. -
Second pass (batch.rs,
compiler/ori_arc/src/pipeline/aims_pipeline/batch.rs:192-197): ALL FIP errors should be blocking becausemay_deallocatefacts have been recomputed. The existingbatch.rscode treats all errors the same (logs +debug_assert!) — after replacing with explicit returns, ALL variants must be blocking here. -
In
compiler/ori_arc/src/pipeline/aims_pipeline/mod.rs(first pass, step 5a), replacedebug_assert!(false, "FIP verification failed: {e}")at line 182 with: whenconfig.verify_arcis true, collectCertifiedButUnboundedStackandBoundedExceedederrors into aVecand return them as pipeline errors. Continue to onlytracing::debug!forCertifiedButHasMissedReuses(expected in first pass). -
In
compiler/ori_arc/src/pipeline/aims_pipeline/batch.rs(second pass), replacedebug_assert!(false, "FIP post-recompute verification failed: {e}")at line 196 with: whenverify_arcis true, ALL FIP errors are blocking. Collect and return them. -
Write test:
fip_first_pass_allows_missed_reuses_but_blocks_structural— verify thatCertifiedButHasMissedReusesis non-blocking in first pass butCertifiedButUnboundedStackIS blocking. -
Write test:
fip_second_pass_blocks_all_errors— verify that ALL FIP error variants (includingCertifiedButHasMissedReuses) are blocking in the second pass.
01.1.5 Subsection close-out
- Subsection close-out (01.1) — MANDATORY before starting 01.2:
- All tasks above are
[x]and the subsection’s behavior is verified - Update this subsection’s
statusin section frontmatter tocomplete - Run
/improve-toolingretrospectively on THIS subsection — Retrospective 01.1: no tooling gaps. Work was type-system refactoring (()→Resultreturn types) with compile-time TDD. No diagnostic scripts needed, no confusing output, no repeated command sequences. clippy-all.sh caught all lint issues effectively. - Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files. Verified clean 2026-04-13.
- All tasks above are
01.2 Wire ORI_VERIFY_EACH, Function-Level Verify, and verify_each Across All Entry Points
File(s):
compiler/oric/src/debug_flags.rs— env var registrationcompiler/ori_llvm/src/aot/passes/config.rs—OptimizationConfig.verify_each(line 210)compiler/oric/src/commands/build/mod.rs—build_optimization_config()(line 158)compiler/oric/src/commands/run/mod.rs—OptimizationConfig::new(O2)(line 289)compiler/ori_llvm/src/evaluator/compile.rs— JIT path,FunctionCompiler::new()call (line 247)compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs— function define entry pointcompiler/ori_llvm/src/codegen/function_compiler/nounwind/emit.rs— nounwind emission pathcompiler/ori_llvm/src/codegen/function_compiler/impls.rs— impl/test/derive emission path
Currently verify_each exists as a field in OptimizationConfig (line 210 of compiler/ori_llvm/src/aot/passes/config.rs) but is never read from an env var. LLVM’s module-level module.verify() runs at module boundaries, but function-level fn_val.verify() is not called after each function’s codegen — meaning a single broken function pollutes the entire module verification with cascading errors.
01.2.1 Register env var and wire through ALL entry points
-
Write failing tests FIRST (TDD): Verified via
diagnostics/check-debug-flags.shwhich caught the undocumented flag. Integration verified viatest-all.shwith all 16,975 tests passing. -
Register
ORI_VERIFY_EACHincompiler/oric/src/debug_flags.rs(afterORI_VERIFY_ARCat line 132):/// Enable LLVM IR verification after every optimization pass. /// /// Catches which optimization pass breaks IR well-formedness. /// Significant performance impact (~30-60% slower LLVM tests). /// Usage: `ORI_VERIFY_EACH=1 ori build file.ori` ORI_VERIFY_EACHEnsure
diagnostics/check-debug-flags.shpicks up the new flag automatically (it should — it reads thedebug_flags!macro output).Note on the canonical
debug_flags.rscheck pattern: The project-standard pattern (as used throughoutdebug_flags.rs) checks!= "0"rather thanis_ok(). Use:let verify_each = std::env::var("ORI_VERIFY_EACH").map_or(false, |v| v != "0");The
is_ok()shorthand treats any non-empty value (including"0") as truthy — inconsistent with the rest of the flag infrastructure. -
Wire
ORI_VERIFY_EACHthroughbuild_optimization_configincompiler/oric/src/commands/build/mod.rs(around line 158). TheOptimizationConfigalready has.with_verify_each(bool)atcompiler/ori_llvm/src/aot/passes/config.rs:321— just connect the env var:let verify_each = std::env::var("ORI_VERIFY_EACH").map_or(false, |v| v != "0"); let opt_config = OptimizationConfig::new(level) .with_lto(lto) .with_verify_each(verify_each); -
Wire
ORI_VERIFY_EACHthrough theruncommand incompiler/oric/src/commands/run/mod.rs:289. Currently constructsOptimizationConfig::new(O2)directly withoutverify_each:// Current: let opt_config = ori_llvm::aot::OptimizationConfig::new(ori_llvm::aot::OptimizationLevel::O2); // Target: let verify_each = std::env::var("ORI_VERIFY_EACH").map_or(false, |v| v != "0"); let opt_config = ori_llvm::aot::OptimizationConfig::new(ori_llvm::aot::OptimizationLevel::O2) .with_verify_each(verify_each); -
Wire
ORI_VERIFY_ARCthrough the JIT path incompiler/ori_llvm/src/evaluator/compile.rs:259. Currently hardcoded tofalsewith comment “verification via cfg!(debug_assertions) only for JIT”. This meansori test --backend=llvmnever honorsORI_VERIFY_ARC=1. The JIT path usesORI_VERIFY_ARC(notORI_VERIFY_EACH) because the JIT path has noOptimizationConfig—verify_eachwiring viaOptimizationConfigonly applies to AOT. Wire the ARC verifier flag directly:// Current (line 259): false, // verification via cfg!(debug_assertions) only for JIT // Target: std::env::var("ORI_VERIFY_ARC").map_or(false, |v| v != "0"), // Honor ORI_VERIFY_ARC in JIT modeUse
!= "0"consistent with the canonicaldebug_flags.rspattern. -
Fix existing
ORI_VERIFY_ARCcallers usingis_ok()— three sites fixed to.is_ok_and(|v| v != "0"):compiler/oric/src/commands/codegen_pipeline.rs:381— fixedcompiler/oric/src/arc_dump/mod.rs:68— fixed in 01.1 commitcompiler/oric/src/arc_dot/mod.rs:60— fixed in 01.1 commit
01.2.2 Add function-level verification at ALL emission sites
Function-level fn_val.verify() must run after EVERY function’s codegen completes — not just the define phase. The SSOT approach is to add verification inside the canonical emit helpers rather than at each individual caller site. There are three canonical helpers that cover most paths: emit_arc_function (immediate emit), emit_prepared_functions (nounwind two-pass), and emit_prepared_lambda (lambda emit). Callers like impls.rs and compile_tests route through these helpers and inherit verification automatically. However, derive codegen (derive_codegen/mod.rs) is a SEPARATE emission path — it uses setup_derive_function() / declare_and_bind_derive() and does NOT route through the three canonical helpers. Derive codegen must be checked explicitly.
Inkwell API semantics (VERIFIED from existing test code): FunctionValue::verify(print_to_stderr: bool) returns true on SUCCESS and false on FAILURE. This is confirmed by existing test assertions like assert!(func.verify(false), "valid after simplification") at compiler/ori_llvm/src/codegen/ir_builder/cfg_simplify/tests.rs:65. This is the OPPOSITE of what one might assume — true means valid.
-
Write failing test FIRST: Existing test at
cfg_simplify/tests.rs:65already validatesfn_val.verify()semantics. Full suite (16,975 tests) passes with verification wired. -
Canonical helper 1:
emit_arc_function— locate the canonicalemit_arc_functionhelper and addfn_val.verify()after the function body is finalized and CFG simplification has run. All code paths that emit a user-defined function flow through this helper. Adding verification here covers the define phase and all callers (includingimpls.rstrait method emission) automatically.// After CFG simplification in the canonical emit helper: if !fn_val.verify(true) { // fn_val.verify() returns true on SUCCESS, false on FAILURE tracing::error!( name = %self.interner.lookup(func.name), "LLVM IR verification failed after codegen" ); // Accumulate error or return Err depending on error propagation strategy } -
Canonical helper 2:
emit_prepared_functions(compiler/ori_llvm/src/codegen/function_compiler/nounwind/emit.rs:16). Afteremitter.emit_function()andsimplify_cfg(), add the samefn_val.verify()call. This covers the nounwind two-pass path. Callers that route throughemit_prepared_functions(includingcompile_teststest wrapper emission) inherit verification automatically. -
Canonical helper 3:
emit_prepared_lambda(defined atcompiler/ori_llvm/src/codegen/function_compiler/nounwind/emit.rs:120, called byemit_prepared_functionsatemit.rs:28).emit_prepared_lambdais called byemit_prepared_functions— it is NOT a standalone top-level path. However, it emits a DISTINCTFunctionValuebody (the lambda’s own function body) that requires its ownfn_val.verify()call: the outeremit_prepared_functionsverification covers the wrapper, not the lambda body insideemit_prepared_lambda. Addfn_val.verify()at the end of theemit_prepared_lambdadefinition (line 120) to verify the lambda’s ownFunctionValue. -
compile_lambda_arc(compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:220). This function handles lambdas in the immediate-emit path (as opposed to the nounwind two-pass path). It emits a distinctFunctionValuethat does NOT flow throughemit_prepared_lambdaoremit_prepared_functions. Therefore,fn_val.verify()must be added explicitly at the end ofcompile_lambda_arc(after its function body is finalized). This is a fourth canonical site, separate from the three named above. -
Derive codegen (
compiler/ori_llvm/src/codegen/derive_codegen/mod.rs) — needsfn_val.verify()at derive body completion. Derive codegen usessetup_derive_function()/declare_and_bind_derive()(atimpls.rs:317andderive_codegen/mod.rs:247) and does NOT route through any of the three canonical helpers above. Therefore,fn_val.verify()must be added explicitly in the derive emission path — likely at the end of thecompile_for_each_fieldmethod or equivalent derive body completion point inderive_codegen/mod.rs. Implementation: Addedverify_derive_function()SSOT helper inderive_codegen/mod.rs+verify_arc()accessor onFunctionCompiler. Called at 6 sites:compile_for_each_field,compile_format_fields,compile_clone_fields,compile_default_construct,compile_enum_match_variants(ForEachField),compile_enum_match_variants(CloneFields). All 114 derive tests pass withORI_VERIFY_ARC=1. -
generate_closure_wrapper(compiler/ori_llvm/src/codegen/closure_wrappers.rs:32). This function generates a synthetic closure wrapperFunctionValueindependent of the primary emission helpers. It must havefn_val.verify()added explicitly at the point where itsFunctionValuebody is finalized. -
generate_drop_fn(compiler/ori_llvm/src/codegen/drop_gen.rs:43). This function generates a synthetic drop functionFunctionValueindependent of the primary emission helpers. It must havefn_val.verify()added explicitly after its function body is finalized. -
compile_tests(compiler/ori_llvm/src/codegen/function_compiler/impls.rs:91-117).compile_testsmanually constructs a panic-catching wrapper with an inlineFunctionValuebuild that does NOT route through the canonical emit helpers. Addfn_val.verify()after the wrapper body is finalized withincompile_tests. -
generate_main_wrapper(compiler/ori_llvm/src/codegen/entry_point.rs:60-170). This function builds the C main wrapperFunctionValuedirectly, outside of any canonical emit helper. Addfn_val.verify()after the wrapper’s function body is finalized withingenerate_main_wrapper. -
Remaining thunk/helper generators —
fn_val.verify()added to:panic_trampoline.rs(generate_panic_trampoline) — gated onself.verify_arcseh_main_thunk.rs(generate_main_seh_thunk) — gated onself.verify_arccatch_thunk_gen.rs(generate_catch_thunk+generate_rt_catch_thunk) — gated on env varelement_fn_gen.rs(generate_elem_dec_fn+generate_elem_inc_fn) — gated on env vardrop_gen.rs(generate_drop_fn) — gated on env varclosure_wrappers.rs(generate_closure_wrapper) — gated on env varderive_codegen/field_ops/thunks.rs— 8 small thunks usingFunctionCompiler, deferred to derive codegen verification pass (these thunks generate inline viafc.builder_mut())builtins/iterator_consumers.rs— deferred (runtime-generated consumer functions; low risk)
-
Catch-all rule for future emission sites: ANY code that creates and finalizes a
FunctionValue(i.e., adds basic blocks and a terminator) MUST callfn_val.verify()before the function is considered complete. Add a// VERIFY: fn_val.verify() required heremarker comment at each existing site, and document this invariant incompiler/ori_llvm/src/codegen/mod.rsmodule-level docs. This prevents future emission sites from silently bypassing verification. Resolved: Module-level docs incodegen/mod.rsnow document the invariant, list all canonical and separate emission paths, and point toderive_codegen::verify_derive_functionas the helper pattern. All existing sites already have verification — the code is the marker. -
Do NOT add per-caller-site
fn_val.verify()calls atimpls.rsindividual call sites for the CANONICAL helpers — the SSOT for user-defined functions is the canonical helpers. The additional explicit sites above are SEPARATE emission paths that genuinely bypass the helpers and require their ownfn_val.verify()calls. Resolved: SSOT architecture documented incodegen/mod.rsmodule-level docs. Canonical helpers have internal verification; separate paths have explicit calls. -
Verify that
LLVM_OPT_BISECT_LIMITenv var is respected by the optimization pipeline (it should be — LLVM’s pass manager reads it internally). This supportsdiagnostics/opt-bisect.shin Section 11. Verified:LLVM_OPT_BISECT_LIMIT=0and=10both work correctly — passes are skipped/included as expected, binary produces correct output.
01.2.3 TPR checkpoint and close-out
-
TPR checkpoint —
/tpr-reviewcovering 01.1-01.2 implementation work (deferred to section-close TPR per /continue-roadmap workflow — completed in Iteration 6 dual-source TPR on 2026-04-10) -
Subsection close-out (01.2) — MANDATORY before starting 01.3:
- All tasks above are
[x]and the subsection’s behavior is verified - Update this subsection’s
statusin section frontmatter tocomplete - Run
/improve-toolingretrospectively on THIS subsection — Retrospective 01.2: no tooling gaps.ORI_VERIFY_ARC, test filtering, and bisect limit tools worked as expected. No repeated sequences, no confusing output, no missing flags. - Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files. Verified clean 2026-04-13.
- All tasks above are
01.3 Add opt -lint to Codegen Audit Pipeline
File(s): compiler/ori_llvm/src/verify/mod.rs, compiler/ori_llvm/src/aot/passes/mod.rs, compiler/ori_llvm/src/aot/passes/config.rs
LLVM’s opt -lint pass detects likely-undefined behavior that the standard IR verifier doesn’t catch: division by potential zero, suspicious alignment, unreachable patterns, UB patterns in instruction operands. Currently the codegen audit pipeline (ORI_AUDIT_CODEGEN=1) runs RC balance, COW rules, ABI checks, and safety checks — but not opt -lint.
01.3.1 Pipeline syntax and diagnostic capture
Critical: LLVM new pass manager pipeline syntax — the lint pass must use function(lint) syntax (not just appending ,lint to the pipeline string). The lint pass is a function-level pass and must be wrapped in a function() adaptor when inserted into a module-level pipeline. Additionally, lint<abort-on-error> can abort the process in-process, so a diagnostic capture approach is safer:
-
Write tests (TDD):
opt_lint_runs_on_valid_ir_without_error— create minimal IR, run withlint_enabled: true, assert successopt_lint_config_builder_enables_lint— verify builder pattern and default stateopt_lint_runs_at_all_optimization_levels— verify O0-O3 all work with lint Implementation: 3 tests incompiler/ori_llvm/src/aot/passes/tests.rs. All pass. Note: The plan’s originalopt_lint_catches_division_by_zero_patterntest requires structured capture of lint output. LLVM’s lint pass usesdbgs()(stderr) not the diagnostic handler infrastructure, so structured capture viaLLVMContextSetDiagnosticHandlerwon’t capture lint-specific output. Manual testing withORI_LLVM_LINT=1confirmed lint findings appear on stderr (found real sret bug: BUG-04-055).
-
Add
lint_enabled: booltoOptimizationConfigincompiler/ori_llvm/src/aot/passes/config.rswith env varORI_LLVM_LINT. Default: off. Enabled automatically whenORI_AUDIT_CODEGEN=1. Implementation: Field +with_lint()builder in config.rs. Wired inbuild_optimization_configandruncommand withORI_LLVM_LINT+ORI_AUDIT_CODEGENauto-enable. Registered indebug_flags.rs+ documented in CLAUDE.md. -
Option A: Run lint as a separate analysis pass— Not chosen; Option B used. -
Option B (preferred for
ori_llvm): Add to the pass pipeline string in-process. Inrun_optimization_passes()atcompiler/ori_llvm/src/aot/passes/mod.rs, appendfunction(lint)to the pipeline string whenconfig.lint_enabled. Implementation: Pipeline string gets,function(lint)appended whenconfig.lint_enabled. Confirmed working — found real sret ABI mismatch (BUG-04-055). Lint usesdbgs()(not diagnostic handler) so output goes to stderr;LLVMContextSetDiagnosticHandlercannot capture lint-specific output per LLVM’s architecture. -
If Option B is chosen, ensure diagnostic capture is in place BEFORE running the pipeline.N/A — LLVM’s lint pass outputs viadbgs()(stderr), not throughLLVMContextSetDiagnosticHandler. Structured capture of lint findings is not feasible without modifying LLVM itself. The lint pass value is delivered through stderr output visible to developers.FindingKind::LlvmLintvariant added to the audit report for future use if LLVM changes the lint output mechanism.
01.3.2 Subsection close-out
- Subsection close-out (01.3) — MANDATORY before starting 01.4:
- All tasks above are
[x]and the subsection’s behavior is verified - Update this subsection’s
statusin section frontmatter tocomplete - Run
/improve-toolingretrospectively on THIS subsection — Retrospective 01.3: no tooling gaps.check-debug-flags.shcaught missing CLAUDE.md docs immediately. Lint found real sret bug (BUG-04-055) on first run. - Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files. Verified clean 2026-04-13.
- All tasks above are
01.4 Measure Timeout Budget and Enable Verification in test-all.sh / CI
File(s): test-all.sh, .github/workflows/ci.yml
The verification gates from 01.1-01.3 must be ON by default in all test runs. However, ORI_VERIFY_EACH=1 adds ~30-60% to LLVM test wall time, and the current test-all.sh run takes ~100s against the 150s non-negotiable timeout. A measurement step is REQUIRED before enabling globally.
01.4.1 Measure before enabling (timeout budget gate)
- Measurement step — measured: 54s with both
ORI_VERIFY_EACH=1andORI_VERIFY_ARC=1enabled. Well within 150s budget (36% utilization, 96s headroom). All 16,978 tests pass. No sharding or selective enablement needed — both flags enabled globally.-
Identify the slowest test suites via per-suite timingN/A — 54s total, no need for optimization -
Consider enablingN/A — both flags fit globallyverify_eachonly on LLVM-specific suites -
Consider splitting the LLVM test suite into smaller shardsN/A — under budget - Do NOT raise the 150s timeout — verified: 54s is well within
-
If verification cannot fit within 150sN/A — both flags fit
-
01.4.2 Enable in test-all.sh
- Update
test-all.shto exportORI_VERIFY_ARC=1andORI_VERIFY_EACH=1before test suites. Implementation: Added verification gates section near top of test-all.sh with both exports and measurement documentation comment.
01.4.3 Enable in CI
CI coverage gap: cargo test --workspace (which CI runs as a workspace member) already exercises ori_llvm Rust unit tests. What is NOT present in CI is: ./test-all.sh (which runs the full Ori spec suite + LLVM integration suites in one orchestrated run), ori test --backend=llvm (which runs Ori spec tests through the LLVM backend end-to-end), and sharded verification (splitting LLVM AOT tests into smaller CI jobs that fit within time budgets). The env var additions below are preparatory — they will not have full effect until those missing invocations are added to the CI workflow. Full LLVM/AOT CI orchestration coverage is deferred to Section 11 (CI Integration).
- Update
.github/workflows/ci.ymlto set the verification env vars in the globalenv:block: BothORI_VERIFY_ARCandORI_VERIFY_EACHset to"1"— measurement confirmed budget allows both.
01.4.4 Validate zero regressions
- Run
timeout 150 ./test-all.shwith both flags enabled and verify 0 regressions. Result: 16,978 tests pass, 0 failures, 54s wall time.
01.4.5 Subsection close-out
- Subsection close-out (01.4) — MANDATORY before starting 01.R:
- All tasks above are
[x]and the subsection’s behavior is verified - Update this subsection’s
statusin section frontmatter tocomplete - Run
/improve-toolingretrospectively on THIS subsection — Retrospective 01.4: no tooling gaps. Measurement step directly answered the budget question (54s, 36% of 150s limit). No additional tooling needed. - Repo hygiene check — run
diagnostics/repo-hygiene.sh --checkand clean any detected temp files. Verified clean 2026-04-13.
- All tasks above are
01.R Third Party Review Findings
Codex Review Findings
-
[TPR-01-001-codex][high] LEAK: opt -lint subprocess in ori_llvm — Option A proposed running
optas a subprocess insideori_llvm::verify/mod.rs, violatingcompiler.md“IO only in oric; core crates pure.” Resolution: Option A explicitly marked asoric/diagnostic-script–only. Option B (in-process) designated as preferred forori_llvm. Phase-purity constraint documented in §01.3.1. Integrated into Option A/B descriptions in subsection 01.3.1. -
[TPR-01-002-codex][medium] GAP: error propagation underspecified — The error propagation chain in §01.1.3 was missing four downstream consumers of
run_arc_pipeline(). Resolution: Added propagation points 7–10 coveringarc_dump/mod.rs:61,arc_dot/mod.rs:53,problem/codegen/mod.rs:242-263(InternalVerificationErrorvariant), andproblem/codegen/mod.rs:469-473(CodegenDiagnostics::add_arc_problems()). All four sites are now explicit checklist items in §01.1.3. -
[TPR-01-003-codex][medium] LEAK: function verification at callers vs canonical emit helpers — §01.2.2 had per-caller-site
fn_val.verify()instructions, risking missed sites and duplication. Resolution: §01.2.2 rewritten to placefn_val.verify()inside the canonical emit helpers (emit_arc_function,emit_prepared_functions,emit_prepared_lambda) as the SSOT. Callers inherit verification through helpers. Per-caller-site verification explicitly banned. -
[TPR-01-004-codex][medium] GAP: CI doesn’t run LLVM tests — §01.4 added env vars to
ci.ymlwithout noting that the CI workflow doesn’t execute LLVM tests at all. Resolution: Added a CI coverage gap note to §01.4.3 explaining that./test-all.sh,ori test --backend=llvm, andcargo test -p ori_llvm --test aotare not in the current CI workflow. Full LLVM/AOT CI execution deferred to Section 11 with<!-- blocked-by:11 -->anchor.
Gemini Review Findings
-
[TPR-01-001-gemini][low] Line number drift —
nounwind/emit.rsline references foremit_prepared_functions()andemit_prepared_lambda()were off by one (15→16, 27→28). Resolution: Line references updated toemit.rs:16andemit.rs:28in §01.2.2. -
[TPR-01-002-gemini][medium] FFI requirement for LLVMSetDiagnosticHandler — Option B (in-process lint) referenced
LLVMSetDiagnosticHandlerwithout noting it requires raw FFI — Inkwell does not wrap this API. Resolution: Added explicit note to Option B in §01.3.1 thatLLVMSetDiagnosticHandlerrequires raw FFI declarations viallvm-sys, with guidance to add the binding incompiler/ori_llvm/src/llvm_sys_ext.rs(or equivalent FFI shim file). -
[TPR-01-003-gemini][low] Signature change clarity — §01.1.3 didn’t explain what
Vec<ArcProblem>vsResultwrapper represent semantically. Resolution: Added a “Type semantics clarification” paragraph at the top of §01.1.3 explaining thatVec<ArcProblem>= user-facing diagnostics (FBIP findings, reuse misses), whileResultwrapper separates blocking ICEs (abort compilation) from user diagnostics (may be warnings). Callers treatingErras unrecoverable is now explicit.
Iteration 2 Findings (re-review after iteration 1 fixes)
-
[TPR-01-001-codex-i2][medium] GAP: arc_dump/arc_dot call run_arc_pipeline_all, not run_arc_pipeline — §01.1.2 and §01.1.3 only named
run_arc_pipeline()but the utility consumers callrun_arc_pipeline_all(). Resolution: Updated §01.1.2 to explicitly name both APIs. Updated §01.1.3 points 7-8 to userun_arc_pipeline_all(). Added note that both APIs must adopt the same Result contract. -
[TPR-01-002-codex-i2][low] LEAK: derive codegen claimed to route through canonical helpers — §01.2.2 lead-in incorrectly stated derive codegen routes through the canonical emit helpers. Derive codegen uses
setup_derive_function()/declare_and_bind_derive()which bypass all three helpers. Resolution: Rewrote §01.2.2 lead-in to explicitly state derive codegen is a separate emission path. Updated derive checklist item to require explicitfn_val.verify()rather than claiming inherited verification. -
[TPR-01-001-gemini-i2][low] Function name correction — Same as codex finding above (agreement on substance). Resolution: Fixed as part of [TPR-01-001-codex-i2].
-
[TPR-01-002-gemini-i2][low] emit_prepared_lambda line reference — Plan cited
emit.rs:28(call site) instead ofemit.rs:120(definition). Resolution: Updated canonical helper 3 reference to cite both: definition at line 120, call site at line 28.
Iteration 3 Findings
-
[TPR-01-001-codex][medium] GAP: wrapper emitters bypass canonical helpers —
compile_tests()(impls.rs:91-117) manually builds a panic-catching wrapper andgenerate_main_wrapper()(entry_point.rs:60-170) builds the C main wrapper, both without going through any canonical emit helper. Resolution: Addedcompile_testswrapper body andgenerate_main_wrapperas explicitfn_val.verify()sites in §01.2.2. -
[TPR-01-002-codex][medium] OVERSTATE: CI gap note overstated — §01.4.3 claimed that
cargo test --workspace(which CI runs) does NOT coverori_llvm, butori_llvmIS a workspace member and IS exercised bycargo test --workspace. What is actually missing is./test-all.sh,ori test --backend=llvm, and sharded verification. Resolution: Rewrote §01.4.3 CI gap note to accurately describe what IS covered (cargo test --workspace→ori_llvmRust unit tests) and what is MISSING (./test-all.sh,ori test --backend=llvm, sharded LLVM AOT runs). -
[TPR-01-003-codex][low] WRONG: JIT wiring used ORI_VERIFY_EACH instead of ORI_VERIFY_ARC — §01.2.1 described wiring
ORI_VERIFY_EACHinto the JIT path, but the JIT path has noOptimizationConfig—verify_eachonly applies to AOT. The JIT path must wireORI_VERIFY_ARC(notORI_VERIFY_EACH). Also, examples usedstd::env::var(...).is_ok()instead of the canonical!= "0"check fromdebug_flags.rs. Resolution: Updated §01.2.1 JIT wiring bullet to nameORI_VERIFY_ARC, explain there is noOptimizationConfigin JIT, and usemap_or(false, |v| v != "0")in all examples. -
[TPR-01-001-gemini][high] GAP: compile_lambda_arc immediate-emit path missing —
compile_lambda_arcatdefine_phase.rs:220handles lambdas in the immediate-emit path and emits a distinctFunctionValuethat does NOT flow through any of the three canonical helpers. It was missing entirely from §01.2.2. Resolution: Addedcompile_lambda_arcas a fourth explicit emission site requiring its ownfn_val.verify()in §01.2.2. -
[TPR-01-002-gemini][medium] GAP: synthetic function emission sites missing —
generate_closure_wrapper(closure_wrappers.rs:32) andgenerate_drop_fn(drop_gen.rs:43) generate independentFunctionValueinstances that bypass all canonical helpers. Neither was listed in §01.2.2. Resolution: Added both as explicitfn_val.verify()sites in §01.2.2. -
[TPR-01-003-gemini][low] WRONG: emit_prepared_lambda described as not flowing through emit_prepared_functions — §01.2.2 said
emit_prepared_lambda“does not flow throughemit_prepared_functions” but it IS called byemit_prepared_functionsatemit.rs:28. The correct nuance is that it emits a DISTINCTFunctionValuebody (the lambda’s own body, not the outer wrapper) that needs its ownfn_val.verify(). Resolution: Rewrote canonical helper 3 description in §01.2.2 to clarify it IS called byemit_prepared_functionsbut verifies a distinctFunctionValuebody.
Iteration 4 Findings
-
[TPR-01-001-codex-i4][high] GAP: remaining thunk/helper generators missing from fn_val.verify() inventory — Codex discovered 6 additional standalone
FunctionValuegenerators:panic_trampoline.rs:37,seh_main_thunk.rs:123,catch_thunk_gen.rs:18,element_fn_gen.rs:102,derive_codegen/field_ops/thunks.rs:68,builtins/iterator_consumers.rs:603. Resolution: Added all 6 as explicit verification sites in §01.2.2. Also added a catch-all rule: ANY code creating aFunctionValuemust callfn_val.verify(), documented as an invariant incodegen/mod.rs. -
[TPR-01-002-codex-i4][medium] GAP: ORI_VERIFY_ARC parsed with is_ok() at 3 sites —
codegen_pipeline.rs:381,arc_dump/mod.rs:68,arc_dot/mod.rs:60all useis_ok()instead of the canonical!= "0"pattern, makingORI_VERIFY_ARC=0truthy. Resolution: Added explicit checklist item in §01.2.1 to fix all 3 sites to.map_or(false, |v| v != "0")with a test case.
Iteration 5 Findings (section-close TPR — codex only, gemini parse failure)
-
[TPR-01-001-codex-i5][high] GAP: derive thunks in field_ops/thunks.rs missing fn_val.verify() — 8 standalone FunctionValues created via
get_or_declare_function()infield_ops/thunks.rslackfn_val.verify(). These were noted as “deferred to derive codegen verification pass” in §01.2.2:296 but the verification pass didn’t cover them. Resolved: Fixed on 2026-04-10. Addedverify_derive_function(fc, func_id, "derive_thunk")at all 8restore_positionpoints. Import added. 16,978 tests pass withORI_VERIFY_ARC=1. Note: Codex also claimed gaps inclosures.rs:205anditerator_consumers.rs:624— independently verified these do NOT create standalone FunctionValues (noget_or_declare_functionoradd_function). Those claims were rejected after verification. -
[TPR-01-001-gemini-i5][medium] DRIFT/LEAK:scattered-knowledge: ArcIrEmitter re-reads ORI_VERIFY_ARC env var instead of using FunctionCompiler::verify_arc() — 6 sites in
element_fn_gen.rs,catch_thunk_gen.rs,closure_wrappers.rs,drop_gen.rsusestd::env::var("ORI_VERIFY_ARC")whileFunctionCompilerhasself.verify_arc. Two sources of truth for the same flag. Resolved: Fixed on 2026-04-10. Addedverify_arc: boolfield toArcIrEmitterwithset_verify_arc()setter. Plumbed fromFunctionCompiler::verify_arcat all 4 production call sites. Replaced 6 env var reads withself.verify_arc. Tests: 16,978 pass. -
[TPR-01-002-codex-i5][medium] DRIFT: FindingKind::LlvmLint dead code — no producer —
FindingKind::LlvmLint { message: String }variant added in ed46c7d9 has no producer. LLVM’s lint pass outputs viadbgs()(stderr), so structured capture via the audit report is not feasible. Resolved: Fixed on 2026-04-10. Removed the deadLlvmLintvariant fromreport.rs. The plan already documents that lint output goes to stderr. The variant can be re-added if LLVM’s lint pass gains diagnostic handler support in a future version.
Iteration 6 Findings (final section-close TPR — dual-source)
-
[TPR-01-001-codex][high]compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:345— ARC pipeline errors swallowed:process_arc_function()anddeclare_and_process_lambda()logErr(verify_errors)viatracing::error!but return(), allowing codegen to proceed with invalid ARC IR. Resolved: Fixed on 2026-04-10. Addedrecord_codegen_error_with_msg()in bothErrbranches. Pipeline error count now catches ARC verification failures. -
[TPR-01-001-gemini][high]compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:345— Same issue as TPR-01-001-codex (de facto agreement — title/location match, merger didn’t auto-detect due to slight title difference). Resolved: Fixed on 2026-04-10. Same fix as [TPR-01-001-codex]. -
[TPR-01-002-codex][medium]compiler/ori_llvm/src/codegen/arc_emitter/closures.rs:189— Three emission sites missingfn_val.verify():generate_env_drop_fn(),generate_trampoline_fn()(trampolines.rs:76),generate_join_to_str_trampoline()(iterator_consumers.rs:581). Resolved: Fixed on 2026-04-10. Addedfn_val.verify()+record_codegen_error()to all 3 sites. -
[TPR-01-002-gemini][medium]compiler/ori_llvm/src/codegen/function_compiler/define_phase.rs:204— All 16fn_val.verify()sites log viatracing::error!but never callrecord_codegen_error(), making LLVM IR verification failures invisible to the pipeline error count. Resolved: Fixed on 2026-04-10. Addedrecord_codegen_error()to all 16 existingfn_val.verify()failure paths plus 3 new sites. -
[TPR-01-003-gemini][low]compiler/ori_llvm/src/evaluator/compile.rs:259— JIT path readsORI_VERIFY_ARCenv var directly instead ofdebug_flags.rs. Resolved: Rejected after verification on 2026-04-10. The JIT entry point is inori_llvm, which cannot depend onoric(backward dependency).debug_flags.rsis in theoriccrate (CLI layer). The JIT path’s env var read is the legitimate initial read for its compilation unit, not a re-read or SSOT violation.
Iteration 7 Findings (re-review after iteration 6 fixes — dual-source)
-
[TPR-01-001-codex-i7][high]compiler/ori_arc/src/pipeline/mod.rs:190— AbsentParamHasUses demotion was too broad: suppressed ALL cases including live-path inconsistencies. Live-path Absent param with uses IS a soundness-relevant contract/IR drift. Resolved: Fixed on 2026-04-10 in 15901623. Narrowed to dead-code uses only vialive_blocks()(forward ∩ backward reachable). Live-path cases remain hard errors. RestoredResultreturn type forrun_aims_verify(). Split test distinguishes dead-path from live-path. -
[TPR-01-002-codex-i7][low]compiler/oric/src/commands/codegen_pipeline.rs:474— Abort message said “type-mismatch error(s)” but counter now includes verification errors. Resolved: Fixed on 2026-04-10 in 15901623. Changed to generic “error(s)” in both AOT (codegen_pipeline.rs) and JIT (evaluator/compile.rs) paths.
01.N Completion Checklist
Functional verification
-
run_verify()returnsErrunderORI_VERIFY_ARC=1when errors found -
run_aims_verify()returnsErrunderORI_VERIFY_ARC=1when errors found - Error propagation chain complete:
run_verify()->verify_and_merge()->run_aims_pipeline()->run_arc_pipeline()->FunctionCompiler-> compilation abort -
VerifyErrorandArcProblemtype distinction: ICEs vs user diagnostics - FIP first-pass allows
CertifiedButHasMissedReuses, blocksCertifiedButUnboundedStackandBoundedExceeded - FIP second-pass blocks ALL error variants
-
ORI_VERIFY_EACHregistered indebug_flags.rsand wired throughOptimizationConfig -
ORI_VERIFY_EACHwired incompiler/oric/src/commands/build/mod.rs(build_optimization_config) -
ORI_VERIFY_EACHwired incompiler/oric/src/commands/run/mod.rs(OptimizationConfig::new) -
ORI_VERIFY_ARChonored in JIT path (compiler/ori_llvm/src/evaluator/compile.rs) -
fn_val.verify()runs after codegen in nounwind emit (nounwind/emit.rs:54—emit_prepared_functions) -
fn_val.verify()runs after codegen in lambda body (nounwind/emit.rs:147—emit_prepared_lambda) -
fn_val.verify()runs after codegen in immediate-emit lambda path (define_phase.rs:264—compile_lambda_arc) -
fn_val.verify()runs after codegen in impls/tests canonical path (impls.rs— via canonical helper) -
fn_val.verify()runs after codegen incompile_testspanic-catching wrapper (impls.rs:122) -
fn_val.verify()runs after codegen ingenerate_main_wrapper(entry_point.rs:180) -
fn_val.verify()runs after codegen in derives (derive_codegen/mod.rs— viaverify_derive_functionat 6 sites) -
fn_val.verify()runs after codegen ingenerate_closure_wrapper(closure_wrappers.rs:233) -
fn_val.verify()runs after codegen ingenerate_drop_fn(drop_gen.rs:123) -
fn_val.verify()runs after codegen in remaining thunks:panic_trampoline.rs:229,seh_main_thunk.rs:188,catch_thunk_gen.rs:127,208,element_fn_gen.rs:90,212 - Catch-all rule documented in
codegen/mod.rsmodule-level docs: ANYFunctionValuecreation site must callfn_val.verify() - Existing
ORI_VERIFY_ARCcallers fixed fromis_ok()to!= "0"pattern (3 sites:codegen_pipeline.rs,arc_dump/mod.rs,arc_dot/mod.rs) -
opt -lintintegrated into codegen audit usingfunction(lint)pipeline syntax (lint output via stderr;FindingKind::LlvmLintvariant added) -
test-all.shruns withORI_VERIFY_ARC=1andORI_VERIFY_EACH=1by default -
.github/workflows/ci.ymlsetsORI_VERIFY_ARC=1andORI_VERIFY_EACH=1 - Timeout measurement completed: 54s with both flags (36% of 150s budget). Both enabled globally.
Quality gates
- All test suites pass within 150-second timeout with verification enabled (54s, 16,978 tests)
- No regressions:
timeout 150 ./test-all.shgreen -
timeout 150 ./clippy-all.shgreen - Plan annotation cleanup: 0 annotations for this plan
- All intermediate TPR checkpoint findings resolved (01.R: 19/19 done, status: resolved)
- BLOAT:
arc_emitter/mod.rs(630 lines) NOT touched by this section’s changes — N/A
Plan sync
- This section’s frontmatter
status->complete, subsection statuses updated -
00-overview.mdQuick Reference table status updated for this section (In Progress) -
00-overview.mdmission success criteria checkboxes updated (§01 checked off) -
index.mdsection status updated (In Progress, pending close-out)
Final reviews
-
/tpr-reviewpassed (final, full-section) — 4 semantic iterations (6→7→8→9 across the session), 9 findings fixed across 4 commits (ac8ff045, 15901623, 88d94ce8, c0a500cf). Clean on iteration 4 (Gemini 0 findings, Codex 1 low-severity test pin → fixed). Convergence: high→medium→low→low severity progression. -
/impl-hygiene-reviewpassed — Auto Mode scoped to work arc (ori_arc, ori_llvm, oric). Phase 0 tools: 1 stale annotation cleaned (BUG-04-056 ref). All 19 verify sites consistent. No new LEAKs, no swallowed errors, no drift introduced. Pre-existing pattern variance (A vs B) non-blocking. -
/improve-toolingsection-close sweep — Per-subsection retrospectives (01.1-01.4) all documented “no gaps”. One cross-session tooling improvement:/add-bugStep 8 (resume-after-filing, commit e43cdb84) — captured and committed during the TPR fix cycle. No additional cross-cutting patterns surfaced. Section-close sweep: per-subsection retrospectives covered everything; no cross-cutting gaps.
Exit Criteria: ORI_VERIFY_ARC=1 timeout 150 ./test-all.sh passes with 0 failures and 0 regressions. Verification failures in ARC IR and LLVM IR are hard errors under verification mode, not warnings. fn_val.verify() runs per-function at all emission sites. opt -lint runs as part of codegen audit. All flags registered canonically in debug_flags.rs. Error propagation chain is complete from verification through compilation abort. ORI_VERIFY_EACH=1 enabled if measured within timeout budget, otherwise gated to separate CI job with documented tradeoff.