Effect Contracts & Capability Discipline
Effect contracts are Arcana’s operational boundary: signatures declare what code may do, the compiler verifies it, and deployment artifacts preserve it for audit. Compile-Time Safety covers the mechanism — the effect system as a type-system feature. This page covers what that mechanism means operationally: effects as contracts that travel from the moment a function is written, through the compiler’s verification, into the deployment artifact a downstream evaluator can inspect.
Where compile-time-safety says “effects are typed,” this view says “and the typing means something specific, governed, and cross-stage.”
Effects as operational contracts, not a purity device
Section titled “Effects as operational contracts, not a purity device”Most effect systems exist to enforce purity — to mark which functions can’t do IO so the compiler can reorder, inline, or memoize them. Arcana’s effect system exists for a different reason: to give an external evaluator (a human reviewing AI-generated code, an AI reviewing AI-generated code, a deployment manifest auditing what’s about to ship) confidence about what a unit of code is permitted to do without reading its body.
Below is search_posts from tests/rpc-fixtures/blog.arcana — a verified fixture demonstrating the contract framing. The function takes a String parameter (the search query), declares only {Database} in its effect row, and returns an Int. The compiler enforces that the body performs no other effects.
;; pub fn search_posts(query: String) -> {Database} Int(dc-fn :fn (fn-decl :body (block :stmts () :expr (ex-call :args ( (arg-positional :expr (ex-lit :value (lit-string :value "SELECT id, title, body, published FROM posts WHERE title LIKE ?"))) (arg-positional :expr (ex-ident :name "query"))) :fn (ex-ident :name "db_query"))) :contracts () :effects (Database) :name "search_posts" :params ( (param :modifier none :name "query" :type (ty-named :path "String"))) :ret (ty-named :path "Int") :tparams () :vis pub))pub fn search_posts(query: String) -> {Database} Int { db_query("SELECT id, title, body, published FROM posts WHERE title LIKE ?", query)}{Database} is the contract. Whatever the body does, it cannot send email, call the network, write to the filesystem, or perform any other effect — those aren’t declared. For multi-effect signatures (e.g., the {Database(server), Audit} shape an audit-tracked deletion would require, which composes Database(server) from Compile-Time Safety § Effect system with the Audit effect from the Glossary), the same compositional discipline applies — each declared effect adds to what the body may do, nothing else.
The evaluator gets to reason from the signature. The compiler enforces the body matches.
An admission-controlled effect vocabulary
Section titled “An admission-controlled effect vocabulary”The set of effect names is a closed, governed vocabulary, not a free-for-all. Effects are added, retired, or rejected through a documented process with explicit admission criteria. The current set includes {Email}, {SMS}, {CRM}, {Network}, {Database(local)} / {Database(server)} / {Database(synced)}, {ObjectStore(read)} / {ObjectStore(write)}, {FileSystem}, {Monitor}, {Render} — among others (see the language specification for the full normative inventory; the Arcana repository publishes publicly alongside the v1.x complete release).
Separately, the codegen-target dimensions (Web · iOS · Android · Server · Edge) are tracked through an effect-availability matrix rather than as effects themselves — {iOS} is not an effect; iOS is a target that constrains which effects compile to it.
What this admission discipline produces in practice:
- Effects get rejected, with documented rationale.
{Notify}and{Search}were proposed and rejected — the project does not invent generic effects to cover everything; it requires concrete justification. - Effects get retired.
{Log}was retired in favor of a unified{Monitor}effect. - Effect parameterization is constrained. Object storage splits into
{ObjectStore(read)}and{ObjectStore(write)}because the difference between reading customer data and writing customer data is too important to collapse into one effect name.
The point: a generator (human or AI) cannot just invent an effect named {Whatever} to silence the compiler. The vocabulary is closed. The check holds.
Contracts travel: authoring → checking → deployment
Section titled “Contracts travel: authoring → checking → deployment”The same effect contract appears at three stages of the pipeline:
- Authoring — the function signature declares its effects. This is what the writer (often an AI) commits to.
- Checking — the compiler verifies the body matches the signature. Effect contagion propagates: if function
Acalls functionBdeclaring{Database}, thenAmust also declare{Database}(or contain the effect within a scope the type system permits). - Deployment — the compiled artifact emits a machine-readable capability manifest (today: effect-row overflow detection on exported functions; the full manifest payload — effect row per exported function, work-package range, compiler version, configuration content hash, dependency versions — is roadmap, not yet shipped) describing what every exported function can do, so a deployment manifest auditor (or another piece of software) can verify the binary against the declared shape without re-running the compiler. The mechanism exists; the content is filling in.
The AI-Repair-Loop spoke (machine-readable diagnostics)
Section titled “The AI-Repair-Loop spoke (machine-readable diagnostics)”Compiler output as a protocol, not prose. Every error code carries a stable identifier (E####), a structured message format (expected X, found Y at location), and an explicit work-package reference for further reading. The error-code registry is normative — every E/W code follows the same shape.
E2020: XSS marker '<script' detected in render output — expected sanitized output (use `safe_html` or `@sanitizer`-annotated function), found unsanitized string interpolation at templates/profile.arcana:42:18. See WP-34 §7.1.9.The intent: turn an AI generator’s “the compiler rejected my code” loop from parse the prose, guess at the fix into read the structured payload, apply the named pattern. The format flag (machine-readable JSON output) ships today. The full agent-grade payload — suggested-fix-as-diff, confidence levels, causal-chain linking between related diagnostics — is a roadmap layer, not yet shipped.
This spoke is what makes Arcana navigable by AI agents rather than just compilable.
Where this pillar stops (honest hedges)
Section titled “Where this pillar stops (honest hedges)”- Capability manifest (
D286): overflow-detection mechanism shipped; full manifest content is partial. Don’t read “machine-readable capability manifest” as “all manifest fields populated today.” - Structured diagnostics (
D284): format and error-code registry shipped; agent-grade fix-as-diff + confidence + causal chains land in a later release. @hermeticannotation (D285, as amended by D285a): checker-enforced today — functions annotated@hermeticARE rejected by the compiler if their effect row includes any of the denied effects{Network, FileSystem, Database, Process}. Lowering- and emission-level determinism are deferred; this is checker-enforcement of a contract, not a codegen-level determinism guarantee.- Effect intersection / policy (
D219): the general[[effect_policy]]mechanism for SDK-declared intersection rules is approved for a later release; not shipped.
See Honest Scope for the canonical per-mechanism status table.
What this pillar gives every other pillar
Section titled “What this pillar gives every other pillar”- Compile-Time Safety is the mechanism; this pillar is the governance and cross-stage propagation of that mechanism. Read together they describe the full effect-system story.
- Batteries-Included depends on the admission-controlled vocabulary — the first-class capabilities
{Email}/{SMS}/{CRM}/{Network}/{ObjectStore}/{Monitor}are governed effects, not arbitrary library calls. - Governance & Honest Scope uses the same governance machinery to admission-control the marketing claims. The discipline is shared.