Proposal: Capability Propagation Completion
Status: Draft
Author: Eric (with AI assistance)
Created: 2026-03-22
Affects: Compiler (type checker, evaluator, LLVM)
Related: capability-composition-proposal.md (approved), capset-proposal.md (approved), stateful-mock-testing-proposal.md (approved)
Research: plans/deep-safety/research.md (Part 9 — prerequisite infrastructure identified by third-party review)
Summary
Complete the implementation of capability propagation as already specified in the capabilities spec (§20.6-20.7). Currently, capability provision to called functions is partially implemented — several spec-mandated behaviors are skipped or stubbed. This proposal identifies the gaps and defines the completion criteria.
This is not a new language feature. It is completing an already-approved design to establish the foundation for all future capability work, including the without clause (negative effects) and Deep Safety capabilities.
Problem Statement
Current State
The capabilities system has the following implementation gaps (as identified by the third-party review on 2026-03-22):
-
Capability provision to callees: When a
with Cap = impl in { body }block is active, functions called withinbodythat declareuses Capshould receive the provided implementation. This is partially working — some test paths show skipped provision. -
Stateful handlers: The
handler(state: init) { op: (s) -> (s', val) }pattern from the stateful-mock-testing proposal is not fully implemented in the evaluator or LLVM backend. -
LLVM/AOT capability support:
usesandwith...inare handled in the evaluator but not in the LLVM codegen path. This means capability-tracked code cannot be compiled ahead-of-time. -
Marker capability discharge propagation:
unsafe { }and theSuspendmarker exist syntactically but the type checker does not fully enforce the propagation rules (§20.9.2) — specifically, that calling a function withuses Unsafewithout either declaringuses Unsafeor wrapping inunsafe { }should be error E1250.
Why This Must Be Fixed Before Deep Safety
Every Deep Safety feature depends on correct capability propagation:
withoutclause (negative effects) requires denied sets to propagate through call chains- Low-level capabilities (
InterruptCtx,VolatileIO) require callers to declare them - Capability-gated FFI (
uses FFI("lib")) requires parametric provision viawith...in - Contract verification on capability-gated functions requires correct capability context
Building Deep Safety on incomplete propagation infrastructure would produce silent correctness bugs — functions appearing to work without the required capability.
Design
This proposal does not introduce new syntax or semantics. It defines completion criteria for the existing spec.
Criterion 1: Positive Propagation
A function that declares uses X can only be called from a context where X is available. Availability means one of:
- The caller declares
uses X - A
with X = impl in { ... }block is active in the caller’s scope - An imported
def impl Xis in scope
Test: A function @f () -> void uses Http = ... called from @g () -> void = f() without Http available must produce E1200.
Criterion 2: with...in Provision
When with X = impl in { body }, all functions called within body that require X receive impl as their implementation. This must work for:
- Direct calls
- Indirect calls through function values
- Calls through trait method dispatch
- Nested
with...inblocks (inner shadows outer)
Test: with Http = MockHttp {} in { fetch_data() } where @fetch_data () -> str uses Http must dispatch Http operations to MockHttp.
Criterion 3: Marker Capability Enforcement
Marker capabilities (Unsafe, Suspend) shall:
- Propagate through call chains like any capability
- Cannot be bound via
with...in(E1203) - Be discharged by their specific mechanism (
unsafe { }forUnsafe, runtime forSuspend)
Test: Calling @f () -> void uses Unsafe without unsafe { } or uses Unsafe → E1250.
Criterion 4: Evaluator Completeness
The evaluator must:
- Track active capability bindings through
with...inscopes - Dispatch capability trait method calls to the provided implementation
- Handle stateful handlers (state threading through handler operations)
- Correctly scope capability bindings (inner
with...inshadows outer)
Criterion 5: LLVM/AOT Completeness
The LLVM codegen must:
- Propagate capability implementations as implicit parameters (or through a global context)
- Generate correct dispatch for capability trait method calls
- Handle
with...inscope entry/exit in the generated code - Support
unsafe { }as a transparent wrapper (already a no-op in codegen)
Implementation
Phase 1: Audit Current Gaps (1-2 days)
Run the existing tests/spec/expressions/with_expr.ori and tests/spec/capabilities/ test suites. Identify which tests are skipped, failing, or missing. Produce a gap list.
Phase 2: Type Checker Fixes (1-2 weeks)
- Fix capability propagation to callees — ensure E1200 fires when a required capability is unavailable
- Fix marker capability enforcement — ensure E1250 fires for uncontained
uses Unsafe - Fix E1203 enforcement — ensure marker capabilities cannot be bound via
with...in - Add missing test coverage for propagation through indirect calls, trait dispatch, nested scopes
Phase 3: Evaluator Fixes (1-2 weeks)
- Complete
with...incapability provision in the evaluator - Implement or complete stateful handler support
- Verify correct scoping (inner shadows outer)
- Add spec tests for all handler patterns from stateful-mock-testing proposal
Phase 4: LLVM/AOT Support (2-4 weeks)
- Design the runtime representation of capability bindings (implicit parameter? thread-local? global table?)
- Generate
with...inscope entry/exit code - Generate capability dispatch code for trait method calls
- AOT tests for all capability patterns
Spec Changes Required
None. The spec already defines the correct behavior (§20.4-20.7, §20.9). This proposal completes the implementation.
Success Criteria
All of the following must pass:
cargo st tests/spec/capabilities/
cargo st tests/spec/expressions/with_expr.ori
cargo t -p ori_types # capability propagation unit tests
cargo t -p ori_eval # evaluator capability dispatch tests
cargo t -p ori_llvm # AOT capability tests
No skipped tests in the capability test suites. All E1200, E1203, E1250 error codes fire correctly.