Sema’s design is recorded as a numbered decision log (the “D-log”) in the
language specification. Each entry states a decision, the evidence behind it, and
the alternatives it rejected. This page summarizes the load-bearing decisions,
grouped by theme. For the full normative record — every entry with citations — see
Decision record; for the motivation
in prose, see Why Sema.
Pythonic indentation, not a Python superset; PEG grammar with soft keywords; editions from v0.1.
LLMs already emit Python fluently, so a Python-shaped surface transfers that prior; a superset would inherit Python’s semantics (which Sema deliberately replaces). Mojo/Codon precedent.
D27
No classes. Methods live in struct/enum bodies; polymorphism is traits + ADTs with laws-as-contracts, header or impl conformance, and coherence rules.
Trait laws make obligations (e.g. reducer associativity) assure-checkable instead of merely asserted; inheritance and structural duck typing are rejected.
D28
Immutable bindings by default, mut to opt in; value semantics for structs/collections.
The trust lattice and contracts sit on the binding model; pervasive shared mutability would let trust labels launder through aliasing. Rust-grade borrow checking was judged too costly for the audience.
D43
Idiomatic ergonomics: lambda/=>, one *args + one **kwargs, ...expr spread, generic [T] params erased at runtime.
Day-one LLM emission needs idiomatic variadics and lambdas; erased generics add expressiveness without a second guarantee regime (contracts + rows stay the guarantee story).
D26
Native dict/set/comprehensions/slicing, homogeneous, one Iterable/Iterator protocol; canonical sorted-order flattening.
Guarantees that LLMs emit dict literals and comprehensions on day one; collections cannot cross an FFI bridge without losing trust labels and policy meet.
The capability discipline that makes the deterministic core provable.
#
Decision
Why
D7
Typed effects-and-handlers spine.policy = capability/effect restriction plus a Cedar-shaped decision layer with compile-verified examples; typed effects, never string matching.
One mechanism covers policy, replay, mock, and batching; every string-based gate is respellable and therefore unsound. Rejected a Turing-complete (Rego-class) policy language.
D11
Trust latticeuntrusted < validated < trusted on all values; generative outputs are born untrusted; endorsement only via contracts, verifiers, or human approval.
Object-capability cleanliness from day one (CaMeL/FIDES lineage). Pure control-flow confinement without value labels was rejected.
D71
Effect-operation calls are checked. Calling an unrecognized op on a known namespace (fs.raed(...)) raises NameError at the call site; effect rows stay open (!{fs.raed} still parses).
Closes the last silent-ignore: a typo’d effect call must fail like any builtin, while capability declarations stay extensible.
D72
Effect namespaces are fully real + configurable — real fs/net (HTTP+HTTPS)/db (embedded SQLite, swappable by DSN or a @provides("db") backend)/env/proc/ui.
”No stubs”: every effect performs its real operation, and the HTTP knobs and SQL server swap via config + providers without touching Rust.
Making model calls first-class, legible, and honest.
#
Decision
Why
D5
simulate def … by <model> — a model implements the body, with sem descriptors, a public cached meaning-IR, contracts, budgets, and untrusted labeling.
Adopts the published, user-studied Meaning-Typed-Programming result; rejects prompt-template DSLs (LMQL died) and LLM-as-VM designs.
D44
Semantic operations are first-party: the ~ sigil family (~=, ~<, ~in, ~+, ~and, ~[query], …) all derive model.invoke, plus a semantic namespace of primitive verbs and a coercion protocol (a type picks its own embed/sem_text).
SymbolicAI proved semantic operators are ergonomic but hid failure behind fuzzy bools; marking the operation keeps model calls legible and forces a complete strict/bitwise/semantic logic story.
D2
~= returns a graded Sim, not a bool. Branching on it requires calibration; regions are typed statistical(α).
Fuzzy-bool casts are the SymbolicAI defect class; a calibrated conformal threshold gives an honest certificate instead of a silent coercion.
D3
semantics() pins a judge in the type — (judge hash, calibration id, α) — evaluated by protocol, never one raw judge.
Hallucination is inevitable and single-judge truth is ill-posed; the judge identity is part of the program’s semantics.
D13
Models are pinned first-class values with roles and calibrations; no floating string refs, ever.
A "latest" string resolved at runtime makes the program’s semantics non-reproducible; the model artifact is pinned like any other dependency.
Contracts in the public signature. Failed values are typed-failed and cannot flow; check (graded, monitored) vs ensure (fatal); Findler–Felleisen blame everywhere.
Enforcement, not advice — advisory contracts (comments/decorators outside the type) are rejected.
D6
Verification is default-on. The opt-in testable keyword is retired; assure bronze/silver/gold grades with a red/amber/green verdict and a mutation-adequacy gate.
Weak suites launder wrong LLM code (EvalPlus); opt-out beats opt-in; property-based testing surfaces ~50× the mutant density of line coverage.
D34
Authored test declarations are native (test "name": block) with ensure/check as the assertion vocabulary and record-replay under pinned seeds; red-verdict counterexamples materialize back into test blocks.
Every mainstream language ships native test entry points; reusing contract clauses keeps one semantics for all expectations. A separate matcher DSL was rejected.
D35
Semantic assertions reuse the contract forms — hard ensure semantics(...), soft check semantics(...) — with no new keyword; assert is a reserved, rejected token with a fix-it to ensure/check.
One assertion semantics for deterministic and semantic predicates; Python’s assert strips under -O and would teach the wrong semantics.
D68
Real static checker + verification engine + constraint solver.sema check catches arity/field/type errors conservatively (zero false positives); sema assure fuzzes properties and mutation-tests at gold; solve: does finite-domain search.
Backs the “statically typed + default-on verification + neurosymbolic” claim with real machinery, not lint.
D15
Monitor-or-decay. A statistical(α) obligation needs an active monitor on its input; without one it decays to best_effortat the type level. The compiler derives shared input monitors where none is declared.
The α certificate is honest only while the deployment distribution matches calibration; the monitor is what guards that assumption.
No unwinding exceptions. Failures are Error-trait values in Result/sums, handled by expect/except, propagated by a trust- and blame-preserving ?; unwrap is a checked abort rejected under assure gold.
Unwinding is invisible to effect rows and hostile to replay and blame; “a failed value cannot flow into non-handling code” needs a defined handling construct.
D31
No colored functions.async/await do not exist; concurrency is structural (scope/spawn/parallel over non-blocking effect handlers).
The runtime is already non-blocking under structured concurrency; a vestigial async token would invite LLMs to emit an unspecified construct.
D32
One with <expr> as x: construct unifies scoped resources, policy scoping, and model rebinding, with deterministic journaled release and no user destructors.
Nondeterministic finalization breaks replay; effect-handler scoping is the mechanism the runtime already uses.
D10 / D14
Self-healing is supervision-scoped and repair-only (supervise/heal, patch-scoped code.patch, a deterministic gauntlet) — not a program-wide mode, and not program growth. Sanctioned growth is descriptor-space regeneration at simulate sites plus human-approved patch-scope widening.
Intrinsic self-modification without external grounded feedback degrades results; a general write capability would break healing’s escalation-proof property.
Split native (bind) vs ported (translate with a differential gate); foreign code uses typed bridge membranes by default (normal .py/.ts/.c files + expose def signatures), with inline begin/end blocks as small trusted glue.
Bind ecosystems, translate only self-contained code; guarantees hold only at typed membranes, which keep native toolchains while adding Sema’s contracts, policy, and re-validation.
D57 / D58 / D59 / D60
Python bridge + native packages.python.call runs real Python behind a persistent warm worker (non-JSON results become object handles); sema add/remove/list wraps uv for PyPI and installs native Sema packages by path/git.
Ecosystem access from day one is table stakes; a warm worker makes real classes/objects first-class Sema values.
D47 / D56 / D61
Real, feature-gated model backends.sema-model = pure-Rust local GGUF inference on candle (Metal/CPU); a real candle BERT embedder; both behind the real-model feature so default builds link no ML stack (mock stays the hermetic default).
The mock needs a credible real counterpart; candle keeps it single-binary and Python-free; feature-gating preserves fast portable builds.
D62 / D63 / D64
Documentation & debugging via reflection.sema doc reflects signatures + docstrings to Markdown; the trace keyword reflects error frames into a self-repair packet; sema repl + sema dap share the real evaluator.
Docs must not drift (reflect them); a stack trace is already the agent’s self-repair context; a separate debug interpreter would drift from the real one.
D49
Opt-in bytecode VM. The tree-walker stays the reference/default; SEMA_VM=1 runs compilable functions on a stack VM with function-granularity fallback and delegated value ops.
Beating CPython needs slot resolution + flat dispatch; partial-but-safe (fallback + delegated semantics) ships incrementally with no divergence.