Skip to content

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:

  1. the scope grantmeet(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);
  2. 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);
  3. the budget — the L3 cost-model parameters (node/edge ceilings, eigensolve dimension cap, walk budget) the refusal gate reads (core.dreaming.evaluate);
  4. 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:

  1. Provenance carries the condition. A conditioned artifact records (subspace_id, generation, staged-item digests) in its data, and its derives tails include the staged items' content addresses. The mark RIDES the existing shape: derived_from is a flat tuple of arbitrary string refs (it carries staged digests as tails), and data is a free-form dict (it carries the condition record) — no durable-store schema change (Q3 verified at build start). The mark in data is what distinguishes a staged tail from an authored leaf, so the sharpened grounding rule (clause 4) is auditable.
  2. 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.
  3. 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.
  4. 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-grounding rule); 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 changed RAISES (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 notesmirror, 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 ScopeExpression composes scope operations (meet / restrict / anchor-shift) without touching a store. Composing k of them is pure core.scope arithmetic — zero row reads.
  • L2 — one materialization boundary. Evaluator.force(grant, cut[, generation]) → readings is 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 fails assert_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 CostEstimate computed from the unevaluated expression against an injected StatsProvider (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 over core/complex/hodge.py's Hodge decomposition, a gap-family sibling of hole narrating 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 of dream_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's structural_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.