54 KiB
Compiler Contracts
1. Scope / Trigger
Applies to AST/HIR contract metadata, typed LLVM/resource/coroutine lowering, private fields, range/failure/effect analysis, structural warnings and public API baseline enforcement. Keep clause-only control flow and ordinary value semantics. Official sources receive the same hard checks; no blanket recovery annotation or bundled exception.
2. Signatures
-
llvm::emit_executable[_with_resources]andemit_test_executablewrap the existing callable roots in Cmain. Process startup owns SIGPIPE initialization; callable roots preserve host policy. Success/failure paths release outputs, typed faults, rendered Text and diagnostic Buffer, then flush the existing logger. Test main validates one decimal index and uses the same index for execution and all fault/output owners. Private CLI defaults to these entries and never invokes a host compiler or Rust fallback. -
llvm::emit_kernel(&Program, &SourceMap, entry) -> Result<String, String>lowers typed ordinary function kernels and inferred-suspending coroutines, not the default application backend. It consumes only checked HIR and existing specialization/Domain metadata; no Rust source, generic Value or interpreter dispatch is emitted. Keep direct typed arguments, explicit output/fault pointers, clause projections, value-copy mutation, static handlers, source evaluation order, short-circuiting and checked numeric semantics. Fault origin and each caller reference the emitted source-span table; frame capacity is reachable specialization count plus one, so acyclic calls never truncate a trace. Collect nominal types from nested reachable expressions as well as locals/signatures. Validate and collect every reachablespecialize::failurestype and its recursive owned fields, including Port-declared errors unused in implementation bodies: fault layout/release still references them. Reject unsupported reachable types/effects/application roots at their source location before returning IR; never silently substitute a value or fallback backend. -
llvm::emit_application(&Program, &SourceMap) -> Result<String, String>emits callable compiler-owned CMD, HTTP/REST and Job roots.dever_application_entry(Unit*, fault*) -> i32uses existing output/fault release exports. CMD reads a qualified name and one JSON object, decodes checked inputs, invokes App/selected Dever or external Adapter and prints the existing success envelope; a mixed HTTP/CMD application must not bind HTTP when executing CMD. HTTP/REST uses static route/auth/permission descriptors and concrete callbacks, reusing the existing API, JWT/business verify, site, tenant, RBAC, Upload and log owners. No dynamic Value enters business code. Model/SQL/Related/migration/Seed/DbError, Job resources and hidden transactions share one invocation-owned application Session.emit_application_with_resourcesadditionally consumes the packager's verifiedEmbeddedResourcetable; private CLI adds an executable process entry; managed Linux compilation rechecks portable sources in a trusted daemon worker. Formal target packs remain unfinished. -
LLVM external lowering reuses checked Port names, declared failures and wire field codecs. Decode selected Setting before starting a Worker. Named result/error objects require every top-level field, including nullable fields; unknown/missing fields, invalid types and undeclared error identities remain source-located runtime faults. Move fully decoded outputs or exact nominal Choice payloads into their owner once. JSON exists only at the process boundary. Embed immutable bytes and metadata with the native backend's shared digest/dedupe helpers. Production resources/startup never enter a fake-only Test graph.
-
llvm::emit_test_suite(&Program, &SourceMap) -> Result<String, String>emits one module/executable with stable case indices from case-local checkedtest_programmetadata. It exportsdever_test_count,dever_test_entry,dever_test_fault_size,dever_test_fault_release,dever_test_fault_renderanddever_test_text_release. Allocate the selected fault size with eight-byte alignment; render/release with the same index. Cases retain their own effects, fakes, faults, private symbols, database and virtual clock. Only declared internal LLVM symbol/type tokens are qualified; never rewrite strings, comments or shared ABI declarations. Production routes/auth are removed and unreachable Jobs pruned before lowering; reachable Job payloads still use the shared typed wire contract. No deployment config, real Lib or service startup is allowed in ordinary tests. -
LLVM application Dever Port dispatch reuses checked production Adapter candidates and
Settingsselection/validation. Decode only the selected typed Setting; a single unconfigured Adapter without Model needs no settings file. Concrete selection/Setting/database binding slots are module-private. A nonblocking atomic entry gate rejects overlapping/reentrant roots that own Port, database, application or clock slots. The root Scope drains before same-runtime Session close, selected Setting drop, slot reset and gate release, including partial initialization and faults. Child Tasks read immutable selected slots but detach transaction context; they neither reload config nor own independent application roots. Writing CMD begins after input decode and commits only after output encoding, before stdout. Nested/sequential calls share one transaction without savepoints; cancelled unconfirmed operations discard the connection. Database ABI/storage/error contracts and live acceptance are owned bydatabase-guidelines.md§9, not a second ORM implementation. -
LLVM inferred-suspending functions are
ptr @f(...typed inputs, ptr out, ptr fault, ptr state) presplitcoroutine; synchronous functions remaini32 @f(...typed inputs, ptr out, ptr fault). Both share clause/binding/statement emission, TypeOwner guards and specialized typed invocation. Coroutine/runtime descriptors and fixed ABI signatures live intoolchain-and-library.mdand the canonical C header. -
Application source identity is
module/<component>/<domain>/<role>.dever[.md]or a cohesive role topic file; role is app/domain/model/port/adapter/api/job. Generated API/CMD/Job roots replace applicationmain.dever. Model/API root files may coexist with topic directories; other roles keep root/directory exclusivity and non-API topics are flat. Reject generic common/shared/utils/helper/base/service buckets. Application source has no package/exposes/import declarations;publicis limited to an individual HTTP declaration. -
App functions use logical
<component>.<domain>.<function>names; role/topic never enter the call. Main calls App; API calls its own App; App calls App or same-domain Domain/Port; Domain calls same-domain Domain; Adapter calls only same-file helpers and standard capabilities. Model operations remain owned by their domain App. API handlers and qualified Adapter/fake implementations are not source-callable. -
Port operations are one bodyless ordinary signature with typed value inputs, unbounded outputs and required
fails app.ErrorChoice(or public standard error choice). The choice contains an explicit error variant and belongs to the same-domain public App contract. Port/Adapter may reference the App types used by this contract, never call App. Each production Adapter completely implements one Port identity; a test file can fake multiple Ports. Input names/types and ordered output names/types agree exactly. Every implementation failure set is a subset of the declaration. -
An external Adapter is
external <exec|pip|npm|go> "relative/entry" { ... }in an Adapter-role file. Body clauses are newline-separatedlib "name@version"andallow <capability>;libderives its ecosystem from the declaration, while exec uses explicit ecosystem-prefixed Lib specs. It may coexist with onesettingrecord, but not with Dever functions. The compiler synthesizes every operation of the domain's single Port identity; App code still calls the Port and never receives Worker, process or JSON values.ExternalWorkerContract::sdk_manifest()exposes the same checked setting/input/output/error wire DAG and fixed identity for SDK generation, never a separately maintained type registry. -
App parameter, output and inferred failure types are public contract. Reject an App capability that leaks a private Domain/Adapter type; define externally visible business error choices in App and let same-domain private roles refer to them through
app.<Type>. -
Fields:
private name: Typefor records and Models; ordinary record privacy is package-owned, Model privacy belongs only to the owning domain App.name: Int >= low and <= high(also Decimal) applies to record/payload/output/handler fields. -
Choice:
error Failed(message: Text); markers are explicit, never inferred from variant names. -
fail(Error.Variant(...))terminates a clause; ordinary calls propagate inferred errors.result(named_call(...))requires a choice with one success variant matching the call outputs and an exact recoverable error set. -
Functions:
name(inputs) (outputs) pure recover("reason"); modifiers optional, identical across all clauses of one signature. Source has noasyncmodifier orawait(...)form. -
Transaction functions use
transaction name(inputs) (outputs)and infer a single physical database effect through their complete call graph; source never receives a transaction handle. Sequentialblockingis allowed only through its existing synchronous/no-database/no-concurrency contract; detached, parallel, stream and channel work remain forbidden. -
Model files synthesize opaque
model.id, generatedid/created_at, a record Page type and static short CRUD symbols. Anonymous Model blocks are contextual syntax, not general Map values. -
Program::api_snapshot() -> String,check_api(&str) -> Result<(), String>,application_errors() -> Result<Vec<Diagnostic>, String>,application_warnings(entry) -> Result<Vec<Diagnostic>, String>. -
Application tests use
test/<component>/<domain>/<topic>.dever[.md]; the filename selects the one ordinary zero-input, zero-output<topic>() ()entry. Test helpers/types remain private to that file. Tests call same-domain App/Domain and cross-domain App only; they cannot call Model operations, Port, Adapter, API or another test, and production cannot call tests. -
Test assertions are compiler-owned
assert(Bool)andassert_eq(actual, expected). Equality requires the same comparable type; onlynull/empty expressions that already require context receive the left type, so numeric promotion does not make unequal source types valid. Business failures continue throughresult(call)and explicit recovery. -
CLI:
check <root>,test <root>,run <root> [--tenant <id>] [-- <cmd> <json>],build <root> --output <new-file>,tenant migrate <root> <id>,tenant owner <root> <id> <site> <user-id>andtenant component enable|disable <root> <id> <component>. Run/build collect checked API/CMD/Job declarations into one generated entry and reject applicationmain.dever. Test checksmodule/ + test/before running stable-sorted cases; check/run/build load only module/. Deployment and database settings come only fromconfig/setting.json. -
CLI check and application compilation share
Program::application_errors()before resource preparation: C016 rejects unreachable App/Domain functions and recognized trivial private forwarders or Model CRUD wrappers, not every wrapper shape. Within production-reachable App/Domain, it also rejects same-owner private implementations with identical full contracts/bodies and empty transitive effects, and repeated pure calls with unchanged inputs whose previous result remains available. Reuse the W003 structural key and W004 version/result proof rather than interpreting warning text. Do not promote effectful W003 matches: the structural key does not encode every Model query property. Keep different owners/contracts, mutations, Adapter and bundled code outside these two hard rules. Check remains static and offline, with no Worker preparation, runtime pack, native compilation, service or database execution. Test retains its case-local roots and Port fakes without applying production application errors; core library checking still permits exports whose consumers are unknown. -
Module API files contain declarations such as
get profile = app.profile,post publish = app.publish,cmd bootstrap = app.bootstrapandrest model; they do not contain handler function bodies. HTTP routes inherit the App signature and return the fixed envelope.publicis valid only on one HTTP declaration. Recursiveapi/<site-path>/<topic>.deversupplies configured site ownership without sourcesitestatements. -
Authentication providers, sites, external HTTP origins, Cookie names/lifetimes and tenant routing come only from
config/setting.json. Verify is one read-only App function fromClaimsto an App-owned record with exactlyid: Text,user_id: ModelId?, andtenant_id: ModelId?; it cannot return permissions. A protected site's generated entry verifies its configured provider, enters trusted tenant scope, checks every reachable tenant component and authorizes the exact permission before reading business input or dispatching App. Apublicdeclaration ignores an ambient browser Cookie, but an explicitly supplied invalidAuthorizationcredential remains an authentication error. -
Trusted
auth.user_id()/tenant_id()keep their defaultInt?result. An explicit nullable ModelId context selects the same identity intrinsic with that nominal type; absence remains nullable and arbitrary Int casts remain forbidden. Configured validation walks every protected API's reachable functions and each generated REST field binding, matching the selected ID against its actual verify identity field;owns_user(ModelId)follows the same user-ID rule. Source-only checking defers provider matching, never configured builds. Native wraps the existing nullable i64; LLVM retains its nullable ModelId ABI. Public/CMD/Job/Test capability rules still apply. Ordinary tests must reject reachable identity effects instead of synthesizing a trusted user.
3. Contracts
The current LLVM kernel accepts ordinary checked functions with supported value types, including Decimal, Text/Id, Bytes standard operations, List/Map and nested Record/Choice/Nullable, File/Stream, Task/Group/Channel, AsyncStream, TCP Socket/Listener and HTTP/TLS/WebSocket resources. Time/calendar, process arguments, stdout/logging, Uuid and Secret/crypto use the same typed runtime bridge. List/Bytes each/filter/find/reduce/reduce_until/sum and Stream/AsyncStream traversal use static typed handlers, including the existing checked suspending-handler contracts, never a generic Value interpreter. dever_entry(ptr out, ptr fault) -> i32 initializes both slots, returns 0 on success and 1 on checked runtime or business failure; outputs are read only after success. Fault is {i32 code, i32 origin, i32 depth, [capacity x i32] caller_locations, {ptr, i64} message, i32 business_type, i32 business_variant, [words x i64] business_payload} with separate source-span metadata. Keep fields 0..4 stable; the aligned payload holds the complete concrete Choice and is sized for the largest reachable error type. Named fault codes (overflow=1, division-by-zero=2, RuntimeAbi=3, Business=4) are not the runtime C ABI status. RuntimeAbi retains original owned diagnostic bytes; Business retains nominal identity (type_id+1, 0 means absent), variant and typed payload. Callers release root outputs and both fault payloads through dever_outputs_release and dever_fault_release, including zero-initialized outputs after failure. Application entries and unsupported application intrinsics remain source-located rejections.
File create uses create_new and never truncates an existing path; clone/close preserve shared owner semantics. File chunks yield a shared synchronous Stream cursor, with one terminal Failed before End. Source traversal uses only its existing each/reduce/reduce_until contracts; stream_pull is internal ABI, not a new source pull/first(Stream). Preserve aliases and unvisited rows on early stop, and release resources on both typed business and runtime faults.
AsyncStream constructors use List/Bytes/Channel/ticks or the existing TCP producer; aliases share progress and closure. Register its consumption-close guard only after source, initial state and context expressions finish evaluating. Early stop, normal return, fault and cancellation close the shared producer; unlike synchronous Stream, another alias cannot continue. Release pending operations before closing the producer. Terminal ReadEvent/ConnectResult Failed remains one actual typed row before End. TCP operations reuse runtime net deadlines, direction locks and partial-write cancellation rather than blocking wrappers. Map async statuses explicitly before decoding standard resource choices.
HTTP values cross the ABI as fixed named fields plus opaque resource handles; clone/register every owned field before fallible header conversion. Static sync/suspending handlers and optional context share the existing coroutine descriptors; borrowed request/context inputs become owned before initial suspend. Handler faults retain typed ownership until terminal request-boundary rendering, log and produce 500/abort as the existing runtime requires, then permit later requests. Do not turn a handler fault into a server-wide fault or serialize intermediate values through JSON. Uuid is an actual UUID owner, not Text; Secret stays non-observable. Password operations preserve checked blocking boundaries. Reachable Log/HTTP-server roots flush after scope drain on success and failure; pure kernels do not initialize a logger.
Timeout consumes a Task and uses an independent presence flag with the full output row: successful null and zero-output success are not timeouts. Only an actual timeout invokes its statically specialized fallback after runtime cleanup; numeric, business and RuntimeAbi faults propagate with their original kind and spans. Race uses canonical output descriptors shared by same checked signatures, consumes tasks only after non-null operation creation and drains all losers on every completion path. ParallelEach uses the existing scoped concurrent, bounded blocking and async stream owners for each checked sequence/handler combination; a plain Group loop is not equivalent to capacity-before-pull and failure observation while a producer is idle.
Coroutines clone borrowed inputs before initial suspend; all live guards, operation owners, values, output slots and typed faults survive real Pending. Initial/pending destroy runs reverse cleanup once; normal completion runs cleanup then complete/final suspend, and final destroy frees only the frame. Generated wrappers reuse the existing single task Scope/supervisor and bounded blocking pool, never per-function block_on. Validate cross-thread Send before returning IR against checked inputs/outputs, inferred error-variant fields and all reachable suspending frames including expression temporaries. Task/Group affine locals are frame-safe, not source-transferable. Non-suspending blocking functions may create/drop a Stream locally without transferring it. Internal Unit/Outputs ABI rows derive transferability field-wise (Unit=true); never copy their source Type::transferable=false property or change the language property to fix ABI metadata.
LLVM fail transfers the concrete Choice into the business tail and disarms its temporary owner; normal propagation appends the call's source frame. result(named_call) shares ordinary invocation and uses only specialize::failures plus capture::targets, including handler specialization. Success packs zero/one/multiple ordered outputs into the checked success variant. A matching business failure transfers directly or wraps one error-only Choice according to that mapping, then clears the entire fault; explicitly raised outer variants must not be unwrapped. Numeric and RuntimeAbi faults remain uncaptured and propagate with their original origin and caller frames. Root fault release statically dispatches nominal error types through the existing typed drop owner, including nonzero variants. Do not add runtime generic Value, parser-based error matching or a parallel failure registry.
BytesToText/BytesFromInts/BytesSlice use the existing runtime handle ABI: status 0 transfers a success value; only status 1 creates the standard Failed(Text) from the original diagnostic Buffer, freeing that Buffer after Text construction; status 2 stays RuntimeAbi. Standard Bytes wrappers then use the same fail/capture channel, not a separate error-return shortcut. Never inspect a success output on a failing status.
LLVM ordinary function inputs are borrowed; clause bindings, locals and temporaries own typed copies. Track ownership with entry-initialized guards, recursively retain/drop only present Nullable payloads and active Choice variants, and release on normal and fault exits. Success transfers outputs and disarms the corresponding guards. Reuse native last-use/field-update analyses rather than duplicating them; a final field move clears that field while preserving its containing record's owner. An ABI _take consumes its receiver even on failure, so disarm before calling it. First/Get allocate output storage for the actual List element or Map value type, not just the inner type of the nullable result. The ABI's outer presence flag only determines whether this row may be read: an already-nullable row is transferred intact, not wrapped again or overwritten with Some.
Reuse clause interval normalization and facts/domain containment at every constrained construction, write, output and handler boundary. Concrete handlers may establish outputs by inference; forwarded signatures require input contravariance and output covariance. Unknown operations establish no new bounds.
Facts preserve value snapshots and invalidate the modified path. Use shared immutable field graphs and bounded proof work, not recursive copying of a type/value DAG. contracts::MAX_PROOF_WORK is 16,384; exceeding proof work reports C015 and never grants a guarantee. Before analysis, nominal type depths are computed iteratively and must not exceed the shared 128-level syntax depth limit. Failure-free nominal type graphs are memoized and skipped by failure expansion.
Failure origins survive aliases, aggregates and projections. An unknown List may be empty and Nullable may be null, so possible error payloads do not establish guaranteed failure. A short-circuited handler or empty traversal cannot consume a pre-existing obligation. Empty reduce returns the original state's obligation unchanged. Replacing a Map entry cannot retain the replaced failure's identity in the new Map. Partial selection is conservative about the unselected remainder.
A capture error variant may contain one error-only choice payload, e.g. error Database(error: dever.database.Error). It wraps that choice's inferred failures without renaming them or parsing messages. Explicitly raised outer variants retain their nominal identity. Success shapes, complete error sets and non-overlapping wrappers are checked before emission; captured failures still carry the ordinary handling obligation. Native, LLVM and reference execution share the same capture mapping, including specialized handler error sets.
Effects and effective recovery reasons propagate through the existing call/handler substitution flow. An unused handler argument adds no effective recovery. Recovery is not an external effect and is allowed in pure functions, but its reason belongs in reachable public API summaries even when declared in a private helper. Keep private helper names and private record representation out of snapshots.
Port remains a Function ID with compiler-owned successors. Shared dependencies, effect worklists and specialization include every production implementation; failure inference seeds the declared error set, independent of selection. Resolve the complete signature type graph before type-shape access checks, including App DTOs nested in Port-local DTOs; unrelated App types remain inaccessible to Port/Adapter. Unmediated file/network I/O propagates through functions and static handlers and is cleared only at the Port boundary. App/Domain reject it; only the compiler-generated application root may start API/Job service loops. Other effects retain existing policy. Production summaries exclude Test bodies. Checking and suite emission reuse one case-specific closed graph with that case's fakes, including failure-subset checks for unused fake operations and declaration checks for uninstantiated handler helpers. Each case gets an independent native module and sync/async entry; one rustc invocation still produces one suite binary. Never union different cases' fake effects or run a synchronous case under another case's async runtime. Production settings and fallback implementations are absent from the reachable suite.
An Adapter-role external declaration synthesizes exactly one complete implementation of the domain's single Port identity. Its schema hash is derived deterministically from the optional setting wire schema and every operation's ordered input/output wire shape, including top-level field names and declared business error payload fields. The synthetic functions enter the existing dependency, effect, failure and specialization graphs; do not add a parallel external-call registry. Only fixed network, file, process and gpu capabilities are accepted, and they seed conservative effects. An external declaration may coexist only with one setting record and never with Dever implementation/helper functions. Test graphs replace production implementations with case-local fakes and therefore never start an external Worker. Ecological declarations do not weaken these checks or imply their target packager is implemented.
Database effects carry a typed DatabaseOwner::Model or DatabaseOwner::Job, resolved centrally by Program to connection plus global/tenant scope. A transaction must reach at least one database operation (including enqueue), may resolve to only one physical database and cannot mix global/tenant scopes. It cannot start detached, parallel, streaming or channel work; a validated sequential BlockingCall does not escape the transaction. Ordinary database helpers accept a generated hidden transaction context so nested transaction calls and enqueue reuse the outer physical transaction. Never synthesize a Model to represent a queue.
Job declares an explicit database and a private job name(payload?) () retry(n) timeout(ms) entry. One input must be a same-domain App record; no outputs, overloading, multiple clauses, pure/recover/fails or direct non-App calls. App enqueue uses a checked static same-domain target and lowers to a dedicated HIR node. Enqueue propagates only its queue connection/failures, not handler effects, failure or synchronous recursion. Native execution reachability adds handlers as independent roots; application test closures apply the case's Port fakes to those roots too. UTC cron checking and runtime scheduling share one bounded parser.
Every Job enqueue requires a compiler/runtime-established execution identity. Generated CMD, cron and Test roots establish System; a protected API establishes User only after provider verification, component checks and automatic authorization. Missing identity never falls back to System, and a public API call graph that can enqueue a Job is rejected. User enqueue persists a re-verifiable provider/site/subject/session/tenant reference plus the one exact permission key of its HTTP entry; it never persists credentials, roles or a permission collection. Every attempt invokes verify again, validates the restored tenant, confirms the key still belongs to the current compiled permission catalog, checks reachable component state and performs the current role query in that order before opening the business transaction. Chained enqueue inherits the restored identity and permission key.
Protected custom API permissions are component.domain.site.action; REST reserves read/create/replace/delete. The HTTP method is catalog metadata, not part of the key. Two declarations cannot own the same key even if their method or URL differs. public is the only anonymous form and emits no permission; its complete reachable graph cannot touch a tenant component. The service atomically synchronizes compiled permissions into the global control catalog and marks removed rows inactive. Site and tenant are hidden context for role management; source never writes auth.require, an access clause or a permission list in Identity.
Suspension is an internal monotone effect inferred from async runtime intrinsics, ordinary calls, bound static handlers and collection handlers. HIR records suspends; API snapshots do not expose it. Direct source calls preserve sequential completion, while run is the explicit concurrency boundary and wait consumes Task/Group values. A fully non-suspending entry emits no Tokio runtime.
Facts, effects and failures share contracts/dependencies.rs for function/static-handler dependencies and initial order. Effects/failures enqueue reverse callers only when a summary changes; conservative dependency cycles still converge without discarding obligations. Type comparison/move/transfer properties are computed once per nominal definition after type-cycle validation, avoiding repeated expansion of shared type graphs.
Domain dependency edges come only from resolved type, function and handler references. Physical role files in one domain share one dependency boundary; cross-domain cycles remain invalid and function recursion remains independently invalid. Source code does not duplicate edges in a header, and dependency inference does not install or download packages.
API snapshots sort semantic names and contracts, not source paths/IDs. A baseline is optional, explicit and create-new; checks never update it. Protect its edits outside the language. Program retains all warnings. CLI suppresses bundled-source suggestions and W003/W004/W005 already represented by a C016 with the same primary and nonempty ordered related spans. Different evidence or warning codes remain visible, as do bundled hard errors. Baseline failure takes precedence and retains original warnings; API/Test do not apply production-error suppression. Entry-specific export advice must not infer unknown library consumers.
Test authority comes from compiler-assigned source origin, never a user-controlled path string. A checked TestCase holds the private function ID and database-effect metadata; native compilation accepts only that checked identity and does not relax normal entry visibility. Each case runs serially in its own native process and temporary project. Successful child output stays captured; failed stdout/stderr is reported in labelled sections, later tests continue, and any failed case makes the command fail. Tests cannot reach dever.api.serve().
For module/<component>/<domain>/api.dever, the route is /<component>/<domain>/<action>; recursive api/<scopes>/<file>.dever inserts scopes and file before action. get/post/put/delete bind same-domain App functions and inherit their wire-safe input/output shapes; GET/DELETE read query, POST/PUT read a unique-key JSON object. rest generates Model CRUD and can use checked owner/create/replace/search field bindings. Each successful request receives JSON {code:0,message:"ok",data:<value>} with HTTP 200; standard API errors map to fixed 400/401/403/404/409/429 envelopes and unknown failures become a redacted 500. A top-level POST Upload switches the statically known route to bounded multipart parsing and affine ownership. No environment-variable config or implicit database fallback is introduced.
Response Header/Cookie mutations are staged in request-local pending metadata. Generated dispatch serializes the response value, commits the database transaction, and only then promotes pending metadata for the server response; serialization, business, commit or rollback failure discards it. Cookie issue/clear uses the configured name, lifetime and attributes. Credential-changing requests require Origin and Host to exactly match the site's configured external HTTP/HTTPS scheme, host and effective port; a missing or cross-origin value is rejected without trusting forwarding headers. A write API call graph containing password verification or hashing does not receive an entry-wide transaction. Every reachable write must instead cross an explicit short transaction function, and password crypto is forbidden inside that transaction. Other write entries retain their generated transaction.
4. Validation & Error Matrix
wire.rs is the sole Type-to-wire eligibility owner; API checking and native/wire.rs consume its interned DAG. Policy (Output, ApiInput, SettingInput, Job) participates in the versioned fingerprint and specialization cache. Records reject private or bounded fields until concrete bound validation exists; Choice, Map, Related and resources are rejected. ModelId encodes as i64 while retaining nominal Model name in the fingerprint, never unstable compiler IDs. Secret is decode-only for ApiInput/SettingInput. Program::wire_schema exposes checked nominal schemas; no consumer may add a parallel Type allow-list. Concrete helpers retain field order and map missing nullable fields to None, while unknown/missing required fields fail. Persisted Model fingerprints never include wire schemas.
Sensitivity belongs to the cached type graph in types.rs: Secret and private Model data propagate through nominal records/choices and every container, including Related association cycles via a monotone reverse-edge worklist. Ordinary record private fields retain their existing package access contract. App inputs reject private Models; App/entry outputs and error payloads reject both sensitive categories. API JSON and assertion rendering reuse the same observable property. Generate Render only for observable nominal types; Debug for runtime Secret is always redacted. Test-only secret(Text) is resolved from compiler-assigned source origin and reserved against user declarations.
| Condition | Result |
|---|---|
| Reachable LLVM kernel type/effect/application root is not implemented | Source-located Err before IR is returned; no Rust fallback or successful stub |
| Dynamic LLVM Int add/sub/mul/neg overflow or div/rem invalid operation | Entry status 1 with original source-span index and every caller frame; never unchecked poison/trap arithmetic |
| Runtime value error during a managed LLVM call other than a recoverable Bytes operation | RuntimeAbi fault with the original diagnostic Buffer and source/caller spans; clean all guards and release message through the caller boundary |
| Explicit business fail or its ordinary-call propagation | Business fault with concrete nominal type/variant/payload and original source/caller spans; release through the caller boundary unless captured |
| Result matches a declared business failure | Transfer direct/wrapped typed payload and clear fault before any following call; do not swallow numeric/RuntimeAbi faults |
| Bytes conversion/range value error; invalid ABI | Value error becomes the standard Failed(Text); invalid ABI remains an uncaptured RuntimeAbi fault |
| File I/O value error; negative time/task sleep | Standard original Failed(Text); only the operation's recoverable status is captured |
| Pending, optional receive End, or Channel element null | Pending initializes no row/fault; receive reads a row only when present; preserve the element's full Nullable state |
| Async initial/pending/final destroy | Drop live guards/operation owners once at initial/pending; final destroy frees frame only after normal cleanup |
| Non-Send task/blocking frame or inferred failure payload | Source-located lowering Err before IR; no unsafe Send shortcut or erased fault |
| First/Get has no row, or finds a row whose value is null | No row: return zero Nullable without reading untouched output; nullable row: preserve its own null flag and full concrete layout |
| Invalid role layout, generic bucket, file/directory conflict or one-file role directory | C003 |
package/exposes/public application syntax or forbidden role call |
P001 / C006 |
| App signature or propagated failure exposes a private type | C006 |
| Duplicate API method/path | C002 |
| API non-prefixed/unsupported input or output | C005 |
| API missing/duplicate/extra or malformed request inputs | JSON 400, code=400 |
| Unknown route / unsupported method on known route / handler failure | JSON 404 / 405 (Allow header) / 500 |
| Unproved record/payload/write/output/handler bound | C011 |
| Discarded, overwritten or merely logged failure | C012 |
| Capture error set mismatch or overlapping nested error wrappers | C012 |
| Effect in pure function or inconsistent clause contract | C013 |
| Non-transferable value live across an inferred suspension point | C005 |
| Blocking or parallel effect executed inline on a suspending path, including a concretely bound handler | C005 |
| Invalid Model or transaction database contract | C014 |
| Contract analysis exceeds bounded work | C015, no executable Program |
| Proven redundant check / duplicate private implementation / repeated pure call / trivial private forwarding | W002 / W003 / W004 / W005 |
| Production App/Domain orphan, recognized forwarding/CRUD wrapper, same-owner identical private effect-free implementation or proven reusable pure call | C016 before resource preparation; libraries/Test retain warnings |
| Unused or overwritten write | Existing W001, no duplicate W006 |
| Unneeded exposure for a selected application | W007, not a hard error |
| API drift or unreadable baseline | CLI failure before native compilation |
| Existing snapshot output | CLI failure, existing bytes preserved |
Invalid test path, missing/overloaded/non-ordinary entry or duplicate .dever/.dever.md identity |
C002/C003/C005 before any test runs |
| Test crosses a private role, calls Model/API/another test, or production calls a test | C006 before native compilation |
assert receives non-Bool or assert_eq receives unequal/non-comparable types |
C005 at the assertion |
| Test assertion, uncaptured business error or runtime fault | Current case fails; later cases run; final status is nonzero |
external outside Adapter, mixed with a Dever function, or unable to select exactly one domain Port identity |
P001/C005 before native generation |
External entry is absolute, escapes with ./.., contains empty/Windows-only segments, or names an unknown/duplicate capability |
C002/C005 before native generation |
| External input/output/error payload is not eligible for the shared wire policy | C005 before native generation |
public API can reach Job enqueue, or enqueue has no trusted execution identity |
C006 / runtime rejection before persistence; never synthesize System |
public API reaches a tenant component |
C014 before native generation |
public API reaches authorization administration, or GET reaches role mutation |
C006 / C013 before native generation |
Duplicate component.domain.site.action across methods or paths |
C002 before native generation |
| Protected API has no current role grant | JSON 403 before business input/App dispatch |
| User Job provider/site/reference, compiled permission, component or current role fails | Block with a redacted identity/component category; do not enter the business transaction |
| Credential-changing request has missing or non-matching Origin | JSON authentication error; no Cookie/Header is committed |
| Response serialization, business transaction or commit fails after metadata was staged | Discard staged response metadata |
| Password crypto API reaches a write outside an explicit transaction, or a transaction reaches password crypto | C014 before native generation |
5. Good / Base / Bad Cases
LLVM base: lower checked Int 40+2, emit and link real objects, execute on the native host. Good: a nested nominal value that exists only inside a comparison still declares all required LLVM types; a short-circuited failing RHS never runs; managed aliases survive COW updates and fault cleanup. First/Get/Find on List<Text?> or Map<Text,Text?> preserve null and present values without double wrapping. List/Map Float values containing NaN remain non-reflexive under equality. Resource/async good: a second create_new fails without overwriting distinct content; a large owned multi-output survives Pending; stopping pending tasks drains descendants and releases frames; internal Unit and Outputs rows transfer through typed sync Task/blocking descriptors. Bad: consider IR substring or hand-written coroutine smoke sufficient checked-source evidence, clone parameters only after initial resume, omit temporary nominal/Send types, shrink a nullable row output slot or treat foreign-target object generation as successful execution.
Base: direct Port { value = 8080 } satisfies Int >= 1 and <= 65535; a project without test/ reports zero tests. Good: test/user/account/register.dever calls app.register, asserts returned values and uses result(call) for expected business failures. A protected post publish = app.publish automatically owns news.article.admin.publish; an enqueued User Job stores that one key and rechecks the current catalog and role on every attempt. A login reads credentials and verifies the password outside a transaction, then calls one short transaction that rechecks mutable account/tenant/membership state and creates the session. An external Adapter declares one owned entry and the minimum fixed capability set while its tests replace the production Worker with case-local Port fakes. Bad: call model.create or an API handler from a test, share test helpers across files, expose test entries, configure databases through an environment variable, enqueue from public, put permissions in Identity, write auth.require, copy a token/role/permission snapshot into Job storage, let password work overlap a database transaction, guess that every public POST NotFound means Unauthorized, write response Cookie/Header before commit, or let an external declaration coexist with helper functions.
6. Required Tests
LLVM resource/async changes select llvm_resource_native, llvm_async_native and llvm_async_source plus existing managed/result/kernel regressions. Use explicitly built runtime-only archives, actual checked source -> object -> archive execution and an atomic allocator ledger (one warm-up + 64 repeated calls). Cover create_new's second creation failing within the same run and verify distinct existing content; aliases, EOF/terminal error, early shared cursor stop, each business failure and runtime unwind. Async cases assert real Pending, initial/final destroy, large typed Text/List/Map/record and multi-output transfer, async static handlers, sync Task and Group, bounded backpressure, nullable Channel row/End, wait/stop/nested descendants, typed business failure/capture/refail, division code2 with exact origin and runtime ABI code3 with original bytes. Six-target object generation is not six-OS execution; bounded allocation balance is not RSS/performance acceptance.
AsyncStream/TCP/composition changes additionally select llvm_stream_network_source: nullable rows, Channel backpressure, ticks and alias closure, async/sync handlers and all ParallelEach dispatch categories, owned multi-output/nullable/Unit timeout and race, original business/numeric/runtime faults, TCP short reads/EOF/shared close, exact creation errors and one terminal failure. An owned loopback cancellation fixture observes peer EOF after timeout returns to prove descendant Socket release. Keep the hand-written C smoke's invalid status assertion separate: async invalid input is 4, not typed-fault 2. Repeat actual native allocations through the same atomic ledger; do not claim performance or six-platform execution.
LLVM business/Bytes changes select llvm_lowering plus opt-in llvm_result_native, reusing the runtime-linked runner in test/dever-tests/tests/support/llvm_managed.rs. Assert independent expected success/failure branches (especially zero-output capture), ordered multi-output payloads, direct/wrapped/explicit-outer identity, specialized each/reduce failures, capture-success-recapture, nested owned COW, root ownership transfer and nonzero-variant root release. Root faults must retain exact original source/caller spans. Dynamic division and duplicate Map-key diagnostics must remain uncaptured. Bytes cases cover Unicode, empty buffers, aliases, invalid UTF-8, -1/256 byte values and invalid/reversed ranges with original messages. Repeat native ownership checks through the same bounded archive/allocator fixture as managed tests; no recursive archive build or default database/service checks.
LLVM changes select root llvm_lowering and embedded-bridge llvm_native: real checked sources to IR/object/LLD/native execution, static handlers and aligned nested Record/Choice/Nullable, multiple outputs, short-circuit faulting RHS, checked Int extrema, IEEE Float and original fault/caller spans. Managed changes also select llvm_managed_native with embedded/runtime-abi: Unicode and Decimal, collection COW/order/key types, nullable First/Get/Find, Unit handlers, owned reduce state/early stop, nested field replacement, original runtime diagnostic and failure/root-output cleanup. Its opt-in native runs link the explicitly prepared runtime-only archive, initialize outputs through the real entry and check allocation balance across 64 repetitions after warmup; this is ownership regression evidence, not throughput/RSS/64-or-128-MiB acceptance. Simple kernels link on all six targets; complex/managed aggregates emit on all six but only native host execution is evidence of execution. Windows CRT/stack-probe dependencies require a real target runtime pack, not fixture symbols. Runtime ABI changes select root native_runtime_abi plus the explicitly prepared native_runtime_link C/LLVM acceptance fixture. Prepare only an offline runtime-abi staticlib; author C/Rust tools are not product runtime dependencies or formal release assets. Tests remain under root test/ and run no database or service by default.
Select structured_concurrency, async_native, contract_syntax, contract_facts, contract_semantics, contract_api, contract_redundancy, contract_execution, error_effects according to changes. Assert suspension propagation through ordinary calls and concrete handler substitution, non-transferable liveness, worker boundaries, API omission, alias mutation, handler variance, short-circuit/empty traversal, overwrite/projection obligations, bounded shared graphs and unchanged native results. Error capture tests cover native/reference wrapping, explicit outer identity, ambiguity and discarded captures. Parser tests must reject the removed package-header dependency clause; formatter round trips must prove it cannot be emitted. Do not run the entire suite or service tests by default.
For C016 duplication changes, contract_redundancy must exercise actual production roots, identical private pure implementations and reusable pure calls, unchanged library warnings, and exclusions for effects, input/field/result mutation, owners and output/recovery contracts. CLI llvm_cli must reject both proven cases identically through check/run/build before missing runtime packs, database access or output creation; show each hard error and its evidence once, keep distinct-proof/unrelated warnings, and preserve baseline/API/Test behavior. Statically check maintained CMS plain/Markdown and skill examples with application errors; no native execution or database is required for this gate.
For this source/API contract select source_architecture, source_visibility, contract_execution, markdown_source, api_declarations, rest_model, native_entry, api_routes, auth_runtime, authorization_runtime, secure_contracts, tenant_database, durable_jobs and upload_boundary as needed. Assert App aliases, topic hiding, role call direction, Model ownership, layout rejection, generated roots, strict inputs, JSON envelopes, Markdown parity, site/auth ownership, exact permission keys, duplicate-key rejection, public-to-tenant rejection, REST row scope and Upload cleanup. Authentication coverage includes public Cookie isolation, explicit invalid Authorization, exact Origin, staged metadata ordering, generated System roots, site-scoped multi-role union, Owner isolation and User Job current-role checks. Actual loopback HTTP verification requires an explicitly scoped service check.
Application-test changes select application_testing, formatter and cms_project. Assert stable discovery, plain/Markdown duplicates, filename entry validation, both visibility directions, assertion typing/rendered source locations, existing result-choice recovery, failure continuation/output capture, zero-test success, per-case SQLite Seed isolation, ignored deployment settings, production commands ignoring test sources and module/test formatting preflight.
External Adapter changes select port_adapter, external_component and application_testing. Assert Adapter-only contextual syntax and formatting, setting/top-level wire names in the schema hash, complete Port effect/failure propagation, reference rejection, case-local fakes, strict framed messages and request IDs, business-error decoding, bounded cancel/timeout/crash/restart/shutdown, queued-call admission closure, explicit child reap and native end-to-end dispatch.
external command reuses the external Port boundary but not the Worker protocol. Require exactly one operation with named args: List<Text> and optional second stdin: Bytes?, one named output: dever.process.Output, and fails dever.process.Error; reject setting/lib declarations. The checked Command wire policy alone admits Bytes as strict padded base64; API, Job and protocol Worker policies retain their previous allowed types. HIR Worker contract/entry queries exclude commands, while external_command_contracts() shares their contract construction. Both typed backends use the same external async ABI and Bytes wire bridge. Test plain/Markdown formatting, wrong signatures, fake isolation and six-target object emission separately from actual runtime execution.
7. Wrong vs Correct
LLVM application wrong: emit an unbound auth descriptor, accept a nonpublic route without its exact permission, clone a borrowed handle but return the original SSA value, or give DELETE's encoded null two owners. Correct: validate auth metadata at source and again at the private ABI; return the actual guard-held clone before releasing its source; register one REST response owner through encoding/commit and transfer it once. Channel/Task/Group wrapper clones can change address even though Text Arc retain does not.
LLVM request scopes must receive one boxed compiled-handler Future. Inline embedding the same large Future in every auth/tenant/job task-local branch amplifies debug poll stacks and caused a real nonpublic HTTP SIGSEGV. Keep one request-level indirection with the original scope/cancellation ownership; do not enlarge thread stacks, relax the allocation oracle or box every database operation. Permanent probes are llvm_api_source (private REST including DELETE, concurrent identities, rollback and 64 repeated roots) and llvm_async_source::cloned_channel_fields_survive_their_source_scope.
LLVM wrong: collect types only from signatures/locals or assume every object needs no platform runtime. Correct: visit all reachable nested expressions, verify actual typed IR and native behavior, and distinguish cross-target object/link evidence from formal target runtime and OS execution acceptance.
Managed LLVM wrong: bit-copy an owned handle, overwrite an owned field without dropping it, disarm a whole record when moving one field, or use the nullable result payload as First/Get's physical row slot. Correct: use typed lifecycle callbacks/guards, reuse final-read analyses, transfer only the selected owner, and allocate the full concrete row before interpreting outer presence. Preserve internal null rather than constructing Some(null).
LLVM Result wrong: stringify business payloads, remap errors by variant name/message, catch numeric faults, leave a captured fault live, or accept either success or failure in every test expectation. Correct: share checked capture targets, preserve typed nominal payload and exact source frames, transfer then clear business ownership, propagate non-business faults, and assert the expected branch for each input.
LLVM async wrong: use source Unit/Outputs transferability for internal ABI rows, clone arguments only on first resume, mark Send from parameters alone, drop PreparedSync input inside invoke, or use a RuntimeAbi-string oracle for division. Correct: field-wise ABI metadata, initial-frame ownership, transitive suspend-frame checks including temporaries, runtime-owned synchronous input cleanup, and exact fault-kind/source oracles. Resource tests must make erroneous overwrite observable with different contents and a mutually exclusive result.
LLVM protocol wrong: round-trip source records through JSON, render a sensitive failure variant, make one failed request stop the server, or call all six targets runtime-tested after generating objects. Correct: fixed field ABI, typed resource/handler ownership, checked observable terminal errors, original request-boundary behavior, independent wire peers and explicit host-execution evidence.
Wrong: preserve application package/import/main syntax, accept arbitrary run/build entries, call private roles across domains, make topic filenames part of App calls, turn API declarations into handler functions, trust client tenant/user fields, infer System from an absent identity, put permissions in verify Identity, write manual permission strings, persist a credential/role/permission snapshot, publish pending response metadata, or count a possibly-empty List as proof of returned failure.
Correct: derive one source-role identity from each path, publish only logical App capabilities, keep API declarations and private roles narrow, generate application roots and exact permissions from checked API/CMD/Job contracts, establish System only at compiler-owned roots, and re-verify persisted User references plus the one entry permission on every Job attempt. Preserve conservative HIR facts and require explicit recovery where the program intentionally degrades. Derive Test identity from a compiler-owned source root, retain private checked entries and reuse the normal HIR/native/error pipeline; expose response metadata only after serialization and transaction commit.
External wrong: expose JSON/process handles to App, hand-write a second operation registry, omit setting or top-level wire names from schema identity, or start the production Worker from a Test. External correct: synthesize the complete implementation from one checked Port, reuse shared wire/effect/failure/specialization owners, and bind tests only to case-local Dever fakes.