core.stores
core.stores
Outer-ring residue of the store layer (dn-inner-outer-core §2.7, K1 / bp-090).
The two file-backed content stores (rawstore — the content-addressed immutable archive — and
sourceset, + the package's inner init text) moved to core/kernel/stores/. What remains here is
the outer half: the sqlite/duckdb/lancedb/pyarrow-backed stores — the austere persistence plumbing
the owner's v2 ruling (§2.1) placed in the outer ring beside the machinery that operates it
(chatlog, derived, edges, runledger, catalog, causal_edges, chat_events, agent_observations,
authored_supersession, code_observations, observation_history, reference_edges, versions,
curated_store, telemetry, vectorstore, verdicts, staging, claim_ops). This init is
stdlib-import-free so it stays inner by construction (a pure package marker); the residue submodules
beside it are the outer machinery.
agent_observations
OBSERVED-only store for agent (self-sensing) observations (ratified self-sensing.md B-b).
One row = one fact reading of one commit: the agent's own operation is the THIRD stream
through the sensing seam (after the biometric stream and the code stream, bp-012), and the
self sensor (ops/self_sensor.py) is the sole interpreter φ_self (§2.2 — deterministic,
transform-attributed, sole path in, stateless). Observations enter through the
AgentSensingHandoff seam (core/sensing.py, the sensing-seam's third sibling) and land
here wearing observed — there is deliberately NO provenance parameter on any API surface,
so a caller physically cannot launder an agent reading into an authored (or any other)
class: the same structural move as DerivedStore.add, SensedObservation.to_row, and
CodeObservation.to_row.
This plan (B-b) licenses exactly ONE stream: stream == 'cost' (build-plan cost:
frontmatter blocks — estimate at the plan's landing commit, actual at its seal commit).
Additional streams re-enter per-stream with their own small plans (note PD-a) — this store's
schema is stream-generic (the stream column), but nothing in THIS plan projects anything
else.
Mirror-opacity (§2.6): observed is not in MIRROR_READABLE, so a MirrorView refuses
these rows by construction and the self-model never reads them. The only typed container
is ObservedView (all_rows returns view-compatible dict rows).
HONESTY NOTE (finding-0020 class, code-store precedent): no consumer reads these rows yet (bp-019 non-goal §9 — "any consumer (nothing reads ObservedView here)"). This store is write-side only; the live first projection over history is bp-020's, deliberately deferred.
Engine: SQLite (plan Q6) — an identity-keyed append-style ledger, the runs/versions/
snapshots convention, not the DuckDB telemetry lane. Reset semantics (plan §6(h)): this
store is CORPUS-side (the observed stratum) and joins reset_targets() — wiped with the
corpus, unlike the snapshot LEDGER pattern. That corpus-side call covers current READINGS
only, which rebuild by re-projection from git; the worldview HISTORY — generations
superseded when a bumped interpreter re-projects — lives in the ledger-class, reset-guarded
sidecar (core/stores/observation_history.py, discriminator store='agent';
dn-self-sensing §2.5 ruling).
MissingHistoryError
Bases: RuntimeError
A superseding write arrived with history=None — refusing to silently drop a
worldview generation (the bp-018 §6(c) archive-then-replace discipline, verbatim).
AgentObservation
dataclass
One fact reading of one commit (note §2.3, verbatim columns).
Deliberately has NO provenance field: like CodeObservation/SensedObservation, the
class label is minted at to_row() with no parameter — the wire payload (to_dict)
carries nothing a caller could forge a class with.
commit_sha
instance-attribute
stream
instance-attribute
subject_id
instance-attribute
key
instance-attribute
payload
instance-attribute
from_dict(d)
classmethod
Parse one handoff wire payload (the seam's inbound half, the sibling shape).
to_dict()
The handoff wire payload — schema fields only, NO provenance (nothing to forge).
to_row()
The observed-tier row. Provenance is HARDCODED — there is no parameter, so no
caller can launder an agent reading into another class (the CodeObservation.to_row
move, verbatim). ObservedView admits these rows; MirrorView refuses them (§2.6).
AgentObservationStore
dataclass
The observed stratum's agent-observation table. Writes observed UNCONDITIONALLY —
no method on this class accepts a provenance value (Item 5 falsifier, ruled out by
construction and pinned by test).
path
instance-attribute
add_batch(observations, *, interpreter, history=None)
Land one projection batch under a declared interpreter version. Returns (new rows, superseded rows). Three cases per identity key (§6(b)):
- no existing row → INSERT (a new reading);
- existing row, SAME interpreter → no-op (idempotence — the B-b falsifier, inverted);
- existing row, DIFFERENT interpreter → archive the existing generation to
history(store='agent'), then replace: versioned supersession (§2.2), and the main table stays exactly latest-per-identity by construction. A superseding write withhistory=NoneraisesMissingHistoryError— a generation is never silently dropped.
all_rows(*, provenances=None)
Full scan, optionally restricted to provenance classes (the RowSource shape).
Every stored row is observed, so a filter containing OBSERVED sees ALL rows and
any filter excluding it sees NONE — there is no third case.
rows_for(commit_sha)
count()
is_projected(commit_sha, interpreter=None)
Was commit_sha projected under interpreter? With interpreter=None: under
ANY interpreter (the any-generation read, kept for parity with the code store's
finding-0047 shape). The sensor always passes its version.
mark_projected(commit_sha, content_hash, interpreter)
Record that φ_self-at-interpreter projected commit_sha. INSERT OR IGNORE
on (commit_sha, interpreter): first mark per worldview wins, and a NEW interpreter's
mark is a NEW row — the versioned supersession §2.2 promises.
chain_for(commit_sha, stream, subject_id, key, history)
The queryable worldview chain at one identity key (§2.4): archived
generations + the current row, oldest → current. Each element carries its own
interpreter — the second orthogonal history (across interpreter at fixed
identity), readable without touching default reads.
close()
batch_content_hash(observations)
Content hash of a projection batch — sha256 over the canonical (sorted-key, sorted-row)
JSON of the wire payloads. Deterministic (§2.2): re-running φ_self over the same commit
yields the same hash, so the project_agent_observations attestation is content-addressed.
Sort key: (commit_sha, stream, subject_id, key) — the identity key, module-local (this
store's own copy; §11 parked decision — a fourth stream re-decides the shared-helper
question).
open_agent_observation_store(config=None)
The open_* helper: data/agent_observations.sqlite (plan §6(b) — the sibling-store
convention beside code_observations, no dedicated cfg path; registered in
reset_targets() as a corpus-side wipe target, plan §6(h)).
authored_supersession
Owner-declared authored-historical supersession store (the-edge-model.md §4a; PD11).
A K₀↔K₀ supersession — "authored document B supersedes authored document A" — is a THIRD
dispositional edge type, distinct from note-version supersedes (versions of ONE doc_id,
core/stores/versions.py) and claim supersede (dialogue, core/recursion_ops.py).
It connects two documents, carries no warrant, mints no derived alternative; both endpoints
stay authored.
Ungated only because it is owner-declared — enforced HERE, structurally. The "no verdict gate"
property rests on it being the owner's hand. A supersession between two authored notes CAN
be machine-derived (Item 10's s(C,D) over authored E_geom; the curator finder), so
ungated-ness follows the AUTHORITY, not the edge type. This store admits ONLY an owner-declared
write: record() requires an OwnerDeclaration and verifies it at the boundary, so fail-closed
survives a careless future caller (capability-dissolution, the-sacred-boundary.md §3 — the
machine-write capability is removed, not guarded with a forgeable flag). A machine-inferred
authored↔authored supersession is a dreamer-proposed candidate for the blessing gate
(supersession-lifecycle.md §3), never a row here.
Append-only, keyed on the two authored digests; superseded() is the active-projection filter
(the superseded digest leaves the active view, as ClaimOpStore.superseded did — but the write is
owner-authorized). Ordering is the append at timestamp, never edge topology. Zone A, no network.
MachineAuthorityRefused
Bases: PermissionError
A write to the authored-historical store carried no valid OWNER authority — refused at the store's own boundary (fail-closed, STRUCTURAL). This is the guarantee the owner-declared-only design exists for: a machine/model/scheduler/dreamer caller is rejected HERE, so the rule holds even if a future refactor routes a machine call through what used to be an owner-only path.
OwnerDeclaration
dataclass
Capability proving a supersession is OWNER-ASSERTED (a founding manifest / an owner CLI), not
machine-derived. Construction-guarded: a direct OwnerDeclaration() raises, because only
owner_declaration() passes the module-private token. Holding a store reference is thus not
enough to write it — a caller must present owner authority the store can verify.
AuthoredSupersession
dataclass
superseded
instance-attribute
superseding
instance-attribute
at
instance-attribute
note = ''
class-attribute
instance-attribute
AuthoredSupersessionStore
dataclass
path
instance-attribute
record(superseded, superseding, *, declaration, note='')
Append an OWNER-DECLARED authored-historical supersession (superseding replaces
superseded in the active projection). Idempotent on the pair (INSERT OR REPLACE).
Fail-closed, STRUCTURAL: declaration must be a valid OwnerDeclaration (owner authority),
VERIFIED here at the store's own boundary — None, a forged object, or anything a machine
caller could fabricate is REFUSED (MachineAuthorityRefused). The store checks; it does not
rely on "no machine path calls it". A machine-inferred supersession belongs in the blessing
gate as a dreamer-proposed candidate, never here.
superseded()
Every superseded digest — the active-projection filter (a consumer excludes these
from the active view; the superseded note lives on in history). Same role as
ClaimOpStore.superseded, but every entry here is owner-authorized by construction.
all()
count()
close()
owner_declaration()
Mint an owner-authority token. Call ONLY from an owner-operated entry point (the founding ingest / an owner CLI). Importing this into a model / scheduler / dreamer path is a boundary violation an import-lint should catch (follow-up); the store's boundary check is the primary structural defense regardless.
verify_owner_declaration(declaration)
Raise MachineAuthorityRefused unless declaration is a valid owner-authority token.
The ONE owner-capability check, factored out of record() so a second boundary — the
owner-gated doc_id re-key primitives (versions.migrate_rekey_doc_id,
catalog.migrate_rekey_doc_id; bp-034, §11 ruling 2026-07-14) — reuses this exact structural
verification instead of minting a second owner token. There is ONE owner-capability system-wide
and it lives here. Verifies not just the type (isinstance) but the guarded token identity —
getattr(..., "_token", None) defends against a bypass-constructed
object.__new__(OwnerDeclaration) — so a machine/model/scheduler/dreamer caller is refused at
the store boundary regardless of how the value was produced (fail-closed).
open_authored_supersession_store(config=None)
catalog
Vault catalog — the active/tombstone ledger for incremental ingest (vault-sync task).
The Phase-1 ingest is content-addressed: identical bytes store once (raw is sacred). That
gives dedup for free but says nothing about which source files currently hold which content,
which is exactly what an incremental watcher needs to answer "unchanged?", "changed?",
"deleted?". This SQLite catalog is that map — source_path -> (digest, active) — and the
authority for the tombstone semantics (design-notes/vault-sync-and-capture.md):
- unchanged — the file's current digest equals the recorded one and it is active → no-op.
- changed — a new digest → re-embed; the previous digest's derived rows are dropped iff no other active file still references them.
- deleted —
tombstone()marks the row inactive; derived rows are dropped, raw is kept so a re-add dedups and nothing is lost.
It carries only local bookkeeping (paths, digests) — no note content, no network. All notes
the watcher records are authored-solo (the owner's own writing) — the §1 spectrum split is
now realized, so Provenance.AUTHORED_SOLO is the concrete tag (was the single authored).
Dialogue capture records authored-dialogue and curated ingest records curated through the
same catalog, by passing provenance= to record.
CatalogEntry
dataclass
source_path
instance-attribute
digest
instance-attribute
title
instance-attribute
active
instance-attribute
provenance = Provenance.AUTHORED_SOLO.value
class-attribute
instance-attribute
VaultCatalog
dataclass
path
instance-attribute
get(source_path)
record(source_path, digest, title, *, provenance=Provenance.AUTHORED_SOLO, doc_id=None)
Upsert a file as active at digest (re-adding a tombstoned file reactivates it).
doc_id binds the note's stable identity (bp-031 Item 2): pass an explicit id (an existing
id::, or a renamed predecessor's carried id) to bind it; omit it and a NEW row defaults
doc_id := source_path (identity == path) while a re-record PRESERVES the stored doc_id.
An explicit doc_id DOES overwrite on conflict — but sync only passes one at first bind,
never to switch a historied note's identity (the re-key is owner-run bp-034).
doc_id_for(source_path)
The stable doc_id bound to this source_path — the identity the version store keys on.
Equals source_path (identity == path) until a mechanism (bp-031 Item 2) diverges it. An
unknown path resolves to itself, so a first-ingest resolve is well-defined even before the
catalog row exists (the caller records the row, then resolves).
tombstone(source_path)
Mark a file inactive (deleted from the vault). Returns the digest it held, or None if it was unknown. The raw blob is intentionally NOT touched — raw is sacred; true deletion is the separate, owner-gated purge (core/ingest/purge.py).
active_refs(digest)
How many ACTIVE files currently hold this content. Derived rows for a digest may be dropped only when this is 0 (so dedup-shared content isn't pulled out from under a still-present file).
active_paths()
active_entries()
relabel_provenance(old, new)
Rewrite every entry's provenance from old to new. Returns rows changed.
The catalog-side half of the §1 spectrum-split migration (relabel legacy 'authored'
→ 'authored-solo'). Same-trust-tier relabel, idempotent (a second run matches no
old rows).
migrate_rekey_doc_id(source_path, new_doc_id, *, declaration)
Owner-gated identity migration (the catalog twin of versions.migrate_rekey_doc_id;
bp-034, §11 ruling 2026-07-14): rebind a note's resolved doc_id to new_doc_id, keyed by
the UNCHANGED PK source_path (the in-place id:: mint never moves the path). Same owner-
authority gate — this marks the write as a deliberate migration, not the runtime record
path, even though the catalog is not append-only.
Fail-closed. doc_id carries NO unique index, so this method is the ONLY guard against a
resolution-level lineage merge: it REFUSES if any OTHER row already resolves to new_doc_id
(guardrail 5). Idempotent — a row already at new_doc_id (a re-run) is a no-op; an unknown
source_path matches 0 rows and is a silent no-op.
remove(source_path)
Delete the catalog row entirely (used by the gated purge after raw removal).
paths_for_digest(digest)
remove_digest(digest)
Delete every catalog row for a digest (the gated purge removes only tombstoned
content — callers must verify active_refs(digest) == 0 first). Returns rows removed.
close()
causal_edges
The C-fiber causal-edge store — the integrator's proven output (bp-071 Item 1).
One row = one proven cross-strata edge: a DIALOGUE L1 action → the endpoint it produced.
Two species (finding-0111): a commit event resolves (by abbreviated-sha prefix match) to a
ledger commit — dst_type='commit', pair_cut_sha=the full sha (the (digest, sha) consistent
cut); a file_edit/build_plan/finding/design_note event mints its endpoint directly (the
Write tool record is the proof) — dst_type='file'|'doc', pair_cut_sha='' (a working-tree
write has no commit anchor). The endpoints are NOT fanned out from a commit's file set: the
commit ledger stores the full tree, not the diff, so fanning would be an inferred edge (the
falsifier). Composing action→commit with commit→file is Δ's ComposedGraph job (C≠D composition).
Sibling-store convention (chat_events.py/reference_edges.py): SQLite, no dedicated cfg path —
data/causal_edges.sqlite beside the L1 store. A corpus-side derived layer (a pure function of
retained raw + the ledger), so it joins reset_targets() and rebuilds by re-integration.
EDGE_KINDS = frozenset({'C', 'F'})
module-attribute
DST_TYPES = frozenset({'commit', 'file', 'doc'})
module-attribute
CausalEdge
dataclass
One proven C-fiber edge: a DIALOGUE action → its produced endpoint. dst is STRUCTURAL
(sha | path | artifact-id). The witness is (witness_digest, witness_turn) plus the L1
event's own (kind, ref); the pair-cut is (witness_digest, pair_cut_sha) — a full sha for
a commit edge, '' for a working-tree write (no cross-clock cut).
edge_id
instance-attribute
session_id
instance-attribute
event_order
instance-attribute
kind
instance-attribute
dst_type
instance-attribute
dst
instance-attribute
witness_digest
instance-attribute
witness_turn
instance-attribute
pair_cut_sha = ''
class-attribute
instance-attribute
mint(*, session_id, event_order, kind, dst_type, dst, witness_digest, witness_turn, pair_cut_sha='')
classmethod
Construct with the content-derived identity; validates the closed vocabularies at the boundary (a typo'd fiber/dst_type is unrepresentable in the store).
CausalEdgeStore
dataclass
The C-fiber edge table. replace_session is the only mutator — it wipes and rewrites one
session's edges atomically (a grown session re-integrates cleanly) and records the L1 digest
they were minted from, so digest_for drives incremental re-integration (the landed L1
pattern). The sole writer is the model-free integrator (core/integrator.py).
path
instance-attribute
replace_session(session_id, edges, transcript_digest)
Replace one session's edges wholesale (the resolver is deterministic, so a re-run over
a grown transcript rewrites the full set) and record the digest they came from. Returns
the number of edges written. Every edge must belong to session_id — a mismatch would
orphan a row past the keyed DELETE, so it fails loudly rather than silently.
digest_for(session_id)
The L1 digest this session's edges were last minted from — None if never integrated. The incrementality signal: unchanged digest ⇒ skip re-integration (no churn).
edges_for(session_id)
One session's edges, in event order.
all_edges()
count()
sessions_with_edges()
close()
open_causal_edge_store(config=None)
data/causal_edges.sqlite beside the L1 store (the sibling-store convention; no dedicated
cfg path). Registered in reset_targets() as a corpus-side wipe target — rebuilt by
re-integration from the immutable rawstore-backed L1 + the commit ledger.
chat_events
The L1 action-log store for the dialogue sensor (bp-069 Item 3).
One row = one typed ACTION in one Claude Code session, at (session_id, ord) grain: the actor
(owner|agent), the kind (prompt|response|commit|file_edit|build_plan|finding|design_note|ratify|
tool_use), a STRUCTURAL ref (sha|path|artifact-id|turn_index — never verbatim content), and the
turn_index backpointer into the L0 chatlog (the projection fiber). The projector
(core/chat_events.py) is the sole writer; it reads the session's OWN raw transcript via the
chatlog's transcript_digest and re-extracts iff that digest changed (replace_session).
Sibling-store convention (code_observations.py/chatlog.py): SQLite, no dedicated cfg path —
data/chat_events.sqlite beside the chatlog. A corpus-side derived layer, so it joins
reset_targets() (launcher) as a wipe target, rebuilt by re-projection from the immutable rawstore.
ChatEventStore
dataclass
The dialogue stratum's L1 action-log table. replace_session is the only mutator — it wipes
and rewrites one session's log atomically (a grown session re-extracts cleanly), and records the
transcript_digest it was extracted from so digest_for drives incremental re-projection.
path
instance-attribute
replace_session(session_id, events, transcript_digest)
Replace one session's action log wholesale (the extractor is deterministic, so a re-run over a grown transcript rewrites the full ordered log) and record the digest it came from. Returns the number of events written.
digest_for(session_id)
The transcript digest this session's log was last extracted from — None if never projected. The incrementality signal: unchanged digest ⇒ skip re-extraction (no churn).
events_for(session_id)
One session's action log, in order (ord).
count()
sessions()
close()
open_chat_event_store(config=None)
data/chat_events.sqlite beside the chatlog (the sibling-store convention; no dedicated cfg
path). Registered in reset_targets() as a corpus-side wipe target — rebuilt by re-projection
from the immutable rawstore (the orchestrator's post-merge step).
chatlog
OBSERVED-only store for chat utterances (ratified dn-chat-sensor CS-2/CS-3).
One row = one utterance-grain reading of one Claude Code session transcript: the owner's
and the agent's natural-language prose, extracted at (session_id, turn_index, speaker,
text) grain with tool exhaust structurally stripped (the sensor ops/chat_sensor.py is
the sole interpreter φ_chat — deterministic, model-free, sole path in). Every row lands
wearing observed — there is deliberately NO provenance parameter on any API surface, so
a caller physically cannot launder a chat reading into an authored (or any other) class:
the SAME structural move as core/stores/code_observations.py (CodeObservation.to_row),
DerivedStore.add, and core/sensing.py's SensedObservation.to_row. In particular
provenance is NEVER derived from speaker: owner utterances and agent utterances both land
observed (CS-2 — decided against auto-classing owner CLI prose as AUTHORED_DIALOGUE;
CLI sessions mix registers, and machine authorship-inference is exactly what the taxonomy
forbids, core/provenance.py:74-77). /capture remains the one working promotion path;
the typed promote(x: Derived[T], cap: OwnerVerdict) -> Authored[T] seam
(core/provenance.py:145) is registered here as a consumer and depended on by nothing.
Mirror-opacity (CS-2): observed ∉ MIRROR_READABLE (core/provenance.py:78-80), so a
MirrorView (core/mirror.py:66) refuses these rows by construction — the self-model
never reads them, and the proof extends to chat rows without touching the view. The only
typed read container is ObservedView (core/sensing.py:190); all_rows returns
view-compatible dict rows, so the ratified cross-strata correlator (CS-5, the sole future
reader — its own scoped grant) inherits "I read exhaust, never ground truth".
CS-1 (verbatim-first): the sensor stores each closed transcript byte-verbatim in the
immutable rawstore (core/stores/rawstore.py) BEFORE any extraction; every row carries the
transcript_digest it is recoverable from. This store is the DERIVED, regenerable layer
over those bytes — the same two-layer shape as ingest (raw → derived), no new pattern.
Engine: SQLite — an identity-keyed append-style ledger, the sibling-store convention
(code_observations.py), not the DuckDB telemetry lane. Reset semantics (Q6): this store
is CORPUS-side (the observed stratum) and joins reset_targets() (ops/lifecycle/
launcher.py) as a wipe target — wiped with the corpus, rebuilt by re-ingest from the
IMMUTABLE rawstore (which is NOT a reset target — raw is sacred). [cross-ref: extension,
dn-chat-sensor; the launcher registration is the orchestrator's post-merge step.]
Spine-invisible in v1 (dn-chat-sensor §3): this plan writes NO chain and registers NO
stratum. bp-064 (clock wiring, CS-4) joins the store to the spine as a g1-chained store
(chain-key = session_id, position = turn_index) with session-close cut certificates.
ts_bookmark is METADATA ONLY — order is turn index, never wall time (Law C4; CS-4).
INTERPRETER_VERSION = '1.0.0'
module-attribute
SPEAKERS = ('owner', 'agent')
module-attribute
ChatUtterance
dataclass
One utterance-grain reading of one session transcript (CS-3 grain, verbatim columns).
Deliberately has NO provenance field: like CodeObservation/SensedObservation, the
class label is minted at to_row() with no parameter — the wire payload carries nothing
a caller could forge a class with, and speaker is metadata, never a provenance input.
session_id
instance-attribute
turn_index
instance-attribute
speaker
instance-attribute
text
instance-attribute
transcript_digest
instance-attribute
ts_bookmark = ''
class-attribute
instance-attribute
to_dict()
The wire payload — schema fields only, NO provenance (nothing to forge).
to_row()
The observed-tier row. Provenance is HARDCODED — there is no parameter, so no
caller can launder a chat reading into another class, and speaker is NEVER read to
decide it (CS-2 — the never-automatic rule). ObservedView admits these rows;
MirrorView refuses them (mirror-opacity).
ChatlogStore
dataclass
The observed stratum's chat-utterance table. Writes observed UNCONDITIONALLY — no
method on this class accepts a provenance value (the item-1 falsifier, ruled out by
construction and pinned by test), and none derives provenance from speaker. Identity
key (session_id, turn_index): a re-ingest of a frozen session is idempotent.
path
instance-attribute
add_batch(utterances)
Land utterances, returning the count of NEW rows. Idempotent by the identity key
(session_id, turn_index): a re-add of an already-stored utterance is a no-op (an
already-frozen session re-ingested writes 0). INSERT OR IGNORE — first write per
identity wins; a grown open session is out of v1 (Q4 — a session is frozen once
ingested).
all_rows(*, provenances=None)
Full scan, optionally restricted to provenance classes (the RowSource shape).
Every stored row is observed, so a filter containing OBSERVED sees ALL rows and any
filter excluding it sees NONE — there is no third case. Ordered by the chain grain
(session_id, turn_index) for a stable read.
rows_for(session_id)
One session's utterances, in chain order (turn_index).
count()
sessions()
The distinct session ids present — the sensor's idempotency read (a session already ingested is frozen, Q4).
close()
open_chatlog_store(config=None)
The open_* helper: data/chatlog.sqlite (the sibling-store convention beside
code_observations, no dedicated cfg path; registered in reset_targets() as a
corpus-side wipe target — the orchestrator's post-merge step, Q6).
claim_ops
The claim-operations persistence — ClaimOpStore + apply_operations (bp-089, S1′).
The inner-ring promotion (dn-inner-outer-core §2.6b) moves the sqlite-backed ClaimOpStore and the
DerivedStore-consuming application logic (apply_operations, stale_closure) OFF
core/recursion_ops.py — so that module keeps only the pure dialogue-operations vocabulary and
becomes inner. Item 3's DRY audit (finding-0144) confirmed NO existing core/stores/* covers
claim_ops: authored_supersession is a distinct owner-declared K₀↔K₀ edge type; versions is
note-version supersession. A new store is genuinely needed — this one.
Claim-supersede is a DISTINCT relation in a DISTINCT store from version-supersedes (§4A C3):
warrant-bearing reasoning, never a note edit and never a semantic ± edge. Byte-identical behavior:
the store DDL, the record/query methods, and the apply_operations/stale_closure bodies are
relocated verbatim from recursion_ops.py; the pure vocabulary (OpKind, ClaimOp, Supersede,
…, _op_id, _utcnow) is imported from its inner home. Zone A: reads/writes the claim-ops sqlite +
reads/writes the DerivedStore; no model, no network.
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()
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)
code_observations
OBSERVED-only store for code observations (ratified code-observation-projection.md B-b).
One row = one symbol-grain reading of one commit: the repo is an instrument, commits are
its readings, and the code sensor (ops/code_sensor.py) is the sole interpreter φ_code
(§2.2 — deterministic, transform-attributed, sole path in). Observations enter through the
CodeSensingHandoff seam (core/sensing.py, the sensing-seam sibling) and land here
wearing observed — there is deliberately NO provenance parameter on any API surface, so
a caller physically cannot launder a code reading into an authored (or any other) class:
the same structural move as DerivedStore.add and SensedObservation.to_row.
Mirror-opacity (§2.6): observed is not in MIRROR_READABLE, so a MirrorView refuses
these rows by construction and the self-model never reads them. The only typed container
is ObservedView (all_rows returns view-compatible dict rows).
HONESTY NOTE (finding-0020 class): the daemon (Ouroboros) does NOT consume these rows yet.
This store is write-side only — like the dispositional stores, the substrate lands before
its consumer (the Track-D correlator / detangling instruments read ObservedView when they
arrive). references_out is carried as a typed JSON column but is emitted EMPTY by B-b;
the deterministic reference extractor (Lane 1, V4-seeded patterns) is B-c / bp-013.
Engine: SQLite (plan Q2) — an identity-keyed append-style ledger, the runs/versions/
snapshots convention, not the DuckDB telemetry lane. Reset semantics (plan Q4): this store
is CORPUS-side (the observed stratum) and joins reset_targets() — wiped with the corpus,
unlike the snapshot LEDGER (build history, reset-guarded). [cross-ref: extension, bp-018]
That corpus-side call covers the current READINGS only, which rebuild by re-projection
from git; the worldview HISTORY — generations superseded when a bumped interpreter
re-projects — lives in the ledger-class, reset-guarded sidecar
(core/stores/observation_history.py; dn-self-sensing §2.5 ruling).
KINDS = ('module', 'class', 'function', 'async_function')
module-attribute
MissingHistoryError
Bases: RuntimeError
A superseding write arrived with history=None — refusing to silently drop a
worldview generation (bp-018 §6(c): archive-then-replace, never replace-and-forget).
CodeObservation
dataclass
One symbol-grain reading of one commit (note §2.3, verbatim columns).
Deliberately has NO provenance field: like SensedObservation, the class label is
minted at to_row() with no parameter — the wire payload (to_dict) carries nothing
a caller could forge a class with.
commit_sha
instance-attribute
path
instance-attribute
qualname
instance-attribute
kind
instance-attribute
signature = ''
class-attribute
instance-attribute
docstring = ''
class-attribute
instance-attribute
references_out = ()
class-attribute
instance-attribute
from_dict(d)
classmethod
Parse one handoff wire payload (the seam's inbound half, SensedObservation shape).
to_dict()
The handoff wire payload — schema fields only, NO provenance (nothing to forge).
to_row()
The observed-tier row. Provenance is HARDCODED — there is no parameter, so no
caller can launder a code reading into another class (the SensedObservation.to_row
move, verbatim). ObservedView admits these rows; MirrorView refuses them (§2.6).
CodeObservationStore
dataclass
The observed stratum's code-observation table. Writes observed UNCONDITIONALLY —
no method on this class accepts a provenance value (Item 3 falsifier, ruled out by
construction and pinned by test).
path
instance-attribute
add_batch(observations, *, interpreter, history=None)
Land one projection batch under a declared interpreter version. Returns (new rows, superseded rows). Three cases per identity key (§6(c)):
- no existing row → INSERT (a new reading);
- existing row, SAME interpreter → no-op (idempotence unchanged — the B-b falsifier, inverted);
- existing row, DIFFERENT interpreter → archive the existing generation to
history(store='code'), then replace: versioned supersession (§2.2), and the main table stays exactly latest-per-identity by construction. A superseding write withhistory=NoneraisesMissingHistoryError— a generation is never silently dropped.
all_rows(*, provenances=None)
Full scan, optionally restricted to provenance classes (the RowSource shape).
Every stored row is observed, so a filter containing OBSERVED sees ALL rows and
any filter excluding it sees NONE — there is no third case.
rows_for(commit_sha)
count()
is_projected(commit_sha, interpreter=None)
Was commit_sha projected under interpreter? With interpreter=None:
under ANY interpreter — the pre-bp-018 read, kept for callers asking only
"was this sha ever projected?" (finding-0047: the §6(c) pin required the
argument; one out-of-scope caller wants exactly the any-generation semantic,
so the default carries it honestly). The sensor always passes its version —
Item 4's bump→re-projects test pins that end-to-end.
mark_projected(commit_sha, content_hash, interpreter)
Record that φ_code-at-interpreter projected commit_sha. INSERT OR IGNORE
on (commit_sha, interpreter): first mark per worldview wins, and a NEW
interpreter's mark is a NEW row — the versioned supersession §2.2 promised,
mechanical since bp-018 (this comment described intent only, pre-B-a).
chain_for(commit_sha, path, qualname, history)
The queryable worldview chain at one identity key (§2.4): archived
generations + the current row, oldest → current. Each element carries its own
interpreter — the second orthogonal history (across interpreter at fixed
identity), readable without touching default reads.
close()
batch_content_hash(observations)
Content hash of a projection batch — sha256 over the canonical (sorted-key, sorted-row)
JSON of the wire payloads. Deterministic (§2.2): re-running φ_code over the same commit
yields the same hash, so the project_observations attestation is content-addressed.
open_code_observation_store(config=None)
The open_* helper: data/code_observations.sqlite (plan Q2 — the sibling-store
convention beside derived_store, no dedicated cfg path; registered in
reset_targets() as a corpus-side wipe target, plan Q4).
curated_store
The curated literature vector store (dn-external-grounding §2.2/§2.4).
A SECOND VectorStore instance, physically separate from the authored-mirror vector_store,
holding the embedded open-access full text of curated references (the EMBED tail, bp-029).
It reuses the proven LanceDB VectorStore unchanged — same schema, same embedder/dimension —
at a DISTINCT path (cfg.paths.curated_store, default data/research_curated.lance).
Two invariants are load-bearing and both hold STRUCTURALLY here, not by convention:
- Never pollute the mirror. Curated rows carry
provenance="curated"— a class that is deliberately excluded fromMIRROR_READABLE(core/provenance.py), so a mirror/dreaming read (provenances=MIRROR_READABLE) cannot surface curated content. And the store is a separate file from the mirror, so objective-about-the-world text never lands in subjective-about-owner space even by accident. - Inv 11 (the corpus never transits a third party; full text never enters git). The path
lives under
data/(gitignored) with a*.lance/suffix (also gitignored) — the full source text is never committed and never egresses; the sealed core reasons over it offline.
This module is deliberately thin: it does NOT edit or subclass VectorStore (if the base store
needed a change, that is a spec-defect finding, not an edit here — bp-029 §5). It is only the
factory that aims the proven store at the curated path.
open_curated_store(config=None)
Open the curated-literature store at cfg.paths.curated_store (a separate LanceDB).
Mirrors open_vector_store but for the curated path; the embedding dimension is shared
(the same local embedder embeds both corpora — §8 derived layer).
derived
Derived-artifact store for the INTERPRETED layer (BUILD-SPEC §8).
The interpreted layer is what the system inferred — dreams (thematic synthesis) and
curator findings (near-duplicate / prune / contradiction candidates). Per §8 it is kept
SEPARATE and PROVENANCE-MARKED from the owner's authored ground truth: this store holds
INTERPRETED only and exposes NO way to write any other provenance — so the derived layer
can never masquerade as authored ground truth. That is the structural form of "explicit vs
interpreted — separate, provenance-marked layers"; it is not an honor-system check.
Everything here is regenerable: reset() drops it and a fresh dreaming/curation run
rebuilds it from the (immutable) corpus. Artifact ids are content-derived, so re-running a
cron pass is idempotent (INSERT OR REPLACE) rather than accumulating duplicates.
DREAM = 'dream'
module-attribute
FINDING = 'finding'
module-attribute
DREAM_LOG = 'dream_log'
module-attribute
DERIVES = 'derives'
module-attribute
DerivationCycleError
Bases: ValueError
Inserting an artifact would create a cycle in the derivation DAG (Invariant 10).
Confidence decay c ≤ γ^d·g is only well-defined on an ACYCLIC graph with authored
leaves — a chain that closes on itself has unbounded (or undefined) depth, the formal
shape of the rumination loop the recursion bound exists to tame. So a cycle is refused at
insert time, structurally, rather than detected later.
Artifact
dataclass
id
instance-attribute
kind
instance-attribute
subkind
instance-attribute
provenance
instance-attribute
summary
instance-attribute
subjects
instance-attribute
data
instance-attribute
created_at
instance-attribute
derived_from = ()
class-attribute
instance-attribute
attestation_id = None
class-attribute
instance-attribute
Hyperedge
dataclass
One derives B-arc of the derivation hypergraph ℋ (companion III §1.3): the tail set
supp(κ) jointly entails the single head κ. The typed, normalized form of an artifact's
derived_from — named for what it is. Today every head-set has size 1.
edge_id
instance-attribute
head
instance-attribute
tails
instance-attribute
rel_type = DERIVES
class-attribute
instance-attribute
DerivedStore
dataclass
path
instance-attribute
add(*, kind, summary, subjects, data=None, subkind=None, derived_from=None, attestation_id=None)
Store one INTERPRETED artifact. There is deliberately NO provenance parameter:
the derived store writes INTERPRETED and nothing else (§8 firewall, structural).
derived_from records the refs this artifact was built from (gap G2): authored note
digests (leaves) and/or other artifact ids. The edge set is checked for acyclicity
BEFORE insert — a cycle is refused (DerivationCycleError), so the derivation DAG is
always acyclic and depth d(κ) is computable (Invariant 10).
attestation_id links this record to the signed attestation that produced it (the
runtime proof layer, attestation-layer.md §5); None when written without an attestor.
is_artifact(ref)
True if ref is an interpreted (DERIVED) artifact id; False if it is an authored leaf
digest (external, depth 0). The public authored-vs-derived predicate for a grounding
decision — e.g. a supersede may ground a revision on an authored C (bedrock, g=1) but
never on a derived C (which decays / is superseded without a verdict); see
core.kernel.recursion_ops.apply_operations.
depth(artifact_id)
Derivation depth d(κ): 0 for an authored leaf; for an interpreted artifact, 1 + the max depth of its interpreted parents (authored-leaf parents count 0). An artifact with no recorded scaffolding is depth 1 (interpreted, minimally one step from ground). Well-defined because the graph is acyclic by construction.
leaf_refs(artifact_id)
The support closure's LEAVES — every ref reachable from artifact_id that is not
itself an artifact (i.e. authored note digests). A caller checks these are authored
(Invariant 10: 'every leaf of the support-closure is authored').
hyperedges()
The derivation hypergraph ℋ as typed B-arcs (the normalized form of every artifact's
derived_from). What the reasoning complex (family 5, core/complex/) consumes.
tails_of(head)
The tail set supp(κ) of artifact head read from the junction — equals, as a set, its
derived_from (the invariant _write_hyperedge maintains).
all(*, kind=None, subkind=None)
count(*, kind=None)
reset()
Drop all derived artifacts and their hyperedges. Interpreted data is regenerable (§8): a fresh dreaming/curation run rebuilds it from the immutable corpus.
close()
artifact_id(kind, subkind, subjects)
Public, stable artifact id for a (kind, subkind, subjects) triple — same value add()
will assign. An emitter precomputes it so an attestation can record this record as its
output BEFORE the record is written, then add(..., attestation_id=...) links back.
open_derived_store(config=None)
edges
The typed/signed edge store — the fiber ε(e) = (t, w, s, τ) (companion III §1.2; Prompt H1).
A binary typed edge carries a relation type, a strength w ≥ 0, and a polarity s ∈ {+1, −1}
(EdgeSign — the R1 enum). This is the persistent home for edges that are not recomputable from
embeddings (BUILD §1.1): explicit contradictions/links a detector or the owner asserts. Similarity
edges are recomputed each pass from the embeddings and are NOT stored here (that would duplicate a
regenerable signal); this table stores the polarity/relations the cosine graph cannot carry —
chiefly contradiction, the input to balance.py.
Derivation (a B-arc, tail set → head) is a hyperedge, stored in the DerivedStore junction, not
here; the two are deliberately distinct structures (companion III §1.3). Zone A, no network.
SIMILAR = 'similar'
module-attribute
SUPPORTS = 'supports'
module-attribute
CONTRADICTS = 'contradicts'
module-attribute
CONTEXTUALIZES = 'contextualizes'
module-attribute
Edge
dataclass
One typed/signed binary edge — the fiber (w, s, rel_type, τ) over the pair (u, v).
edge_id
instance-attribute
u
instance-attribute
v
instance-attribute
w
instance-attribute
sign
instance-attribute
rel_type
instance-attribute
created_at
instance-attribute
provenance
instance-attribute
EdgeStore
dataclass
path
instance-attribute
add(u, v, *, sign, rel_type, w=1.0, provenance='interpreted', created_at=None)
Assert a typed/signed edge. sign is the EdgeSign enum (±1); w ≥ 0 is the strength.
Idempotent on (u, v, rel_type) — re-asserting replaces (INSERT OR REPLACE).
all(*, rel_type=None)
count()
reset()
Drop all edges. Similarity edges are regenerable; asserted edges are re-derivable by the detector/owner that created them.
delete_rel_type(rel_type)
Delete every edge of a given rel_type; returns rows removed. The migration for build
plan Item 6: retire any misplaced supersedes rows a prior build wrote here, now that
note-version history lives in the dedicated VersionStore the balance math cannot read.
close()
open_edge_store(config=None)
memberships
The membership store — occupancy as a first-class relation (dn-vector-membership-store, bp-152).
A point is a point: geometry, assertion-free. Meaning lives in membership — who contains it —
and history in lineage — which occupancy chains pass through it. The vector plane
(core/stores/vectorstore.py) holds ONE row per distinct idea-atom (layer, content_hash),
append-only; this store holds everything that used to be duplicated onto those rows once per
version:
- A version is a fiber.
M(path, blob_sha)— the complete projection of one file version. Landing a version writes its fiber; re-landing the same blob writes nothing new, because derivation is a pure function of(path, source)so the fiber is equal by construction. - A re-land is idempotent BECAUSE reconciliation converges — never because the call
short-circuits. This is the C1 lesson the repo has already learned once
(
core/stores/versions.py:22-27: content-keyed identity cannot hold a revert). On A → B → A the fiber for blob A already EXISTS withcurrent=false; a lander that returns early on "fiber exists" leaves B current, which is silent D3 corruption with nothing to see. Soreconcile_currencyruns on every land, including the ones that wrote no row. current_anyis a cache, this store is the truth (D8/R3). The lancecurrentcolumn is the cheap ANN prefilter; membership rows are what it caches, andrepair_current_anyrebuilds it from them. Write order is vector inserts FIRST (append-only, an unreferenced atom is harmless dormant geometry), fiber SECOND (one SQLite transaction), currency LAST — every step after the first is re-derivable, so a crash anywhere is repaired by the next land.- Append-only, with ONE removal. No API here deletes a vector except
purge_atom(D5, finding-0164 — owner-gated, privacy outranks lineage), and a purge leaves a RECORDED HOLE: the row is gone and its memberships are tombstoned, never silently dropped.
Lineage is DERIVED here, never stored (PD-3): slot_runs / slot_edges collapse a path's
first-parent blob chain into runs of equal occupants per slot, so a revert reads as 3 runs and 2
edges rather than being flattened away. Chain members are a strict subset of the version set (D4/F3
— a side-branch fiber is a real member of M with no place on any chain), so the edge invariants are
quantified over the chain that is handed in, never over all fibers.
EmbedderIdentity
dataclass
The geometry an atom's stored vector came from — EmbeddingConfig.model + dim.
Embed REUSE (D2 step 2, "insert only the atoms absent from the plane") is only valid within one
embedder, and the owner pinned that explicitly (2026-08-01, issue #27 sub-confirmation 2): an
atom already in the plane carries a vector from whichever embedder landed it, and serving it
beside freshly-embedded atoms mixes two geometries in ONE ANN space — a corruption no
downstream measurement can detect. So atom PRESENCE is keyed to (layer, content_hash) and
this identity; a hit whose embedder differs from the live config is not a hit.
query_instruction is deliberately excluded: it conditions queries, not stored document
vectors, so two configs differing only there share a geometry.
model
instance-attribute
dim
instance-attribute
from_config(config)
classmethod
Membership
dataclass
One occupancy: "atom content_id sits in version (path, blob_sha) at this slot".
The key is (path, blob_sha, layer, chunk_index) — the occupancy's COORDINATES, not its
content. That is the multiset pin (the note's F5): two byte-identical L0b windows in one blob
differ only in chunk_index, and keying on content would silently merge them.
⚑ slot_line_start / slot_line_end are the SLOT's declared extent — where the symbol
lives — and never the atom's text coverage (Amendment A2, issue #34). They coincide for
leaf symbols. For a symbol with nested children the children's lines are carved OUT of the
parent's chunk while the span still reports the parent's full lineno..end_lineno; for the
module shell the span is the ENTIRE FILE by construction. The columns are named for what they
measure precisely so the bad reading loses the vocabulary it was hiding in: a consumer that
wants "where is this symbol" uses the span, and a consumer that wants the atom's content uses
the stored text. Rendering the span and calling it the atom renders, for the shell, the whole
file.
path
instance-attribute
blob_sha
instance-attribute
layer
instance-attribute
chunk_index
instance-attribute
content_id
instance-attribute
slot
instance-attribute
slot_line_start
instance-attribute
slot_line_end
instance-attribute
current = False
class-attribute
instance-attribute
tombstoned = False
class-attribute
instance-attribute
CurrencyReport
dataclass
What D2 step 4 actually changed. Both counts are rows whose flag MOVED, so a converged re-land reports (0, 0) — the honest reading of "idempotent by convergence".
made_current = 0
class-attribute
instance-attribute
superseded = 0
class-attribute
instance-attribute
PurgeReport
dataclass
The recorded hole (D5). A purge that silently no-ops satisfies "never deletes" vacuously, so both halves are counted and a caller can assert the hole EXISTS.
vector_rows_deleted = 0
class-attribute
instance-attribute
memberships_tombstoned = 0
class-attribute
instance-attribute
MembershipStore
dataclass
The occupancy relation, in SQLite beside the vault catalog — outer ring, never imported by the kernel.
Reads are cheap point/range queries over the two indexes; the whole surface is deliberately small, because everything history-shaped (runs, edges, forks, joins) is DERIVED from these rows rather than stored (PD-3: one source of truth for lineage).
path
instance-attribute
known_atoms(content_ids, embedder)
Which of content_ids are already in the plane UNDER THIS EMBEDDER (D2 step 2).
The embedder half is the whole point: an atom landed by another model is present as a row but not usable as a reuse, because reusing it would put two geometries in one ANN space. A suite that only ever exercises one embedder cannot see the difference, which is why the pin carries its own test case.
record_atoms(atoms, embedder)
Record (content_id, layer) pairs as landed under embedder. Returns rows written.
A re-land under a CHANGED embedder overwrites the identity (the atom's vector really was re-embedded), so the ledger always describes the geometry currently in the plane.
ledger_atom_ids()
forget_atom(content_id)
Drop one atom from the ledger — the purge's other half (D5). Never called by anything else: nothing else removes geometry.
write_fiber(rows)
Write a version's fiber (D2 step 3). Returns rows actually inserted.
INSERT OR IGNORE: an existing fiber's rows STAND, because derivation is pure so the
re-derived fiber is equal by construction. Returning 0 is therefore the correct, expected
answer on a re-land — and is precisely why it must NOT be read as "nothing to do": the
caller still owes step 4. One transaction, so a crash leaves the fiber whole or absent,
never half (D8: SQLite is the reference truth).
fiber(path, blob_sha)
One version's complete projection, in chunk_index order — i.e. in the order the pure
derivation emitted the chunks, so a fiber read back IS the version's chunk list.
blobs_of(path)
Every blob this path has a fiber for, oldest-recorded first (by insertion rowid).
fibers()
fiber_sizes()
count()
|M| — the total number of occupancies.
reconcile_currency(path, head_blob_sha)
Set current=1 on exactly the fiber whose blob is the path's HEAD, and current=0 on
the path's every other fiber. NEVER skipped, even when the fiber write was a no-op.
This is the whole reason a re-land is idempotent. The tempting shortcut — "the fiber
already exists, so return" — is the C1 bug in its exact original form: land A, land B, land
A again; A's fiber exists with current=false, the short-circuit skips this call, and the
store is left claiming B is HEAD. Nothing raises, nothing logs, and every default
(current-view) read is now wrong. Convergence, not short-circuiting.
Idempotent by construction: the counts are of rows whose flag actually MOVED, so a second call reports (0, 0) and writes nothing.
n_doc(content_id, *, current_only=True)
Distinct PATHS holding this atom — the document-frequency reading, immune to
within-file repetition. current_any(v) ⇔ n_doc(v, t) > 0 is the carried invariant (R3).
n_occ(content_id, *, current_only=True)
Membership ROWS holding this atom — the multiset reading, where L0b's repeated windows
count. Never conflated with n_doc (the F5 pin: they are different questions).
atom_ids_of_path(path)
currently_held(content_ids)
Which of content_ids have at least one current, un-tombstoned occupancy — i.e. the
set whose current_any should be true. One query, so D2 step 5's crossing arithmetic is
cheap even when a path's history is long.
occupancies(content_id, *, include_superseded=False)
Where this atom lives. One atom may resolve to SEVERAL occupancies — that is the feature, not a defect: a hit natively answers "this idea lives in versions v3–v7 of X and also in Y". Default consumers see current occupancies only (D3).
slot_runs(path, chain)
Per slotted (path, slot), the occupancy chain collapsed into RUNS of equal occupants
along chain (the path's FIRST-PARENT blob sequence, oldest first).
ADJACENT collapse, never distinct-collapse — this is the C1 formulation and the whole
reason §4 was re-keyed on runs: A → B → A gives runs [A, B, A], three runs and two edges,
so a revert stays visible. Collapsing distinct occupants would report one edge and quietly
erase the revert, which is the same failure core/stores/versions.py documents at note
grain. ops/code_lineage.py:151-156 already collapses only adjacent repeats at file grain,
so the two grains agree.
chain is handed in rather than read from this store because chain MEMBERSHIP is not a
membership fact: chains are first-parent while the ledger walks all commits, so a
side-branch fiber is a real member of M that sits on NO chain (D4/F3). Quantifying over
every fiber instead of over chain members is the error this signature makes hard.
Slotted means L0a — the LAYER, not a non-empty name (D1/R4). L0b and L1 carry
qualname='' as built and are membership-only, honestly chainless; the L0a MODULE SHELL
also carries '', but that empty string is a real slot (the shell is a symbol-shaped
region of the file) and it chains like any other. Reading slottedness off slot != ''
would silently drop the shell's lineage — the one slot every file has.
slot_edges(path, chain)
The supersession edges: consecutive-run pairs per slot, so per slot
|edges| = |runs| - 1 by construction. Edge identity is
(path, slot, old_hash -> new_hash, at blob transition); the endpoints differ by
construction because runs collapse equal adjacent occupants.
tombstone_atom(content_id)
Mark every occupancy of a purged atom as a hole. Returns rows tombstoned.
orphan_atom_ids()
Atoms in the plane with NO occupancy at all — dormant geometry from a land that crashed between the vector insert and the fiber write (D8's named window).
The state is deliberately OBSERVABLE rather than merely harmless: "nothing dangles by reference" is true of a store that never wrote anything, so a crash test that cannot see the orphan proves nothing about repair. Nothing here deletes them — the idempotent re-land adopts them at zero embed cost, which is exactly why the write order puts vectors first.
close()
ResolvedHit
dataclass
One ANN hit, resolved (D3). row is the atom — geometry, text, _distance if the hit came
from a search — and occupancies are the places it lives.
⚑ occupancies carry the SLOT's extent, not the atom's text coverage (A2). A consumer
rendering slot_line_start..slot_line_end as "this atom" is wrong, and maximally wrong for the
module shell, whose extent is the whole file: the atom's content is row["text"].
row
instance-attribute
occupancies
instance-attribute
resolve_occupancies(memberships, hits, *, include_superseded=False)
The D3 read-path join: top-k atoms -> their occupancies (path, blob, slot, lines, ...).
Rows that are not shed atom rows (note rows, and any pre-D1 per-version code row) resolve to no occupancy and keep their own coordinates — this join adds a lane, it does not take one away.
repair_current_any(vectors, memberships)
Rebuild the current_any cache from membership truth (D8/R3). Returns (raised, lowered).
current_any is a cache with a rebuild path, and this is the rebuild path: the flag is
recomputed as n_doc(v, t) > 0 over every atom in the plane, and only the DRIFTED rows are
written. Called after a crash, or on cadence as the R3 ratchet.
current_any_drift(vectors, memberships)
Atom ids where the lance flag disagrees with membership truth — the R3 ratchet's reading,
and the current_any(v) ⇔ n_doc(v, t) > 0 invariant as a checkable list (empty ⇒ holds).
purge_atom(vectors, memberships, content_id)
The ONE removal (D5, finding-0164 — owner-gated; privacy outranks lineage).
Delete the vector row, tombstone its memberships, forget its ledger entry: a RECORDED HOLE, never a silent one. Both counts are returned because "no code path deletes a vector" is satisfied vacuously by a purge that does nothing — the criterion is that the hole EXISTS.
open_membership_store(config=None)
The configured membership store — SQLite beside the vault catalog, exactly as
open_version_store sites the version history.
observation_history
The history sidecar for the observation-store family (bp-018, dn-self-sensing §2.4/§2.5).
ONE store for the FAMILY, discriminated by member name (store: 'code' today; 'agent'
lands with bp-019). When a member store replaces a row because a NEW interpreter version
re-projected the same identity key (archive-then-replace, code_observations.add_batch),
the superseded generation lands here verbatim (row_json) — so the chain across
interpreter at a fixed identity key is the fossil record of the changing worldview
(§2.4's second orthogonal history), queryable oldest-first via chain().
Reset semantics split by re-derivability (owner ruling 2026-07-12): current READINGS are corpus-class (wiped with the corpus, rebuilt by re-projection from git); this HISTORY is ledger-class, reset-guarded — a superseded generation was produced by an interpreter that no longer exists at HEAD, so a wipe would be unrecoverable erasure of the epistemology record the stratum exists to keep.
No provenance parameter exists anywhere in this module: rows are archived VERBATIM —
whatever class label the member row carried rides inside row_json, and this store mints
nothing (it is bookkeeping about generations, not a provenance boundary).
Engine: SQLite — an identity-keyed append-only ledger (the runs/versions/snapshots convention), same reasoning as the member stores' Q2.
IDENTITY_KEYS = {'code': ('commit_sha', 'path', 'qualname'), 'agent': ('commit_sha', 'stream', 'subject_id', 'key')}
module-attribute
ObservationHistoryStore
dataclass
APPEND-ONLY: no delete/update method exists on this class — ledger-class is structural, like the no-provenance-parameter move (the test suite sweeps the class surface and pins the absence).
path
instance-attribute
archive(store, rows)
Land superseded generations: each element is (identity-keyed row verbatim, its interpreter, the superseding interpreter). INSERT OR IGNORE on (store, identity_json, interpreter) — re-archiving the same generation (a crashed archive-then-replace re-run) changes NOTHING. Returns the number of NEW rows.
chain(store, identity)
Archived generations at one identity key, oldest first (insertion order —
supersession only ever appends, so rowid IS the generation order). Each element
is the superseded row verbatim (parsed row_json, its own interpreter inside).
count(store=None)
close()
open_observation_history_store(config=None)
The open_* helper: data/observation_history.sqlite (the sibling-store
convention, no dedicated cfg path). GUARDED (bp-018 Item 4): named in _RESET_GUARD,
never a reset target — dn-self-sensing §2.5, history does not rebuild.
reference_edges
The Lane-1 reference-edge store — typed cross-references, balance-isolated (B-c).
One row = one deterministic reference observed at one commit: a code docstring citing a
design note (code_to_corpus), a design note naming a code path (corpus_to_code), or
(bp-026) a design note/finding/brainstorm citing another one (corpus_to_corpus) via
front-matter (design_ref/links/depends_on/warrant/supersedes/superseded_by),
inline note-citation, or [[wikilink]]. Extraction is φ_code (ops/code_sensor.py), the
sole interpreter, minting within project_observations.
[banner: schema v2 — bp-026] The v1 schema (code-observation-projection.md's original
shape, bp-013) had ASYMMETRIC endpoints: a code side (commit_sha, code_path, qualname)
fixed as the first slot and a corpus side (corpus_ref, corpus_kind) fixed as the second,
with direction ∈ {code_to_corpus, corpus_to_code} stored to say which was which. That
shape had no room for a corpus_to_corpus edge (findings 0059/0061/0062 — the reference
graph is doc→doc-blind, and the store's own field names encode the gap). v2 replaces the
fixed code/corpus slots with a SYMMETRIC (source_kind, source_ref, source_detail) →
(target_kind, target_ref, target_detail) pair, kind ∈ KINDS = ("code", "corpus") on
EITHER side, admitting code_to_corpus | corpus_to_code | corpus_to_corpus (and
code_to_code, reachable, not minted anywhere yet). direction is now DERIVED
(f"{source_kind}_to_{target_kind}"), never a stored column — it cannot drift from the
endpoints that define it. The migration is WIPE + RE-PROJECT (bp-026 §3 Q1/Q2: this store
is corpus-class, a deterministic projection of git history with near-zero reader blast
radius — no in-place row surgery, no attempt to preserve v1 edge_ids; every edge is
re-minted under the v2 identity formula from scratch. See docs/build-plans/bp-026/plan.md
§6(b) for the pinned interface and Q1/Q2/Q3 for the migration-safety argument.
Why a dedicated store and not EdgeStore (v1 Q1, unchanged by v2 — the isolation
rationale). These edges are geometry-class authority (observer-independent facts, the
edge model's §2 ownership rule) BUT their endpoints may be CROSS-STRATUM: an observed-stratum
code symbol on one side, an authored/curated corpus artifact on the other (or, since v2, both
sides authored/curated). The mirror's reasoning complex 𝔎|_MR is authored-only, and
EdgeStore feeds A_signed — so a cross-stratum edge landing there would smuggle
observed-stratum structure into the introspective balance math. The separation pattern is
core/stores/versions.py's: a store build_complex has no parameter for.
build_complex(view, *, edges=None, derived=None, sim_floor=...) cannot receive this store;
core/complex/** never imports this module (grep-asserted in the isolation test). Separated
not because the edges carry intent (they don't — they are facts), but because their endpoints
may cross strata.
The balance math holds no handle to this store. The 2026-07-10 survey's standing fact
— nothing mints E_geom fibers; the balance math runs on recomputed cosine (plus EdgeStore
polarity overlays) — remains TRUE for E_geom/A_signed after this store exists: reference
edges live entirely outside the complex, and no instrument (balance, Laplacian, curvature,
clustering) can observe their presence or absence. Falsifier (B-c, verbatim): "any
instrument result changes when reference edges are added or removed" — automated forever
in tests/integration/test_reference_edge_isolation.py.
Endpoints (v1 Q2, generalized). source_kind/target_kind ∈ KINDS. For kind="code":
ref = file path within the tree, detail = qualname ('' = file/module grain) — the
observed reading's coordinates. For kind="corpus": ref = repo-relative path
(design-note/findings/brainstorm target), detail = '' (path-kind) or a digest (reserved
for vault-note targets when one becomes resolvable — none arise from bp-011's validated
patterns, so detail='' in every edge minted to date).
Direction (v1 Q3, unchanged in spirit). Stored AS EXTRACTED, but no longer as its own
column — it is DERIVED from (source_kind, target_kind): code_to_corpus, corpus_to_code,
and (v2) corpus_to_corpus are different assertions by different authors; this store never
auto-symmetrizes. Consumers may symmetrize on read.
Append-only. Identity-keyed (source endpoint, target endpoint, ref_type, source_line) via a content-derived edge_id; INSERT OR IGNORE — the first reading of an identity wins and is never mutated (re-projection of the same commit is a no-op; a φ_code upgrade is a versioned re-interpretation, §2.2, never an in-place overwrite).
Reset semantics (v1 Q4, unchanged). Corpus-layer, like code_observations.sqlite: wiped
with the corpus via reset_targets() (registration is the orchestrator's post-merge step,
oq-0013 concurrence), unlike the snapshot LEDGER (build history, reset-guarded).
Consumers: the detangling instruments, the parked s(C,D) external-corroboration feature
(finding-0021), and (bp-026's warrant) the dn-core-query-protocol algebra's references_to
query surface — this store is its prerequisite substrate, not yet its consumer.
Zone A, no network, no model anywhere in the path.
REF_TYPES = ('note-citation', 'path-mention', 'symbol-mention', 'design-ref', 'dn-slug', 'finding-id', 'inherits', 'calls')
module-attribute
KINDS = ('code', 'corpus')
module-attribute
DIRECTIONS = ('code_to_corpus', 'corpus_to_code', 'corpus_to_corpus', 'code_to_code')
module-attribute
CORPUS_KINDS = ('path', 'digest')
module-attribute
ReferenceEdge
dataclass
One typed, directed reference — symmetric endpoints (bp-026 v2), no sign, no
weight: this is a FACT record, not a balance input (no EdgeSign here on purpose —
nothing about this row is assembled into any adjacency).
edge_id
instance-attribute
ref_type
instance-attribute
commit_sha
instance-attribute
source_kind
instance-attribute
source_ref
instance-attribute
source_detail
instance-attribute
target_kind
instance-attribute
target_ref
instance-attribute
target_detail
instance-attribute
source_line
instance-attribute
created_at
instance-attribute
direction
property
DERIVED, never stored (bp-026 §6(b)) — cannot drift from the endpoints that
define it: f"{source_kind}_to_{target_kind}".
code_path
property
qualname
property
corpus_ref
property
corpus_kind
property
mint(*, source_kind, source_ref, target_kind, target_ref, ref_type, commit_sha, source_detail='', target_detail='', source_line, created_at=None)
classmethod
Construct with the content-derived identity; validates the closed vocabularies at the boundary (a typo'd kind/ref_type is unrepresentable in the store).
ReferenceEdgeStore
dataclass
The Lane-1 reference-edge table. Append-only: INSERT OR IGNORE on the content
identity — a re-extracted reference never mutates the first reading. Deliberately
unreachable from core/complex/** (see module docstring; isolation test-pinned).
path
instance-attribute
add_batch(edges)
Land extracted edges. Idempotent on identity (INSERT OR IGNORE, append-only) — a second extraction of the same commit changes NOTHING. Returns NEW rows.
all(*, direction=None, ref_type=None, source_ref=None, target_ref=None)
direction filters on the DERIVED value (source_kind_to_target_kind), computed
server-side from the two kind columns — no stored direction column exists.
source_ref/target_ref are bp-026's addition: the "references TO doc X" query
(all(target_ref=...)) and its dual (all(source_ref=...)).
for_commit(commit_sha)
count()
close()
open_reference_edge_store(config=None)
The open_* helper: data/reference_edges.sqlite — the sibling-store convention
beside code_observations.sqlite. Corpus-layer (Q4): a reset_targets() wipe target
(registered by the orchestrator post-merge, oq-0013 concurrence).
runledger
The run ledger — the harness's append-only record of dream runs + claims (E2, bp-043).
Carried from Track L L1 (the protocol annex of record in the superseded
live-adoption-and-longitudinal-harness.md §2 — its dream_runs / dream_claims column lists are
honored VERBATIM here). Two append-only tables:
dream_runs— one row per (pipeline, snapshot) execution (phase7 | dream_v2), carrying the run'sconfig_fingerprint+corpus_digest(so two pipelines over "one snapshot" are provably comparable — dn-evaluation-harness §2.2) and cheap descriptive stats.dream_claims— one row per claim, addressed by a content-addressedclaim_id= sha256(kind ‖ canonical(support) ‖ polarity)— EXCLUDING surface wording + confidence (§2.2): "the same tension, found twice" is one id, however it was worded.novelis computed ON INSERT against ALL prior runs (an INDEX onclaim_idbacks the check), so re-emitted claims are markednovel=Falseand inherit prior verdicts (E6's job).
SQLite/WAL, scheduler single-writer (scheduler/__init__.py — one supervisor owns the queue;
the run ledger follows the same discipline, written only by the trough handler in production; unit
tests write a tmp/:memory: ledger directly). Append-only: no update, no delete. This store holds
no model and no network — it is a passive record. The distinct SQLite engine (not E1's DuckDB
eval-results table) is the A-4 routing pin: the access pattern here is point lookups + inserts, not
analytical group-by.
DEFAULT_POLARITY = '+'
module-attribute
RunLedger
dataclass
Append-only SQLite/WAL ledger. Writes (start_run, add_claim) and reads (runs,
claims) are distinct method groups over one single-writer handle (SQLite single-writer
discipline, §3 Q5). path accepts ":memory:" for tests as well as a real on-disk Path.
path
instance-attribute
start_run(*, pipeline, config_fingerprint, corpus_digest, node_count, edge_count, duration_s, spectral_stats)
Open a run (one (pipeline, snapshot) execution) and return its fresh run_id. A run is
an EVENT — a new id every invocation even for the same snapshot (claims carry the identity,
runs carry the occurrence).
add_claim(run_id, *, kind, confidence, support, surface_text, polarity)
Append one claim; compute its claim_id + novel (unseen claim_id across ALL prior
runs, this row included on re-emit within the same run). Returns novel. Append-only:
a re-emitted claim is a NEW row marked novel=False, never an update of the first.
runs(*, pipeline=None)
claims(*, run_id=None, novel_only=False)
close()
claim_id(kind, support, polarity)
Content-address a claim EXCLUDING its surface wording + confidence (§2.2). The canonical
support set is sorted(set(...)) so identity is order-insensitive and duplicate-insensitive
— "the same pattern, found twice" hashes to one id.
polarity_for(kind)
The polarity of a claim kind for claim_id (§3 Q3). Unmapped kinds default +.
polarity_and_flag(kind)
(polarity, defaulted) — defaulted=True when kind has no explicit polarity mapping and
fell back to + (§3 Q3's "unknown -> + flagged"). Lets a caller log the under-specified kind
once per run rather than silently.
open_run_ledger(config=None)
Open the configured run ledger — its SQLite file lives beside the derived store (the
telemetry precedent). Import of config.loader is lazy so the module stays dependency-light.
staging
The HYPOTHETICAL staging store (dn-synchronic-diachronic-dreamer §2.6-2/3/4; bp-081 H-1).
Staged hypotheses live ONLY here — never in a durable store. The design is laundering-proof by
CONSTRUCTION, not by a gate: there is no promotion path from HYPOTHETICAL to anything (note
§2.6-3). A hypothesis the owner comes to believe enters the corpus the way everything does — the
owner authors it, or its real source ingests through the normal pipeline. So this store has no
promote, no commit_to, no durable-store handle; it can only append staged rows, read them
by generation, and tombstone them on expiry. That absence is the whole invariant, and the API
surface scan in the tests asserts it structurally (the plan's spine).
The clock (§2.6-2). Admission and expiry are append events on the store's OWN chain — a
per-stratum event clock N_hyp whose ticks are GENERATIONS. Every write (a stage admission, a
sweep tombstone tick) advances the generation by one and logs a bookmark in staging_generations.
Reads are GENERATION-ADDRESSED (read_at(g)), so a dream report that pinned generation g stays
reproducible AS A RECORD even after the rows expire. Wall time (at, ttl_wall) is a COORDINATE
CHART for owner-convenience lookup only — it NEVER orders anything (Law C4); the wall→generation
resolution the sweep does is interval-valued and ambiguity-widening (D8), and lives sweep-side.
Stratum ≠ provenance. A staged row records its would-be stratum (where it would live if it were real — mirror, interpreted, …) AND its would-be provenance, both as ROW DATA. The row's overlay stratum is always HYPOTHETICAL (implicit — that is the visibility class). A would-be stratum of HYPOTHETICAL or FOUNDATION is refused: the overlay is not a promotion target and the denylist is never a home.
IllegalWouldBeStratum
Bases: ValueError
A staged row named a would-be stratum that is not a durable home (HYPOTHETICAL / FOUNDATION). A staged row's would-be identity is where it WOULD live if real — never the overlay class, never the denylist. Refused at admission (fail-closed).
StagedItem
dataclass
One hypothesis to admit: its would-be stratum + provenance (ROW DATA — stratum ≠ provenance),
its content digest (the content address the conditioning law's derives tails cite), and an
opaque payload. No generation here — the store assigns it at stage.
would_be_stratum
instance-attribute
would_be_provenance
instance-attribute
content_digest
instance-attribute
payload = ''
class-attribute
instance-attribute
StagedRow
dataclass
A staged row as stored: its identity (row_id), the subspace_id it belongs to, the
generation it was admitted at, its would-be stratum/provenance + content digest, its opaque
payload, an optional wall-denominated TTL (ttl_wall — owner convenience, resolved to a
generation at sweep; NEVER an ordering key), the generation a sweep tombstoned it at
(tombstoned_at_gen, None while live), and the wall at bookmark of its admission.
row_id
instance-attribute
subspace_id
instance-attribute
generation
instance-attribute
would_be_stratum
instance-attribute
would_be_provenance
instance-attribute
content_digest
instance-attribute
payload
instance-attribute
ttl_wall
instance-attribute
tombstoned_at_gen
instance-attribute
at
instance-attribute
StagedBatch
dataclass
The result of one stage admission: the generation the batch was admitted at and the ids of
the rows appended (so a caller can pin the (subspace, generation) it staged).
generation
instance-attribute
row_ids
instance-attribute
GenerationEvent
dataclass
One tick of N_hyp — a bookmark in the generation chain. kind ∈ {genesis, admission,
sweep}; at is the wall bookmark (lookup only — never orders). The sweep's wall→generation
resolver reads these to bracket a wall time into a generation interval (D8).
generation
instance-attribute
at
instance-attribute
kind
instance-attribute
StagingStore
dataclass
Append-only, generation-clocked staging for the HYPOTHETICAL overlay.
The store's ONLY handle is its own sqlite connection — no durable store is reachable from here, which is what makes "a staged row reaches a durable store" unrepresentable rather than forbidden (the no-promotion spine invariant, note §2.6-3). Generations are monotone and owned here; wall time is a bookmark, never an ordering key.
path
instance-attribute
current_generation()
The latest N_hyp tick — the generation a bare read is addressed at.
generations()
The N_hyp chain — the generation bookmarks the sweep's wall→generation resolver reads
(D8). Ordered by generation (never by wall).
stage(subspace_id, items, *, ttl_wall=None)
Admit a batch of staged items under subspace_id. ONE admission = ONE generation tick
(an append event on N_hyp); every row in the batch shares that generation. Append-only —
rows are never mutated after admission except a sweep's tombstone stamp.
Refuses (fail-closed) a would-be stratum that is not a durable home
(HYPOTHETICAL/FOUNDATION, IllegalWouldBeStratum). Returns the generation + the appended
row ids so the caller can pin the (subspace, generation) it staged.
read_at(generation=None)
The staged rows VISIBLE at generation (default: the current tick) — admitted at or
before generation and NOT tombstoned as of it. Generation-addressed and reproducible: the
same generation always yields the same rows, so an expired dream stays a record. Ordered
by (generation, row_id) — by the event clock, NEVER by wall (Law C4).
subspace_at(subspace_id, generation=None)
The visible rows of one subspace at generation — the counterfactual overlay a composed
read consumes (its digests are the conditioning law's derives tails).
all_rows()
EVERY staged row, tombstoned or not — the audit view (append-only, so history is whole). Ordered by (generation, row_id).
tombstone(row_ids)
Advance N_hyp by one (a sweep tick) and TOMBSTONE row_ids at that generation — the
SD-d default disposition (append-only discipline; the row leaves every read_at(g') for
g' ≥ the tick, but the record survives). Idempotent on already-tombstoned rows (they keep
their original tombstone generation). Returns the sweep tick's generation.
This is the ONLY mutation after admission, and it is read/tombstone-only: it moves NO row anywhere — least of all durable-ward. There is deliberately no inverse (no un-tombstone, no promote).
count()
Total rows ever staged (append-only; tombstoned rows still count as records).
close()
open_staging_store(config=None)
Open the staging store beside the other core stores (the store-layer house pattern). Sqlite-backed (parked engine default: sqlite, not in-memory — reading records must outlive the process).
telemetry
DuckDB telemetry store (BUILD-SPEC §8).
Quantitative time-series — system vitals only at launch (the system is itself a
sensor source). Access is scoped in code (CONVENTIONS): a TelemetryWriter has no read
methods and a TelemetryReader has no write methods, so the wrong access is impossible,
not merely discouraged. The dormant sensor_readings table is the body/health adapter
target, built now so a wearable can later emit into the same store without rework
(§8, §20.6) — no adapter writes to it yet.
SCHEMA_VERSION = 3
module-attribute
TelemetryWriter
dataclass
Write-only handle. No read methods exist on this object BY DESIGN (scoped access).
record_vital(metric, value, *, unit=None, source='core', labels=None)
record_vitals(readings, *, source='core')
Bulk-write objects exposing .metric/.value/.unit/.labels (e.g. vitals.Reading).
record_context_usage(agent, report, *, job_id=None, tier=None)
Record a context-budget outcome (BUILD-SPEC §13). report is duck-typed (a
scheduler.budget.BudgetReport) so telemetry stays independent of the scheduler.
record_harness_cost(run_id, *, wall_clock_s, models_resident, cells_completed, cells_skipped, note=None)
Record one harness run's cost/residency (dn-evaluation-harness §2.4, bp-044 Item 10) —
surfaced as the report's cost appendix. run_id links to the run ledger (E2).
TelemetryReader
dataclass
Read-only handle. No write methods exist on this object BY DESIGN (scoped access).
latest(metric)
count(metric=None)
window(metric, seconds)
context_usage_count(agent=None)
harness_costs(run_id=None)
The harness cost ledger's rows (bp-044 Item 10), ordered (ts, run_id) deterministically
— the report's cost appendix reads through here. Read-only; no clock, no model.
harness_cost_count()
TelemetryStore
dataclass
path
instance-attribute
writer()
reader()
close()
open_store(config=None)
vectorstore
LanceDB thought-graph vector store (BUILD-SPEC §7, §8).
Embedded, no daemon. Every chunk row carries its provenance so retrieval can be
filtered by provenance class — this is what makes the mirror=AUTHORED-only firewall
(design-notes/observed-data-and-the-assistant-tier.md) structural, not advisory: a
mirror query passes provenances={AUTHORED} and cannot surface observed exhaust.
Vectors are a derived, regenerable layer; the raw store remains the source of truth.
TABLE = 'chunks'
module-attribute
LAYER_PROSE = 'prose'
module-attribute
LAYER_CODE_AST = 'code_ast'
module-attribute
LAYER_CODE_TEXT = 'code_text'
module-attribute
LAYER_CODEDOC = 'codedoc'
module-attribute
ATOM_ROW_SHED = {'digest': '', 'source_path': '', 'chunk_index': 0, 'qualname': '', 'line_start': 0, 'line_end': 0}
module-attribute
VectorStore
dataclass
path
instance-attribute
dim
instance-attribute
add(rows)
count()
reset()
Drop the vector table. Vectors are derived (§8): a full re-ingest rebuilds them from the raw corpus, so this is the idempotent path for re-indexing.
delete(*, digest)
Drop all derived rows for a source note (by its raw-store digest). Idempotent.
The incremental watcher uses this to retire stale embeddings when a note changes or is
deleted — derived layer only; the raw blob is untouched (§8). digest is a hex SHA-256, so
the escaping is belt-and-braces rather than load-bearing.
rows_for_source(source_path)
Every stored chunk row for one source document (by source_path) — the note's current
projection. The amendment path (ingest-identity §4) reads this to REUSE unchanged chunks'
vectors instead of re-embedding, so this read must keep carrying the vector column.
[banner: correction] Was: materialize the WHOLE table Arrow→Python, vectors included, and
keep the rows whose source_path matched — the read half of finding-0169. Two premises of
that shape were wrong. The first, that a Python-side filter avoided "a quoting hazard on
arbitrary source paths", died with bp-100: _sql_str solves the hazard. The second, that
the predicate could not be pushed down, died with bp-103: scan() (the shim's honest name
for LanceDB's search(None)) takes the predicate server-side, so only the matched path's
rows ever cross into Python. limit(0) means UNLIMITED — verified empirically against the
installed 0.33.0 on a 137-row path, and pinned by a ratchet in
tests/unit/test_typedshim_lancedb.py, because a silently reintroduced default cap would
under-read a deep path and corrupt the amendment it feeds.
NO select() projection here, deliberately: vector is the column the caller came for.
delete_source(source_path)
Drop every derived row for one source document, by source_path (the stable doc identity
an amendment replaces a projection under — §4). Idempotent.
[banner: correction] Was: materialize the WHOLE table (rows_for_source), rebuild an
id IN (…) list from it, delete by that. The path is itself a predicate — pushing it down
removes the scan entirely (finding-0169, and this is the note-amendment hot path at
core/ingest/index.py:87, not only the code lane). Selecting on the same source_path
column the Python filter used, it deletes exactly the same rows — and strictly fewer in the
one case they differ: an id is {doc_id}:{chunk_hash} where doc_id may diverge from
source_path (a rename, an id:: property), so the old id-list could reach a row belonging
to another path.
supersede_source(source_path)
Keep-and-link (dn-temporal-code-corpus D2, bp-099): flip every CURRENTLY-current row of
source_path to current=false while RETAINING it — a superseded code version is never
deleted. Returns the number of rows flipped (0 if the path had no current rows).
ONE predicate, pushed down: a filtered count_rows for the return value, then a single
in-place update. No read, no re-land, nothing materialized into Python — the cost is
a function of the matched rows, never of the store's size, which is exactly finding-0169's
bound and the condition on the daemon restart. Idempotent by construction: a path with
nothing current counts 0, skips the write entirely, and returns 0.
The vector column is never named, so it is never read, so it cannot be re-derived or
dropped (§8). That is a strictly STRONGER guarantee than the byte-equality assertion in
test_vectorstore_supersede.py — which is kept anyway, as a regression net on the shape of
the method rather than on this implementation of it.
[banner: correction] Was: read the whole path → delete it → re-add every row with the flag
flipped, justified as staying "portable — no dependency on a LanceDB in-place update".
That portability claim was false at the pinned version (bp-100 Q3, re-verified by
bp-103 against the installed package rather than the docs): lancedb 0.33.0 has
Table.update(where, values), and the re-land was paying a full O(total store)
materialization — vectors and all — to flip one boolean. The re-land is now deleted
entirely, not merely bounded; bp-100's interim [cross-ref: extension] note (which
recorded it as retained-but-halved, blocked on the typedshim) is retired with it. Warrant
finding-0176; the two xfail(strict=True) ratchets it cites are now ordinary green
tests in tests/unit/test_store_cost_ratchet.py.
The count comes from count_rows(where) and NOT from update(...).rows_updated:
UpdateResult is the 0.33 return shape, while pyproject.toml:12 pins lancedb>=0.10, a
range whose older members returned None. A filtered count is server-side and materializes
nothing, so portability costs no scan (bp-103 §11, first parked decision — re-entry is a
plan that owns pyproject.toml and raises the floor).
[cross-ref: extension] The predicate names current, so unlike the old body this raises on
a PRE-bp-099 store whose schema has no such column (the migrations arm on add, and
code_corpus.sync supersedes before it adds). The old body silently returned 0 there and
then let add stamp every row current=true — leaving the superseded version AND the new
HEAD both current, i.e. silent D3 corruption. Failing loudly is the improvement; see
finding-0180 for the migration-arming question, which is a design call, not a builder's.
relabel_provenance(old, new)
Rewrite every row's provenance from old to new. Returns rows relabeled.
Used by the §1 spectrum-split migration to relabel the legacy 'authored' rows to
'authored-solo'. This is a SAME-TRUST-TIER relabel (both are mirror-readable), not a
promotion across the §8 firewall — so it is a safe, deterministic data migration, not a
gated provenance change. Idempotent by construction: a second run finds no old rows
and is a no-op. Implemented as delete-then-re-add (the store's existing re-index idiom)
so it stays portable — no dependency on a LanceDB in-place update.
all_rows(*, provenances=None, include_atom_rows=False)
Full scan, optionally restricted to provenance classes — the read the dreaming
agent clusters over. The clustering itself is deterministic and model-free (§9), so
the mirror passes provenances={AUTHORED} and observed exhaust never seeds a dream.
Single-user corpus scale; filtered in Python after the Arrow scan for portability.
[banner: correction] The shed-atom guard (bp-152 Item 3, the note's §3 Q5 gap). An
UNSCOPED read (provenances=None) now excludes shed CODE-atom rows unless the caller asks
for them by name. The reason is a silent corruption, not tidiness: every structural
group-by-digest consumer keys on a column an atom row does not have.
core/kernel/stores/sourceset.py's source_sets(store) defaults to ALL strata by design
("a structural grouping utility, not a mirror read"), and group_sources keys on
r["digest"] — so shed rows, all carrying digest='', would collapse into ONE bogus
SourceSet keyed ''. MixedProvenanceError cannot catch it (it needs a digest spanning
several provenances; these rows are uniformly CODE), so it fails with no visible error at
all. core/curator/curator.py's prune_candidates has the identical shape and would
report the whole atom plane as one orphaned digest.
The guard is here rather than in sourceset deliberately: the kernel module may never
learn about the outer-ring membership store (the C5/D3 ring pin — an import would demote
sourceset from the inner-ring fixed point), so the shed side owns the consequence of its
own shed. Excluding is the fail-closed half of the note's "excludes them or raises": a
structural grouping over geometry-without-occupancy is not a smaller answer, it is a wrong
one, and a code consumer reaches source objects through membership fibers (D3) — never
through group-by-digest.
A caller that genuinely wants the whole physical table passes include_atom_rows=True;
a caller that wants the code lane passes provenances={CODE}, which is how
CodeCorpusSync and the eval battery already read it, and is unaffected.
atom_rows()
Every shed CODE-atom row (D1) — the vector plane V, as rows. len(atom_rows()) is |V|
for the append-only invariant (§4: no test may ever observe |V| decrease except across a
logged purge).
set_current_any(ids, value)
Set current_any on exactly the named atom rows (D2 step 5). Returns rows written.
current is a lance column, so a flip rewrites fragments — which is why D2 step 5 and the
note's §3 pin say only the atoms whose current-membership count crossed 0↔1. This method
takes the crossing set and nothing else; computing it is the lander's job (it is pure
membership arithmetic and belongs in SQLite, not here). An empty set writes nothing.
Predicates are chunked so a large crossing set cannot build an unbounded SQL string.
delete_atom(content_id)
Delete one atom row by its (layer, content_hash) id — the D5 PURGE path, and the ONLY
machinery in this module that removes a vector row (finding-0164; owner-gated, privacy
outranks lineage). Returns rows deleted, so a purge that silently no-ops is observable:
"never deletes" is satisfied vacuously by a purge that does nothing, so the count is the
thing a test asserts on. The membership half of the hole (tombstoning) is the membership
store's — see core.stores.memberships.purge_atom, which owns both halves.
search(vector, *, k=5, provenances=None, include_superseded=False)
Nearest-neighbour search, optionally restricted to provenance classes.
provenances=None searches everything; the mirror passes {AUTHORED}.
Default retrieval is CURRENT-VIEW (dn-temporal-code-corpus D3, bp-099): a superseded code
version (current=false, kept by keep-and-link) never surfaces unasked, so every existing
consumer is unchanged (note rows carry the vacuous current=true). A temporal consumer opts
into history with include_superseded=True.
Under D1 (bp-152) the same clause serves the atom plane with the current_any reading —
"does ANY current membership contain this atom" — so an atom whose every occupancy is
superseded drops out of the default search exactly as a superseded version used to. This
search returns ATOMS; resolving each hit to its occupancies (path, blob, slot, lines) is
the membership join (D3, core.stores.memberships.resolve_occupancies), and the join is
where a code consumer learns where a hit lives.
is_code_atom_row(row)
Is this row a shed CODE atom row (D1) rather than a source-object chunk row?
An atom row is geometry with no occupancy: its occupancy lives in the membership relation
(core/stores/memberships.py), so it carries no source_path and no digest. This predicate
is the ONE place that reading is spelled out, so all_rows' structural guard and the
membership store's repair pass cannot drift apart.
open_vector_store(config=None)
verdicts
Append-only signed verdict store (design-notes/verdict-authority.md; live-adoption §3, L2).
Persists owner verdicts as the labeled ground truth the longitudinal apparatus is missing, with
the sacred-boundary upgrade the plain L2 claim_verdicts schema lacked: each row carries the
owner's Ed25519 signature (VERIFIED before it is stored) and a monotonic sequence number. A
compromised transport (a tampered Ambassador) can DROP or REORDER — both refused or made visible
here — but can never FORGE a verdict, because the store holds only the owner PUBLIC key
(verdict-authority.md §4: the Ambassador degrades to transport).
APPEND-ONLY IS STRUCTURAL, like the attestation store (core/attestation/store.py): this class
exposes append + reads and NO update/delete. Corrections are new verdicts at a higher seq
(supersession by sequence), never in-place edits — the same discipline the ingestion boundary
uses. Verdicts are operational ground truth, NOT mirror content (they label interpreted-tier
output; they never enter MIRROR_READABLE). Zone A, no network.
The APPLY half — what promote / supersede DO to the graph — is deliberately NOT here: it
depends on the promotion mechanism (recursive-strata I1), which is parked. This store is the
buildable, lower-blast-radius half of Item 4b; apply lands when the promotion mechanism does.
VerdictSignatureError
Bases: ValueError
A verdict was offered whose signature did not verify under the owner public key — the illegal state the boundary deletes (fail closed): an unsigned or forged verdict is never stored, so no compromised transport can inject an owner authorization.
VerdictSequenceError
Bases: ValueError
A verdict's seq did not strictly exceed the stored maximum — a replay, a reorder, or a
reused number. Refused so the sequence is monotone; a genuine DROP shows up as a forward gap
(detectable via gaps()), never as a silently-accepted lower number.
VerdictCategoryError
Bases: ValueError
A verdict category outside the configured ratified taxonomy (when one is set). Absent a
ratified set (allowed_verdicts=None) any category is accepted — the taxonomy is an owner
decision (build plan R3), and this store must not hard-code it.
VerdictRecord
dataclass
One stored, signature-verified owner verdict.
seq
instance-attribute
subject_id
instance-attribute
verdict
instance-attribute
timestamp
instance-attribute
signature
instance-attribute
signer
instance-attribute
recorded_at
instance-attribute
as_signed()
Reconstruct the SignedVerdict for re-verification (tamper-evidence over the store).
VerdictStore
dataclass
path
instance-attribute
allowed_verdicts = None
class-attribute
instance-attribute
append(signed, *, public_b64)
Verify + persist one owner verdict. Fail closed, in order:
- category ∈ the ratified taxonomy (when configured), else
VerdictCategoryError; - the signature verifies under
public_b64, elseVerdictSignatureError; - seq strictly exceeds the stored maximum, else
VerdictSequenceError.
Only if all three hold is the row appended. The whole check+insert is under the lock, so a concurrent append cannot race the monotonic-seq guard.
latest_seq()
The highest stored seq, or None if empty — what the next verdict must exceed.
all()
get(seq)
gaps()
The missing sequence numbers between the smallest and largest stored seq — the censorship signal (verdict-authority.md §4: a dropped verdict is a visible gap). Empty when the stored sequence is contiguous.
verify_all(public_b64)
Re-verify every stored verdict's signature under public_b64 — tamper-evidence over
the store as a whole (a mutated row fails). True iff all rows verify (or the store is
empty).
count()
close()
open_verdict_store(config=None, allowed_verdicts=None)
Wire a VerdictStore beside the other core stores. allowed_verdicts is the ratified
taxonomy once the owner decides it (build plan R3); None keeps the honest accept-any default.
versions
Append-only note-version history (ingest-identity-and-amendment.md §4A; build plan Item 6).
A note edited over time is a sequence of VERSIONS, and "v2 supersedes v1" is a PRIMARY provenance
fact — distinct from the semantic support/contradiction edges the balance math consumes. It lives
HERE, not in the EdgeStore, for two reasons the shipped implementation got wrong (§4A C1–C2):
- Keyed on version identity, not content digest. Endpoints are
(doc_id, version_seq), so a revert (v1 → v2 → back to v1's exact bytes) is v3 at seq 3 — distinct from v1 even though the digest repeats. The chain stays linear; NO cycle-guard is wanted (rejecting the revert would refuse truthful history and break append-only). Content-hash stays the key for the vector projection; version-seq is the key here — two layers, two identities. - The balance math cannot read it. A version relation must never enter the signed-edge graph
(a placeholder
signcorrupts λ_min / frustration).build_complextakes anEdgeStoreand has no handle to this store, so the exclusion is structural — not a rel-type-filter discipline every consumer must remember (the prior design was excluded only accidentally; see Q8).
Append-only: each version is one row, version_seq monotonic per doc_id. The current version is
max(version_seq); supersession is the consecutive-seq relation — both DERIVED from the ordered
sequence, never from edge topology (§4A Ordering authority). Zone A, no network.
One owner-gated identity migration is admitted (bp-034; §11 ruling 2026-07-14):
migrate_rekey_doc_id relabels which doc_id a chain is filed under — needed exactly once per
identity switch (the id:: mint) so the switch does not FORK lineage, which is the outcome
append-only exists to prevent. doc_id is the RESOLVED identity label (provisional
== source_path until diverged — see the DDL note), not historical content: the relabel preserves
every row's (version_seq, digest, at) exactly, refuses to merge two chains, and is fail-closed on
owner authority. Runtime paths remain append + reads only.
RekeyRefusedError
Bases: RuntimeError
An owner-gated doc_id re-key was refused by a safety gate — a bad/empty key, or a request
that would MERGE two live lineages onto one id (old and new both hold rows). The
PurgeRefusedError pattern: fail-closed, named, never a silent merge or partial write. Owner
authority is refused separately, via MachineAuthorityRefused at the same boundary.
Version
dataclass
doc_id
instance-attribute
version_seq
instance-attribute
digest
instance-attribute
at
instance-attribute
VersionStore
dataclass
path
instance-attribute
current(doc_id)
The current (highest-seq) version of a document, or None if never recorded.
record(doc_id, digest)
Append the next version of doc_id at digest (version_seq = current + 1, or 1). A
revert to an earlier version's bytes is a NEW version at a higher seq — never a cycle, never
a merge (§4A C1). Append-only: no prior row is mutated.
history(doc_id)
Every version of a document in version-seq order (the append-only chain).
supersessions(doc_id)
The (superseded_seq, superseding_seq) pairs — consecutive versions, DERIVED from the
ordered sequence (never from edge topology, §4A Ordering authority).
migrate_rekey_doc_id(old, new, *, declaration)
Owner-gated identity migration: relabel a chain's doc_id from old to new, keeping
every row's (version_seq, digest, at) byte-for-byte (bp-034; §11 ruling 2026-07-14). A
RELABEL, never a history rewrite — the label moves, the sequence/contents/order never do;
the ONE admitted write to this append-only store, needed once per id:: mint so an identity
switch does not fork lineage. Returns rows relabeled.
Fail-closed on owner authority (verify_owner_declaration — a machine caller refused here).
CHECK ORDER matters — the no-op cases are decided BEFORE the merge refusal, so a partial run
(the note re-keyed but interrupted before the next store) converges on re-run instead of
raising:
(i) old == new → no-op (0): nothing to relabel.
(ii) old holds NO rows → no-op (0): nothing to move — this is what makes a
re-run of an already-migrated chain converge.
(iii) old AND new both hold rows → REFUSE (RekeyRefusedError): never merge two lineages.
(iv) else → relabel (one UPDATE, one statement, one txn).