Skip to content

Semantic Values

This section — the Neurosymbolic Core — is what makes Sema unlike any other language. Models, similarity, contracts, and structured generation are not library calls bolted onto a runtime; they are language constructs with types, effect rows, and verification. Everything starts here, with the idea that a value can mean something to a model as well as compute deterministically.

Every value of a type that implements the Semantic trait carries a lazily computed, cached embedding alongside its exact representation. The exact value is what == and pattern matching see; the embedding is what the graded operators of /neurosymbolic/similarity/ see. They coexist on one value — you never wrap a value in a Symbol object or flip it into a “semantic mode.”

str implements Semantic natively. Sema structs and enums derive it automatically via canonical flattening (below) unless the author explicitly opts out. Enums flatten as their descriptor plus the variant name plus the flattened payload, so categorical values are comparable and monitorable too. Foreign or opaque values (FFI returns) are not Semantic until you write an adapter that gives them a canonical rendering.

struct Article:
sem "A news article ingested from a feed"
title: str sem "Article headline as published by the source"
body: str sem "Full article body text"
source: str sem "Publisher or feed identity"
# a.embedding is lazy, cached, content-hash interned; flatten(a) is the canonical text.

You do not compute a.embedding yourself and you rarely name it. It exists so that a ~= b, a check semantics(...) clause, or a monitor channel has something to compare. The embedding is:

  • Lazy — computed on first use, not at construction.
  • Cached — computed once per value.
  • Content-hash interned — two values that flatten to identical text share one embedding, so repeated literals and de-duplicated data cost nothing extra.

flatten(v) -> str is a deterministic, compiler-generated rendering of a value: its descriptors, field names, and field values, in a stable order. It is the canonical text that gets embedded, and it is recorded in the ABI so that embeddings are comparable across builds — a value that flattens the same way in two builds gets the same embedding under the same judge.

Flattening walks the type: the struct-level sem descriptor comes first, then each field’s descriptor and value; enums render descriptor + variant + payload. Because the rendering is fixed and recorded, flatten is not a debugging convenience — it is the semantic identity of the value.

Because ~= sites are compiler-visible IR operations — not opaque library calls — the optimizer can do things no library can: hoist embeddings out of loops, batch cold misses, and pre-embed string literals into the binary. Embedding computation is also tiered: the default tier is an always-resident static-embedding model (~30 MB, hot-loop viable), and escalation to a heavier transformer embedder is explicit or scheduler-driven. The tier is part of the judge identity (see /neurosymbolic/similarity/) — swap the tier and you have changed the meaning of every comparison that used it.

sem is the descriptor form for human meaning at every useful granularity: field, struct, function, operator, and long out-of-line declaration. Inline field descriptors are first-class syntax, not comments. They feed:

  • canonical flattening (so meaning is part of what gets embedded),
  • generated wire schemas (field guidance for constrained decoding),
  • contract diagnostics and stack traces,
  • policy decisions and monitor channels,
  • self-repair context on a boundary parse.
struct IntakeProfile:
age: int sem "Human age in whole years; accepts numerals or spelled-out English" where 0 <= value <= 130 coerce by parse_age

A field declaration may carry three things beyond its type:

  • sem "..." — the field’s natural-language meaning.
  • where <expr> — a deterministic refinement checked over value after parsing or coercion (here, 0 <= value <= 130).
  • coerce by <fn> — a normalizer that may turn boundary data such as "I am seventeen" into the declared representation before validation runs.

Long descriptors that would clutter a field can be declared out of line:

sem SafetyReport.narrative = "Untrusted medical narrative from trial operations"

Struct-level sem describes the object as a whole. It participates in canonical flattening before the field descriptors, and it is the anchor for holistic check semantics(...) clauses that validate coherence after every field has passed its own deterministic contracts:

struct LocaleProfile:
sem "Locale-routing profile; never a protected-class decision"
display_name: str sem "User supplied display name"
languages: list[str] sem "Languages the user can read"
region_hint: str sem "Non-authoritative region hint for content localization"
check semantics("region_hint is supported by languages and other profile fields",
self, alpha=0.02)

Boundary contracts — the deterministic-generative edge

Section titled “Boundary contracts — the deterministic-generative edge”

Every public data boundary is also a contract boundary. The moment untrusted or model-produced data tries to become a typed Sema value, the field’s descriptor, refinement, and normalizer all become part of the validation context — and part of the blame report if it fails. This is the native join point where aspect-style validation happens, but as typed language semantics instead of decorator convention.

A failed field contract does not throw an untyped exception. It produces a typed ContractViolation that carries:

  • the field path and its sem descriptor,
  • the raw value and the normalized value (if coerce by ran),
  • the blame party (who violated the contract), and
  • the stack trace.

Crucially, the invalid value is still typed as failed and cannot flow onward. In supervised code the runtime may retry or repair the normalizer, but a value that did not pass its boundary contract never silently reaches downstream logic. This is the inverse of the “forward-runs-anyway” behavior of earlier neurosymbolic libraries: in Sema the boundary holds.

Field descriptors are the R2 stage of the decode-and-repair ladder used when a model produces structured output — see /neurosymbolic/schemas/. The same descriptor that documents a field also drives its self-repair.

Some semantics(...) checks — inferring a protected demographic class from a name or a language signal, say — are not harmless validators. The default prelude treats them as policy-sensitive sites: they require an explicit policy grant and may not feed access, pricing, employment, medical, or legal decisions unless the policy and domain law allow it. Sema can express such a check; it will not let one run unexamined. See /governance/policy/.

  • sema check <project> verifies that field refinements, descriptors, and coercers are well formed, and flags any misplaced clause as an unrecognized directive (the silent-no-op guard). A where that references an unknown name, or a coerce by naming a missing normalizer, is a check-time error, not a runtime surprise.
  • sema run <project> enforces boundary contracts at every public edge; a violated field contract surfaces as a typed ContractViolation. Run under SEMA_STRICT=1 to turn recoverable degradations into hard errors while verifying.
  • Because flatten and the ABI record embeddings’ identity, an embedding-model or descriptor change that would alter comparisons shows up as a signature-level change, not a silent behavior drift.