I made claims in this document from reading source alone. I then decoded
[internal module] directly (label table + 20-byte records, per
persistence/compact.rs:322). Three of my claims were wrong.
[internal module] pushes straight into layer.synapses and
re-serialises the file. **It never calls apply_ltp, so the fan-out cap does not
apply to it at all.** The cap is a runtime guard on edge *creation*, not a
property of the file. Restoring works. I said the opposite.
Measured out-degree, 49,731 labels:
Half the graph is frozen. The other half is not. And 189,542 free slots is
three times the 63,815 recovered edges — there is room for all of them even
through the runtime path. "At the ceiling" was true of the average and false of
the distribution.
(The max of 293 is a fossil: those edges were made when the lattice was ~359k
cells and the cap was 30. The cap never removes what it already allowed.)
I reported 605,674 synapses from the boot log. The file on disk holds
613,276 across 49,731 labels. It has grown ~7,600 since that boot.
---
Weight — min 0.0105, p25 0.0792, p50 0.3573, p75 1.0000, p99 5.0000
a quarter of the graph is roughly 90 minutes of live sweeps from deletion.
Clock / idle — last_fire_tick min 1815, p25 2970, p50 3529, max 4650.
on 2026-08-29. They are gone — the selective rebase worked. Every stamp on
the graph now carries real information.
4650 - 2500 = tick 2150. **1,401 synapses (0.2%) are alreadypast it**, 230 of those under weight 0.05. That is the live exposure if
[config flag] goes to 1 right now — small, and survivable.
fire_count — p50 13, p90 175, p99 2158, max 196,865.
23% of the graph on the rich-get-richer track described in section 8.
---
[internal module] (63,815 pairs, already re-screened through the
tightened v9.10.838 gate) still carried assistant filler. Measured: **2,206 pairs
(3.5%)** had chat/tutor scaffolding on at least one side — you're welcome,
I'd be happy to, as an AI, here's a tiny lesson, let's, Q:/A: drills.
120 pairs had it on both sides.
That is a small fraction — the 838 gate did most of its job, and I should not
imply otherwise. But those 2,206 are exactly the class that produced the
"0 bridges" seeds in the log you asked about.
Written:
[internal module] — 61,609 pairs, filler removed[internal module] — the 2,206, kept for inspectionNothing in data/ that the engine reads has been modified.
---
Recorded 2026-08-31. Every function in the loop, read in source, with what it does to what.
Live numbers used throughout, from the boot log: 40,093 cells, 605,674 synapses.
---
run_synaptogenesis_loop oracle_server.rs [internal service] every 2s, forever
└─ get_ungrounded_concepts oracle_server.rs [internal service] pick 1 seed
└─ is_junk_concept_label oracle_server.rs [internal service] reject noise
└─ SynapticLayer::strongest_from synapse.rs "has this cell any synapses?"
└─ NeuralBus::query_multi_hop synapse.rs:973 walk the graph 3 hops
├─ Universe::query_in_regions hop 0, geometric
├─ SynapticLayer::propagate synapse.rs:339 hops 1..3, follow edges
├─ Universe::get_cell_by_label LINEAR SCAN, 40k cells
└─ effective_score synapse.rs rank
└─ SynapticLayer::record_co_firing synapse.rs:279 Hebbian LTP
└─ apply_ltp synapse.rs:799 the only thing that WRITES
---
run_synaptogenesis_loop — oracle_server.rs [internal service]Does: sleeps 2s, builds one seed, queries, writes, prints, repeats. Forever.
Kill switch: TRAINING_DISABLED.flag file, or [config flag]=0. Checked
each pass; when set it sleeps 2s and does nothing else.
The throttle is dead code.
let max_boost: f32 = 0.0; // "Disabled boost to prevent parallel crashes" let p_scaled = ...; // biological plateau curve let ease = p_scaled * p_scaled * (3.0 - 2.0 * p_scaled); // smoothstep let throttle = 1.0 + max_boost * ease; // == 1.0, always let batch_size = (throttle.max(1.0).round() as usize).min(15); // == 1, always
An entire smoothstep curve is computed and then multiplied by zero. batch_size is
permanently 1.
→ THIS IS WHY IT ALWAYS SAYS seed[0] AND Processing 1 parallel concepts.
There is only ever one seed. The plural is a leftover.
P is dead too. p = synapses / (cells * 4) clamped to 1.0.
605,674 / (40,093 x 4) = 605,674 / 160,372 = 3.78 → clamped to 1.0000.
It has been pinned at maximum for a long time and cannot move. It reports nothing.
(And even if it moved: p > 0.80 sends p_scaled to (1-p)/0.20, so at P=1.0 the
curve evaluates to 0 anyway.)
Locking: seeds are processed in chunks(2) with a sleep(250ms) between chunks,
specifically so [internal endpoint] can get the universe read lock. With batch_size 1 there
is only ever one chunk — so every cycle still pays the 250ms sleep for a
concurrency problem it no longer has.
---
get_ungrounded_concepts — oracle_server.rs [internal service]Does: builds a Vec<usize> of all 40,093 indices, shuffles it, then walks it
until it finds batch_size (=1) cells that pass the junk filter AND have zero synapses.
Cost: a 40,093-element allocation + full Fisher-Yates shuffle, **30 times a
minute**, to select one item. If most cells already have synapses, it also calls
strongest_from on each candidate as it walks — and strongest_from copies every
synapse of that label into a Vec and sorts it, just to ask "is this empty?"
Fallback: if this returns nothing, the loop picks a random cell instead. So the
system moves from "ground the unconnected" to "re-stir the connected" without saying so
in the log.
---
is_junk_concept_label — oracle_server.rs [internal service]Does: rejects a label if it is <8 chars, fails ingest_filter::judge_ingest, ends
with , or (, starts with (, contains chat pollution markers (language sample,
[mirror], leo:, pred_err=, ...), starts with an agent name, or contains
": " in the first 40 characters.
The hole your seeds came through: the colon rule matches ": " — colon **plus a
space**. Your seed was:
> Here's a tiny lesson for your AI studen[local path]"so
The colon is followed by a newline, not a space. It passes. Same for
The correct answer is based on understanding how prefixes mo — that has no early
colon at all. Both are LLM answer text stored as cells, which is exactly what this
filter exists to keep out, and exactly what is being fed in.
---
NeuralBus::query_multi_hop — synapse.rs:973Called as query_multi_hop(&u, &sl, phi_g, seed, 15, &[], "", 3) → n=15, max_hops=3.
Does:
universe.query_in_regions(text, n*2 = 30, ...) — geometric/VSA retrieval.synaptic_layer.propagate(frontier) returns every post-synaptic partner of every frontier label, sorted by boost. Capped at [config flag] (default 64)
per hop; next frontier truncated to [config flag] (default 24). Signal decays
0.7^hop; anything under 0.05 after decay is dropped.
universe.get_cell_by_label(&label), which is a **linear scan over all 40,093 cells** (universe.rs:2918). This is the documented cause of the
141-second [internal endpoint] (v9.10.845 note in-file).
merged.truncate(n + max_hops * 2); // 15 + 3*2 = 21
→ THE RESULT IS HARD-CAPPED AT 21 HITS.
---
record_co_firing — synapse.rs:279Does: if labels.len() < 2 { return; }, then for every ordered pair (i,j), i!=j,
calls apply_ltp.
chi_gate = (1.0 - chi*0.8).max(0.05) // chi=0.1 → 0.92
ltp_gain = BASE_LTP * (1 + dopamine*0.8) * (1 + phi_g*0.5) * chi_gate
= 0.035 * (1 + 0.8*0.8) * (1 + phi_g*0.5) * 0.92
≈ 0.0528 * (1 + phi_g*0.5) ≈ 0.053 – 0.079
The tick is 0. This loop passes tick = 0. Since v9.10.565 the line is
self.tick = self.tick.max(tick), so passing 0 can no longer rewind the clock — but it
also does not advance it. Only ltd_sweep_inner does self.tick += 1.
---
apply_ltp — synapse.rs:799 — THE ONLY FUNCTION THAT WRITESTwo paths:
A. Edge already exists → weight = (weight + gain).min(max_w), fire_count += 1,
last_fire_tick = tick, total_ltp += 1. max_w is MAX_WEIGHT = 1.0, or 5.0
once fire_count > 50 ("hyper-synapse").
B. Edge does not exist → checks the fan-out limit first:
if fan_out >= dynamic_fan_out(lattice_size) { return; } // silent, no-op
pub fn dynamic_fan_out(n) -> usize { (0.075*n).powf(1/3).ceil().max(8) }
For your lattice: (0.075 * 40,093)^(1/3) = 3007^(1/3) = 14.44 → ceil → 15.
Max possible synapses = 40,093 cells x 15 fan-out = 601,395.
You have 605,674. (Above the ceiling because the cap is recomputed as the lattice
grows; edges made when it was 16 stay.)
Average out-degree = 605,674 / 40,093 = 15.1. The graph is **at its fan-out
ceiling. For most labels, path B returns immediately and creates nothing**.
New-edge path also has a latent_traces hash check that multiplies gain by 15x
for a pre/post pair that existed before and was pruned — a relearning bonus.
---
Logistic Throttle Velocity: 1.00x (P=1.0000) | Processing 1 parallel concepts...Two dead constants and a hard-coded 1. Zero information.
seed[0]: "…" cut off mid-words.chars().take(60) — 60-char truncation, no ellipsis. The full label is sent to
the query (a v9.10.x note says truncating to 60 broke resonance and produced 0 hits).
The blank line you see is a literal \n inside the cell label, printed raw.
Established 420 new geometric bridgeslet n = hits.len(); let pair_bridges = n * (n - 1); total_wired += pair_bridges;
hits is capped at 21 by merged.truncate(21). 21 x 20 = 420.
420 is a constant. It means "the retrieval returned its maximum." It will print 420
every single time the seed is not isolated. It is not a count of anything created.
Worse, on three counts:
1. Nothing is measured. record_co_firing is called *once* and returns ().
total_wired is a formula computed *before* any write, never compared to reality.
2. "new" is unverified. Most of those 420 pairs already exist; they got a weight
bump, not a creation. apply_ltp knows which path it took and tells nobody.
3. Many cannot be created at all — fan-out is full at 15 (section 6), so path B
silently returns.
(0 seed(s) with no multi-hop neighbors skipped)Count of seeds whose hit list had len() <= 1. Zero means the one seed found neighbors.
Established 0 new geometric bridges (1 seed(s) had <2 multi-hop hits — seed may be isolated or too noisy)The one seed came back with 0 or 1 hit. record_co_firing bailed at
if labels.len() < 2 { return; }. Nothing ran. Given the seeds are ungrounded cells —
cells with no synapses by definition — hops 1-3 have nothing to follow, so the
result depends entirely on hop 0 geometric retrieval finding something.
---
Every 2 seconds, permanently:
The direction is one-way. ltd_mode() defaults to "dry" ([config flag]
unset). Dry analyses and mutates nothing. So nothing is weakened and nothing is
pruned unless you explicitly set [config flag]=1. Weights only go up.
Saturation. At ltp_gain ≈ 0.053-0.079 against MAX_WEIGHT = 1.0, a synapse
saturates after ~13-19 co-firings. At 30 cycles/minute against a fixed retrieval
set, everything the retrieval keeps returning is already pinned at 1.0. Past that,
fire_count > 50 lifts the ceiling to 5.0 for the ones that fire most — so the
already-strongest edges are the only ones that can still grow. **That is a rich-get-
richer ratchet with no counterweight.**
No new information enters. The set being strengthened is the set the retrieval
already returns. This reinforces what the graph already believes. It is not learning
from the world; it is deepening a groove.
---
1. Make the counter measure instead of compute. Have apply_ltp return an enum
(Created / Strengthened / RefusedFanOutFull / Saturated) and print the four
counts. One afternoon. Turns the log from decoration into an instrument. **Do this
before changing behaviour** — otherwise there is no way to tell if a change helped.
2. Log mean weight delta per batch. If it is ~0, the batch did nothing and you can
see it.
3. Drop the 250ms sleep when seeds.len() <= 2. It is paying for a chunking
strategy that no longer chunks.
4. Cache the ungrounded set instead of shuffling 40,093 indices 30x/minute.
Recompute on a slow tick.
5. Fix the junk filter's colon rule — match : followed by whitespace, not ": ".
Both of the seeds in the reported log would have been rejected.
6. Decide on LTD. With [config flag] unset there is no forgetting at all. Run
dry first and read the report before going live.
7. Then decide about max_boost. Raising it above 0 is the only way batch_size
ever exceeds 1 — but the comment says parallel crashed. That is worth reproducing
before re-enabling.
Nothing here says the mechanism is wrong. It says the log is not reporting it, the
graph is at its structural ceiling, and there is no counter-force. Those are three
separate problems and only the first one is cheap.