core — top-level modules
core.agent
A trivial agent that inherits the Constitution (the inheritance + self-eval seam).
Every agent — static, scheduled, or minted by the factory (Phase 5) — is built this
way: the Constitution is its outermost frame and the role/task nest inside it
(Invariant 6), and no agent returns output without passing through the Constitution
pre-return check (§IV). The factory will extend this with tool scope, tiers, and the
scope ceiling; the Librarian (Phase 2, core/librarian/) is the first real specialization.
The self-evaluation logic lives in core.selfcheck and is re-exported here so callers
and tests can keep importing it from the agent module.
Finding
dataclass
directive
instance-attribute
status
instance-attribute
detail = ''
class-attribute
instance-attribute
SelfCheck
dataclass
Result of the pre-return Constitution check (§IV).
passed
instance-attribute
findings = ()
class-attribute
instance-attribute
notes
property
Compact summary, e.g. ("grounded-citations:pass", "mirror-not-oracle:deferred").
failures()
Agent
dataclass
name
instance-attribute
role_prompt
instance-attribute
tier = 'routine'
class-attribute
instance-attribute
server = None
class-attribute
instance-attribute
build_context(task, *, history=None)
The agent's context, Constitution outermost (Invariant 6).
respond(task, *, history=None, think=None)
self_evaluate(output, *, sources=None, judge=None)
Run the pre-return Constitution check.
sources: the legitimate citation targets. Pass a list of Source (title + stable
digest) for the well-posed, collision-detecting grounding check (gap G1); a bare set of
titles still works (legacy). Omit it (None) for an agent with no retrieval context.
judge: optional small-model judge for the subjective directives; when absent those
directives are reported as deferred (Phase 10 wires the judge + baseline).
core.complex_types
Typed enums for the reasoning-complex graph (family 5; companion III §1.2–§1.3).
Small closed sets that would otherwise be free ints/strings — made enums so an illegal value
is unrepresentable rather than merely unexpected (the MirrorView/ProposedChange move,
MATHEMATICAL-REFRAMING.md §B.1: make it a type when that deletes an illegal state). These are
the shared vocabulary the derivation-hypergraph junction (core/stores/derived.py) uses today and
the signed edges table (Prompt H1) will use next; kept in a leaf module with no core imports so
both Zone-A consumers depend on it without a cycle. Nothing here touches the network.
EdgeSign
Bases: IntEnum
Polarity of a typed edge (companion III §1.2, §2.3): +1 support / −1 contradict.
An IntEnum so the value itself is the ±1 the signed-Laplacian arithmetic and the
edges.sign column consume — EdgeSign.CONTRADICT * w is just -w. The enum deletes the
illegal sign = 3 (or 0) state: polarity is a closed two-element set. A non-edge is the
absence of a row, never a zero sign, so 0 is deliberately not a member.
SUPPORT = 1
class-attribute
instance-attribute
CONTRADICT = -1
class-attribute
instance-attribute
HyperedgeRole
Bases: StrEnum
A node's role in a derivation B-arc (companion III §1.3, §2.5): the tail set T(e) = supp(κ) jointly entails the single head κ.
role ∈ {tail, head} — the closed set the hyperedge_nodes.role column stores. A StrEnum
so the stored value is the readable word while any other string is unconstructable. Today
every head-set has size 1 (one head per derives hyperedge).
TAIL = 'tail'
class-attribute
instance-attribute
HEAD = 'head'
class-attribute
instance-attribute
core.constitution
Load and frame the Constitution — the fixed point inherited by EVERY agent (Invariant 6, BUILD-SPEC §4).
This module is the inheritance mechanism: it loads CONSTITUTION.md and assembles each
agent's context OUTERMOST-FIRST, so the Constitution is always the outer frame and
task-specific instructions nest strictly inside it and can never displace it. The
factory (Phase 5) mints agents through this same seam; static agents use it directly.
The Constitution is read-only here — no agent may modify it (Invariant 9). Its SHA-256 fingerprint is the frozen-anchor identity used by drift audits (BUILD-SPEC §15).
REPO_ROOT = Path(__file__).resolve().parent.parent
module-attribute
CONSTITUTION_PATH = REPO_ROOT / 'CONSTITUTION.md'
module-attribute
Message
Bases: TypedDict
One chat turn, Ollama chat-API shaped (bp-006 T2 convention: TypedDict).
Runtime-identical to the plain dict this replaced — TypedDict is erased to dict — but the shape now crosses module boundaries visibly to the checker.
role
instance-attribute
content
instance-attribute
load_constitution()
cached
constitution_fingerprint()
Stable SHA-256 of the Constitution. Drift audits compare against this to detect any change to the fixed point (BUILD-SPEC §15).
frame_context(role_prompt, task=None, *, history=None, context_blocks=None)
Assemble an agent's context outermost-first (BUILD-SPEC §13 priority order): Constitution -> role -> retrieved RAG context -> history -> task. The Constitution is ALWAYS messages[0]; everything else nests inside it and may never override it (Invariant 6).
context_blocks are retrieved grounding (e.g. the Librarian's RAG chunks), injected
after the role and before history per the §13 priority order.
core.dreams_view
The dreams reading scope — surfacing the INTERPRETED layer, mirror-not-oracle.
The dreamer + curator write thematic syntheses and housekeeping findings to the DerivedStore
(INTERPRETED provenance, BUILD-SPEC §8). Before this, nothing showed them to the owner — the
whole dreaming layer ran in the background and stayed invisible (WIRING-AUDIT DANGLING #1). The
Ambassador's DREAMS path reads through here.
Two rules shape it
- Read-only, the OpsView move —
DreamsViewbinds ONLY the store's read methods as callables; it holds noadd/reset, so the Ambassador cannot write the interpreted layer through it (assurance tier: static + guard, likeOpsView; weaker than MirrorView's structural copy, and labelled so). - Mirror, not oracle (Constitution §III.2, the §8 firewall). A dream is what the SYSTEM inferred, never what the owner wrote — so the narration marks it as interpretation, holds it loosely, cites the authored notes it spans in [[brackets]], and hands the judgment back. It must never read as authored ground truth; that asymmetry is the whole point of keeping the interpreted layer separate and provenance-marked.
ArtifactReads
Bases: Protocol
The read slice of a DerivedStore this view binds — reads and ONLY reads.
all(*, kind=..., subkind=...)
count(*, kind=...)
RetractedReads
Bases: Protocol
A duck-typed source of RETRACTED subject ids (a DispositionStore.retracted).
retracted()
DreamsView
dataclass
Read-only view over the DerivedStore's INTERPRETED artifacts (dreams + findings).
Construct with DreamsView.over(store); the fields are bound READ callables only — there is
no mutator (add/reset) on this type's surface (asserted in tests/integrity).
over(store, *, dispositions=None)
classmethod
Bind the store's reads (+ an optional retracted disposition read).
The returned view exposes those and only those — the store's add/reset are unreachable
through it. Passing dispositions makes it the ACTIVE projection: retracted dreams are
excluded from recent_dreams. Omit it to keep the prior behavior byte-identical.
recent_dreams(limit=5)
The most recent thematic dreams, newest first (the store orders oldest-first), excluding any the owner has RETRACTED by verdict — the active projection (ingest-identity §6).
dream_count()
finding_count()
narrate_recent(limit=5)
Reflect recent dreams back in plain language, framed as interpretation the owner judges — never as authored fact (§III.2).
core.effect_proposal
Compose a reversible-write proposal, tailored to the owner (Track G, item G5).
This is the point §7 names: an effector that writes in the owner's voice must read a model of the
owner — and that read is a MirrorView (authored-only; the firewall holds even here), with the
output a proposal, never a sent artifact. So the whole of this module is: read the mirror,
tailor a body, return a ProposedEffect. There is deliberately no send, no stage, and no Effect
construction here — composing the proposal ("the model advises") is strictly separate from acting
on it ("code acts", after the gate: ops/effect_gate → ops/effect_ledger → the edge effector).
Two boundaries make the separation structural, not a convention:
- The firewall.
tailoris typedCallable[[MirrorView, str], str]. AMirrorViewcannot hold observed or curated rows (core/mirror.pyraises), so a steered composer physically cannot tailor a reply from third-party exhaust — only from the owner's own authored notes. - Propose, never send. The return type is
ProposedEffect— an actuator name + allowlisted string params and nothing more (no send field exists to set). The class is asserted REVERSIBLE against the catalog (fail-closed): this composer proposes reversible writes and nothing else.
The proposal then rides the ordinary path: a human approves it (LIGHT, EffectLedger.approve), an
Effect is constructed under that approval, and the edge effector STAGES a draft the owner can
delete (edge/effectors/writes.py). Sending that draft is a different, irreversible, full-gated
act (G6) — never something this module can reach.
Tailor = Callable[[MirrorView, str], str]
module-attribute
NotAReversibleWriteError
Bases: ValueError
A non-reversible actuator was handed to the reversible-write proposer (fail-closed): sensing
has its own path (core/sensing.py) and irreversible sends are composed + gated elsewhere (G6),
never proposed here where approval is only LIGHT.
ReversibleWriteProposer
dataclass
Composes class-2 (reversible) effect proposals. Holds only a tailor (advice); it never
holds a store handle, a credential, or a send path. Every method returns a ProposedEffect.
tailor = _grounded_default_tailor
class-attribute
instance-attribute
propose_draft_reply(*, to, subject, request, mirror, rationale='')
Propose a DRAFT reply, its body tailored from the owner's authored notes (mirror). The
result is a proposal — never a sent artifact. mirror is a MirrorView, so the tailoring
cannot draw on observed/curated exhaust (the firewall). Validated against the catalog via
.resolve() before return (fail-closed on any bad param).
propose(actuator, params, *, rationale='')
Propose any cataloged reversible write (calendar_hold, stage_file, …) from explicit
params. No tailoring read — use propose_draft_reply for a voiced body. Fail-closed on a
non-reversible actuator or any param outside the catalog's closed allowlist.
model_tailor(server, *, tier='routine', max_notes=12)
A tailor backed by the local model, reading the owner's authored notes to draft in their
voice. The model only ADVISES: its output is a proposal body wrapped into a ProposedEffect and
never sent. It sees a MirrorView (authored-only) — never observed exhaust, never a credential.
Parsing is forgiving; an empty reply degrades to the grounded default (honest, not a fabricated
draft). Lazy about the model interface (duck-typed .chat) so this module imports no server.
core.interface
Core side of the interface handoff (BUILD-SPEC §6, §12; Invariant 2).
The sealed core never speaks to a messaging service. Instead the networked gateway (Zone B) drops a sanitized request into the handoff directory; this inbox — running inside the sealed core — reads it, dispatches the query to a core handler (the librarian / a minted agent), and writes the answer back to the handoff directory. The gateway relays it onward.
The ONLY coupling to the outside is these JSON files on disk: no network, no adapter import,
no shared memory (the structural form of "network and private data never share a component").
The wire format is a small JSON object, mirrored — not imported — by the gateway side:
requests/
Handler = Callable[[str], str]
module-attribute
REQUESTS = 'requests'
module-attribute
RESPONSES = 'responses'
module-attribute
CoreInbox
dataclass
handoff
instance-attribute
handler
instance-attribute
process_once()
Process every pending request; return how many were handled. A handler error becomes an error response rather than crashing the inbox.
run(*, poll_interval=0.5, max_cycles=None)
Serve the handoff in a loop. The scheduler (Phase 3) can also drive this as a job.
build_core_inbox(config=None)
Wire the inbox to the Ambassador — the conversational front door (Track B). The
Ambassador reasons about intent and routes to retrieve / explain / status / capture inline,
delegating heavy work; conversations are captured as authored-dialogue.
This base wiring has no DELEGATION queue handle (the core never imports the scheduler — that
would invert the layering), so TASK here still attests + narrates effort but enqueues nothing.
The full delegating inbox (task → gate → queue, with completed-result surfacing) is
scheduler.interface.build_conversation_runtime, used by the CLI and the scheduled path.
agents.ambassador is imported lazily (function-level): it transitively reaches the pure
scheduler.budget budgeter, and a top-level import would invert core's layering — the
Ambassador is core-side but is assembled, not imported, at module load (no network either).
core.mirror
The mirror projection as a TYPE (Invariant 6, BUILD-SPEC §8; gap G3).
I6 — the firewall — requires that introspective agents (the dreamer; the curator's theme /
contradiction scan) read ONLY the mirror-readable provenance classes
(MIRROR_READABLE = {authored}), so third-party observed exhaust can never seed a dream or
enter the behavioral baselines (§15). Until now that was a call-site convention: remember to
pass provenances=MIRROR_READABLE to all_rows. The formal-properties catalog (G3) asks to
promote it to structural.
MirrorView is that promotion. It is the only thing the introspective agents cluster over, and:
- its sole normal constructor,
project, applies π_MR — it reads the source restricted toMIRROR_READABLE; and __post_init__re-validates every row's provenance and raises on a non-authored row,
so a MirrorView holding observed (or any non-MR) data cannot be constructed at all — not
by project, not by hand. Handing an introspective agent non-authored data is therefore
unrepresentable (the wrong state cannot be built), the top tier of the assurance hierarchy,
rather than "checked and refused". Functions typed to accept a MirrorView inherit the proof.
Note this is the introspective read path. The curator's prune scan deliberately reads ALL
provenances (orphaned derived weight is dead regardless of provenance); that is not a mirror
read and correctly does not go through MirrorView.
RowSource
Bases: Protocol
Anything that can yield provenance-filtered rows (the VectorStore, or a test fake).
all_rows(*, provenances=None)
NonMirrorRowError
Bases: ValueError
A row whose provenance is outside MIRROR_READABLE was offered to a MirrorView.
MirrorView
dataclass
An authored-only projection of the thought-graph. Every contained row is guaranteed
provenance ∈ MIRROR_READABLE — the type itself is the proof. Obtain one via
MirrorView.project(store); direct construction with non-authored rows raises.
project(source)
classmethod
π_MR — the mirror projection, and the only sanctioned way to build a MirrorView.
Reads source restricted to MIRROR_READABLE; __post_init__ then re-checks, so even
a buggy source cannot smuggle a non-authored row past the type (fail-closed).
rows()
The authored rows (a fresh list; the view is immutable).
core.ops_view
The operational-introspection read scope (Track B / B3; nervous-system-and-ambassador.md §4).
The Ambassador has a SECOND reading scope beyond the authored mirror: the system's own operational state — the attestation chain (what it has done), the proposal ledger (what self-modifications are pending/decided), and the drift gauge (is it healthy). This is the one role permitted to read the audit layer to narrate it — and it still cannot write to it.
Read-only, the MirrorView move: an OpsView captures ONLY the read methods of those stores
as bound callables. It holds no reference to a mutator on its public surface — approve,
deny, append, mark_*, propose are simply not attributes of this type, so the Ambassador
cannot reach them through the view (asserted in tests/integrity/test_ops_view.py). Python can't
make reach-through-__self__ impossible the way a copied immutable tuple can (MirrorView), so
the honest assurance tier here is static (typed read Protocols) + guard (the no-mutator
integrity test) — strictly weaker than MirrorView's structural guarantee, and labelled as such.
It also renders its state in plain language (narrate) — never the internal nouns (tier
names, "synthesis job", credentials, accessors) the authoritative note §4 forbids. That plain
register is the conversational surface of "what have you been doing?" and "is the system
healthy?", and the backing for the Ambassador's effort narration.
AttestationReader
Bases: Protocol
The read surface of the append-only attestation store (no append).
all()
by_role(role)
count()
ProposalReader
Bases: Protocol
The read surface of the proposal ledger (no approve/deny/mark_*).
all()
pending()
OpsSnapshot
dataclass
A plain, model-free summary of operational state — the data the status path renders.
attestation_count
instance-attribute
recent_actions
instance-attribute
pending_proposals
instance-attribute
drift_within_tolerance
instance-attribute
constitution_intact
instance-attribute
OpsView
dataclass
Read-only introspection over attestations + the proposal ledger + the drift gauge.
Construct with OpsView.over(...); the fields are bound READ callables only — there is no
mutator on this type's surface (B3's read-only guarantee).
over(attestations, ledger, *, drift=None)
classmethod
Bind the read methods of the live stores. The returned view exposes those and only those — the stores' mutators are unreachable through it.
attestation_count()
recent_actions(limit=5)
The most recent (role, action, timestamp) triples, newest first.
actions_by_role(role)
pending_proposals()
all_proposals()
drift_report()
snapshot()
narrate()
A plain-English status summary for "what have you been doing / are you healthy". Deliberately avoids tier names, job/queue nouns, credentials — the shape of the work, never the plumbing.
core.provenance
Provenance classes for the data architecture (BUILD-SPEC §8; design-notes/ observed-data-and-the-assistant-tier.md; the §1 provenance-spectrum growth path).
Every stored datum carries a provenance class so a query or agent can always distinguish "the owner wrote it" from "the system inferred it" from "a third party observed it" from "the owner selected someone else's words". The classes do not mix — that separation is the firewall (BUILD-SPEC §8).
The spectrum (Track B realizes the §1 split that the formal spec already assumes):
* authored-solo — the owner wrote it alone (notes, journals). Ground truth, feeds
the mirror. This is what the single authored tag used to mean;
existing rows relabel to it (a same-trust-tier relabel, not a
promotion across the firewall — both authored classes are
mirror-readable).
* authored-dialogue — the owner's own words to the Ambassador. Still authored ground
truth ("your words to it are more yours than its words to you"),
so it is mirror-readable too — closing the capture loop.
* curated — others' words the owner selected (books, highlights, and the
system's own white papers / design notes = its self-knowledge
graph). Lives in its own graph; never merged into the authored
mirror (curated ∉ MIRROR_READABLE — the same firewall shape as
book-dreaming). The Ambassador reads it only via a deliberate,
non-default provenances={CURATED} query.
* interpreted — system inference. Structurally unforgeable (the derived store has
no provenance parameter).
* observed — third-party behavioral exhaust. Assistant-tier only; never the
mirror, never the baselines. Reserved (dormant schema).
T = TypeVar('T')
module-attribute
MIRROR_READABLE = frozenset({Provenance.AUTHORED_SOLO, Provenance.AUTHORED_DIALOGUE})
module-attribute
Provenance
Bases: StrEnum
AUTHORED_SOLO = 'authored-solo'
class-attribute
instance-attribute
AUTHORED_DIALOGUE = 'authored-dialogue'
class-attribute
instance-attribute
CURATED = 'curated'
class-attribute
instance-attribute
INTERPRETED = 'interpreted'
class-attribute
instance-attribute
DERIVED_STRATUM = 'derived-stratum'
class-attribute
instance-attribute
OBSERVED = 'observed'
class-attribute
instance-attribute
Authored
dataclass
Bases: Generic[T]
A value obtained exclusively from mirror-readable (authored) sources.
An information-flow label, not a claim the owner typed this exact value: a note centroid
computed over authored rows is still Authored[NoteVector] — what the firewall tracks is
the provenance CLASS of the sources. @final: even deliberate subclass-laundering
(a Derived masquerading via inheritance) is a type error, not just an accident.
value
instance-attribute
Derived
dataclass
Bases: Generic[T]
A value that transited system inference (the INTERPRETED lane) — or mixed with one.
The meet of the two-point lattice: any computation touching a Derived input yields
Derived output. The only way UP is promote, which demands the owner's capability.
value
instance-attribute
OwnerVerdict
PLACEHOLDER capability token for verdict-gated promotion (I1) — taxonomy UNRATIFIED.
Deliberately a NOMINAL class, not a Protocol: an empty Protocol is structurally satisfied
by every object, which would let promote(d, object()) type-check and vacate the
capability constraint. @final keeps it unforgeable-by-subclass at the type level.
This class answers NO design questions (recorded in bp-009's journal for /triage):
whether it unifies with the runtime verdict machinery (core/verdict/,
core/stores/verdicts.py), whether a verdict names its target authored class, and its
scope (per-value / per-artifact / per-run) are all open until the I1 taxonomy ratifies.
At runtime it confers nothing — promote raises regardless.
promote(x, cap)
The ONLY up-move of the two-point lattice — signature per §2.4, verbatim.
Extends the promotion comment above MIRROR_READABLE ("Promotion up to an authored
class is a deliberate human re-tag-from-raw (§8), never automatic"): at the type level,
a call site that never received an OwnerVerdict cannot even EXPRESS a promotion, so
the accidental-violation class is removed at authorship time.
STUB — verdict-gated promotion (I1) is unbuilt (recursive-strata parked) and the verdict taxonomy is unratified, so this body deliberately implements NO policy. The typed signature is the contract the future implementation must satisfy.
core.recursion
Recursion-decay bound for interpreted artifacts (Invariant 10; BUILD-SPEC §8 analogy).
Interpretation is hypothesis; tame the recursion; evidence decides, not persuasion.
An interpreted artifact's confidence may not compound with derivational distance from ground
truth — it must decay. With derivation depth d(κ) (0 = an authored leaf; computed by
DerivedStore.depth, well-defined because the derivation graph is acyclic by construction —
gap G2) and a base grounding score g(κ) ∈ [0, 1], the bound is
c(κ) ≤ γ^{d(κ)} · g(κ), γ ∈ (0, 1).
Because γ < 1, a self-referential loop loses potency every pass instead of amplifying — the
formal shape of taming "the stack-overflow of a mind thinking only about itself". This module
is the small, pure home of that bound: depth + γ + g make c computable.
decay_bound is the depth-decay ceiling γ^d·g. The full, clamped confidence a claim actually
carries — c = min{1, γ^d · g · (1 + λ(|Agr| − 1))} — is claim_confidence, the single
definition the adjudicator calls (companion III §5.3/§7.2). The min{1,·} clamp + the γ^d factor
make c ∈ [0,1] and non-increasing in depth by construction: a c>1 or a depth-rising c is
unrepresentable because no caller assembles the bonus itself.
γ bound (gap G7): γ is held small enough that a depth-3 artifact is clearly subordinate to ground truth — at the default γ = 0.5, depth-3 confidence is capped at 0.125·g (an eighth), so third-order interpretation cannot out-rank a first-order reading of the same evidence. It is a declared constant here, not a magic number scattered at call sites; calibrate on the real corpus before the adjudicator ships.
DEFAULT_GAMMA = 0.5
module-attribute
DEFAULT_LAMBDA = 0.1
module-attribute
decay_bound(depth, *, grounding=1.0, gamma=DEFAULT_GAMMA)
The confidence ceiling c ≤ γ^depth · g for an artifact at derivation depth with base
grounding g (Invariant 10). Non-increasing in depth for γ ∈ (0,1) and g ≥ 0 — confidence
strictly decays away from authored ground, never compounds.
claim_confidence(depth, *, grounding=1.0, agreement=1, gamma=DEFAULT_GAMMA, lam=DEFAULT_LAMBDA)
THE single definition of an interpreted claim's confidence (companion III §5.3/§7.2):
c = min{1, γ^d · g · (1 + λ(|Agr| − 1))}.
decay_bound is the depth-decay ceiling γ^d·g (Invariant 10); this multiplies in the
bounded corroboration bonus (1 + λ(|Agr|−1)) — agreement across |Agr| distinct methods is a
multiplier, not a vote (g=0 ⇒ c=0) — and applies the min{1,·} clamp. Together the clamp
and the γ^d factor guarantee, for every admissible input:
- c ∈ [0, 1] — no path can produce c > 1 (closes the companion III §7.2 clamp tension);
- c is non-increasing in depth d for fixed (g, |Agr|) — belief decays away from authored ground, never compounds.
This is the only place confidence is assembled; callers (the adjudicator) must not multiply the bonus in themselves, so an out-of-range or depth-rising c is unrepresentable at source.
core.recursion_ops
Dialogue operations — corrections that act on claims, not peer nodes (dialogue-ingest §3–§4).
A note is a claim; a dialogue is a derivation whose output is a set of OPERATIONS on existing claims (§3), never a new peer node beside them (the §2 failure — two content-addressed claims disagreeing, lighting up a false contradiction). The ratified starter vocabulary (§4; build plan Item 2a) is three operations:
Supersede(C, conclusion, warrant)— the dialogue's conclusion C′ replaces C in the ACTIVE projection; C is retained in history with the warrant as the reason. C′ is a DERIVED conclusion (interpreted, γ^d-damped — never an authored peer), minted through theDerivedStore.AttachDefeater(C, defeater)— records that C is contested and how (C stays, marked).RecordWarrant(warrant, {C, C′})— the reasoning linking the initial and final positions.
Three separations keep this honest (all confirmed against code):
- Distinct from version-supersedes (§4A C3). Claim-
supersedeis warrant-bearing reasoning; note-supersedes(v1,v2)is a file edit (core/stores/versions.py). Different relations, different stores — never the same rel-type, never the balance-fedEdgeStore. - The conclusion is INTERPRETED and grounds on the WARRANT'S anchors (Item 9). C′ is minted
via
DerivedStore.add, carryingINTERPRETEDprovenance (I5) and a derivation depth, socore.recursionbounds its confidence by γ^d (I10): a dialogue conclusion can never out-rank the authored claim it revised without an owner verdict (I1). Itsderived_fromis the warrant's K₀ anchors (surviving grounding of C + the dialogue's new evidence). Grounding a revision on a derived[C]is refused — it cites what it discredits and, because the grounding ratio is transitive, collapsesgwhen C is superseded and builds the cross-stratum tower (§4.2). Grounding on an authored[C]is legitimate: bedrock does not decay, so g=1 and the revision is not weightless. TheC→C′relation is carried by the dispositionalClaimOpStoreedge alone, not a grounding fiber; the γ^{d≥1} "can't out-rank authored" guarantee comes from depth ≥ 1. - Budgets floored (PD4). The recursive-strata I5 population / edge budgets are parked; with none enforced these ops are recorded flatly and the Dreamer does not yet consume them recursively — exactly the non-recursive floor, recovering current behavior. The hook is named here, enforced when recursive-strata unparks.
The dialogue → operations EXTRACTION is a model task (an LLM reads the dialogue and proposes the
operations); it is an injected DialogueAnalyzer seam with a deterministic default of NO operations
(document-only ingest, unchanged). This module is the deterministic core: the types, the store, and
apply_operations (record + re-project). Zone A, no network.
DIALOGUE_CONCLUSION = 'dialogue_conclusion'
module-attribute
DialogueOp = Supersede | AttachDefeater | RecordWarrant
module-attribute
OpKind
Bases: StrEnum
SUPERSEDE = 'supersede'
class-attribute
instance-attribute
ATTACH_DEFEATER = 'attach_defeater'
class-attribute
instance-attribute
RECORD_WARRANT = 'record_warrant'
class-attribute
instance-attribute
Supersede
dataclass
The dialogue concluded conclusion, which replaces claim in the active projection; the
warrant is why. claim is an existing claim id (a note digest or an artifact id); conclusion
is the new position's text, minted as a DERIVED interpreted claim on apply (never an authored
peer).
anchors are the warrant's K₀-reaching authored digests — the grounding C′ actually rests on
(Item 9; supersession-lifecycle.md §4.2). A DialogueAnalyzer supplies them (surviving
grounding of C + the dialogue's new evidence). Left empty, apply falls back by C's type: a
DERIVED C inherits its surviving authored leaves (leaf_refs, never [C] — a derived claim
decays or is superseded without a verdict, so routing grounding through it is unsafe); an
AUTHORED (K₀) C grounds on [C] itself (bedrock — authored content does not decay, so g=1 and
the revision is not weightless). The discredited claim is refused as grounding only when
derived.
claim
instance-attribute
conclusion
instance-attribute
warrant
instance-attribute
anchors = ()
class-attribute
instance-attribute
AttachDefeater
dataclass
claim is contested by defeater; the claim stays but is marked (not silently dropped).
claim
instance-attribute
defeater
instance-attribute
RecordWarrant
dataclass
The warrant links the claims in links (typically the initial and final claim).
warrant
instance-attribute
links
instance-attribute
DialogueAnalyzer
Bases: Protocol
Turns a dialogue's text into operations — a MODEL task. Injected; the default emits none.
analyze(text)
ClaimOp
dataclass
op_id
instance-attribute
kind
instance-attribute
claim_id
instance-attribute
related_id
instance-attribute
text
instance-attribute
at
instance-attribute
ClaimOpStore
dataclass
Append-only store of dialogue operations over claims. A DISTINCT structure from the version store and the balance-fed edge store (§4A C3): claim-supersede is warrant-bearing reasoning, not a note edit and not a semantic ± edge, so it shares no rel-type or store with either.
path
instance-attribute
record(kind, claim_id, *, related_id='', text='')
superseded()
Claim ids with a SUPERSEDE op — the active-projection filter (a consumer excludes these,
exactly as DispositionStore.retracted does for verdicts; the superseded claim lives on in
history).
defeaters(claim_id)
all()
count()
close()
ApplyReport
dataclass
superseded
instance-attribute
conclusions
instance-attribute
defeaters
instance-attribute
warrants
instance-attribute
stale = ()
class-attribute
instance-attribute
no_op_analyzer(_text)
The deterministic default (build plan PD4 floor): a dialogue emits NO operations → the existing document-only ingest, byte-for-byte unchanged. A real deployment injects a model-backed analyzer that proposes operations for owner/verdict review.
stale_closure(derived, claim)
Stale(C) = { x : C is reachable from x along grounding fibers } — C's grounding-descendant
closure (supersession-lifecycle.md §5). When C is superseded, every x that transitively grounds
on C routes its support through a dead node, so its grounding ratio g will fall; this names
them at the moment of supersession — the PROACTIVE complement to the detective grounding gauge.
These are flagged for re-examination, not resolved: whether a derived claim survives its
parent's revision is a semantic judgment the Dreamer proposes later (terminating in proposals,
never silent edits). Read-only; walks the derived_from DAG (x → … → C). Note the Item 9
grounding correction keeps a revision chain from self-generating this set — C′ grounds on
warrant anchors, not on its predecessor, so the closure holds only genuine dependents (§5).
apply_operations(ops, *, ops_store, derived)
Apply dialogue operations: record each as a claim relation and re-project.
A Supersede mints its conclusion C′ as a DERIVED artifact grounded on the WARRANT'S K₀
anchors (Item 9; supersession-lifecycle.md §4.2), so γ^d bounds it (I10/I5) and C leaves the
active projection without C′ entering as an authored peer (the §2 failure avoided). Explicit
op.anchors win; empty falls back by C's type — a DERIVED C inherits its leaf_refs (never
[C], which decays); an AUTHORED C grounds on [C] (bedrock, g=1, so the revision is not
weightless). On supersession we also compute Stale(C) (§5) — grounding-descendants to flag for
re-examination — surfaced in the report for the digest; nothing is cascade-retracted. Budgets
floored (PD4).
open_claim_op_store(config=None)
core.runtime
Sealed-core runtime entrypoint.
Any Zone-A process starts here. It installs the egress guard FIRST (Invariant 1), so "the core has no egress" holds before any work runs, then wires the Zone-A services (models, telemetry, vitals) and exposes an agent factory seam. Sealing is done here — explicitly, at startup — rather than as an import side effect, so importing core modules for tests/tools is free of surprises.
Core
dataclass
config
instance-attribute
models
instance-attribute
telemetry
instance-attribute
vitals
instance-attribute
constitution_fingerprint
instance-attribute
make_agent(name, role_prompt, tier='routine')
Mint a trivial agent bound to the model server. Every agent inherits the
Constitution via core.constitution.frame_context (Invariant 6).
bootstrap(config=None)
core.sealing
Structural network-egress guard for Zone A (the sealed core).
Invariant 1 (BUILD-SPEC §3): the sealed core has zero network egress, enforced
structurally, not by convention. The ideal enforcement is OS-level — a separate
network namespace with --network=none, or a pf anchor denying outbound for the
core's uid — and that is the deployment-time hardening layer (see docs/runbook.md).
On bare macOS during development we cannot hand the core a Linux netns, so this module
is the in-process structural layer: a fail-closed guard, installed process-wide, that
intercepts every socket connect/connect_ex and permits ONLY loopback destinations
(127.0.0.0/8, ::1) plus AF_UNIX. The single legitimate "egress" the core makes is to
the local Ollama model server on 127.0.0.1 (BUILD-SPEC §5, §7) — a loopback IPC
channel, not egress to the outside world. Any attempt to reach a non-loopback address
raises SealedCoreEgressError before a packet leaves.
Defense in depth: neither layer alone is the whole story (a native extension opening
its own socket could bypass a Python-level guard), but the guard fails closed, is
process-wide, and is verifiable in tests — and it composes with the OS-level layer at
deployment. The guard is installed by the core runtime entrypoint (core.runtime),
never as an import side effect.
DNS note: resolving a hostname is itself egress (it leaks intent to a resolver). The only host the core dials is an IP literal (127.0.0.1), so name resolution is never required inside the walls — we therefore refuse to connect to any non-loopback or non-literal host rather than resolve it.
SealedCoreEgressError
Bases: RuntimeError
Raised when sealed-core code attempts to connect to a non-loopback address.
is_egress_allowed(family, address)
Pure decision: may a socket of family connect to address?
AF_UNIX (local IPC) is always allowed. AF_INET/AF_INET6 are allowed only to a loopback host. Everything else is denied. Side-effect free, so it is unit-testable without touching a real socket.
seal()
Install the process-wide egress guard. Idempotent.
Call once at core-process startup, before any work. After this returns, any connect() to a non-loopback address raises SealedCoreEgressError.
is_sealed()
assert_sealed()
core.selfcheck
The Constitution pre-return self-evaluation check (BUILD-SPEC §4, §15; Constitution §IV).
Every agent runs this before returning output (Invariant 6 / §IV). Two layers, matching the Constitution's own mandate:
-
Deterministic, always-on (cheap): verify the output is grounded — every note it cites must resolve to a source that was actually retrieved. "A cited identifier that does not resolve is a failure" (Constitution §III.1). This is the concrete, deterministic check the spec explicitly calls for.
-
Subjective (mirror-vs-oracle, overclaimed certainty, consequential deference): these are NOT decided by brittle keyword matching. The spec is emphatic (§4, §15): a small-model judge, A/B'd against a known-good baseline snapshot, never scored cold. The baseline/anchor machinery is part of the safety fixed point and lands with the self-modification loop (Phase 10). Until then this module exposes a
judgeseam; when no judge is wired these dimensions are reported asdeferred— honestly not-yet-evaluated, never silently passed off as conforming.
passed is True iff there are no FAIL findings; a deferred finding does not fail.
PASS = 'pass'
module-attribute
FAIL = 'fail'
module-attribute
DEFERRED = 'deferred'
module-attribute
Sources = 'set[str] | Iterable[Source]'
module-attribute
SubjectiveJudge = Callable[[str], 'list[Finding]']
module-attribute
Source
dataclass
A citable retrieved note (gap G1). digest is the STABLE citation identity — the
raw-store content id, which never drifts; title is only the human-facing label the
model writes in [[...]]. Grounding decidability rests on the digest: Cit(A) ⊆ Ret is
well-posed exactly when each cited title resolves to a single retrieved digest. A title
that resolves to two distinct digests is an ambiguous (ill-posed) citation, which the
grounding check now surfaces instead of silently — and arbitrarily — accepting it.
Callers may still pass a bare set of titles (the legacy path, where each title is taken
as its own stable id); pass Sources when digests are available (librarian, dreamer) to
get the well-posed, collision-detecting check.
title
instance-attribute
digest
instance-attribute
Finding
dataclass
directive
instance-attribute
status
instance-attribute
detail = ''
class-attribute
instance-attribute
SelfCheck
dataclass
Result of the pre-return Constitution check (§IV).
passed
instance-attribute
findings = ()
class-attribute
instance-attribute
notes
property
Compact summary, e.g. ("grounded-citations:pass", "mirror-not-oracle:deferred").
failures()
check_grounding(output, sources)
Deterministic: every [[cited]] note must resolve to exactly one note that was actually retrieved (Constitution §III.1, "a cited identifier that does not resolve is a failure").
Decidability rests on a STABLE identity — the content digest (gap G1). A cited title is: * unresolved (FAIL) if it matches no retrieved note; * ambiguous (FAIL) if it matches two distinct retrieved digests — a title-only citation that cannot be decided, now surfaced rather than silently accepted; * grounded (PASS) if it resolves to exactly one retrieved digest.
sources=None means there was no retrieval context (e.g. a generic agent), so the check
is not applicable and is reported as deferred rather than failing.
grounding_score(support, authored)
g(κ) ∈ [0,1] (§6/§8): the fraction of a claim's support refs that resolve to AUTHORED leaves — the dream adjudicator's ranking currency (R1). This extends the binary grounding predicate above into a score: the currency is resolvable evidence, never rhetoric.
A ref that does not bottom out in authored ground (e.g. a prior-dream/interpreted id) contributes 0 — the formal "chains may not close within INTERPRETED" rule (Invariant 10). g = 1.0 means every support ref is authored (the only case the R0/R1 panel produces, since its inputs are a MirrorView); g < 1 is the recursion guard biting once R3 exists. Empty support is ungrounded (0.0): a claim with no evidence is not a grounded claim.
self_evaluate(output, *, sources=None, judge=None)
Run the pre-return Constitution check.
sources: the legitimate citation targets. Pass a list of Source (title + stable
digest) for the well-posed, collision-detecting grounding check (gap G1); a bare set of
titles still works (legacy). Omit it (None) for an agent with no retrieval context.
judge: optional small-model judge for the subjective directives; when absent those
directives are reported as deferred (Phase 10 wires the judge + baseline).
core.sensing
Core side of the sensing handoff (Track G, item G3 — read-only hands, β = 0).
Sensing hands are just new sensors: sandboxed fetch → de-identified request → observed-tier
view. This module is the sealed-core half of that path; the fetch itself lives in
edge/effectors/sensing.py (Zone B), which never imports this module — the wire shapes below
are mirrored, not imported, exactly like the research airlock (edge/bridge/protocol.py):
<handoff>/requests/<id>.json = de-identified sense request (core writes → edge serves)
<handoff>/observations/<id>.json = the sensed result (edge writes → core reads)
Two boundaries, both structural:
- Outbound —
SenseRequestis the only thing that crosses toward the network, and it cannot carry note content or an address:termspass the SAME conservative scrubber as airlock criteria (core.research.criteria.clean_term— one policy, one implementation), andupstreamis a short NAME into the edge-side reviewed allowlist, shaped so a URL, host, or path is unrepresentable. Even a reasoner steered by poisoned content cannot express "fetch attacker.com" here — there is no field that can hold it (the confused-deputy answer, made structural). - Inbound — a
SensedObservationis third-party exhaust.to_row()stamps provenanceobservedwith NO parameter (the DerivedStore move: a sensing result physically cannot claim to be authored), and the only typed container for these rows isObservedView, whose constructor refuses anything else.MirrorViewrefusesobservedrows (I6), so the two views PARTITION the tiers: sensing output provably cannot reach the authored mirror or the §15 baselines. The Track-D correlator is the intended consumer ofObservedView; until it lands, the view is the seam it will read.
The result type deliberately has no actuator field (§3): an observation cannot be replayed or confused into an action — data comes back, effects never do.
Dispatch through SensingHandoff.emit requires an Effect, and admission is the construction
of an EffectView at ceiling SENSING (ε = 0): a reversible or irreversible effect offered to
this surface raises before anything touches the handoff — the §4 filtration enforced by type,
not review.
REQUESTS = 'requests'
module-attribute
OBSERVATIONS = 'observations'
module-attribute
EffectorsDisabled
Bases: RuntimeError
[effectors] enabled is false — the sensing surface refuses to build (fail-closed).
SenseRequest
dataclass
The de-identified sense request — the ONLY thing that crosses toward the effector.
By construction it carries no note content and no address: a registered actuator name, a
short upstream NAME (resolved to a URL only inside the edge zone, against the owner's
reviewed allowlist), and scrubbed topical terms. to_request() is the exact wire payload.
actuator
instance-attribute
upstream
instance-attribute
terms = ()
class-attribute
instance-attribute
id = field(default_factory=(lambda: uuid4().hex))
class-attribute
instance-attribute
assert_clean()
Re-validate at the trust boundary (defense in depth) — a hand-built request cannot
bypass the scrubber on its way out. Raises DeidentificationError on any violation.
to_request()
The outbound wire payload — de-identified fields only, no corpus content.
SensedObservation
dataclass
One sensed result — third-party exhaust, observed-tier by construction.
Deliberately has NO actuator field (§3): a sensing result cannot express or be confused
into an action, the same way ResearchCriteria cannot carry a note. error is the
effector's honest refusal/failure note ("" = a real body came back).
request_id
instance-attribute
upstream
instance-attribute
ts
instance-attribute
body
instance-attribute
error = ''
class-attribute
instance-attribute
from_dict(d)
classmethod
to_row()
The observed-tier row. Provenance is HARDCODED — there is no parameter, so no caller
can launder a sensed result into an authored (or any other) class; the only way this
data enters a store or view is wearing observed (I5's unforgeability, reflected).
NonObservedRowError
Bases: ValueError
A row whose provenance is not observed was offered to an ObservedView.
ObservedView
dataclass
The observed-tier projection — the assistant-tier read boundary, dual to MirrorView.
Every contained row is guaranteed provenance == observed; the type itself is the proof,
so the Track-D correlator (this view's intended consumer) inherits "I read exhaust, never
the owner's ground truth" — and conversely MirrorView refuses these same rows, so the
two views PARTITION the tiers with no representable overlap (Invariant 6, both directions).
from_observations(observations)
classmethod
The sanctioned constructor: rows minted by to_row() (observed-stamped, no
parameter); __post_init__ re-checks, so even a buggy caller cannot smuggle a
differently-labeled row past the type (fail-closed).
rows()
The observed rows (a fresh list; the view is immutable).
SensingHandoff
dataclass
Core-side handoff for sensing (airlock-shaped). The sealed core never opens a socket: it writes a clean request into the handoff and later reads the observation back; the edge effector is the only thing that touches the network, and it never reads the vault.
handoff
instance-attribute
emit(request, effect)
Write one sense request to the handoff. Returns the request id.
Admission IS the construction of an EffectView at ceiling SENSING (ε = 0): an effect
of any acting class raises CeilingExceededError here, before anything reaches the
handoff — this surface can express read-only sensing and nothing else (§4 filtration).
The request is re-scrubbed at the boundary (assert_clean), mirroring the airlock.
collect(*, consume=True)
Read every available observation (and by default consume the files). The returned
objects are observed-tier by construction — hand them to ObservedView, never to a
mirror path (which would refuse them anyway; that refusal is tested, not assumed).
sense_request(actuator, upstream, terms=())
Build a SenseRequest from proposed (possibly model-suggested) inputs, conservatively:
un-cleanable terms are dropped; malformed actuator/upstream names raise. Unlike the airlock
builder, an EMPTY term list is legal — many sensors (weather, a status endpoint) take no
query at all — but if terms were proposed and none survive scrubbing, that is a refusal,
not a silent downgrade to an unqueried fetch.
build_sensing_handoff(config=None)
Wire the core-side sensing handoff. REFUSES (fail-closed) unless [effectors] enabled
— the whole Track-G surface is OFF by default; a fresh clone cannot emit a sense request
until the owner deliberately turns the flag on.
core.vitals
System-vitals emitter (BUILD-SPEC §8, §9 reactive tier).
"The system is itself a sensor source." At launch this is system vitals only — memory headroom, CPU, load, process RSS — written into the DuckDB telemetry store. Queue depth, model-load time, error rates, and cron durations join as those subsystems come online (Phases 3+). Body/health sensors are a deferred, dormant adapter (§20.6).
This is deterministic measurement, not a model (the reactive tier escalates to a model only when a threshold is crossed — that logic arrives with the scheduler in Phase 3).
Reading
dataclass
metric
instance-attribute
value
instance-attribute
unit
instance-attribute
labels = None
class-attribute
instance-attribute
VitalsCollector
dataclass
writer
instance-attribute
source = 'vitals'
class-attribute
instance-attribute
collect_once()
Sample current system vitals and write them to telemetry. Returns the readings written (so callers can verify the path end to end).