SyFox / docs /ARCHITECTURE.md
Mr-DS-ML-85's picture
Upload folder using huggingface_hub
2b2bae2 verified
|
Raw History Blame Contribute Delete
31.6 kB
# SyFox Architecture β€” the SI substrate core
This document specifies exactly what happens between "state in" and "decision
out", and which mechanisms are ported from the Synthetic-Intelligence (SI)
research substrate. The rule that governs this codebase:
> **The core is SI physics only.** No transformer, no neural network, no
> pattern-matching classifier. Everything below is field dynamics over an
> explicit concept graph. Tools (JSON, CLI, HTTP, calibration math) live
> outside the core and never rewrite it.
## 1. Concepts and acoustic mass
Every lowercase folded token interned by the engine becomes a **concept node**
(`core/si_substrate.hpp`, `Substrate::intern`). Nodes carry:
* **mass** β€” a raw occurrence count: `intern()` adds exactly `1.0` each time
the concept appears in any lesson. It is **linear, not log-compressed**.
*Lineage:* SI "acoustic mass" β€” heavier units respond less to the same
stimulus. The sub-linear behavior lives at the **use sites**, not in the
counter: injection deposits `energy / sqrt(mass)` and Hebbian bind strength
scales by `1/sqrt(mass)`, so frequent concepts ("the", "please") cannot
flood the field.
* **energy** β€” transient; injected and dissipated per decision.
(An earlier revision also carried a `salience` field. Audit found it was
write-only β€” incremented at injection, read nowhere; gating selects sources
by energy β€” so it was removed. Dead state in the core is doc debt.)
Token folding (`fold`) is deterministic string normalization (plural / `-ed` /
`-ing` / trailing `e`), applied identically to states, options, and
instructions. It is I/O hygiene, not linguistics and not pattern matching.
## 2. Lanes (Hebbian bindings)
Lanes are weighted edges between concepts, stored sparsely per node with a
per-node lane cap (weakest lane evicted, bounded memory).
* **Bind** (`hebbian_lesson`): for a labelled lesson, every active state
concept binds to every outcome concept with
`η · (1/√mass_a + 1/√mass_b) · scale`. Adjacent state tokens also bind
(the co-occurrence fabric that lets energy diffuse inside a phrase).
*Lineage:* SI Hebbian lane bindings in `physics.hpp`.
* **Weaken** (`weaken`): counter-evidence subtracts lane weight; a lane whose
weight reaches zero dissolves. Used by Noul lessons labelled false.
* **Decay** (`lane_decay`): every lesson multiplies all lanes by 0.995 β€”
unused routes fade.
Learning is substrate rewiring. There are no fitted weights anywhere in the
core; the calibration tool (below) is external and read-only.
## 3. Injection
A state is tokenized; every token that exists in the vocabulary deposits
`inject_energy / sqrt(mass)` on its node. Unknown tokens stay dark β€” this is
the first half of the honest-silence contract (a state of nothing but unknown
words settles zero energy and defers).
## 4. Settle (the System One pass)
`settle()` runs up to `k_settle` (default 8) dissipative diffusion passes:
1. Sources are gated by **source cap** (`source_cap`, 24 by default): the
top-K nodes propagate each pass β€” ranked **by energy** by default, or by
**salience** when `salience_gating` is on. Gated nodes keep their energy
(they remain readout-visible); the cap gates flow, it does not
annihilate. (An earlier version pruned energy outright and destroyed 97%
of the field β€” the gating form is the correct physics and the tests pin
it.)
**SI salience lineage, restored after audit.** The SI substrate runs a
cavity salience integrator, `s = tanh(sΒ·decay + gainΒ·|velocity|)`
(`physics.hpp`, `salience_gain = 0.05`, `salience_decay = 0.995`), and
its TSDA layer samples the live working cap from
`[working_capβˆ’4, working_cap]` = [5,9] (Miller 7 Β± 2). SyFox ports both:
the integrator runs **every pass** on the motion proxy `|Ξ”E|` (a node at
rest is an exact fixed point, mirroring SI's sparsity guard), and
`miller_window = true` samples the live cap from
`[source_capβˆ’4, source_cap]` each decision. One deliberate adaptation:
SI draws the sample from a seeded mt19937 stream; SyFox derives it from
the decision's state hash, so the same state always settles to the same
field bit-for-bit (the persistence contract outranks stochasticity).
`inject()` spikes salience to 1.0 on touch (TSDA spike semantics).
*Benchmark (10 in-domain decisions, 3 domains).* default energy gating
10/10 with calibrated-shaped confidences; salience ranking at the wide
cap 4/10 (motion history is a poor selector when the cap rarely trims);
salience + literal [5,9] window 10/10 argmax but probabilities saturate
at 1.0 (calibration collapse β€” needs the v0.2 eval harness before
adoption); Miller window at wide cap 9/10. Verdict: default stays
energy-gated at a fixed 24; the SI-faithful modes ship behind config
flags until a held-out eval says otherwise.
2. Each source retains `(1 βˆ’ diffusion)` of its decayed energy and flows
`diffusion` out along its lanes, split proportionally to lane weight:
`next[b] += eΒ·decayΒ·diffusionΒ·(w_ab / Ξ£w_a)`.
3. Total energy is non-increasing (dissipative); the pass loop stops early
when the field relaxes (`total_before βˆ’ total_after < eps`).
One settle per decision β€” all questions read the same settled field. Adding
questions never re-settles the substrate: flat marginal latency by structure,
not by scheduling.
**Derivation, not retrieval.** Because diffusion is multi-hop, a state that
was never in any lesson still settles to a computed answer: energy crosses
the co-occurrence fabric into outcome lanes laid down by *other* lessons.
Probe (two lessons, `alpha beta`β†’x and `beta gamma`β†’y): the untaught state
`alpha` alone settles with y at 0.494 β€” lesson 2 never mentioned alpha; the
two-hop path alpha→beta→y carried the evidence. The boundary is the taught
vocabulary and lane fabric: concepts never interned have no node, unknown
words settle to zero energy and defer (Β§6). This is the substrate-level
kernel of the SI stack's explicit derivation layers (meta-learner
macro-rules, dreamer emergent resonances, analogical mapping) β€” not yet
ported; see ROADMAP v0.3.
## 5. Readout (resonance sweep, two lanes)
Probes read the settled field at their own concepts: direct node energy plus a
hop term through lanes. Two readout lanes exist because two question shapes
need two different questions of the field:
* **Specific** (`choice`, `score`): mean lane support β€”
`hop Β· Ξ£ wΒ·e_n / Ξ£ w`. Rewards precise coupling; a node bound diffusely to
half the vocabulary cannot out-read a node bound exactly to this state.
Options are then normalized by softmax at the fitted temperature.
* **Support** (`noul`): active lane mass β€” `hop Β· Ξ£ wΒ·e_n` (unnormalized).
A statement may be corroborated broadly; what matters is how much
lane-connected energy the field offers it. The ratio to total field energy
is the statement's **support**.
Both are field measurements. No weights are fitted at readout; no classes
exist in the core.
## 6. Honest silence
If settled field energy is below `silence_floor` (0.05):
* empty state β†’ `deferred: true, reason: "empty_state"`
* all-unknown vocabulary β†’ `reason: "unknown_vocabulary"`
* settled but dark β†’ `reason: "honest_silence"`
The engine refuses to guess from nothing. *Lineage:* the SI interface's
honest-silence dispatch β€” answers only when the readout actually collapsed.
## 7. Calibration (a tool, not core)
`fit_calibration` collects readout energies on labelled rows and fits, purely
outside the core:
* **temperature** per choice/score β€” golden-section search on NLL of
`softmax(E_correct/T, E_wrong/T)`.
* **Platt scaling** for noul β€” logistic regression `sigmoid(aΒ·support + b)`
on supports, gradient descent to convergence (separable data needs a steep
slope; the fit runs 4000 iterations with decaying lr).
Calibration changes how energies are *reported* as probabilities, never how
they are produced. Confidence for choice/score is the normalized-entropy
margin of the distribution; for noul it is `|p βˆ’ 0.5|Β·2`.
## 8. Persistence
`save_model` writes `substrate.bin` (vocabulary + masses + lanes, binary),
`calibration.json`, and `meta.json`. Loading is exact β€” the same state settles
to the same readout bit-for-bit (pinned by tests).
## 9. Provenance
| Mechanism | Origin |
|---|---|
| Energy injection + field settle | SI `physics.hpp` substrate dynamics |
| Source capping (top-K, energy or salience) | SI working-set cap + TSDA live_cap ([capβˆ’4, cap], Miller 7 Β± 2) |
| Salience integrator tanh(sΒ·decay + gainΒ·motion) | SI `physics.hpp` cavity salience (verified live there) |
| Hebbian lane bindings + decay | SI lane learning |
| Honest silence | SI dispatch contract |
| Typed Choice/Score/Noul API | interface shape inspired by TypeSafe Jev |
| Temperature/Platt calibration | classical statistics (tool layer) |
| Derivation layer (Β§10) | SyFox-native design after studying SI meta_learner / dreamer / analogy as mechanism reference β€” no code copied; weight algebra on lanes instead of typed relation rules |
| No-regression gate (Β§11) | SyFox-native: transactional derive + bit-exact fabric snapshot/restore; policy refined by a full strength-scan (taught-row integrity + no manufactured certainty) |
| Jev-parity bench (Β§12) | SyFox-native: axis lineage from TypeSafe's published Jev material + community classification benchmarks; all numbers produced by this repo's binary |
| Recall (Β§13) | Hopfield-style associative memory reinterpreted as settled-field cosine β€” SI-physics-native, zero symbol-space similarity |
## 10. Derivation layer (offline, explicit)
SyFox's lanes so far carried only lived experience (`learn`). The derivation
layer lets the field grow knowledge **derived from** its own fabric β€” the
substrate-level kernel of what the upstream SI stack does with explicit rule
machinery (meta-learner macro-rules, dreamer emergent resonances, analogical
mapping). The primitives differ by constitution: SI composes typed relation
triples over a fact graph; SyFox composes **weighted lane paths** β€” weight
algebra and field dynamics, no classifiers. All engines are OFFLINE, explicit
CLI steps; `decide()` stays read-only and byte-identical unless the operator
derives on a model. Provenance: derived lanes carry a **generation counter**
(experienced / human-promoted = 0, each composition step +1, cap 3), persisted
as a versioned tail in `substrate.bin`; v1 files load clean (generation 0).
**1. Lane induction, compose mode** (`syfox derive --model DIR`): a two-hop
path Aβ†’Bβ†’C is evidence for A↔C, with three guards that each came out of a
real benchmark failure:
* *acoustic-mass damping* β€” path evidence is damped by `1/√mass(B)`, the same
law `settle()` applies to energy through B; without it, hub tokens ("the",
"command") fabricated corroboration between unrelated concepts and two demo
argmaxes flipped;
* *top-K corroboration* (K=3) β€” a dense fabric offers hundreds of two-hop
paths; treating them as independent evidence saturated the field (noul
collapsed to 0.999 everywhere);
* *ghost-guarded verifier* β€” every derived lane is re-checked against the
LIVE fabric (snapshot ghosts of already-dissolved lanes cannot justify
anything), over-claims are healed down to their justification, unsupported
ones dissolve. Composition is raise-only: observed lanes are never weakened.
**2. Lane induction, harvest mode** (`syfox derive --model DIR --examples
FILE.jsonl`): static algebra guesses; the settled field knows. Replay states
through inject→settle and record which concept pairs genuinely **co-activate**.
Dissipation does the filtering β€” cross-scenario energy decays before it
registers. Observed lanes are untouchable; gen-1 lanes must be re-nominated by
every run or they dissolve (justification is recomputable, hence deterministic).
Labels are not needed: the field learns structure from unlabelled exposure.
**3. Dreamer** (`syfox dream --model DIR [--steps N] [--seed S]`): inject
small random energy patterns, settle, and watch for undriven nodes that lit
up **without any direct lane to the driven set** β€” reached only through the
topology's own interference. Candidates go to `model-*/mutations.jsonl`. The
substrate is never modified by dreaming; a human sets `validated:true` on a
line and `syfox promote` applies it as a premise-grade lane. Same seed β†’ same
dream, bit for bit.
**4. Analogy** (`syfox analogs --model DIR --concept WORD`, read-only): a
concept's signature is its lane neighbourhood (who it touches, both
directions); structural isomorphism = signature Jaccard; novelty potential
follows the L9 formulation `Phi = IΒ·exp(kΒ·d)`. High Phi = structurally aligned
AND fabric-distant: a transfer *hypothesis* for the human, never auto-applied.
*Benchmark (v0.2 β†’ v2.1, honest).* The v0.2 verdict was measured on
resubstitution (eval rows = training rows): compose sharpened tickets demos
(technical conf 0.251β†’0.454) but flipped game/guard rows; harvest lifted
billing 0.604β†’0.912 but flipped a close call; no strength avoided taught-row
flips on the mixed-label fabrics. v2.1 replaces the measurement basis: the
gate now replays the HELD-OUT split (generalization safety, not memorized
behavior) and the harness decides per model β€” game ships derived (253 lanes,
0 held-out flips, accuracy held 0.667β†’0.667), tickets (9 flips) and guard
(1 flip) ship un-derived with the reason logged. Same enforcement philosophy,
honest measurement basis.
## 11. The no-regression gate (transactional derivation)
Derivation writes into the fabric; the gate (`core/gate.hpp`, CLI
`syfox derive --gate FILE.jsonl`) makes that write safe by construction:
1. replay every labelled row + generated close-call probes (cross-domain
state mixtures, deterministic generator shared with `bench`) β†’ baseline
decision signatures;
2. snapshot the fabric **bit-exactly** β€” `snapshot_fabric()` copies each
node's lane vector in insertion order plus the provenance map, because
`settle()` sums over lanes in vector order (a weight set is not the
state);
3. run the derivation (conservative presets: harvest co_floor 0.15/gain
0.35/budgets 8Β·512, compose gain 0.25/top-2/budget 4);
4. replay the same probe set β†’ compare;
5. **policy**: (a) any argmax flip on a TAUGHT row reverts β€” labelled
knowledge must survive derivation; (b) any RISE in mean confidence on the
MIXED probes reverts β€” close-call states are ambiguous by construction,
their argmax may re-resolve, but manufactured certainty about them is the
exact failure the gate exists to kill;
6. revert = `restore_fabric(snapshot)` β†’ the fabric is bit-identical and
`decide()` output is byte-identical (pinned by test); commit = the caller
saves the model.
Strength-scan evidence (scripts/syfox_gate_scan.cpp, all strengths from
default down to 32 lanes): tickets reverts everywhere (8–18 taught flips β€”
its seed data mixes refund/invoice labels across billing and sales), guard
reverts at every useful strength, game commits at the conservative strength.
Per-model outcome: `model-game` ships derived (668 lanes, 0 taught flips,
mixed mean confidence 0.975β†’0.886 β€” the fabric got MORE honest about close
calls; demo argmaxes 3/3 unchanged; `make models` reproduces). `model-tickets`
and `model-guard` ship un-derived because the gate proves it, not because a
human remembered to check.
## 12. The Jev-parity benchmark (`syfox bench`)
`core/bench.hpp` measures the axes the System One model class is judged on
(axis lineage verified against TypeSafe's published Jev material and the
community classification benchmarks, Sept 2026): decision accuracy, latency
percentiles, calibration (ECE, 10 bins, + conf-when-correct vs
conf-when-wrong gap), honesty (OOD probes built from deterministic nonsense
vocabulary checked against the model's own β€” untaught tokens must defer),
guardrail hold precision/recall (noul confusion at the 0.5 threshold),
determinism (full replay compared byte-wise), and close-call margin
distribution (mixed cross-domain states; the same generator the gate
replays). Accuracy/calibration/guardrail aggregate over LABELLED rows only;
unlabelled mixed probes never pollute accuracy denominators (a real bug the
e2e suite caught). Every report carries a `jev_reference` block with the
PUBLISHED figures (67.8% workflow accuracy, 70–500 ms, pi-warden 88% hold
precision) for side-by-side reading β€” axes shared, numbers not compared
against toy-data resubstitution.
Seed-model results, v2.1 methodology β€” HELD-OUT split (70/30, stratified,
deterministic; `make bench-heldout`), post-gate derivation state. The v0.2
table that stood here measured in-domain resubstitution (eval rows = training
rows) and is retired; in-sample numbers remain available via `make bench` as
a regression contrast only.
| model | held-out choice acc (n) | score acc (n) | choice ECE | OOD defer | p50 / p95 |
|---|---|---|---|---|---|
| tickets | 1.000 (6) | 0.667 (6) | 0.012 | 1.00 | 64 / 80 Β΅s |
| game (derived, gate PASS) | 0.667 (3) | β€” | 0.329 | 1.00 | 29 / 40 Β΅s |
| guard | 0.750 (4) | β€” | 0.200 | 1.00 | 34 / 45 Β΅s |
Reading: the held-out gap against in-sample (tickets 1.000 vs 1.000; guard
0.750 vs 0.778) is now measured instead of assumed. Calibration is fitted on
held-out rows only (2–3 scalars; multi-class NLL objective, 1-bit ECE
adoption guard) β€” tickets reaches ECE 0.012; game/guard are held above the
0.1 bar by a single held-out error each, which is arithmetic (1 wrong of
3–4 emitted forces ECE β‰₯ ~0.2), not a tuning failure. The headline metric is
the coverage-vs-accuracy curve (`make coverage`): tickets trades 100%
coverage @ 83.3% accuracy for 50% coverage @ 100% β€” the confident subset is
trustworthy, measurably. Paraphrase augmentation was implemented, measured on
the held-out split, and REJECTED by default (intern mass is linear, injection
damps 1/√mass: re-teaching near-duplicates re-weights the field toward the
training surface forms; tickets 1.000 β†’ 0.500). The derivation gate replays
held-out rows and decides per model: game ships derived, tickets/guard ship
un-derived. Honesty stays structural (1.00 OOD defer everywhere); latency is
three to four orders of magnitude under the Jev band with the same one-pass
shape.
## 13. Recall (associative retrieval in energy space)
`core/recall.hpp`, CLI `syfox recall --state '...' --memories FILE.jsonl`.
Content-addressable memory the only way the constitution allows: settle the
query into an energy fingerprint (one float per node, L2-normalized), settle
each stored memory the same way, rank by cosine of the two settled fields.
No token comparison, no string distance, no n-gram overlap, no embedding
table, no transformer β€” similarity is measured in the substrate's own state
space, so two states resonate exactly as far as the field routes them
together. Unknown vocabulary resonates with nothing (empty hits β€” honest
silence, since `inject` skips unknown tokens). Read-only, bit-deterministic;
memory stores accept `{"state","label"}` rows or the training schema
(label = first label value). On the derived game model the zombie query
recalls the flee lessons at 0.9696–0.9421 with fight lessons at ≀0.856.
## 14. v3 β€” the hidden-test firewall and the evidence ledger
### 14.1 Firewall (core/firewall.hpp)
The 70/15/15 train/cal/hidden contract is enforced where a typo cannot
bypass it: the CLI consults the file's split role (decided by its filename
suffix β€” `_train`, `_cal`, `_hidden`, `_heldout`, anything else is
unclassified and stays readable, because worksheets and paraphrase files
must remain learnable) before opening anything.
| role | suffix | learn | calibrate | derive --gate | bench |
|-----------|-------------------|-------|-----------|---------------|-------|
| train | `_train.jsonl` | YES | yes | yes | yes |
| heldout | `_heldout.jsonl` | yes | YES | yes | yes |
| cal | `_cal.jsonl` | no | YES | yes | yes |
| hidden | `_hidden.jsonl` | NO | NO | NO | YES |
Rationale: calibration files exist to fit 2–3 scalars (temperature/Platt)
on rows the fabric never learned from. Hidden files exist to be SCORED,
once. A hidden row that leaks into any build path is not a mistake β€” it is
a different (worthless) number. `make firewall-check` runs the four
refusals against the real binary.
### 14.2 Evidence ledger (v3, Milestone 3)
Every lane key carries a `LaneEvidence` record: `support_events`,
`counter_events` (anti-Hebbian dissolutions), `generation` (derivation
provenance), `first_seq` / `last_seq` (teach-event window), and the
engine-set context tag (which substrate/model owned the event). The ledger
persists as an optional tail on `substrate.bin`; v2 files load unchanged
(the tail is detected at EOF) and v3 files load on v2 readers that stop at
the v2 end.
`decide --evidence` projects the ledger for the lanes the decision
actually used β€” a READ-ONLY view. The field is driven by lane weights;
the ledger never feeds back into physics. It exists so a decision can be
audited after the fact: which lanes, how strong, taught when, by which
corpus, disputed how many times.
### 14.3 Contradictions
Teaching the same (state, question) with a different outcome is a
contradiction: it increments the learn report's `contradictions` counter,
writes a contradiction record (old outcome, new outcome, both seq numbers,
state hash, context), and marks the affected lanes with a counter event β€”
the anti-Hebbian term weakens the disputed binding exactly as the physics
specifies. There is no last-write-wins: the field keeps the binding its
weights support, and the dispute stays on the record (`contested: true`
in the decide evidence view). Silent override is a design error, and the
adversarial suite (Β§15 of the README; `make adv-big`) tests for it with a
control arm that separates contradiction-specific damage from the generic
cost of re-teaching.
## 15. v3 β€” multicore settle and the GPU gate (M5)
### 15.1 CSR mirror
The settle hot path reads a compressed-sparse-row mirror of the out-lane
fabric: `csr_off_` (n+1 offsets), `csr_dst_`, `csr_w_` β€” contiguous
buffers, rebuilt lazily when the fabric mutates. The build copies each
source's lane vector verbatim, so per-source iteration order is exactly
the map order the sequential settle used: every float sum keeps its exact
operand order and results are bit-identical. This is the layout a GPU
port generalizes.
### 15.2 Deterministic OpenMP settle
`make omp` builds the same sources with `-fopenmp`. The diffusion pass
partitions sources with a static schedule (contiguous ascending chunks);
each thread scatters into its own buffer; the buffers are combined in
ascending thread order; therefore every accumulator sees contributions in
ascending SOURCE order β€” the sequential order. Bit-identity is a gate,
not a hope: `make omp-identity` fails the build if sequential and
`--threads 2` reports differ in any block (routing, calibration, honesty,
guardrail). Measured honestly: below ~10k nodes on a 2-core sandbox the
deterministic parallel settle is slower than sequential (thread
coordination exceeds the gain); it pays on denser fabrics.
### 15.3 Batched throughput and the GPU gate
`bench --throughput N` measures decisions/sec with N worker threads, each
owning a PRIVATE engine copy (decisions mutate the field, so workers never
share a substrate). It is a performance axis, not an accuracy headline β€”
a non-zero checksum proves the work happened. Measured on the 3,518-node
tickets fabric: 2,390 β†’ 3,714 decisions/sec at N=2 on 2 cores.
The GPU port gate is MEASURED, not assumed: `make density` reports per-
fabric density and mean out-degree (tickets 0.0067 @ degree 23.5, game
0.0458, guard 0.0485). A GPU port happens when dense substrates make the
transfer costs pay for themselves β€” until then it stays design, and the
SoA/CSR buffers above are the only GPU-specific preparation the core
carries. No neural network enters the core at any point; the parallelism
is the SAME physics, executed on more cores.
## 16. v3.2 β€” the semantic field, context-sensitive lanes, retrieval by default, the two-stage router
The largest boundary-layer addition since v3.0, and the first that adds a
second field to the substrate. Everything below is deterministic, seeded by
nothing, fitted to nothing β€” there is still no neural network, no
transformer, and no pattern-matching classifier in the core.
### Stage 1 + 4 β€” the semantic vector field (64-dim, resonance)
Every concept node carries a 64-dim semantic vector built in two
deterministic steps. The LEXICAL LAYER hashes the concept string's character
trigrams into 64 buckets with FNV-1a-signed weights and L2-normalizes β€”
"card_arrival" and "card_delivery" share trigrams, so their base vectors
align; unrelated words stay near-orthogonal. FABRIC GROUNDING then runs two
smoothing passes over the Hebbian lanes (v_i <- normalize(v_i + 0.5 *
lane-weighted mean of v_j)): the fabric's own co-occurrence structure shapes
the vectors, which is meaning diffusing along the lanes, not a fit. From the
vectors, three derived quantities:
- **omega_semantic** (Stage 1, "concept frequency encoding") β€” a scalar
projection onto one fixed deterministic direction, mapped to [0,1]. Two
nodes with close omega resonate harder, like coupled oscillators that are
nearly tuned; the fixed axis makes "card" map to the same omega in every
fabric.
- **resonance edges** (Stage 4, "semantic field") β€” the top-6 cosine
neighbours with cos >= 0.50, stored as a CSR adjacency in the substrate's
v4 file tail. During settle, every SOURCE (and only sources β€” the working
set stays capped) leaks a fraction (sem_coupling 0.12) of its post-diffusion
energy along these edges, distributed proportionally to cos x
frequency-match. Energy is CONSERVED exactly: the pool is subtracted from
the source and distributed; decay applies next pass as always.
- **typed reads** (Option 2) β€” cos >= 0.82 reads as synonym-grade kin, >=
0.66 as related; `syfox analogs` and the evidence surface expose the type.
The v2.1 synonym folding table remains the string-level canonicalization;
the vectors add the fabric-shaped layer above it.
Readout gains a semantic-neighbour term (sem_hop 0.10 x cosine x neighbour
energy): energy resting on semantically similar nodes counts for a probe
even where no lane connects them.
### Stage 2 β€” context-sensitive lanes
A lane may carry a CONTEXT SIGNATURE: required and forbidden context words,
learned from the co-occurrence statistics of the lessons that laid it
(`add_ctx_support` accumulates counts at learn time; `finalize_contexts`
promotes surviving counts β€” top-4 with count >= 2 β€” into required sets, and
cross-lane diffs (strong in a sibling lane's context, absent here) into
forbidden words, top-2). At settle, a lane's effective weight is
w x factor: any forbidden word present in the decision's own injected
tokens -> x0.20; required words missing -> x0.60..1.0 interpolated by match
count; all present -> x1.0 (bit-identical to the plain path). The node's
total outflow scales by sum(w x f)/sum(w), so damped lanes carry LESS and
the energy stays home β€” context-mismatched routes fade physically instead of
being pruned by a rule. The same "card" can now route toward card_arrival
when arrive/receive are in the state and toward card_delivery_estimate when
estimate/how-long is.
### Persistence and the replay contract
The semantic field, resonance edges and lane contexts live in a magic-
guarded v4 tail of substrate.bin. Pre-v3.2 files simply end at the v3
evidence tail: has_semantics() is false and every semantic code path is
inert, so every v2/v3 model replays bit-for-bit under the new binary
(test-enforced). `intern()` invalidates the field when the fabric grows β€”
a stale top-k neighbourhood must never be indexed β€” and the next
`save_model()` rebuilds it deterministically. `--no-semantics` /
`set_semantics(false)` is the runtime kill switch.
### Retrieval by default
A model dir may ship `memories.jsonl` (rows {"label": ..., "state": ...}).
load_model fingerprints each memory once (its own settled field, the
recall.hpp Hopfield-style mechanism); every decide then ranks memories by
settled-field cosine against the query and injects the top-5 outcomes at a
faint dose (0.30 x inject_energy) BEFORE the state settles β€” a physical
prior from lived experience, deterministic, bit-reproducible for the same
state + memories. No memories file => the whole path is inert (pre-3.2
behavior). Flags: --memories FILE (explicit store), --retrieval-topk,
--retrieval-dose, --no-retrieval. usage.retrieval discloses what primed the
decision, in the CLI, the C API and the HTTP bridge alike.
### Stage 3 β€” the semantic hierarchy
A model dir may ship `hierarchy.json` {"intents": {intent: category},
"categories": {category: {"criteria": ...}}, "floor": 0.35}. Both levels are
TRAINED anchors in one fabric; at decide, stage-1 category energies scale the
stage-2 intent candidates by floor + (1-floor) x cat/max_cat β€” a readout-side
two-stage classification. MEASURED on bank77 (cal, 1,003 rows): gate OFF
0.133 > floor 0.85: 0.129 > 0.5: 0.113 > 0.35: 0.111 β€” the category readout
is not additive on this fabric (consistent with the v3.1.0 finding that the
hierarchical first-token split was measured-negative), so the shipped
model-b77-sem carries floor 1.0 = gate off, kept as documentation. The
mechanism stays available (--no-hierarchy to disable elsewhere).
### The dedicated bank77 fabric + the two-stage router
The v3.2 answer to high-cardinality collapse is ARCHITECTURAL, as the
v3.0 design intended: a DEDICATED fabric per hard domain, routed by a small
dedicated router fabric.
- **model-b77-sem** (dedicated bank77): 9,000 intent lessons + 9,000
category lessons (12 chunks), 1,648 nodes / 217,729 lanes, 7,728 resonance
edges, 141,920 lane contexts, 256 retrieval memories, calibrated. Hidden
(3,080 rows, scored once, energy-norm): **0.158** β€” vs 0.081 (v3.1.0
dedicated+opaque) and 0.023 (77-way in the shared giant fabric). Ablations
on cal: --no-semantics 0.039 (the semantic field is the jump: 0.039 ->
0.133), retrieval neutral, hierarchy gate negative (above).
- **model-router16** (two-stage, stage 1): a 4,742-node fabric trained ONLY
on router questions (16 anchors, one per giant domain, 60 rows/domain).
Cal 16-way routing 0.444 (chance 0.0625), ECE 0.380 -> 0.086.
`decide --router model-router16 ...` settles the state on the router
fabric, picks the domain anchor, then the mapped domain fabric (router.json
"models") decides the real questions; the route is disclosed in the output
as route:{anchor,confidence,top,model}. Physics-based routing, no
classifier β€” the two-stage architecture from the v3.0 design, now measured.
### Zero-shot, re-measured under v3.2 (docs/ZEROSHOT.md Part 4)
Email spam on the tickets-only fabric (never taught spam): 6/6 (plain) and
6/6 (semantic rebuild). SMS spam: 5/6 both. Snake on the giant fabric: 1/8
both; Tic-tac-toe: picks 1 at conf 0 β€” multi-constraint composition is
still not a fabric property, and the semantic field does not fake it.
Honest as ever: the semantic field moves TRAINED-discrimination and
vocabulary-overlap zero-shot, not symbolic reasoning.