§01 — AIMS FFI Contract Extension
Context
Approved proposal §1 (docs/ori_lang/proposals/approved/ffi-boundary-safety-proposal.md) states that AIMS today treats extern calls as opaque — assume-the-worst conservative — because extern declarations do not produce MemoryContract fragments. This section makes extern declarations first-class contract providers, so the existing interprocedural SCC fixpoint (IC-1 / IC-2 / IC-3 / IC-4 / IC-5) consumes them alongside native Ori callees.
Invariant #5 is load-bearing here. Any implementation approach that introduces a parallel structure (shadow contract table, separate FFI lattice, independent ownership annotation pass, or backend-mechanism field) is out of scope AND will be rejected at /tpr-review. The extension MUST be additive on MemoryContract / ParamContract / ReturnContract / EffectSummary and freeze stable logical event identities in the shared ExecutableProgram.
Backend-neutral seam. AIMS owns the logical owner-credit, transfer, cleanup, effect, and unwind facts. VmLayoutPlan and CompiledLayoutPlan(TargetSpec) are sibling consumers that choose physical mechanisms and prove plan satisfaction. LLVM is one adapter over the compiled plan; LLVM IR, helper calls, counters, headers, ABI details, and VM opcodes are never AIMS facts.
§01.1 — Design Log FIRST (gate — do not implement before this)
Before any Rust changes land, write plans/ffi-boundary-safety/section-01-design-log.md answering:
- Which
ParamContractfield(s) carry the FFI-declared ownership (ownedvsborrowed)? — default: reuseParamContract.access(Owned/Borrowed) since that is the existing SSOT peraims-rules.md §1.1. - Which
ParamContractfield carriesmay_sharefor FFI parameters? — default: reuse the existingmay_sharefield onParamContractperaims-rules.md §5 IC-3. - Which
ReturnContractfield carries the FFI-declared return ownership +preserves_freshness? — default: reuseReturnContract.uniqueness(Uniqueforownedreturns from fresh C allocations) andReturnContract.preserves_freshness(trueforowned+ known-fresh allocator;falseforborrowedreturns which copy immediately per approved Deep FFI). - Which
EffectSummaryfields cover#error(errno)/#error(nonzero)/ etc.? — default:may_throw = truewhen#error(...) != none(error paths produceResult::Err, which the caller’s control-flow graph must account for);may_allocate = truewhen the callee is known to allocate (e.g.,sqlite3_opencreates a handle);may_deallocate = truefor#free(...)functions. - What new field (if ANY) is needed? — if none, note that explicitly. If one is needed, justify why it cannot be expressed on existing fields and verify the addition does not violate L-5 (finite height) or L-10 (monotone join).
- Cite each field mapping against
aims-rules.mdrule anchor (IC-2, IC-3, IC-4, IC-5) — reviewers will check these verbatim.
Acceptance. The design log is complete when it exhaustively lists every FFI-declarable annotation (owned, borrowed, owned CPtr return, borrowed str return, borrowed [byte] return, #error(errno), #error(nonzero), #error(null), #error(negative), #error(success: N), #error(none), #free(fn), out param, #borrow_from(p) — the last deferred to §04 but the schema must accommodate it) and maps each to a concrete MemoryContract field.
Failure mode. If the design log cannot express an annotation using existing contract fields, STOP. Do not add a sibling structure. Either (a) propose a specific field addition with justification, or (b) file a bug per CLAUDE.md §Bug Handling — ZERO DEFERRAL and escalate via AskUserQuestion.
§01.2 — ExternDecl → MemoryContract fragment emitter
Once §01.1 is signed off:
- Add
fn extract_extern_contract(decl: &ExternDecl) -> MemoryContractincompiler/ori_arc/src/aims/interprocedural/extract.rs(NEW function; do NOT modify the existingextract_function_contractcore logic — share helpers only). - Wire into the SCC fixpoint: extern decls appear as nodes in the call graph at IC-1 with their contract pre-populated (no fixpoint iteration needed — externs have no bodies to analyze). Supply those producer-authored facts to the one whole-batch
realize_closed_program()entry perarc.md §Entry Points; do not expose the internal contract fixpoint as an FFI- or backend-callable API. - Each extern function’s contract is produced ONCE at crate-type-check time and cached in the Salsa query layer (per
compiler.md §Salsapurity requirements). - Update
ori_arc/src/aims/contract/mod.rsdocumentation comments to note FFI-origin contracts (reading-only — do not change field definitions unless §01.1 justified a new field).
§01.3 — Call-site refinement (TF-6 interop)
- In the intraprocedural analysis (
compiler/ori_arc/src/aims/intraprocedural/mod.rs), the existing TF-6 (aims-rules.md §3)refine(CONSERVATIVE, callee.return_contract)already handles any callee with a contract, regardless of origin. Verify with a targeted unit test that an extern callee’s contract narrows the call-siteAimsStatecorrectly. - Verify TF-11 argument demand refinement (
aims-rules.md §3 TF-11 Applyrow) fires correctly for FFI arguments: BorrowedAbsent→ zero demand; OwnedAbsent→(arg, Once, Linear)plus the exact logical cleanup obligation currently carried under the transitional RL-5 dec spelling; locality/uniqueness/may_share propagation applies identically to FFI calls. - NO new code path needed here — this subsection validates the existing refinement mechanics work for FFI contracts. If they don’t, that’s a bug in TF-6/TF-11, not a new “FFI refinement” code path.
§01.4 — Realization phase validation
- Verify the current
realize_rc_reuse(Step 5) andrealize_annotations(Step 10) entry points freeze the correct logical owner-credit, transfer, cleanup, COW/reuse, effect, and unwind identities for FFI-touching functions. These function names are transitional implementation spellings; realization must not branch on FFI origin or choose a backend mechanism. - Verify
verify_fip_contract(Step 5a,aims-rules.md §5 IC-6) correctly certifies FFI-only functions: a function whose body islet x = RSA_new(); sign(x, ...); RSA_free(x)with allowned/borrowedcontracts provided should reachFipContract::Certifiedwith zero unmatched logical allocation/cleanup obligations. - Bind the frozen facts into
ExecutableProgramby stable identity and add plan-satisfaction checks for bothVmLayoutPlanandCompiledLayoutPlan(TargetSpec). Neither planner may re-derive ownership from representation or feed a physical verdict back into AIMS. - NO realization-level code changes expected. If changes ARE needed, flag as a design-log deviation and STOP for review.
§01.5 — Matrix test coverage (MANDATORY)
Per CLAUDE.md §Fix Completeness and tests.md §Matrix Testing Rule:
- Failing tests FIRST (TDD order):
- AIMS snapshot/oracle test in
compiler/oric/tests/aims-snapshots/ffi_contract/showing the contract fragment and exact stable owner/transfer/cleanup identities for an annotated extern declaration. - VM and compiled plan-satisfaction tests that consume those same identities without re-analysis; an unsupported FFI execution lane must fail explicitly rather than silently omit an obligation.
- Current compiled-projection AOT FileCheck test in
compiler/ori_llvm/tests/aot/ffi_contract.rsthat asserts zeroRcInc/RcDecactions in emitted LLVM IR for the canonical owned-chain program. This check validates one counter plan only.
- AIMS snapshot/oracle test in
- Matrix dimensions (must test ALL cells):
- Ownership × Error protocol:
owned/borrowed×#error(errno)/#error(nonzero)/#error(null)/#error(negative)/#error(none)= 10 cells. - Return types:
c_int,owned CPtr,borrowed CPtr,borrowed str,borrowed [byte],Result<..., FfiError>(auto-wrapped by#error(...)!=none) = 6 cells. - Argument patterns:
owned CPtrarg + dead elsewhere;borrowed CPtrarg + used after call;owned CPtrchained into another FFI call (ownership transfer);borrowed str+ interior mutation attempt (should stay COW-safe).
- Ownership × Error protocol:
- Semantic pins:
- One Ori program
tests/spec/ffi/aims_zero_rc.ori(legacy filename retained for continuity) whose primary assertion is an exact logical ownership chain with no redundant credit/release event. Reverting §01 must change that frozen trace. - For the current compiled counter projection only, retain the FileCheck assertion (
CHECK-NOT: call void @ori_rc_inc/CHECK-NOT: call void @ori_rc_dec) and bind every surviving physical action to a frozen event identity. - One negative logical pin: a program with an
owned CPtrreturned and used twice must retain exactly one additional owner-credit event. If the compiled plan selects counters, its projection must emit exactly one correspondingRcInc; that physical spelling is not the AIMS rule.
- One Ori program
- Verification layer matrix:
- VF-1 structural check clean on FFI-touching functions (
cargo test -p ori_arc -- verify::check_function). - VF-2
AbsentParamHasUsesdoes not false-positive on FFI absent params. - VF-3 oracle cross-check independently verifies the frozen FFI contract and logical event identities against the declared contract (
cargo test -p ori_arc -- oracle). - VF-4 FIP certification matrix:
FipContract::Certified,FipContract::Bounded(N),FipContract::Conditional,FipContract::Nevereach reachable via a test program with appropriate FFI call mix.
- VF-1 structural check clean on FFI-touching functions (
- Multi-executor parity: Every admitted FFI executor matches the evaluator/handler oracle for value, typed error, effects, and cleanup behavior. VM and compiled lanes preserve the same frozen event identities; the current compiled counter lane additionally reports zero leaks under
ORI_CHECK_LEAKS=1. - Projection boundary: LLVM FileCheck failures diagnose the current compiled physical plan or adapter. They may not redefine the AIMS contract, and LLVM-only success cannot close this section.
- Debug + release: both build modes pass all tests.
§01.6 — AIMS rule additions (documentation)
- Update
.claude/rules/aims-rules.md §5to note thatParamContract/ReturnContract/EffectSummaryaccept FFI-origin contracts identically to native contracts — add a one-paragraph note near IC-2/IC-3 citing this section. Co-commit with §01.2. - Update
.claude/rules/arc.md §"What AIMS does TODAY"bullet list to mention FFI contract participation once §01 ships. Co-commit with §01.2. - NO changes to the formal rules themselves — they already admit FFI contracts; this is a documentation sync.
Completion Checklist
- §01.1 design log exists, cites aims-rules.md anchors, passes independent reading.
- §01.2 extract_extern_contract lands; Salsa-cached; unit-tested.
- §01.3 call-site refinement validated via unit tests.
- §01.4 logical realization validated; stable identities frozen; FipContract::Certified reachable for pure-FFI bodies; VM and compiled plan-satisfaction checks pass.
- §01.5 matrix tests green (all cells), logical semantic pins green, sibling-projection checks green, current LLVM FileCheck green, negative pin green, both debug + release.
- §01.6 aims-rules.md + arc.md documentation sync committed.
-
./test-all.shgreen (full suite). -
./clippy-all.shgreen (zero warnings introduced). -
ORI_CHECK_LEAKS=1 ./binaryreports zero leaks on the FFI test programs. -
/tpr-reviewrun to consensus (clean). -
/impl-hygiene-reviewrun to consensus (clean). -
/improve-toolingsection-close sweep run. -
/sync-claudesection-close doc sync run. - Plan status flipped:
sections[id=01].status: complete;reviewed: true; overview Quick Reference updated.
§01.R — Third Party Review Findings
- None.