core.dreaming
core.dreaming
Zone A — theme clustering / synthesis (cron, mirror-not-oracle). BUILD-SPEC §9.
The dreaming agent clusters the AUTHORED corpus into themes (deterministic, model-free) and reflects each back to the owner as a lens on their own notes — never external truth. Output is INTERPRETED + regenerable, self-checked before it is kept, and only runs in troughs.
The Phase-7 Dreamer is the LIVE path. The interpreter panel (R0) + adjudicator (R1) are a
flag-OFF R&D track (design-notes/dream-phase-rnd-charter.md) — exported here for tests
but never wired into scheduler/cron.py; their entry points refuse to run unless the
[dream_rnd] enabled flag is set (core.dreaming.rnd).
Synthesizer = Callable[[list[Message]], str]
module-attribute
DreamLogEntry
dataclass
One consensus group in the ranked dream log: a hypothesis, never a verdict.
statement
instance-attribute
methods
instance-attribute
evidence
instance-attribute
grounding
instance-attribute
agreement
instance-attribute
depth
instance-attribute
confidence
instance-attribute
terminates_in_authored
instance-attribute
members = field(default_factory=tuple)
class-attribute
instance-attribute
Cluster
dataclass
members
instance-attribute
titles
property
digests
property
size
property
NoteVector
dataclass
digest
instance-attribute
title
instance-attribute
vector
instance-attribute
Dreamer
dataclass
store
instance-attribute
synthesize
instance-attribute
derived
instance-attribute
threshold = 0.62
class-attribute
instance-attribute
min_cluster_size = 2
class-attribute
instance-attribute
max_clusters = 8
class-attribute
instance-attribute
clusterer = cluster_notes
class-attribute
instance-attribute
judge = None
class-attribute
instance-attribute
attestor = None
class-attribute
instance-attribute
edge_store = None
class-attribute
instance-attribute
snapshots = None
class-attribute
instance-attribute
clusters()
Deterministic note-level clustering over the AUTHORED mirror (model-free, §9).
The rows come from a MirrorView (Invariant 6, structural): its only constructor is
the MIRROR_READABLE projection and it cannot hold a non-authored row, so observed
exhaust reaching this clustering is unrepresentable — not merely filtered out.
dream()
Run a full dreaming pass: cluster -> synthesize each theme -> self-check -> store. Returns the themes produced (also persisted as INTERPRETED dreams).
dream_v2(*, config=None)
The strong-Dreamer pass — deterministic structure first, the earned model call last:
1. BUILD 𝔎|_MR (firewall structural: the complex is built from a MirrorView)
2–5. LOCATE / THEME / TENSION / GAPS — the interpreter panel over the complex 6. SUPPORT — noisy-OR multi-path grounding on the derivation DAG (§6.1) 7. ADJUDICATE — c = min{1, γ^d·g·(1+λ(|Agr|−1))}, confidence-ordered 8. SYNTHESIZE — the ONLY model call(s): narrate each selected candidate, grounded in its authored evidence, mirror-not-oracle 9. STORE — interpreted-only, derives→authored leaves, acyclic, attested 10. MEASURE — append the structural snapshot (§5.4; feeds the A2 drift axes)
Gated by the dream-R&D hard boundary ([dream_rnd] enabled, OFF by default): the live
dream() above is UNCHANGED and remains the cron path until a deliberate flip. Every
structural judgment here is deterministic and model-free; self.synthesize is the only
model seam, invoked once per stored dream and nowhere else. Trough-only when wired
(a dream job routes to the synthesis tier, which the foreground gate blocks).
Theme
dataclass
titles
instance-attribute
summary
instance-attribute
check
instance-attribute
artifact
instance-attribute
MirrorGraph
dataclass
Note-level similarity graph over the authored mirror. sim is the full cosine matrix;
edges are pairs with sim >= sigma. Deterministic given the MirrorView's row order.
notes
instance-attribute
sim
instance-attribute
sigma
instance-attribute
n
property
build(view, *, sigma)
classmethod
π_MR → centroids → σ-adjacency. Input is a MirrorView, so the graph is provably
over authored notes only (a non-authored node is unrepresentable upstream).
digest(i)
title(i)
neighbors(i)
Indices j != i with cos(i, j) >= sigma — deterministic ascending order.
degree(i)
local_clustering(i)
Clustering coefficient of node i: fraction of its neighbour pairs that are themselves adjacent. LOW clustering at a high-degree node = a structural hole / bridge (Burt): the neighbours form separate groups this node holds together. Degree<2 => undefined => 0.0.
digests_for(indices)
The authored content digests for a set of node indices — the evidence refs (G1).
titles_for(indices)
Claim
dataclass
A candidate pattern-claim from one interpreter. support is the set of authored note
digests the claim rests on — content-addressed evidence (G1), and the LEAVES that ground it
(G2). data is method-specific. No confidence here; ranking is the adjudicator's job (R1).
method
instance-attribute
statement
instance-attribute
support
instance-attribute
data = field(default_factory=(dict[str, Any]))
class-attribute
instance-attribute
DreamRnDDisabledError
Bases: RuntimeError
An R&D dream entry point was called while the feature flag is OFF (the default).
This is the boundary: the interpreter panel / adjudicator never run unless
[dream_rnd] enabled = true is set deliberately. Not reachable from the live path.
adjudicate(claims, *, authored_digests, agreement_jaccard, gamma=DEFAULT_GAMMA, lam=DEFAULT_LAMBDA, support_of=None)
Rank claims into a confidence-ordered dream log (no model; grounding decides). Agreement across DISTINCT interpreters multiplies confidence; a claim found by one lens still appears (disagreement is information, not noise) — just lower.
support_of (H8, §6.1): an optional multi-path grounding scorer — evidence refs → g via
noisy-OR message passing on the derivation DAG (core.complex.support.grounding_with_support
partially applied). None (the default) keeps the flat resolvability grounding_score; the two
are numerically identical whenever no evidence ref is an interpreted node (property-tested),
so the confidence law (R1's clamp) is untouched — only g's computation generalizes.
run_dream_rnd(view, derived, *, config=None)
R0+R1 end to end behind the flag: run the interpreter panel, adjudicate, and persist the confidence-ordered dream log as INTERPRETED artifacts. Refuses unless the R&D flag is on.
cluster_notes(notes, *, threshold, min_size=2)
Single-linkage connected components: notes whose cosine similarity >= threshold
are joined into a theme. Returns clusters of at least min_size members, largest
first (ties broken by the first member's title — deterministic ordering).
near_duplicate_pairs(notes, *, threshold)
Distinct note pairs whose centroids are near-identical (cosine >= threshold).
These are near-duplicate CANDIDATES the curator flags — never auto-merged, because
authored notes are immutable ground truth (§8). Sorted most-similar first.
note_centroids(rows)
Aggregate chunk rows (one per vector) to one centroid per note (keyed by digest). Insertion order follows first appearance, so the result is deterministic.
note_snippets(rows, *, limit=600)
Per-note grounding text: that note's chunk texts concatenated in row order and
truncated to limit chars. Keeps a synthesis/contradiction context lean (§13) while
still grounded in the owner's actual words.
build_dreamer(config=None, *, tier='synthesis')
Wire a Dreamer against the real configured stores + synthesis model. Pulling the synthesis-tier model is required only to actually run it (the unit path injects a fake).
run_panel(view, *, config=None, census=None)
Run every registered interpreter (σ-graph lenses + structural lenses over one shared
reasoning complex) and return all candidate claims (R0 — no adjudication). Refuses unless
the R&D flag is on (hard boundary). An optional census reading (bp-080 Item 5) joins the
arrow-aware census claims equal-citizen behind the SAME flag; None keeps the panel unchanged.
require_rnd_enabled(config=None)
Fail closed unless the R&D flag is explicitly on. Called by every R0/R1 entry point.
adjudicator
R1 — the evidence-based adjudicator (design-notes/dreaming-v2-interpreter-panel.md; §6/§8).
Ranks the panel's competing claims and logs a confidence-ordered dream log, each entry
carrying content-addressed authored evidence. The load-bearing rule: evidence, not
persuasion. The currency is resolvable grounding (core.selfcheck.grounding_score), never
rhetoric — no model scores argument quality here, so the most eloquent claim cannot win.
Confidence of a group κ (the single clamped definition, core.recursion.claim_confidence):
c(κ) = min{1, γ^{d(κ)} · g(κ) · (1 + λ(|Agr(κ)| − 1))}
where g(κ) is the authored-grounding score (the gate: g=0 ⇒ c=0, so agreement can never
manufacture confidence from nothing — agreement is a multiplier, not a vote), |Agr(κ)| is
the number of DISTINCT interpreters that corroborate the claim, λ is the bounded corroboration
bonus (core.recursion.DEFAULT_LAMBDA), and γ^d is the recursion decay (DEFAULT_GAMMA).
d(κ)=1 here: every claim's support is authored leaves (R0 reads a MirrorView), so the chain
terminates in authored ground (Invariant 10) and depth is uniform — γ^d is order-preserving and
present for honesty (a first-order interpretation is γ·g, explicitly a hypothesis) and for R3
readiness. Confidence is NOT a probability and never combined with utility (a separate axis,
R2): c decides what to believe, utility decides what to surface; one scalar is forbidden.
Output is stored INTERPRETED-only (DerivedStore, no provenance parameter — structural §8) with
derived_from = the authored evidence digests (acyclic, depth-1 — G2). Reproducible and
tamper-evident: a dream log entry is pinned to sha256 evidence refs.
AUTHORED_LEAF_DEPTH = 1
module-attribute
DreamLogEntry
dataclass
One consensus group in the ranked dream log: a hypothesis, never a verdict.
statement
instance-attribute
methods
instance-attribute
evidence
instance-attribute
grounding
instance-attribute
agreement
instance-attribute
depth
instance-attribute
confidence
instance-attribute
terminates_in_authored
instance-attribute
members = field(default_factory=tuple)
class-attribute
instance-attribute
adjudicate(claims, *, authored_digests, agreement_jaccard, gamma=DEFAULT_GAMMA, lam=DEFAULT_LAMBDA, support_of=None)
Rank claims into a confidence-ordered dream log (no model; grounding decides). Agreement across DISTINCT interpreters multiplies confidence; a claim found by one lens still appears (disagreement is information, not noise) — just lower.
support_of (H8, §6.1): an optional multi-path grounding scorer — evidence refs → g via
noisy-OR message passing on the derivation DAG (core.complex.support.grounding_with_support
partially applied). None (the default) keeps the flat resolvability grounding_score; the two
are numerically identical whenever no evidence ref is an interpreted node (property-tested),
so the confidence law (R1's clamp) is untouched — only g's computation generalizes.
run_dream_rnd(view, derived, *, config=None)
R0+R1 end to end behind the flag: run the interpreter panel, adjudicate, and persist the confidence-ordered dream log as INTERPRETED artifacts. Refuses unless the R&D flag is on.
charter
The dream-dispatch record (dn-synchronic-diachronic-dreamer §2.2 SD-2, N1).
A dream dispatch is a typed DreamCharter binding four things:
- the scope grant —
meet(owner_grant, dreamer_scope(strata)): the owner declares strata (per-scope-grant, dn-cross-strata-dreamer), the role constructor supplies the region, and the meet is the ratified delegation law (Scope.meet, non-negotiable #6). This module never re-implements the algebra — it is a client of it (§2.3, the algebra-as-tools ruling); - the instrument grant — the dreamer's senses are named tool handles over evaluators (σ/MST,
conductance-profile, census, persistence), granted as a set
⊆ INSTRUMENT_MAX, resolved at construction with the factory's existing ceiling pattern (core/factory/roles.py:24-40: capability =scope ∩ MAX, refuse at construction, never widen — and, per the falsifier, never silently clamp). Instruments are NOT a scope coordinate — they are a capability over code*, result-side machinery over already-granted reads (§2.1 visibility test); - the budget — the L3 cost-model parameters (node/edge ceilings, eigensolve dimension cap,
walk budget) the refusal gate reads (
core.dreaming.evaluate); - the gauge — ANCHORED by default; RETRO/ARCHIVAL are declared descriptors (the enum keeps them, so a reading can pin its gauge fingerprint) but their dispatch paths are parked (SD-b), so constructing a charter with one refuses, naming the park.
PURE-CORE: imports only core.scope and core.agent_scope (both pure-core themselves). It reads no
store, materializes no clock, wires no read-path gate — the enforcement is the algebra's own
(admissibility) plus the guard-tier tests. The materialization boundary lives next door in
core.dreaming.evaluate; this module is only the record and its construction-time refusals.
INSTRUMENT_MAX = frozenset(Instrument)
module-attribute
Instrument
Bases: StrEnum
A named tool handle over an evaluator — the dreamer's senses (§2.2-2, §2.3). Each is a
capability over code (a name-to-callable binding at mint), NOT a scope coordinate. The initial
registry (the note's §2.2 exemplars); the code does not yet settle a member's machinery beyond
the handle, so a member demanding more than a name-to-callable binding is a finding (plan §10,
Q3). Their math is built elsewhere (core/graph/, spine-side census, FB-1) and consumed by
later plans (bp-080/082) — this registry only names what a grant may hold.
SIGMA_STAR_MST = 'sigma_star_mst'
class-attribute
instance-attribute
CONDUCTANCE_PROFILE = 'conductance_profile'
class-attribute
instance-attribute
CENSUS = 'census'
class-attribute
instance-attribute
PERSISTENCE = 'persistence'
class-attribute
instance-attribute
Gauge
Bases: StrEnum
The gauge of a (past) read (graph-at-a-past-cut D4) — a result-side declared descriptor,
NOT a scope coordinate (§2.1). ANCHORED (today's vectors, membership-at-c) is the only live one;
RETRO (content-at-c re-embedded) and ARCHIVAL name then-geometry whose dispatch paths are parked
(SD-b, waits on graph-at-a-past-cut's graduation). The enum keeps all three so a reading can
pin its gauge fingerprint (the declared-descriptor discipline); constructing a charter with a
parked gauge refuses (see DreamCharter.__post_init__).
ANCHORED = 'anchored'
class-attribute
instance-attribute
RETRO = 'retro'
class-attribute
instance-attribute
ARCHIVAL = 'archival'
class-attribute
instance-attribute
Budget
dataclass
The dispatch's cost ceilings (§2.2-3 / §2.4 L3) — the parameters the estimate-then-force
refusal gate (core.dreaming.evaluate) compares an estimate against. Metadata-scale integers
(node/edge counts, eigensolve dimension, walk steps); a force whose estimate exceeds any of
these is refused before a single row is read (L3, rule-#8 kin — the memory-ceiling scheduler
refusal extended to views).
node_ceiling
instance-attribute
edge_ceiling
instance-attribute
eigensolve_dim_cap
instance-attribute
walk_budget
instance-attribute
InstrumentCeilingError
Bases: ValueError
An instrument grant names a handle outside INSTRUMENT_MAX. Refused at construction — the
factory's scope ∩ MAX ceiling shape (core/factory/roles.py:35-40), and per the D-0 falsifier
the refusal is a REFUSE, never a silent clamp (grant ∩ MAX would narrow, hiding the owner's
over-grant).
DreamCharter
dataclass
A dream dispatch as a typed record (§2.2 SD-2). Construct via mint — it composes the scope
grant from owner_grant and dreamer_scope(strata) (the ratified meet) and applies every
construction-time refusal. The stored grant is the composed Scope; instruments is the
resolved instrument grant (⊆ INSTRUMENT_MAX); budget the cost ceilings; gauge the declared
descriptor (ANCHORED live).
Refusals (all at construction, guard/structural tier):
* an instrument outside INSTRUMENT_MAX → InstrumentCeilingError (refuse, never clamp);
* a grant naming FOUNDATION (𝔇) → ValueError (the denylist ideal, ⊤_Σ = R ∖ 𝔇);
* a grant that does not preserve the dreamer's (READ, W_Σ=1, NONE) output authority →
ValueError (a malformed owner grant cannot narrow the role's interpreted-write bit);
* a parked gauge (RETRO/ARCHIVAL) → NotImplementedError, naming SD-b.
grant
instance-attribute
instruments
instance-attribute
budget
instance-attribute
gauge = Gauge.ANCHORED
class-attribute
instance-attribute
mint(owner_grant, strata, instruments, budget, gauge=Gauge.ANCHORED)
classmethod
Compose the record. The scope grant is meet(owner_grant, dreamer_scope(strata))
via the ratified delegation law (Scope.meet; meet(parent, template) ⊑ parent,
non-negotiable #6), never re-implemented here. All construction-time refusals fire in
__post_init__.
cluster
Deterministic embedding clustering for the dreaming + curator agents (BUILD-SPEC §9).
No model, no scikit-learn — just NumPy cosine similarity and single-linkage connected components over a similarity threshold. This is the §9 principle in miniature: the heavy, deterministic work (grouping notes by theme) is done in cheap code so the scarce inference slot is earned only for the synthesis step (the model reflects a cluster back as a theme).
Clustering is at the NOTE level: each note's chunk vectors are averaged into one centroid, because chunk-level clustering over-fragments a single note across many themes. Given a stable input order the output is fully reproducible — a dream run is deterministic.
NoteVector
dataclass
digest
instance-attribute
title
instance-attribute
vector
instance-attribute
Cluster
dataclass
members
instance-attribute
titles
property
digests
property
size
property
note_snippets(rows, *, limit=600)
Per-note grounding text: that note's chunk texts concatenated in row order and
truncated to limit chars. Keeps a synthesis/contradiction context lean (§13) while
still grounded in the owner's actual words.
note_centroids(rows)
Aggregate chunk rows (one per vector) to one centroid per note (keyed by digest). Insertion order follows first appearance, so the result is deterministic.
similarity_matrix(notes)
Pairwise cosine similarity over note centroids.
cluster_notes(notes, *, threshold, min_size=2)
Single-linkage connected components: notes whose cosine similarity >= threshold
are joined into a theme. Returns clusters of at least min_size members, largest
first (ties broken by the first member's title — deterministic ordering).
near_duplicate_pairs(notes, *, threshold)
Distinct note pairs whose centroids are near-identical (cosine >= threshold).
These are near-duplicate CANDIDATES the curator flags — never auto-merged, because
authored notes are immutable ground truth (§8). Sorted most-similar first.
conditioning
The conditioning law — the anti-laundering tooth of the synchronic/diachronic dreamer (§2.7).
A dream synthesized over graph ∪ subspace is hypothesis-conditioned: part of its grounding
bottoms out in a STAGED hypothesis, not authored evidence. The taint is structural, not editorial —
a hypothesis the owner never authored cannot launder itself into belief through the dreamer's
exhaust. The four clauses (note §2.7), each fail-closed:
- Provenance carries the condition. A conditioned artifact records
(subspace_id, generation, staged-item digests)in itsdata, and itsderivestails include the staged items' content addresses. The mark RIDES the existing shape:derived_fromis a flat tuple of arbitrary string refs (it carries staged digests as tails), anddatais a free-form dict (it carries the condition record) — no durable-store schema change (Q3 verified at build start). The mark indatais what distinguishes a staged tail from an authored leaf, so the sharpened grounding rule (clause 4) is auditable. - TTL inheritance. A conditioned artifact surfaces ONLY while its pinned staged digests are still live in the staging store at the read generation. When the subspace expires (its rows tombstoned by the sweep), the artifact leaves the surfacing set — but it stays READABLE as a record (the artifact is untouched; the staging store's generation-addressed reads keep an expired dream reproducible, §2.6-2). A hypothesis cannot outlive its own expiry through a dream.
- Taint attribution IS the influence computation (the unification that makes this cheap).
The per-claim leave-the-subspace-out recompute is the SAME with/without diff as
core.graph.influence: a claim that holds bit-identically without the overlay is corpus-grounded (may shed the mark); a claim with nonzero influence is conditioned (keeps it). One diff does double duty — influence detection and taint attribution. - Grounding terminates in authored evidence or declared hypothesis, marked — never in prior
interpretation. The recursion bound is untouched: a dream's tails never include a dream
(dreams cannot cite dreams as evidence,
recursive-dreaming-bounded-by-groundingrule); the citation classes split (authored leaf vs staged digest) and the split is visible in every report.
Falsifiers (F-SD7b), all fail-closed: a claim marked corpus-grounded whose reading changes when
the subspace is removed (taint test); a conditioned artifact surfacing after its generation expired
(sweep test); a derives edge over a composed read whose tails omit staged digests (lineage
audit). Any one observed ⇒ the law is broken and surfacing is BLOCKED — never a warning.
PURE-CORE: imports core substrate only (core.stores.{derived,staging}); reads no network,
materializes no wall clock (the staging generation is the clock, Law C4). It does NOT write a
durable store — the marking helpers shape what a (future) dreamer write path passes to the existing
DerivedStore.add; this module only reads and verifies (dry-run over fixtures here).
CONDITION_KEY = 'condition'
module-attribute
ConditioningViolation
Bases: AssertionError
An F-SD7b tooth was observed — the conditioning law is broken. Raised so surfacing FAILS
CLOSED (blocked, never warned): a corpus-grounded claim that changes under the overlay (taint
test), or a conditioned artifact whose derives tails omit staged digests (lineage audit).
These are structural laundering bugs, not the normal expiry lifecycle (which blocks surfacing
without raising — see is_surfaceable).
Condition
dataclass
The hypothesis a conditioned artifact is grounded on (clause 1): the subspace_id it read,
the generation it pinned (the staging store's event clock — reproducible as a record, Law
C4), and the staged_digests (the staged items' content addresses that enter the derives
tails).
subspace_id
instance-attribute
generation
instance-attribute
staged_digests
instance-attribute
TaintSplit
dataclass
The per-claim taint split (clause 3): conditioned are the influence readings the overlay
moved (nonzero delta — they KEEP the condition mark); corpus_grounded are the readings
bit-identical without the overlay (they MAY shed it). The split is computed straight from the
influence output — taint attribution and influence detection are the same diff.
conditioned
instance-attribute
corpus_grounded
instance-attribute
condition_data(cond)
The data payload marking an artifact as hypothesis-conditioned (clause 1). A dreamer write
path merges this into DerivedStore.add(data=...); the mark is what lets a leaf-audit tell a
staged tail from an authored leaf (clause 4). Pure data — no store write here.
conditioned_derives(authored_leaves, cond)
The derives tails for a conditioned artifact (clause 1): the authored-leaf digests PLUS the
staged items' content addresses, so the grounding chain visibly bottoms out partly outside the
corpus. The staged digests appear here (as tails) AND in data (the mark) — the redundancy is
the lineage audit's cross-check (F-SD7b tooth 3). Order-stable; duplicates dropped.
read_condition(artifact)
Parse the condition mark off an artifact's data, or None if it is not conditioned (an
ordinary corpus-grounded dream). The inverse of condition_data.
is_surfaceable(cond, store, *, at=None)
Whether a conditioned artifact may SURFACE at staging generation at (default: the current
generation) — clause 2, TTL inheritance. True iff EVERY pinned staged digest is still live in
the subspace at at; once the subspace expires (its rows tombstoned by the sweep) the digests
drop out of the generation-addressed read and the artifact leaves the surfacing set. This blocks
surfacing WITHOUT raising: expiry is the normal lifecycle, not a laundering bug. The artifact
itself stays a readable record — this function reads, never deletes.
taint_split(influences)
Split per-claim influence readings into conditioned (moved by the overlay ⇒ keep the mark)
and corpus-grounded (unmoved ⇒ may shed it) — clause 3. The input IS the core.graph.influence
output (the leave-the-subspace-out recompute); no second computation.
assert_grounding_terminates(artifact, cond, *, dream_ids)
The sharpened grounding rule (clause 4): every derives tail of a conditioned artifact is
either an authored leaf or one of the condition's declared (marked) staged digests — and NO tail
is a dream (the recursion bound is untouched: dreams never cite dreams as evidence). Raises
ConditioningViolation (fail closed) if a tail is a dream, or if a staged digest in the mark is
missing from the tails (an undeclared hypothesis masquerading as an authored leaf).
verify_surfacing(artifact, cond, split, store, *, dream_ids=(), at=None)
The fail-closed gate a caller runs BEFORE surfacing a conditioned dream. Checks all three F-SD7b teeth and returns whether the artifact may surface:
- tooth 3 (lineage audit) — the derives tails must include every staged digest, and no
tail may be a dream (clause 4). A violation RAISES
ConditioningViolation(a laundering bug, fail closed loudly). - tooth 1 (taint test) — every claim the split marks corpus-grounded must genuinely be
unmoved by the overlay; a corpus-grounded claim that
changedRAISES (an inconsistent mark is a laundering bug). - tooth 2 (sweep test) — if the subspace has expired (a pinned staged digest is no longer live), the artifact does NOT surface: returns False. Expiry is the normal lifecycle, not a bug, so it blocks quietly rather than raising.
Returns True only when all teeth pass AND the subspace is still live — the single sanctioned way a conditioned dream reaches the surfacing set.
dreamer
The dreaming agent (BUILD-SPEC §9) — Zone A, cron/trough tier.
Clusters the AUTHORED corpus into themes, then asks the synthesis-tier model to reflect each theme back to the owner as a lens on their own notes — mirror, not oracle (Constitution §III.2): grounded in the clustered notes, citing them, never presented as external truth.
Firewall: it reads MIRROR_READABLE (AUTHORED only), so third-party observed exhaust can
never seed a dream and dreams never enter the behavioral baselines (§15). Output is stored as
INTERPRETED artifacts in the derived store (regenerable), and each synthesis runs the
Constitution pre-return check (core.selfcheck) before it is kept — a dream that fabricates a
citation is flagged exactly like a librarian answer that does.
Trough-only: a dream job routes to the synthesis tier (scheduler.router), which the
supervisor's foreground gate (HEAVY_TIERS, Phase 3) blocks while the owner is present — so
dreaming is never concurrent with foreground use (§13). The synthesizer is injected so this
module is testable without the (large, possibly unpulled) synthesis model.
Synthesizer = Callable[[list[Message]], str]
module-attribute
Clusterer = Callable[..., list[Cluster]]
module-attribute
DREAMER_ROLE = "You are the dreaming agent of a sealed personal mind-palace. You are shown a cluster of the owner's OWN notes that group together by theme. Reflect that theme back to the owner as a lens on their own thinking — a mirror, never an oracle.\n\nGround every observation in the notes shown and cite them by title in double brackets, e.g. [[note title]]. Do not introduce facts that are not in these notes, do not invent notes or quotes, and do not present anything as external truth. Surface the recurring patterns, tensions, and open questions you see across these notes, and leave the conclusions to the owner. If the notes do not actually cohere into a theme, say so."
module-attribute
Theme
dataclass
titles
instance-attribute
summary
instance-attribute
check
instance-attribute
artifact
instance-attribute
Dreamer
dataclass
store
instance-attribute
synthesize
instance-attribute
derived
instance-attribute
threshold = 0.62
class-attribute
instance-attribute
min_cluster_size = 2
class-attribute
instance-attribute
max_clusters = 8
class-attribute
instance-attribute
clusterer = cluster_notes
class-attribute
instance-attribute
judge = None
class-attribute
instance-attribute
attestor = None
class-attribute
instance-attribute
edge_store = None
class-attribute
instance-attribute
snapshots = None
class-attribute
instance-attribute
clusters()
Deterministic note-level clustering over the AUTHORED mirror (model-free, §9).
The rows come from a MirrorView (Invariant 6, structural): its only constructor is
the MIRROR_READABLE projection and it cannot hold a non-authored row, so observed
exhaust reaching this clustering is unrepresentable — not merely filtered out.
dream()
Run a full dreaming pass: cluster -> synthesize each theme -> self-check -> store. Returns the themes produced (also persisted as INTERPRETED dreams).
dream_v2(*, config=None)
The strong-Dreamer pass — deterministic structure first, the earned model call last:
1. BUILD 𝔎|_MR (firewall structural: the complex is built from a MirrorView)
2–5. LOCATE / THEME / TENSION / GAPS — the interpreter panel over the complex 6. SUPPORT — noisy-OR multi-path grounding on the derivation DAG (§6.1) 7. ADJUDICATE — c = min{1, γ^d·g·(1+λ(|Agr|−1))}, confidence-ordered 8. SYNTHESIZE — the ONLY model call(s): narrate each selected candidate, grounded in its authored evidence, mirror-not-oracle 9. STORE — interpreted-only, derives→authored leaves, acyclic, attested 10. MEASURE — append the structural snapshot (§5.4; feeds the A2 drift axes)
Gated by the dream-R&D hard boundary ([dream_rnd] enabled, OFF by default): the live
dream() above is UNCHANGED and remains the cron path until a deliberate flip. Every
structural judgment here is deterministic and model-free; self.synthesize is the only
model seam, invoked once per stored dream and nowhere else. Trough-only when wired
(a dream job routes to the synthesis tier, which the foreground gate blocks).
build_dreamer(config=None, *, tier='synthesis')
Wire a Dreamer against the real configured stores + synthesis model. Pulling the synthesis-tier model is required only to actually run it (the unit path injects a fake).
evaluate
The materialization boundary — estimate then force (dn-synchronic-diachronic-dreamer §2.4 SD-4).
Laziness is a requirement here, not an optimization (the owner's addendum, adopted as law): the graph grows in size and time, so evaluation strategy is first-class. This module is the dispatch layer's realization of three of the five laws:
- L1 — composition is symbolic; cost is O(expression). A
ScopeExpressioncomposes scope operations (meet / restrict / anchor-shift) without touching a store. Composing k of them is purecore.scopearithmetic — zero row reads. - L2 — one materialization boundary.
Evaluator.force(grant, cut[, generation]) → readingsis the single seam where rows become real, and it applies the admissibility check at the same call. The evaluator is the dispatch's ONLY store-touching capability (the closed-evaluator condition); a store handle not derivable from it failsassert_conforms(guard tier — honestly labelled; the structural v3 is SD-g, parked). - L3 — estimate-then-force (the refusal gate). Every force is preceded by a
CostEstimatecomputed from the unevaluated expression against an injectedStatsProvider(metadata only — chain/node counts, grid sizes, eigensolve dims). The estimate is pure data computed core-side; the refusal is machinery-side (the model advises / code acts split, non-negotiable #3). An over-budget estimate refuses BEFORE a single row is read, reporting budget and estimate, quantified.
PURE-CORE: imports only core.scope, core.agent_scope, core.mirror, and core.dreaming.charter
— all pure-core. It reads no live store: force reads through an injected RowSource (the
core.mirror seam, reused — §2.5), and estimate reads through an injected StatsProvider. Wiring
a live stats source or a live row source is a LATER plan's call (Q4 parked); both are Protocols,
exercised by counting fakes.
ScopeExpression
dataclass
An UNEVALUATED composition of scope operations (L1). A ScopeExpression wraps a resolved
Scope (grant) and records the composition trail (ops) for provenance; every combinator
(meet, restrict, anchor_shift) returns a NEW expression via pure core.scope arithmetic,
touches no store. Composing k expressions is therefore O(expression) with zero row reads — the
honest baseline the force seam sits behind.
grant
instance-attribute
ops = ()
class-attribute
instance-attribute
meet(other)
Compose with another scope (the delegation/intersection law) — symbolic, store-free.
restrict(other)
Narrow this expression by another scope (a restriction is a meet by a narrower grant). Named separately for the composition trail; the arithmetic is the meet.
anchor_shift(window, cut=None)
Rebind the time window (an anchor-shift: same Σ/E/A, a new cut/interval) — symbolic.
The re-anchored scope is a fresh Scope; SLICE re-checks for free at its construction, so a
multi-stratum point anchor supplies its cut here (a downset over a base stratum is already
multi-element, so a point window always carries one).
StatsProvider
Bases: Protocol
The injected metadata surface an estimate reads (Q4, parked — Protocol only, no live wiring). Every method is a METADATA read (chain counts, node/edge counts, grid/eigensolve dims) over a grant — never a row read. A live provider is a later plan's call (the first live dispatch names its source); here it is exercised by counting fakes so the estimate is proven store-free.
node_count(grant)
edge_count(grant)
eigensolve_dim(grant)
walk_steps(grant)
CostEstimate
dataclass
A force priced from metadata only (L3) — pure data computed core-side, no rows touched. Each
field mirrors a Budget ceiling so over(budget) is a componentwise comparison; the refusal
message reports both, quantified.
nodes
instance-attribute
edges
instance-attribute
eigensolve_dim
instance-attribute
walk_steps
instance-attribute
over(budget)
The dimensions where this estimate exceeds budget, as {dim: (estimate, ceiling)} —
empty iff the force is within budget. Pure comparison; reads nothing.
BudgetRefusalError
Bases: RuntimeError
A force refused at estimate because its cost exceeds the budget (L3, F-SD4a). Machinery-side (the model advises / code acts split); the message carries both budget and estimate, quantified, and is raised BEFORE any row is read (the counting fake proves zero reads).
Evaluator
dataclass
The dispatch's single store-touching capability (L2, the closed-evaluator condition). Holds
exactly one RowSource (the core.mirror seam, reused — a later representation swap behind
force touches nothing here: F-SD5) and its declared handle inventory. estimate prices it
from metadata (zero row reads); force is the one materialization boundary; materialize is
the L3 gate (estimate → refuse-or-force). Guard tier: assert_dispatch_conforms checks it
against the grant — a store handle not derivable from the evaluator is a ConformanceError.
source
instance-attribute
handles = field(default_factory=tuple)
class-attribute
instance-attribute
estimate(expr, stats)
Price a force of expr from METADATA only (L3) — reads stats, never source; pure
computed core-side; the refusal it feeds is machinery-side (see materialize).
force(grant, cut, generation=None)
The ONE materialization boundary (L2) — the single point where rows become real, and the
dispatch's only store-touching call. Applies the admissibility check at the SAME call (the
unification), then reads one burst through the RowSource. cut (and, for a counterfactual
read, generation) pin the read; a multi-stratum point read already demanded its cut for
free at the grant's construction (SLICE), so this seam never re-implements legality.
materialize(expr, budget, stats, cut, generation=None)
The L3 refusal gate — estimate-then-force in one seam. Prices expr from metadata; if
the estimate exceeds budget on any dimension, REFUSES (BudgetRefusalError) BEFORE
any row is read; otherwise forces exactly one read burst. This is the only sanctioned way a
dispatch obtains rows, so F-SD4b (a row with no force event) and F-SD4a (a breach with no
prior estimate) are both closed by construction.
assert_dispatch_conforms(grant, evaluator)
Guard-tier closed-evaluator check (L2): the evaluator's handle inventory is within grant
(assert_conforms, reused verbatim — the algebra's own conformance). A store handle not derived
from the evaluator — one reaching a stratum outside Σ, or projection-writing/edge-writing beyond
the grant — raises ConformanceError. Honest label: a construction-site check, not a structural
impossibility (the structural v3 is SD-g, parked; F-SD4b re-opens it).
compose(exprs)
Fold a sequence of expressions by meet — a convenience for the L1 zero-read demonstration.
Pure core.scope arithmetic; touches no store.
graph
The mirror graph G_MR — the shared substrate every interpreter reads (R0; §6/§8).
Built ONCE from a MirrorView (authored-only, Invariant 6 — structural firewall) and handed to
each method-specialist, so the panel computes note centroids + the σ-thresholded adjacency a
single time. Fully deterministic and model-free (NumPy cosine only): the §9 deterministic
floor. The graph is $G=(V,E)$ with $E_{\text{sim}}={(u,v):\cos\ge\sigma}$ over note centroids.
This is read-only structure; the interpreters (interpreters.py) derive claims from it and the
adjudicator (adjudicator.py) ranks them. Nothing here touches a model or the network.
MirrorGraph
dataclass
Note-level similarity graph over the authored mirror. sim is the full cosine matrix;
edges are pairs with sim >= sigma. Deterministic given the MirrorView's row order.
notes
instance-attribute
sim
instance-attribute
sigma
instance-attribute
n
property
build(view, *, sigma)
classmethod
π_MR → centroids → σ-adjacency. Input is a MirrorView, so the graph is provably
over authored notes only (a non-authored node is unrepresentable upstream).
digest(i)
title(i)
neighbors(i)
Indices j != i with cos(i, j) >= sigma — deterministic ascending order.
degree(i)
local_clustering(i)
Clustering coefficient of node i: fraction of its neighbour pairs that are themselves adjacent. LOW clustering at a high-degree node = a structural hole / bridge (Burt): the neighbours form separate groups this node holds together. Degree<2 => undefined => 0.0.
digests_for(indices)
The authored content digests for a set of node indices — the evidence refs (G1).
titles_for(indices)
interpreters
R0 — the interpreter panel (design-notes/dreaming-v2-interpreter-panel.md; §6/§8; BUILD §3.2).
Generalizes the Phase-7 single clusterer into a REGISTRY of deterministic interpreters — the "workers", specialists by METHOD (not source). Each is a different lens on the same authored mirror graph and emits candidate pattern-claims plus the authored graph evidence that supports them:
φ_i : G_MR → 2^K, κ = (statement, support ⊆ authored notes)
All are model-free — the §9 deterministic floor; the model is earned only for narration/judging,
which R0 does NOT do. No adjudication here (that is R1): R0 just produces the raw claims. Inputs
are a MirrorView, so every claim's support is authored (Invariant 6, structural) — observed
exhaust can never seed a claim.
Two generations of lens share the panel (BUILD §3.2 — "each interpreter is a thin adapter over a
core/complex/ function"):
- the original NumPy lenses over the σ-graph: community (connected components), centrality (degree hubs), density (cores + explicit noise);
- the STRUCTURAL lenses over the reasoning complex (H4–H7):
bridge(Forman–Ricci curvature — upgraded from the local-clustering proxy to the real instrument, companion III §3.2),hole(persistent H₁ — conceptual gaps, NEVER contradictions, §4.2),theme(DC-SBM posterior with a model-selected count + a spectral cross-check, §6.2); - the degree-1 lift (design note
dn-edge-dynamics§2.3, bp-022, Lane A L-b):thread— the harmonic H₁ lens overcore/complex/hodge.py's Hodge decomposition, a gap-family sibling ofholenarrating the circulating structure that orbits a hole rather than the hole itself.
Change-point is a registered but DEFERRED seam — it needs a per-note temporal axis the MirrorView
does not yet carry, so it returns nothing rather than fake a trend (the honest-seam pattern).
Contradiction (tension) stays routed through the signed Laplacian (core/complex/balance.py) +
typed contradicts edges; it joins the panel when a contradiction detector exists to assert them.
COMMUNITY = 'community'
module-attribute
CENTRALITY = 'centrality'
module-attribute
BRIDGE = 'bridge'
module-attribute
DENSITY = 'density'
module-attribute
THEME = 'theme'
module-attribute
HOLE = 'hole'
module-attribute
THREAD = 'thread'
module-attribute
TENSION = 'tension'
module-attribute
CHANGE_POINT = 'change_point'
module-attribute
CENSUS_LOOP = 'census_loop'
module-attribute
CENSUS_ASYMMETRY = 'census_asymmetry'
module-attribute
CENSUS_REACH_BACK = 'census_reach_back'
module-attribute
Interpreter = Callable[[MirrorGraph, DreamRnDConfig], 'list[Claim]']
module-attribute
StructuralInterpreter = Callable[[StructuralContext, DreamRnDConfig], 'list[Claim]']
module-attribute
INTERPRETERS = {COMMUNITY: community_interpreter, CENTRALITY: centrality_interpreter, DENSITY: density_interpreter, CHANGE_POINT: change_point_interpreter}
module-attribute
STRUCTURAL_INTERPRETERS = {BRIDGE: bridge_interpreter, HOLE: hole_interpreter, THEME: theme_interpreter, THREAD: thread_interpreter}
module-attribute
Claim
dataclass
A candidate pattern-claim from one interpreter. support is the set of authored note
digests the claim rests on — content-addressed evidence (G1), and the LEAVES that ground it
(G2). data is method-specific. No confidence here; ranking is the adjudicator's job (R1).
method
instance-attribute
statement
instance-attribute
support
instance-attribute
data = field(default_factory=(dict[str, Any]))
class-attribute
instance-attribute
StructuralContext
dataclass
One pass's shared structural state: the reasoning complex 𝔎|_MR at the working σ, plus
the full cosine-distance matrix (the persistence filtration sweeps thresholds, so it must
not be pre-thresholded). Built by run_panel; consumed by the structural interpreters.
complex
instance-attribute
distances
instance-attribute
community_interpreter(graph, cfg)
Connected components over the σ-graph — thematic groups (the Phase-7 lens, as one of many). Each component of >=2 notes is a theme; support = the component's notes.
centrality_interpreter(graph, cfg)
Degree centrality — which notes are load-bearing hubs. The top-k highest-degree notes (degree >= min_degree); support = the hub plus the notes it links.
bridge_interpreter(ctx, cfg)
H4 — the curvature bridge lens: Forman–Ricci over the σ-backbone, most negative first (companion III §3.2 — the principled replacement for the local-clustering proxy). A very negative edge is a surprising cross-domain link: exactly what a synthesis pass should look at first. Support = the two linked notes.
hole_interpreter(ctx, cfg)
H5 — the persistence lens: long-lived H₁ features of the flag complex are conceptual holes — notes pairwise related in a ring with no center. A hole is a GAP to surface (a utility-axis prompt), never a contradiction (§4.2: dissonance is balance.py's job).
thread_interpreter(ctx, cfg)
Lane A L-b — the harmonic lens (design note dn-edge-dynamics §2.3, bp-022 §6(b)):
the flag complex's harmonic classes (ker L₁, bp-021's core/complex/hodge.py) localized to
their carrying cycles — a closed loop of pairwise-related notes orbiting a gap you have not
stated. Routing class: gap-family, NEVER contradiction (dissonance stays with tension_claims
/ the signed machinery, §2.3's routed-split inheritance). The honest seam comes FIRST: β₁ = 0
(no harmonic classes at all) short-circuits before any hole pairing is attempted, so a
filtration hole below scale can never be misread as a thread.
theme_interpreter(ctx, cfg)
H7 — the SBM lens: degree-corrected blocks give theme membership WITH a posterior and a model-selected theme count (§6.2 — "how many concerns, how sure"), cross-checked against the spectral partition (agreement = robust, disagreement = fragile — a signal in itself). The posterior organizes the graph; it never certifies a thought (§6.3).
density_interpreter(graph, cfg)
Density split (the HDBSCAN-style contribution): notes with >= min_degree neighbours are 'core'; notes with no σ-neighbour are explicit NOISE/outliers. Emits a core-region claim and, distinctively, an outliers claim — the signal the connected-components lens hides.
change_point_interpreter(graph, cfg)
DEFERRED seam: temporal change-point detection needs a per-note timestamp, which the MirrorView does not yet carry. Returns nothing rather than fabricate a trend — the same honest-seam discipline as the §4 judge and the contradiction detector. Wire it when an authored temporal axis lands on the mirror rows.
build_structural_context(view, cfg, *, edges=None)
One pass's shared structural state: the σ-backbone complex (optionally with persisted typed/signed edges overlaid — the tension lens's input) + the unthresholded distance matrix (the persistence filtration). Authored-only by the constructor's input type.
tension_claims(kx)
The tension lens (§2.3): every frustrated triangle — an odd number of − edges — is three
commitments that cannot all co-hold ("you keep circling this"). Consumes the signed adjacency
(contradiction = a persisted contradicts edge overlaid by build_complex); with no asserted
contradictions the graph is all-support and this honestly emits nothing. Dissonance lives
HERE, never in H₁ (§4.2).
census_lens(reading, cfg)
Map an arrow-aware census reading onto panel Claims (§2.9 ADOPTED — equal-citizen). support
is the claim's authored member refs (so grounding treats a census claim like any lens's); the
witness and the anchored cut ride in data. The empty census emits ZERO claims — silence,
never filler (§2.9-d). cfg is accepted for interpreter-signature symmetry (no census tunable
today).
collect_claims(graph, ctx, cfg, *, census=None)
Run both registries (σ-graph lenses + structural lenses) plus the tension lens over
already-built state. The un-gated core of run_panel, shared with the loop-v2 dream pass
(which builds its own context so it can overlay persisted edges). When a census reading is
supplied, its arrow-aware claims join equal-citizen (bp-080 Item 5); absent (the default), the
panel is byte-for-byte what it was before the census lens registered.
run_panel(view, *, config=None, census=None)
Run every registered interpreter (σ-graph lenses + structural lenses over one shared
reasoning complex) and return all candidate claims (R0 — no adjudication). Refuses unless
the R&D flag is on (hard boundary). An optional census reading (bp-080 Item 5) joins the
arrow-aware census claims equal-citizen behind the SAME flag; None keeps the panel unchanged.
run_census_lens(reading, *, config=None)
The census lens behind the hard R&D flag (like run_panel) — renders a census reading as
equal-citizen panel claims. Refuses unless [dream_rnd] enabled is set deliberately, so the
arrow-aware narration cannot run in a normal session (it lands BEHIND the flag; bp-080 changes
no R&D wiring).
rnd
The hard feature-flag boundary for the dream-phase R&D track (design-notes/ dream-phase-rnd-charter.md).
The interpreter panel (R0) and the evidence-based adjudicator (R1) are RESEARCH, behind a flag
that is OFF by default. They are deliberately NOT wired into the live dream path —
scheduler/cron.py runs the Phase-7 Dreamer, never this. As a second line of defense, every
R&D entry point calls require_rnd_enabled(config) and raises if the flag is off, so even a
direct import-and-call cannot run the R&D engine in a normal session. To exercise it you must
explicitly construct a config with [dream_rnd] enabled = true — a conscious R&D act.
This keeps the riskiest layer (the one place the system reasons over its own outputs, once R3 lands) gated by construction, not by remembering to be careful.
DreamRnDDisabledError
Bases: RuntimeError
An R&D dream entry point was called while the feature flag is OFF (the default).
This is the boundary: the interpreter panel / adjudicator never run unless
[dream_rnd] enabled = true is set deliberately. Not reachable from the live path.
rnd_config(config=None)
require_rnd_enabled(config=None)
Fail closed unless the R&D flag is explicitly on. Called by every R0/R1 entry point.
shadow
The shadow runner — the harness's single-config run producer (E2, bp-043 Item 6).
Drives BOTH dream pipelines over ONE MirrorView snapshot in one trough window and writes:
- claims -> the run ledger (
core/stores/runledger.py): phase7 = the community lens (the Phase-7 single clusterer, model-free); dream_v2 = the full interpreter panel + the evidence-based adjudicator (model-free — the earned model call, step 8 ofdream_v2, is NEVER made here); - registered metric Readings -> the E1 eval store (
eval/harness/{store,registry}): the built guardrails (drift_D,golden_recall) and dream_v2'sstructural_axes.*, each keyed by this run's unified key (§2.1) so the A/B split is attributable.
The load-bearing property (family-2 discipline): the two pipelines are two derived functors over
ONE raw corpus — the same corpus_digest in yields two diffable claim sets out. The whole-plan
falsifier is the live dream surface changing: shadow reads only a MirrorView (Invariant 6,
structural firewall) and writes only the ledger + the eval store — NEVER the interpreted/derived
store, and NEVER the [dream_rnd] disk flag (dream_v2 is enabled IN-PROCESS via replace).
Two reconciliations of the plan's pins, forced by the model-free invariant (§7 Item 6):
1. Dreamer.dream_v2 makes a model call (step 8, self.synthesize), so the runner runs the
pipeline STEPS directly (collect_claims + adjudicate, no support_of -> flat grounding,
no derived read) rather than the method — satisfying §3 Q4 ("persist nothing but ledger rows").
2. step-10 (the structural snapshot that feeds the A2 axes, §3 Q6) is computed directly into an
EPHEMERAL scratch SnapshotStore (NOT the live structural.duckdb — no live pollution); the
runner then reads latest_structural() from that scratch store. If it returns nothing the A2
axes are logged not-captured (no silent cap, §2.8), never fabricated.
ShadowRunner
dataclass
One snapshot, two runs. Production: ShadowRunner(ledger).run() resolves the mirror + eval
store from config and runs a scratch snapshot store. Tests inject every seam. The guardrail
retriever reads the golden FIXTURE corpus (not the vault — firewall intact); absent,
guardrails are logged not-captured rather than fabricated.
ledger
instance-attribute
store = None
class-attribute
instance-attribute
eval_store = None
class-attribute
instance-attribute
snapshots = None
class-attribute
instance-attribute
retriever = None
class-attribute
instance-attribute
golden = None
class-attribute
instance-attribute
baseline = None
class-attribute
instance-attribute
drift_cfg = None
class-attribute
instance-attribute
seed = 0
class-attribute
instance-attribute
run(*, config=None)
Execute both pipelines over one MirrorView snapshot; return (phase7_run_id,
dream_v2_run_id). Model-free; writes only the ledger + the eval store.