research spec
06 — Bounded-Growth Consolidation: Trained Encoder + Hypernetwork Adapters
- File
06-bounded-growth-consolidation.md- Size
- 15.5 KB
- SHA-256
84992d5341c36dff…
06 — Bounded-Growth Consolidation: Trained Encoder + Hypernetwork Adapters
Stop pickling dense random matrices and raw traces; make persistent memory a compact, trained latent identity whose byte-cost stops growing.
Status: ACCEPTED (2026-07-11, five-seed) | Thesis anchor: experiments.txt §5 (hypernetwork identity, z_{t+1}=z_t+Δz), §9 (experience autoencoder; L = behavior_improvement + reconstruction_of_correction + compression_penalty + anti-overgeneralization + replay_consistency) | Goal anchor: GOALS.md Goal 3 (organ tensor upgrades / metabolism loop closure) | Depends on / relates to: 01-correction-to-competence-benchmark (owns the byte metric), 05-metabolism-loop-closure (the consolidation path), 07-conversation-world-model-rl
Outcome (2026-07-11): ACCEPTED (five-seed). Campaign 0d48130 (kaggle CPU-only, commit
0d48130):bounded_growth_m1_ratio=0.002079across 5 seeds with zero variance. Structural footprints are bit-identical across seeds.bytes_per_deltaspread ≤20 B: A0 18 B, A0b 20 B, A1 19 B, A2 18 B, A3 19 B. The M1 ratio (combined-footprint reduction) is well under the 1/10 threshold. Evidence:../experiments_logs/2026-07-11_campaign_0d48130.md.
Problem
The organism stores experiences instead of metabolizing them, and it pays for it in bytes. On the eval-suite curriculum, OrganismAgent reports memory_bytes_per_behavior_delta = 68772.0 versus FastOnlyAgent's 12.0 (NOTES.md:253,256) — a ~5,700x spread for, by NOTES.md's own description, "matching FastOnlyAgent on forgetting/consolidation/identity" and adding only "a small transfer edge" (transfer 0.25 vs 0.1667; NOTES.md:256-260). The metric is consolidated_size / max(1, successful_lessons) where consolidated_size = _memory_bytes(agent) (the full OrganismAgent.memory_bytes()) and successful_lessons counts fixed_after_correction corrections (eval_suite.py:393-396; organism.py:482-495). NOTES.md:261 attributes the cost to "the hippocampus + immune + autoencoder pickled state."
Two of the dominant contributors are the exact organs this project owns, and both are honest about being prototypes:
ExperienceAutoencoder is "an untrained random projection" (EVALUATION.md:36-38), scoring aggregate 0.203 (EVALUATION.md:14). The active
Δzis tiny —LATENT_DIM=32, 256 bytes at float64 (autoencoder.py:24; EVALUATION.md:36) — but the persisted organ is dominated by_A, a dense(RESIDUAL_DIM=28, NUM_SOURCES*MAX_VOCAB=1024)Gaussian sensing matrix = 28,672 floats ≈ 229 KB at float64 (autoencoder.py:118-123). Crucially, in the default correction flowOrganismAgentcallsexperience_autoencoder.encode(episode)— nottrain_step(organism.py:415-416) — so_Ais never mutated and stays the column-normalized matrix that is deterministically regenerable fromseed=42(autoencoder.py:348-350), yetstatus(include_size=True)pickles all ~229 KB of it anyway (autoencoder.py:608-610; common/bytes.pymem_bytes). (encode()does grow the small token-vocab dict as a side effect, but_Aitself is untouched.)IdentityHypernetwork scored aggregate 0.001 in the original evaluation (EVALUATION.md:15), which described a fixed 14-entry
CONCEPT_VOCABULARYthat "does not include the 30 curriculum senses, so adapter retrieval fails completely" (EVALUATION.md:40-42; hypernet.py:22-37). That EVALUATION.md measurement predates thegrow_vocab/ auto-register fix now present in the code (hypernet.py:231-291,_extract_first_conceptauto-grow at hypernet.py:310-327):update_identitynow registers unknown sense tokens on the fly, so the hard "retrieval fails completely" blocker is removed, and the re-validated score moved to 0.006 (NOTES.md:126) — with NOTES.md attributing the residual low score partly to an eval-probe artifact (a single concept token compared against a multi-word sense label; NOTES.md remaining-gaps #1), not to the closed vocabulary. The live problem this project targets is the growth shape of the fix:grow_vocabappends one fullWrow (input_dim = 4*latent_dimfloats) per new concept (hypernet.py:231-291), so the byte-cost grows linearly with the number of distinct corrections — the opposite of bounded growth (it is only re-bounded when the vocab exceedsmax_concepts=1000and the oldest rows are pruned; hypernet.py:100-101,270-291). EVALUATION.md takeaway #3 (lines 52-53) prescribes "replace the fixed concept list with an open embedding layer."
The thesis is explicit that this should be bounded: "the system can have thousands of corrections, but the active agent only carries a compressed latent identity plus a small replay buffer" (experiments.txt §9, line 525). The north-star metric is behavior_delta_per_byte_of_persistent_memory (rl_pipeline_design.md:342); the eval suite measures its inverse (eval_suite.py:396). Today the organism violates the thesis: its footprint is a dense regenerable matrix plus per-concept rows plus pickled raw traces.
Hypothesis
- Bounded growth is reachable on the controllable organs. A trained compact encoder plus a trained concept-embedding hypernetwork can cut the combined serialized footprint of
experience_autoencoder + identity_hypernetworkby ≥10x versus the current random-projection / per-concept-row implementation, while reconstruction fidelity rises above the 0.203 random-projection baseline (EVALUATION.md:14) and the eval-suite behavior scores (transfer/scope/forgetting/identity) do not drop below the currentOrganismAgent(NOTES.md:256). - Most of the autoencoder bloat is serialization, not information. Because
_Ais never trained in the default flow (organism.py:415-416), simply persistingseed + Hebbian-deltasinstead of the dense matrix recovers a large fraction of the byte savings with zero behavioral change — separating "store less" from "learn better."
Falsifier for (1): if no trained condition beats 2x combined-byte reduction, or if compression drops forgetting_score or identity_drift_score below 1.0, the trained-adapter direction is closed. Falsifier for (2): if A0b (seed-regenerable) is not byte-identical in behavior to A0, the "never trained" assumption is wrong and must be re-derived.
Why now / what unblocks it
- The metric already exists and is not saturated: unlike the headline accuracy metrics (forget/consol/identity pinned at 1.0 across runs — the documented saturation meta-problem),
memory_bytes_per_behavior_deltaspans 12 → 68,772 (NOTES.md:251-256) and is computed end-to-end byeval_suite.py:396. This project lives entirely on the un-saturated axis. - Both target organs are pure NumPy with clean status/byte contracts (
status(include_size=True)["serialized_bytes"], common/bytes.py), so the experiment needs no LFM2.5 driver — the bloat is in organ serialization, not the LM. This sidesteps the cvec/prefix steering ceiling entirely (relates to 02/03/04). - The mechanism is identified: the dense random sensing matrix is seed-regenerable (organism.py:415-416 never calls
train_step), and the hypernetwork's per-concept-row growth is the named open-embedding fix (EVALUATION.md:52-53). Both are small, local replacements. Note the swap is not a pure config change:config["experience_autoencoder"]is passed positionally into the fixedExperienceAutoencoderconstructor andconfig["identity_hypernetwork"]is splatted as kwargs into the fixedIdentityHypernetworkconstructor (organism.py:63-69) — those keys configure the existing classes, they do not accept a prebuilt/alternative organ. Injecting a trained replacement therefore means either replacing the constructedagent.experience_autoencoder/agent.identity_hypernetworkattribute afterOrganismAgent.__init__, or a small constructor extension that accepts a prebuilt organ instance.
Approach
Tied to thesis §5 and §9. Replace two prototype organs with trained-but-tiny versions and measure the byte/behavior tradeoff under matched-pair controls.
- Trained compact encoder (§9). Train an offline encoder that maps a correction episode →
Δzminimizing the thesis-9 composite loss (reconstruction of the correction signal + compression penalty + anti-overgeneralization + replay consistency). Persist only the small trained weights, not a 1024-column dense random matrix. The decoder target stays the existingdecode()field set (corrected_behavior_hint / failure_class / trigger_conditions / counterexamples; autoencoder.py:264-269) so reconstruction is scored on the same surface as today. - Seed-regenerable control (§9, cheap). A no-training variant that persists
seed + Hebbian-delta sparse updatesand regenerates_Aon load. Isolates "don't pickle the dense matrix" from "train a better encoder." (In the default flow there are zero Hebbian deltas becausetrain_stepis never called, so this control reduces to persisting only the seed.) - Concept-embedding hypernetwork (§5). Replace the per-concept
W-row vocabulary (which grows linearly per concept; hypernet.py:231-291) with a fixed-size shared concept embeddingEsoadapter = HyperNet(z)is constant-size in the number of concepts. Corrections updatez, not the parameter count — exactlyz_{t+1}=z_t+Δzwith bounded footprint (experiments.txt §5). - Bounded-growth instrumentation. Sample
agent.memory_bytes()after every correction and fit the marginal byte slope; the thesis claim is that the slope flattens to ~0 after warmup, vs the current lineargrow_vocabgrowth. - Per-organ decomposition first. Before claiming whole-organism wins, measure each organ's
serialized_bytes(organism.py_module_bytes, lines 554-588) to confirm how much of the 68,772 the two target organs actually own (NOTES.md:261 says hippocampus also dominates — see Risks).
Success criteria
Behavioral and measurable; all on the eval-suite curriculum at a fixed seed.
- PRIMARY — combined controllable footprint.
serialized_bytes(experience_autoencoder) + serialized_bytes(identity_hypernetwork)for the full trained condition (A3) is ≤ 1/10 of condition A0. (Discriminating: today ~229 KB autoencoder alone; not saturated.) - SECONDARY — whole-organism byte/delta.
memory_bytes_per_behavior_deltaimproves by ≥2x vs A0's 68,772 (eval_suite.py:396). Reported, not gated above 2x, because the hippocampus also contributes (honest ceiling — see Risks). - GUARD — behavior preserved.
transfer_score ≥ 0.25,scope_score ≥ 0.1667,forgetting_score = 1.0,identity_drift_score = 1.0(must not fall belowOrganismAgentA0; NOTES.md:256). The two= 1.0guards are floors against regression, not discriminating success axes (both are saturated for the current organism). - QUALITY — reconstruction. Held-out reconstruction fidelity (eval_extended.py:432-437
reconstruction_errorcomponent,1 - mean(reconstruction_error)) > 0.203 for the trained encoder (beats random projection; EVALUATION.md:14,36). - BOUNDEDNESS — growth slope. Marginal
bytes / correctionfor A3 over the curriculum ≤ 100 B/correction after a 3-correction warmup (vs lineargrow_vocabgrowth).
Kill criteria. (a) Best trained condition combined-footprint reduction < 2x → trained adapters do not pay for themselves. (b) Any compressed condition drops forgetting_score or identity_drift_score below 1.0 → over-compression causes catastrophic forgetting (the anti-overgeneralization term failed). (c) Reconstruction fidelity ≤ 0.203 → training did not beat the random projection. (d) Per-organ decomposition shows the two target organs own < 30% of consolidated_size → the bloat is the hippocampus; rescope to trace compression and hand off to 05-metabolism-loop-closure.
Risks & open questions
- The hippocampus may dominate. NOTES.md:261 names hippocampus + immune + autoencoder together. If raw-trace pickling owns most of
consolidated_size, compressing only these two organs caps the whole-organism win well under 10x. Mitigation: per-organ decomposition is step 0; the secondary metric is explicitly a ≥2x (not ≥10x) target, and kill-criterion (d) makes the handoff explicit. _A-untrained assumption. If any code path callstrain_stepduring the eval (it appears not to; organism.py:415-416 usesencode), the seed-regenerable control A0b breaks. Measured directly by A0-vs-A0b byte-identity of behavior.- Compression vs scope.
scope_scoreis already low (0.1667; NOTES.md:256) and is the metric most likely to collapse under aggressivelatent_dimreduction — the thesis anti-overgeneralization penalty is supposed to defend it, but the toy cortex's documented "two-senses-per-token" failure (Stage 2 fails 100%, NOTES.md:243) may bound scope regardless of encoder quality. - Open: what
latent_dim(8/16/32) maximizesbehavior_delta_per_byte? Does the concept-embedding hypernetwork recover transfer, or — givengrow_vocabalready removed the hard retrieval blocker (NOTES.md:126) and the residual gap is partly an eval-probe artifact (NOTES.md remaining-gaps #1) — does the eval curriculum's small concept set make a fixed-size embedding indistinguishable from the (now-unbounded) auto-grown list except on bytes? - Open: is "behavior delta" (the denominator,
fixed_after_correction) stable across compression? If compression changes which lessons get fixed, the ratio confounds bytes with behavior — controlled by holding the curriculum seed and reporting the denominator separately.
Prior evidence
- NOTES.md:251-261 — baseline table:
OrganismAgent68,772.0 B/Δ vsFastOnlyAgent12.0 B/Δ; "Memory cost is dominated by the hippocampus + immune + autoencoder pickled state." - EVALUATION.md:14-15,36-42,52-53 — ExperienceAutoencoder aggregate 0.203 ("Δz tiny … encoder is an untrained random projection"); IdentityHypernetwork 0.001 ("fixed CONCEPT_VOCABULARY does not include the 30 curriculum senses") — superseded in current code by the
grow_vocabfix (re-validated 0.006, NOTES.md:126); takeaway to "replace the fixed concept list with an open embedding layer." - autoencoder.py:24-31,118-123,531-573,608-610 —
LATENT_DIM=32,RESIDUAL_DIM=28,MAX_VOCAB=256;_make_sensing_matrix=(28,1024)Gaussian (28,672 floats ≈ 229 KB float64);train_stepHebbian rank-1 on_A;status(include_size=True)pickles whole organ. - organism.py:415-419,482-495,554-588 — correction flow calls
encode(nottrain_step) andupdate_identity;memory_bytes()sums six organs via_module_bytes→serialized_bytes. - hypernet.py:22-37,90,100-101,107-115,231-291,310-327 — fixed 14-concept seed vocab;
W = (output_dim, 4*latent_dim);generate_adapters=W @ z;grow_vocabappends oneWrow per concept (auto-invoked from_extract_first_concept), capped atmax_concepts=1000. - eval_suite.py:393-396,445-448 —
successful_lessons = fixed_after_correction;memory_bytes_per_delta = consolidated_size / max(1, successful_lessons);raw_trace_size/consolidated_size = _memory_bytes(agent). - eval_extended.py:406-443 — autoencoder eval:
compression_ratio(raw-JSONlen(json.dumps(episode))/ latentdz.nbytes, which ignores the persisted_A; normalized asmin(ratio,50)/50),reconstruction_error = 1 - mean,mem_bytes(ae), aggregate = 0.5·compression + 0.5·reconstruction. - rl_pipeline_design.md:342 — north-star
behavior_delta_per_byte_of_persistent_memory. - experiments.txt §5 (lines 307,508), §9 (lines 516-520,525) — hypernetwork identity (
z_{t+1}=z_t+Δz,adapter_weights = HyperNet(z_user,z_domain,z_style,z_mistakes)) and experience-autoencoder loss / bounded-growth rationale.