core.complex
core.complex
The reasoning complex (family 5, companions III) — Zone A, deterministic, model-free.
This package is the foundation of the strong Dreamer: the object (build.py — nodes, the
weighted similarity backbone A, the signed adjacency A_signed, the derivation hyperedges), the
operator (laplacian.py — L, L_sym, signed L̄), the principled clusterer (spectral.py —
Fiedler, diffusion map, spectral/diffusion clustering that dissolves the single-linkage chaining),
and rigorous contradiction (balance.py — λ_min(L̄), frustration, frustrated triangles).
It reaches no network (import-firewall green) and calls no model — the model is earned only for the
final narration step, elsewhere. Everything is deterministic under a fixed seed. The clusterer is
offered behind the DreamerAdapter seam; the live path opts in, and only the adopted subset (this
package's modules) is wired — the deferred instruments (sheaf Laplacian, Ollivier–Ricci, SBM,
persistence) are specified in the companions but not built here.
balance
Signed balance & frustration (companion III §2.3) — rigorous contradiction detection.
A signed graph is balanced when its nodes 2-color so every + edge stays within a color and every − edge crosses — the tensions resolve into two coherent camps. When they can't, there is frustration: irreducible dissonance. Two readings, both exact/cheap and model-free:
- global — λ_min(L̄) of the signed Laplacian is a dissonance proxy: λ_min = 0 ⇔ balanced (Hou; Kunegis). It rises as the graph becomes harder to 2-color.
- local — a triangle is frustrated iff it has an odd number of − edges; enumerating them localizes which commitments can't co-hold ("these three can't all be true — you keep circling this"). O(#triangles), exact.
This replaces the 0.1 draft's deferred contradiction judge with structure. Deterministic; no model,
no network. The signed adjacency comes from build_complex (persisted contradiction edges overlaid
on the similarity backbone); with no contradictions the graph is all-support and trivially balanced.
signed_spectrum(A_signed)
The dissonance proxy: the MAX over connected components of λ_min(L̄) on that component.
On a CONNECTED graph this is exactly §2.3's λ_min(L̄) (0 ⇔ balanced, Hou/Kunegis). On a disconnected graph the raw global λ_min is the min over components (L̄ is block-diagonal), so one balanced domain — or a single isolated note — would MASK a frustrated triangle elsewhere. A dissonance detector must register tension anywhere, so we take the max; every component balanced ⇔ 0 either way. Components of size < 2 are trivially balanced and skipped. Deterministic (fixed ARPACK start; dense-exact fallback).
is_balanced(A_signed, *, tol=1e-08)
True iff the signed graph is balanced (λ_min(L̄) ≈ 0 within tol).
frustrated_triangles(A_signed)
Every frustrated triangle (i<j<k with all three edges present and an ODD number of − edges) — the specific unresolved tensions. Sorted, deterministic. O(#triangles).
frustration(A_signed)
(λ_min(L̄), frustrated_triangles) — the global dissonance proxy plus the localized tensions (companion III §2.3 contract). Balanced graph ⇒ (0.0, []).
blocks
Degree-corrected stochastic block model — themes with a posterior (companion III §6.2; H7).
The spectral clusterer gives a point partition and makes you pick k. The SBM is generative: it says how likely each note belongs to each theme (a posterior, not a guess) and how many themes the data support (model selection). Degree correction (Karrer–Newman) keeps a prolific topic from swallowing the graph.
Light implementation, per the BUILD §2.2 disposition ("custom, ~200 lines, VEM; keep it thin"): a mean-field variational EM for the Poisson DC-SBM —
E: log q_i(r) ∝ log π_r + Σ_j A_ij Σ_s q_js log ω_rs − d_i Σ_s κ_s ω_rs
M: m_rs = qᵀA q, κ_r = Σ_i q_ir d_i, ω_rs = m_rs/(κ_r κ_s), π_r = n_r/n
initialized from the deterministic diffusion embedding (fixed-seed k-means), run a fixed number of rounds — fully deterministic. Model selection by an ICL/BIC-style penalized complete-data likelihood (the Karrer–Newman objective minus a parameter-count penalty); the exact penalty is a declared engineering choice validated on planted graphs (the block-recovery property test), not a derived MDL bound — stated honestly.
The line held (§6.3): the posterior organizes the graph (membership), it never certifies a thought. Deterministic; model-free; no network.
SBMResult
dataclass
The fitted blocks: hard labels, the n×k membership posterior, the model-selected k, and the ICL score per candidate k (the model-selection trace, for the cross-check).
labels
instance-attribute
posterior
instance-attribute
k
instance-attribute
icl_by_k
instance-attribute
sbm(A, *, k_max=8)
Fit the DC-SBM for k = 1..k_max and select k by the penalized objective (ICL/BIC style):
ICL(k) = L_KN(k) − ½·[k(k+1)/2]·ln W − ½·(k−1)·ln n, W = total edge weight.
Returns the winning k's posterior + hard labels. Deterministic end to end.
build
build_complex(view) — assemble the reasoning complex 𝔎 from a MirrorView (companion III §1).
The object the strong Dreamer reasons over, regenerated per trough pass (never a long-lived global, §1.3):
- nodes — one per authored note (its digest), from a
MirrorViewonly, so a non-authored complex is unrepresentable (Invariant 6, structural firewall — the constructor's type IS the proof); - A — the weighted similarity backbone (cosine over note centroids, negatives/self zeroed);
- A_signed — the signed adjacency: A with polarity overlaid from any persisted typed edges
(
EdgeStore; contradiction ⇒ −w). With no persisted edges it equals A (pure support), so the similarity backbone is a balanced signed graph until a contradiction is asserted; - hyper — the derivation B-arcs (tail set → head) touching these nodes, from the
DerivedStorejunction (companion III §1.3); empty for a pure authored view.
Deterministic (fixed embeddings ⇒ fixed graph), model-free, Zone A (no network).
ReasoningComplex
dataclass
𝔎|_MR — the introspective reasoning complex over authored notes (companion III §1.5).
A small immutable snapshot: the node list + index, the weighted (A) and signed (A_signed)
adjacencies, the derivation hyperedges, and per-node layer/creation arrays for §5.4 temporal
tracking. Assembled by build_complex from a MirrorView; the Laplacian/spectral/balance
modules consume it. Never mutated — a fresh pass rebuilds it (regenerable).
nodes
instance-attribute
idx
instance-attribute
A
instance-attribute
A_signed
instance-attribute
hyper
instance-attribute
layers
instance-attribute
created
instance-attribute
titles = field(default_factory=dict)
class-attribute
instance-attribute
n
property
cosine_adjacency(vectors, *, sim_floor=0.0)
Weighted cosine-similarity adjacency: symmetric, zero diagonal, negatives clamped to 0,
and entries below sim_floor dropped (denoising). Zero vectors sit at the origin (no edges).
The similarity backbone A (companion III §2.2). Deterministic. For the lexical/semantic embeddings the Dreamer uses, orthogonal notes have 0 cosine, so A is naturally sparse.
build_complex(view, *, edges=None, derived=None, sim_floor=0.0)
Assemble 𝔎|_MR from a MirrorView (Invariant 6: authored-only is structural — the input
type cannot hold a non-authored row).
edges (optional EdgeStore): persisted typed/signed edges overlaid onto A_signed, so an
asserted contradiction flips a pair's polarity to −w. derived (optional DerivedStore): the
derivation hyperedges whose tails touch these authored nodes. Both default None (pure
similarity backbone, no hyperedges), keeping the introspective pass self-contained.
curvature
Forman–Ricci curvature — the cheap deterministic floor (companion III §3.2; H4).
Curvature is the intrinsic, embedding-free way to find where the interesting structure is: an edge inside a triangle-dense community is positively curved; an edge with high endpoint degree and little triangle support is a bridge spanning a structural hole — negatively curved. Bridges are where cross-domain insight lives, so the Dreamer ranks edges ascending by curvature and looks at the most negative first.
Augmented unweighted Forman form (variants exist; this is the doc's declared one):
Ric_F(u, v) = 4 − deg(u) − deg(v) + 3·|△(u, v)|
computed on the support of the σ-graph (edges present at the working threshold — the same graph the other lenses see; a weighted Forman variant is a later refinement, not silently substituted). O(#triangles) total, exact, deterministic. Ollivier–Ricci (the principled OT form, §3.1) is an optional enrichment gated on cost and is deliberately NOT implemented here — Forman is the floor.
forman(A)
Augmented Forman–Ricci curvature per edge of A's support, keyed (i, j) with i < j.
Negative on bridges (high endpoint degree, low triangle support); positive inside triangle-dense communities. Exact and deterministic — pure degree/triangle combinatorics.
most_negative_edges(A, *, top_k)
The candidate cross-domain bridges: edges ranked ascending by Forman curvature.
Emission rule (deterministic, no magic threshold): candidates are the edges with κ ≤ 0 —
genuinely bridge-like — or, when every edge is positive (tiny/dense graphs), only the edges
achieving the graph's minimum κ (the relatively most bridge-like; never the whole graph).
At most top_k, tie-broken by (κ, i, j) so the ranking is reproducible.
cut
Min-cut-to-authored + conductance — the alignment detector (companion III §3.5; H6/A2).
The same "distance against ground" move as the drift gauge, on the graph:
- conductance Φ(S) = w(∂S) / min(vol S, vol S̄) — how sealed-off a community is from the rest of the mirror. A community whose conductance is falling over time is becoming an echo chamber (Cheeger: ½λ₂ ≤ Φ ≤ √(2λ₂) ties it to the spectral family). The A2 axis is the worst (minimum) community conductance.
- grounding cut — for an interpreted artifact, the min cut (= max flow) separating it from the authored leaves through its derivation refs. Multi-path support through many refs ⇒ a large cut; everything funnelled through one weak parent ⇒ a small one. Adding an authored support edge can never lower it (monotone — capacities only ever increase).
Exact, deterministic, model-free. Max-flow uses scipy.sparse.csgraph.maximum_flow, which needs
integer capacities: unit-weight refs are integers already; fractional weights are fixed-point
scaled (documented at the constant). These feed the drift gauge's additive structural axes
(eval/drift.py, the A2 extension) — detection only, nothing here alters anything.
conductance(A, S)
Φ(S) = w(∂S) / min(vol S, vol S̄) over the weighted adjacency. 0 ⇔ S is disconnected from the rest; 1-ish ⇔ S is not a community at all. Degenerate S (empty / everything / zero volume) returns 0.0 — maximally sealed, the conservative reading for an alignment detector.
min_conductance(A, labels=None)
The worst (minimum) community conductance over a partition — the A2 echo-chamber axis.
labels defaults to the deterministic spectral partition. Communities of size < 2 are
skipped (a singleton is not a chamber). No community ⇒ 1.0 (nothing sealed off, healthy).
grounding_cut(refs_of, artifact, authored)
The min cut separating artifact from the authored leaves through the derivation refs
(refs_of: artifact id -> its derived_from refs; a ref is either another artifact id or an
authored digest). Unit capacity per ref edge — the cut counts how many refs must be severed
to disconnect the artifact from ground. 0 ⇔ ungrounded (no path to an authored leaf).
Monotone in support: adding a ref (an authored support edge) only ever adds capacity, so the cut never decreases — the metamorphic property the A2 detector rests on.
alignment_snapshot(kx)
The A2 structural axes for the drift profile, computed on one complex snapshot:
frustration— λ_min(L̄) of the signed adjacency (rising = growing dissonance);min_conductance— worst community conductance (falling = an echo chamber forming).
Detection only; the caller (a snapshot writer / the drift harness) feeds these into
eval.drift.Profile — Axis is additive, so this is a data change, not a rewrite (A2).
laplacian
The generalized Laplacian family L = δ*δ (companion III §2.1–§2.3) — the operator.
Three members, all built from a sparse adjacency, all PSD by construction (the Dirichlet energy xᵀLx = ‖δx‖² measures disagreement across edges):
- ordinary L = D − A (§2.2: diffusion, clusters, Fourier)
- sym-normalized L_sym = I − D^{-1/2} A D^{-1/2} (§2.2: spectral clustering basis)
- signed L̄ = D̄ − A_signed, D̄_ii = Σ_j|A_ij| (§2.3: balance / frustration)
They differ only in what δ does on an edge (id transport for L/L_sym, ±1 transport for L̄); the deferred sheaf/hypergraph members are the general-transport cases (companion III §2.4–§2.5), not built here. scipy.sparse only; deterministic; no model, no network.
laplacian(A)
Combinatorial Laplacian L = D − A. dim ker L = number of connected components (§2.2).
laplacian_sym(A)
Symmetric normalized Laplacian L_sym = I − D^{-1/2} A D^{-1/2} (§2.2).
The eigenbasis for spectral clustering; eigenvalues lie in [0, 2]. Isolated nodes (degree 0) contribute a zeroed row/column (D^{-1/2} := 0 there), so the operator is well-defined on a graph with singletons — the standard convention.
signed_laplacian(A_signed)
Signed Laplacian L̄ = D̄ − A_signed with absolute degree D̄_ii = Σ_j |A_ij| (§2.3).
PSD, and singular iff the signed graph is balanced (λ_min(L̄) = 0 ⇔ balanced; Hou/Kunegis).
xᵀL̄x = Σ_{+}w(x_u−x_v)² + Σ_{−}w(x_u+x_v)² — the energy that a frustrated cycle cannot drive
to zero. balance.py reads its spectrum for the global dissonance proxy.
spectral
Spectral & diffusion clustering (companion III §2.2) — the principled clusterer.
The bottom eigenvectors of the symmetric-normalized Laplacian are the graph Fourier basis; the Fiedler value λ₂ is algebraic connectivity; spectral/diffusion clustering partitions by those bottom modes. This replaces the cosine single-linkage floor and dissolves the chaining that forced σ = 0.50 in F9: single-linkage merges any two notes joined by a weak bridge, whereas the normalized cut respects global density, so a dense theme is recovered whole and a weak inter-theme bridge is cut.
Deterministic: partial eigensolves use a fixed ARPACK start vector; k-means uses a fixed seed. No
model, no network. Clustering is done per connected component (distinct components are never
merged) with the eigengap heuristic choosing k within each; components smaller than min_size and
isolated notes are dropped, matching the single-linkage clusterer's contract.
fiedler(A)
(λ₂, Fiedler vector) of L_sym — algebraic connectivity and the smallest nontrivial mode. λ₂ ≈ 0 signals a weak cut (a near-disconnection); its eigenvector bisects the graph (§2.2).
diffusion_map(A, *, n_components=8, t=1.0)
Diffusion-map coordinates: the nontrivial bottom eigenvectors of L_sym scaled by the heat weight e^{-tμ} (companion III §2.2). Row i is note i's position in diffusion space; Euclidean distance there is the diffusion distance at scale t. Deterministic.
estimate_k(vals, *, k_max)
Eigengap heuristic: k = the index of the largest gap among the smallest eigenvalues, bounded to [1, k_max]. A clean k-community graph has k small eigenvalues then a jump.
spectral_labels(A, *, k_max=8)
A cluster label per node over the whole graph: connected components are clustered independently (never merged) and their labels offset into a single global labeling.
louvain_labels(A, *, resolution=1.0)
Modularity (Louvain) community labels via scikit-network — a second, independent method
to cross-check the spectral partition (companion III §2.3: three methods cross-checked;
disagreement = a fragile theme). Deterministic (fixed random_state). Not on the live path —
a diagnostic the strong-Dreamer pass can compare against spectral_labels.
diffusion_cluster_notes(notes, *, threshold=0.62, min_size=2, k_max=8, sim_floor=None)
Diffusion/spectral clustering over note centroids — a drop-in for cluster.cluster_notes
(same signature + return type) that the Dreamer/adapter can select behind the seam.
The graph is the weighted cosine backbone with a light denoising sim_floor (default a third
of threshold, capped at 0.15) — deliberately below the single-linkage cut, because spectral
structure, not a hard threshold, separates the themes. Returns Clusters of ≥ min_size,
largest first (ties by first member's title), fully deterministic.
support
Noisy-OR message passing on the derivation DAG — exact multi-path support (§6.1; H8).
When a claim is supported through several independent paths, the principled combination is a noisy-OR over path strengths:
Pr[supported] = 1 − Π_p (1 − s_p)
On a polytree (singly-connected DAG) this is exact and linear (Pearl, BP on polytrees); the derivation structure is depth-1 today, so it is exact now, and the acyclicity guard + bounded depth keep it tractable as recursion deepens.
The adjudicator feed (grounding_with_support) generalizes core.selfcheck.grounding_score
WITHOUT changing the confidence law (R1's clamp stays THE single definition):
- per evidence ref, a path strength: 1.0 for an authored leaf, the DAG-combined noisy-OR for an interpreted node, 0.0 for an unresolvable ref;
- the claim's g = the mean of those strengths — exactly
grounding_scorewhen every ref is authored-or-junk (today's only live case; proven by property test), and a defensible partial credit for interpreted parents once recursion exists. The mean (not a noisy-OR) at the evidence level keeps the anti-fabrication gate strict: one good citation cannot carry nine junk ones ("adjudication not voting" — §6.1's discipline, held).
Deterministic; no model; no network. Bayesian machinery organizes the graph, never certifies a thought (§6.3): these are support strengths for ranking, not truth probabilities.
noisy_or(paths)
1 − Π(1 − s_p) over independent path strengths, each clamped to [0, 1]. Empty ⇒ 0.0.
support_scores(refs_of, authored)
Path-combined support s(κ) for every node in the derivation map (§6.1).
s(authored leaf) = 1.0; s(node) = noisy-OR over its refs' strengths (an unresolvable ref —
neither authored nor a known node — contributes 0). A memoized topological sweep: exact on
the polytree, linear, deterministic. Cycles are impossible at the source (DerivedStore
refuses them at insert), but the sweep guards defensively (a revisit on the path scores 0
rather than recursing forever).
grounding_with_support(evidence, refs_of, authored)
The adjudicator's g, generalized to multi-path support: the MEAN per-ref path strength over a claim's direct evidence (authored → 1, interpreted node → its DAG noisy-OR, unresolvable → 0). Empty evidence is ungrounded (0.0).
Equals grounding_score(evidence, authored) exactly whenever no ref is an interpreted node
(the current live case) — the strict resolvability gate is preserved, not weakened.
temporal
Structural snapshots — the system watching its own structure evolve (§5.4; H9).
The valuable temporal program is not a PDE but a time series of structural invariants: compute β₀, the Fiedler value, frustration, the curvature distribution, the SBM theme count, the worst community conductance, and the H₁ hole count at each trough pass; watch how they move. A rising frustration, a community whose conductance is falling, a domain fragmenting — each is a measurable trajectory. This is exactly the input the drift gauge (A1/A2) and the longitudinal harness (F4) want.
Wall-clock time τ (the graph actually changing) — NOT diffusion time t (a resolution knob on a frozen snapshot); keeping them distinct is §5.1's discipline. Snapshots are DuckDB (the telemetry convention for quantitative time-series), in their own file beside the derived store — derived, regenerable-in-principle data, never the mirror. Detection only: nothing here alters anything.
StructuralSnapshot
dataclass
One trough pass's structural invariants (the §5.4 / BUILD §1.2 row).
taken_at
instance-attribute
n_nodes
instance-attribute
n_components
instance-attribute
fiedler
instance-attribute
frustration
instance-attribute
mean_forman
instance-attribute
frac_neg_curv
instance-attribute
n_blocks_sbm
instance-attribute
min_conductance
instance-attribute
persistence_h1 = None
class-attribute
instance-attribute
structural_axes()
The A2 drift axes this snapshot feeds (eval.drift.Profile optional fields).
SnapshotStore
dataclass
Append-only DuckDB store of structural snapshots + the trajectory readers the drift gauge (A2) and the F4 longitudinal harness consume.
path
instance-attribute
write(snap)
count()
trajectory(metric)
The time series of one invariant, oldest first — the F4 drift-trajectory input.
metric is validated against the schema (no SQL injection by column name).
latest_structural()
The most recent snapshot's A2 axes — directly consumable by
eval.drift.profile_from_report(structural=...). None when no snapshot exists.
close()
compute_snapshot(kx, *, distances=None, sbm_k_max=8, hole_min_persistence=0.15, taken_at=None)
Compute the invariants on one complex. Deterministic, model-free. distances (the
unthresholded cosine-distance matrix) enables the H₁ count; None records NULL rather than a
fake zero (the persistence filtration cannot run on the thresholded backbone alone).
open_snapshot_store(config=None)
topology
Flag complex + persistent H₁ — conceptual holes (companion III §4; H5).
Persistence runs over the flag (clique) complex K_σ of the similarity graph: sweep the cosine-distance threshold (Vietoris–Rips filtration — Rips is the flag complex of the distance graph), track when cycles are born and die. A long-lived H₁ feature is a conceptual hole: notes pairwise related in a ring with no center tying them together — "you orbit this without stating it". The bottleneck stability theorem makes the diagram a stable diagnostic (it moves no more than the input perturbation).
What H₁ is NOT (the §4.2 correction, load-bearing): a 1-cycle is a topological hole — NEVER a
logical contradiction (that is a signed/semantic property, routed through balance.py) and NEVER
circular reasoning (structurally impossible on the acyclic derives-DAG). Route dissonance through
balance/frustration; route gaps through here. Holes are a utility-axis prompt (what to look at),
not a belief claim.
ripser (the BUILD §2.2-adopted C++ backend) is imported lazily inside the compute call — it drags
in plotting libs we never use at module import. Deterministic; no model; no network.
Hole
dataclass
One long-lived H₁ feature: a conceptual hole in the flag complex.
vertices is a deterministic witness on the cycle (the representative cocycle's endpoints,
completed into a cycle through the birth-scale graph) — the notes that circle the hole. A
witness, not the unique minimal cycle (which is not well-defined in general).
birth
instance-attribute
death
instance-attribute
vertices
instance-attribute
lifetime
property
cosine_distance_matrix(vectors)
1 − cosine similarity, symmetric, zero diagonal — the Rips filtration input. Zero vectors sit at distance 1 from everything (orthogonal), matching the backbone's convention.
persistence(D, *, maxdim=1)
Vietoris–Rips persistence over a distance matrix via ripser (lazy import). Returns the raw
ripser output (dgms, cocycles, …) — exact and deterministic for a fixed input.
long_lived_holes(D, *, min_persistence)
The H₁ features with lifetime ≥ min_persistence, each with a cycle witness — the
conceptual holes worth surfacing. Sorted longest-lived first (ties by birth), deterministic.