Internal briefing · architecture · rev 4, frozen

Circe: semantic interaction runtime

Circe is the product and the brand; the legacy Circe is prior art archived as circe-legacy, never a dependency. The kernel is clean-room: execution preconditions freeze with every effect and are checked at the mutation boundary, one logical effect per confirmed revision, UNKNOWN outcomes are reconciled but never retried, affirmations answer live obligations, and replay consumes recorded observations.

The non-negotiable

What core owns, and what it never knows

In core

Meaning and durable interaction state. Entity references, observations with authority tokens, ordered retained scopes, referents, semantic events (act + operations), Intent IR with set-valued slot bindings, immutable effects with frozen preconditions, transactions, provenance, the journal, resolver/classifier interfaces, authority and execution contracts.

Never in core

Execution, vendor and frontend reality. No LLM SDKs, no voice endpointing/VAD/turn-timing, no coding projects/worktrees/devices, no Codex/Claude/Cursor/OpenClaw concepts, no domain schemas, no storage or UI. The prior product's name appears only in docs/prior-art/, evals/derived/circe/, phase-4 adapters/circe/.

Dependency direction · structural enforcement first

apps/inspector · evals  →  resolvers/* + adapters/*  →  @circe/core

@circe/core  →  (nothing)

CI walks every import in core and fails on anything non-relative; a deletion test then removes every adapter and resolver. Identifier scanning is secondary — vendor tokens only, not generic vocabulary. Voice adapters emit bounded final events; core never sees milliseconds.

Four kinds of stateOwnerRepresentation
Authoritative worldExternal systemsReachable only via EntityRef + AuthorityAdapter
Observation / viewRuntime (as observations)WorldView, EntitySnapshot, AuthorityToken
DiscourseRuntimeScope, Referent — durable, not replayed from a chat log
Execution / intentRuntimeIntent, Transaction, Effect

Kernel type system

Identity ≠ observation · authority ≠ execution · language ≠ delivery

TypeMeaningKey rule
EntityRefnamespace · type · id · authorityStable identity only — no version
AuthorityToken · ValidationResultVersion data vs validation outcomeSame entity at token 91/92 is one entity
Scope · ReferentAddressable ordered ref set; language rolesExplicit bounded retention; no magical promotion
SemanticEvent · TurnContextact + operations; bounded finalityTwo facets; endpointing stays in the voice adapter
SlotBindingone per slot; ordered, set-valued refs + provenancetargets = [A, B, C] is one value; corrections replace it whole
AuthorityAdapterobserve + validateTruth owner; may differ from the executor
CapabilityExecutorcapabilities + invoke; policy + execution semanticsIdempotency and conditional-apply are declared
Effectfrozen bindings + arguments + preconditionsAt most one logical effect per confirmed revision; UNKNOWN never retried silently
TransactionDRAFT → … → DISPATCHED → terminalCANCELLED pre-dispatch only; compensation is a new intent
InteractionLogEntryinput, observation, event, intent, confirmation, freeze, dispatch, outcomeReplay consumes the log, never live authorities

Acts: social · backchannel · interrupt · query · request · affirm · reject · clarify · fragment · unknown. Operations: reference · correction · slot-fill · commit · cancel · pause · resume. affirm/reject answer whatever obligation is live — a confirmation gate authorizes execution, a clarification just accepts or rejects a proposal, and with no obligation it is only a backchannel.

State machines

Freeze preconditions, dispatch conditionally

Turn

INGEST → INTERPRET → RESOLVE → REDUCE → COMPILE → GATE → VALIDATE → FREEZE → DISPATCH → SETTLE

VALIDATE is a fast path, not the guarantee: preconditions freeze into the effect. DISPATCH passes the idempotency key and preconditions; executors that support atomic conditional apply check them at the mutation boundary. No consequential mutation executes unless its frozen preconditions still hold there.

Transaction

DRAFT → READY → AWAITING_CONFIRMATION → COMMITTED → DISPATCHED → SUCCEEDED / FAILED / STALE / UNKNOWN

UNKNOWN means dispatch left the runtime and no authoritative outcome was observed. It is surfaced, journaled, and never auto-retried; a recorded reconcile() can still resolve it to SUCCEEDED or FAILED. This is the honest contract: at-most-one logical effect, not exactly-once delivery.

New in rev 4Failure it kills
I15 Mutation-boundary preconditions (atomic where supported; risk tiers and POLICY_BLOCKED otherwise)TOCTOU: valid at validate, changed before apply; promises the downstream cannot keep
I16 At most one logical effect per confirmed revision; UNKNOWN resolved only by reconciliationDouble sends, retry storms after a lost response
Reconciliation via optional CapabilityExecutor.reconcile()Confusing "unknown outcome" with "permanently unknowable outcome"
P7 restated: affirmations with corrective operations cannot authorize the mutated revisionP7 and eval 023 disagreeing about "yeah, but not the second one"
I12 social/backchannel are still journaled; they just carry no semantic consequences"Never mutate durable state" contradicting the event log
Scope retention is GC policy with pin rules, not a semantic lifetime"Scopes live for eight turns" style rules

Review gate

24 replayable semantic evals

Declarative YAML: world before, events, expected acts, operations, scopes, bindings, intents, effects and exact adapter calls. Two fake domains — tasks and messages — run on the same referent machinery. Implementation starts by making all 24 fail for real, then turning them green one by one.

001

Social greeting

"hello" → social, zero calls

002

Backchannel

"yeah" → no state change, no calls

003

Interrupt preserves pending

"wait" pauses dispatch, keeps AWAITING

004

Ordered scope

query → one observe, scope = observed order

005

Ordinal reference

"the second one" + ordinal provenance

006

Control binds referent

"stop that" → frozen target, no invoke

007

One logical effect

confirm once; a second "yes" adds nothing

008

Correction retargets

"the one above" revokes the old gate

009

Set exclusion

"except the last one" removes one target

010

Cancel pending

"actually don't" → CANCELLED, no effect

011

Only execution path

work.execute called only for a request

012

Stale blocks mutation

token change → STALE_REFERENCE, no invoke

013

Confirmed bindings frozen

scope drift cannot change dispatches

014

Explicit supersedes inferred

newer binding replaces older in one slot

015

Pause / resume effects

queued effects keep original bindings

016

Referent survives async

ordinal still resolves during execution

017

Plural & "the other one"

set difference over active scope

018

Slot-scoped correction

target changes, content preserved

019

Clarify and resume

out-of-range ordinal asks, answer continues intent

020

Message full flow

conversation B, same machinery as tasks

021

"yeah" without a gate

backchannel, cannot commit or fill

022

"yeah" with a gate

commits the presented revision exactly

023

"yeah, but not the second one"

mutates, revokes confirmation, nothing dispatches

024

Full-effect freeze

bindings and preconditions frozen at commit

Anti-pattern-matching

Nine metamorphic properties

#PropertyOracle
P1Ordinal invarianceshuffle any scope; "the second one" is always index 1
P2Identity invariancerandom opaque ids behave identically to A/B/C
P3Irrelevant-world mutationunrelated changes never alter "that"
P4Ambiguity expansiona new plausible candidate flips to clarification
P5Bind-then-drifta resolved binding stays after scope reorder
P6Freeze invariancepost-commit drift cannot change dispatch bindings
P7Gate-state dependenceevery affirm token commits under a gate, none without
P8Revision safetyrandom mutate/confirm sequences never dispatch stale revisions
P9Mutation-boundary preconditionsa token change after validate cannot produce a silent stale write

Runner lives in @circe/evals, fast-check generators, shrinkable counterexamples. Spec: evals/properties.md.

Review response

Rev 4 adopted changes and deferred calls

Adopted · rev 4

Circe restored as the product brand (repo and packages included); legacy Circe is prior art archived as circe-legacy. UNKNOWN is reconcilable, not terminal, and never retried. P7 restated so qualified affirmations cannot authorize a mutated revision. Conditional-apply fallback policy with risk tiers and POLICY_BLOCKED. I12 precision: social/backchannel are journaled but carry no semantic consequences. Scope retention is GC policy with pin rules.

Deferred to code

Not blocking. maxUnpinnedScopes default (8); compensation naming for Phase 4; fast-check as property runner; responder as a port with deterministic default; event-log persistence first; fake executors must model atomic conditional apply, PRECONDITION_FAILED and UNKNOWN so P9 can genuinely fail.

Takeaway

The brand is Circe; the coupling is gone

Legacy Circe appears nowhere in the pipeline or the kernel dependencies — it is evidence and, later, one deletable adapter. What remains is the normal hard part: obligation-based meaning, revision-bound authorization, mutation-boundary preconditions, reconcilable unknown outcomes, and recorded replay. Next: make all 24 scenarios and 9 properties fail for real, then implement them one by one without renegotiating the architecture.

github.com/Absterrg0/circe · ARCHITECTURE.md · docs/EVAL-FORMAT.md · evals/scenarios/ · evals/properties.md