- AutoGrowth
accumulate_evidence!receivesstrain_energy(Float64) as Source 5 — but uses it only as one evidence increment whenhippocampal_warrant_active && strain_energy > 0.55. hippococampal_warrant_activeis passed asfalsehardcoded in Main.jl line ~5748.- The 3 unused MLP output heads (semantic_score, relevance_score, disambiguation) are computed, logged, and written to SelfObserver — but never influence any decision system.
SOURCE 9: SEMANTIC COHERENCE GAP (semantic_score)
- When EphemeralMLP reports low
semantic_score(< 0.35), the system recognizes it doesn't semantically understand the input. - Low semantic_score on non-trivial input → evidence that uncovered tokens need node coverage.
- Implementation: After MLP transform, extract
semantic_scorefrommlp_result. Pass toaccumulate_evidence!as new kwargmlp_semantic_score::Float64 = 0.5. - Inside
accumulate_evidence!: ifmlp_semantic_score < 0.35 && intensity > 0.5, each uncovered token getsintensity * (1.0 - mlp_semantic_score) * 0.4evidence tagged as"semantic_gap". - Rationale: Low semantic_score means the brain's pattern-matching couldn't find semantically coherent matches. This is a stronger signal than mere silence — it's the brain saying "I found something but it doesn't make sense."
SOURCE 10: RELEVANCE DROPOUT (relevance_score)
- When EphemeralMLP reports low
relevance_score(< 0.30), the system's responses aren't relevant to the user's input context. - Low relevance_score → evidence for :thesaurus growth type (synonym expansion bridges relevance gaps).
- Implementation: Pass
mlp_relevance_score::Float64 = 0.5toaccumulate_evidence!. - Inside: if
mlp_relevance_score < 0.30, existing thesaurus gap evidence gets a1.0 - mlp_relevance_scoremultiplier boost. Also generatesintensity * (1.0 - mlp_relevance_score) * 0.3evidence for uncovered tokens tagged as"relevance_dropout". - Rationale: If responses are irrelevant, the thesaurus is likely incomplete — missing synonym connections that would let patterns fire.
SOURCE 11: DISAMBIGUATION PRESSURE (disambiguation)
- When EphemeralMLP reports high
disambiguation(> 0.65), the system sees ambiguous input that it can't resolve. - High disambiguation → evidence for :sigil growth (new sigil expansion would help resolve ambiguity) and for specific patterns that disambiguate.
- Implementation: Pass
mlp_disambiguation::Float64 = 0.5toaccumulate_evidence!. - Inside: if
mlp_disambiguation > 0.65, for each token that has sigil overlap, addintensity * mlp_disambiguation * 0.3evidence tagged as"disambiguation_pressure"with growth_type:sigil. Also add evidence for the full pattern as:matchwithdisambiguation * 0.25intensity. - Rationale: The brain detected ambiguity. New sigil entries (noun lexicon entries, relation sigils) provide more resolution paths. New nodes for the ambiguous pattern give future scans more specificity.
SOURCE 12: COHERENCE FIELD DELTA (ΔΦ from CoherenceField)
- When ΔΦ is large and negative (coherence dropping), the system is losing integration — evidence for growth to restore coherence.
- Implementation: Pass
coherence_delta_phi::Float64 = 0.0toaccumulate_evidence!. - Inside: if
coherence_delta_phi < -0.15, uncovered tokens getabs(coherence_delta_phi) * 0.5 * intensityevidence tagged as"coherence_drop". This is a WEAK evidence source — it supplements but doesn't dominate. - Rationale: Coherence drop means the system's existing structure can't integrate the new input. Growth fills the gaps.
SOURCE 13: SELF-OBSERVER PATTERN (from SelfObserver peek)
- SelfObserver records MLP cycle observations. If a pattern recurs in observations (same user_input_hash with low quality), that's cumulative evidence of a persistent gap.
- Implementation: Before calling
accumulate_evidence!, peek SelfObserver for recent low-quality cycles. Passobserver_recurring_gap::Bool = falseandobserver_gap_pattern::String = "". - Inside: if
observer_recurring_gap, addintensity * 0.5evidence forobserver_gap_patterntagged as"observer_pattern". - Rationale: The subconscious noticed the same gap repeatedly. This is an independent signal from the conscious scan — it validates other evidence sources.
At the accumulate_evidence! call site (~line 5745):
# Extract MLP head scores from the mlp_result computed earlier
_ag_semantic = try Float64(get(mlp_result, "semantic_score", 0.5)) catch _ 0.5 end
_ag_relevance = try Float64(get(mlp_result, "relevance_score", 0.5)) catch _ 0.5 end
_ag_disambiguation = try Float64(get(mlp_result, "disambiguation", 0.5)) catch _ 0.5 end
# Extract coherence delta
_ag_delta_phi = try CoherenceField.compute_delta("", NODE_MAP) catch _ 0.0 end
# (Use the already-computed _delta_phi from earlier in the pipeline)
# Check SelfObserver for recurring gaps
_ag_obs_gap = false
_ag_obs_pattern = ""
try
_ag_obs_peek = SelfObserver.peek_pattern(_MLP_OBSERVER_STORE, "low_quality")
if !isempty(_ag_obs_peek)
_ag_obs_gap = true
_ag_obs_pattern = first(_ag_obs_peek).pattern
end
catch; end
AutoGrowth.accumulate_evidence!(
user_text = mission_text,
intensity = 1.0,
node_patterns = _ag_node_patterns,
node_ids_patterns = _ag_node_ids_patterns,
thesaurus_gate_filter = Thesaurus.synonym_lookup,
thesaurus_word_similarity = Thesaurus.word_similarity,
lobe_snapshots = _ag_lobe_snapshots,
attachment_snapshots = _ag_attach_snapshots,
sigil_table_entries = _ag_sigil_entries,
strain_energy = _ag_strain,
hippocampal_warrant_active = _ag_strain > 0.55, # FIX: was hardcoded false!
mlp_semantic_score = _ag_semantic, # NEW
mlp_relevance_score = _ag_relevance, # NEW
mlp_disambiguation = _ag_disambiguation, # NEW
coherence_delta_phi = _ag_delta_phi, # NEW
observer_recurring_gap = _ag_obs_gap, # NEW
observer_gap_pattern = _ag_obs_pattern, # NEW
)Add new growth types:
:flashcard— for arithmetic/math facts (see §3)
- AutoLinker
accumulate_link_evidence!receivesstrain_nodes=String[]— always empty. The strain_pair evidence source (Source 5) is dead code. - Zero EphemeralMLP integration. The Linker doesn't know what the brain thinks.
SOURCE 9: DISAMBIGUATION BRIDGE (disambiguation)
- High disambiguation (> 0.65) means the brain sees ambiguity between candidate nodes.
- If two co-fired nodes both partially matched the same ambiguous input, they should be linked — the bridge creates a resolution path.
- Implementation: Pass
mlp_disambiguation::Float64 = 0.5toaccumulate_link_evidence!. - Inside: if
mlp_disambiguation > 0.65 && length(co_fired_ids) >= 2, each co-fired pair getsmlp_disambiguation * 0.4extra evidence tagged as"disambiguation_bridge". - Rationale: Ambiguous input activates multiple candidates. Linking them creates a disambiguation pathway — next time, the bridge carries the resolution signal.
SOURCE 10: RELEVANCE CROSS-LOBE (relevance_score)
- Low relevance_score (< 0.30) combined with cross-lobe co-firing suggests the lobes aren't communicating well.
- Implementation: Pass
mlp_relevance_score::Float64 = 0.5. - Inside: if
mlp_relevance_score < 0.30, cross-lobe co-fired pairs get(1.0 - mlp_relevance_score) * 0.5bonus evidence tagged as"relevance_cross_lobe". - Rationale: When the brain can't find relevant responses AND cross-lobe nodes co-fired, it means the cross-lobe connection is weak. Strengthening the bridge improves relevance.
SOURCE 11: STRAIN NODES (fix the empty string[])
- Currently
strain_nodes=String[]is hardcoded. Fix: extract actual strain nodes from the MLP result. - When strain_energy > threshold, the nodes that contributed to the strain (low-confidence activated nodes) should be passed as strain_nodes.
- Implementation: After MLP transform, identify nodes with confidence below JITTER_CONFIDENCE_FLOOR (0.50) that still fired. These are the strain nodes.
- Pass
strain_nodes = _strain_node_ids(non-empty when strain is active). - This resurrects the dead Source 5 (strain_pair) in AutoLinker.
SOURCE 12: CHATTER RESIDUAL CO-OCCURRENCE
- ChatterResiduals mines co-occurrence from swap history. These pairs represent "the system chose these nodes together" — a strong signal for linking.
- Implementation: Call
ChatterResiduals.get_co_occur_snapshot()beforeaccumulate_link_evidence!. Pass aschatter_co_occur_pairs::Vector{Tuple{String,String,Float64}}. - Inside: each pair gets
CHATTER_CO_OCCUR_INCREMENT * pair_intensity * 0.5evidence tagged as"chatter_residual". - Rationale: ChatterResiduals sees patterns the active path doesn't — background mining catches slow relationship drift.
At the accumulate_link_evidence! call site (~line 5845):
# Extract MLP signals for AutoLinker
_al_disambig = try Float64(get(mlp_result, "disambiguation", 0.5)) catch _ 0.5 end
_al_relevance = try Float64(get(mlp_result, "relevance_score", 0.5)) catch _ 0.5 end
# FIX: Compute strain nodes instead of passing empty String[]
_al_strain_nodes = String[]
if _ag_strain > 0.55
_al_strain_nodes = filter(v -> v.confidence < 0.50, contributing_votes) |> vs -> map(v -> v.node_id, vs) |> ids -> unique(ids)
end
# Get ChatterResiduals co-occurrence pairs
_al_chatter_pairs = Tuple{String,String,Float64}[]
try
_al_chatter_raw = ChatterResiduals.get_co_occur_snapshot()
for entry in _al_chatter_raw
a = get(entry, "a", ""); b = get(entry, "b", ""); c = Float64(get(entry, "intensity", 0.0))
if !isempty(a) && !isempty(b) && c > 0.0
push!(_al_chatter_pairs, (a, b, c))
end
end
catch; end
AutoLinker.accumulate_link_evidence!(
co_fired_ids = fired_ids,
input_touched_ids = String[],
node_ids_patterns = _ag_node_ids_patterns,
bridge_map_snapshot = _al_bridge_snap,
thesaurus_gate_filter = Thesaurus.synonym_lookup,
thesaurus_word_similarity = Thesaurus.word_similarity,
lobe_of_fn = _al_lobe_of,
strain_nodes = _al_strain_nodes, # FIXED: was String[]
co_occur_map = _al_co_occur,
co_activation_pairs = Tuple{String,String,Float64}[],
mlp_disambiguation = _al_disambig, # NEW
mlp_relevance_score = _al_relevance, # NEW
chatter_co_occur_pairs = _al_chatter_pairs, # NEW
)Simple arithmetic facts and lookup tables don't need new nodes. Writing "3+5=8" as a flashcard in LobeTable is cheaper than growing a node, and the ArithmeticEngine can read it back instantly.
Add to LobeTable.jl:
const CHUNK_FLASHCARD = "flashcard"Add to VALID_CHUNKS:
const VALID_CHUNKS = Set{String}([CHUNK_NODES, CHUNK_JSON, CHUNK_DROP, CHUNK_HOPFIELD, CHUNK_META, CHUNK_FLASHCARD])Since create_lobe_table! iterates VALID_CHUNKS, flashcard chunks will be auto-created for every lobe.
Key: "<expression_hash>" (e.g., hash of "3+5" or "capital:france")
Value: Dict{String, Any} with fields:
Dict(
"expression" => "3+5", # Original expression
"result" => "8", # Computed result
"result_num" => 8.0, # Numeric result (if applicable)
"type" => :arithmetic, # :arithmetic, :lookup, :fact
"lobe_id" => "math", # Which lobe owns this card
"created_at" => 1720000000.0, # Timestamp
"hits" => 0, # Read count (for hot-card tracking)
"ttl" => 0, # 0 = no expiry, >0 = seconds until expiry
)# Write a flashcard
function flashcard_put!(lobe_id::String, expression::String, result::String;
result_num::Float64=NaN, card_type::Symbol=:arithmetic, ttl::Float64=0.0)
# Read a flashcard (returns Dict or nothing)
function flashcard_get(lobe_id::String, expression::String)::Union{Dict{String,Any}, Nothing}
# Check if a flashcard exists
function flashcard_has(lobe_id::String, expression::String)::Bool
# Delete a flashcard
function flashcard_delete!(lobe_id::String, expression::String)::Bool
# Query flashcards by prefix (e.g., all arithmetic cards)
function flashcard_query(lobe_id::String; card_type::Symbol=nothing, min_hits::Int=0)::Vector{Dict{String,Any}}
# Increment hit counter
function flashcard_hit!(lobe_id::String, expression::String)::Bool
# Evict expired flashcards (ttl > 0 and past expiry)
function flashcard_evict!(lobe_id::String)::IntIn Main.jl, after ArithmeticEngine.compute_arithmetic succeeds:
- Check if flashcard already exists via
flashcard_has - If not, write via
flashcard_put!withcard_type=:arithmetic - On subsequent inputs with the same expression,
flashcard_getreturns the cached result — no re-computation needed.
SOURCE 14: FLASHCARD GAP
- When ArithmeticEngine detects math bindings but no flashcard exists for the expression, that's evidence for
:flashcardgrowth type. - Implementation: In
accumulate_evidence!, after tokenization, check if any token pair looks like an arithmetic expression. If so and no flashcard exists, add"fc:<expression>"evidence withintensity * 0.3tagged as"flashcard_gap"and growth_type:flashcard. - Growth action for
:flashcardtype: compute the arithmetic result and write it to the flashcard chunk. No node creation needed.
Not everything needs a node. Simple learning should be INSTANT — no coinflip, no evidence accumulation, no growth delay. The classifier detects petty cases and dispatches to the appropriate fast-path.
module PettyLearner
export classify_petty, dispatch_petty!, PettyResult
struct PettyResult
dispatched::Bool # Was a petty fast-path taken?
path::Symbol # :thesaurus, :flashcard, :lobe_whitelist, :none
detail::String # Human-readable description of what happened
end
"""
classify_petty(user_text, tokens, node_patterns, thesaurus_fn, sigil_entries) -> PettyResult
Determine if the input represents a "petty" learning opportunity —
something so simple it doesn't need node growth. Three categories:
1. NEW WORD → THESAURUS: A single uncovered token that is a known synonym
of a covered token. Just add the synonym pair — instant learning.
2. SIMPLE MATH → FLASHCARD: An arithmetic expression with bindings.
Compute the result, write to flashcard — instant lookup table.
3. DOMAIN TOKEN → LOBE WHITELIST: A single uncovered token that overlaps
with an under-populated lobe's subject. Add to whitelist — instant gating.
Returns PettyResult with dispatched=true if a fast-path was taken.
"""
function classify_petty(
user_text::String,
tokens::Vector{String},
node_patterns::Set{String},
thesaurus_gate_filter::Function,
thesaurus_word_similarity::Function,
lobe_snapshots::Vector{Tuple{String,String,Set{String}}},
sigil_entries::Dict,
arithmetic_bindings::Dict,
)::PettyResult
# ... implementation ...
end
"""
dispatch_petty!(result::PettyResult; kwargs...) -> PettyResult
Execute the fast-path action based on classification result.
"""
function dispatch_petty!(result::PettyResult;
thesaurus_register_fn::Function,
flashcard_put_fn::Function,
lobe_whitelist_fn::Function,
arithmetic_compute_fn::Function,
)::PettyResult
# ... implementation ...
endPath 1: New Word → Thesaurus
- Condition: Exactly ONE uncovered non-stopword token in input. That token has
word_similarity > SYNONYM_SEED_THRESHOLD (0.70)to a covered token. - Action: Call
add_seed_synonym!(new_word, [covered_word]). Instant bidirectional synonym registration. - Skip condition: If 2+ uncovered tokens, this isn't petty — it's a real gap.
Path 2: Simple Math → Flashcard
- Condition:
ArithmeticEngine.has_math_bindings(bindings)returns true. Expression is computable. - Action: Compute result, write to
CHUNK_FLASHCARD. No node growth. - Skip condition: If the expression is too complex (3+ operators, nested), let normal flow handle it.
Path 3: Domain Token → Lobe Whitelist
- Condition: Exactly ONE uncovered token that belongs to an under-populated lobe's subject area (checked via
lobe_snapshotsoverlap). The lobe has < 5 nodes. - Action: Call
add_lobe_whitelist!(lobe_id, token). Instant scan gating. - Skip condition: If the token could belong to multiple lobes, skip — ambiguity needs evidence.
In process_mission, AFTER AutoGrowth accumulate_evidence! but BEFORE maybe_grow_from_evidence!:
# GRUG v10: Petty Learning — instant fast-paths for simple stuff.
# If the classifier dispatches, we SKIP maybe_grow_from_evidence! this turn
# because the gap was already filled by a fast-path. No coinflip needed.
_petty_result = PettyLearner.classify_petty(
mission_text, _ag_tokens, _ag_node_patterns,
Thesaurus.synonym_lookup, Thesaurus.word_similarity,
_ag_lobe_snapshots, _ag_sigil_entries, _arithmetic_bindings
)
if _petty_result.path != :none
_petty_result = PettyLearner.dispatch_petty!(_petty_result;
thesaurus_register_fn = (a, b) -> Thesaurus.add_seed_synonym!(a, [b]),
flashcard_put_fn = (lobe, expr, res; kwargs...) -> LobeTable.flashcard_put!(lobe, expr, res; kwargs...),
lobe_whitelist_fn = (lobe_id, token) -> Lobe.add_lobe_whitelist!(lobe_id, token),
arithmetic_compute_fn = ArithmeticEngine.compute_arithmetic,
)
println("[PETTY] ⚡ Fast-path: $(_petty_result.path) — $(_petty_result.detail)")
endPassively accumulate unknown context. When curiosity overflows, the system asks a question autonomously via _HIPPOCAMPAL_PENDING_ASK.
Store in CHUNK_META under key "curiosity_accumulator":
Dict(
"buffer" => String[], # Queued unknown tokens/patterns
"intensity" => 0.0, # Accumulated curiosity intensity (0.0-1.0)
"quenched_at" => 0.0, # Timestamp of last quench
"overflow_count" => 0, # How many times overflow has fired
)- Each uncovered token from
accumulate_evidence!Source 1 (silence_map) also feeds curiosity:intensity += 0.05per uncovered token. - High novelty_score (> 0.70) from MLP:
intensity += novelty * 0.1. - Low semantic_score (< 0.35) from MLP:
intensity += (1.0 - semantic) * 0.08. - Evidence records that pass frequency floor but NOT intensity floor: their patterns enter the buffer.
CURIOSITY_OVERFLOW_THRESHOLD = 0.85- When
intensity >= CURIOSITY_OVERFLOW_THRESHOLDand buffer is non-empty:- Pick the highest-frequency pattern from the buffer.
- Generate a question:
"I'm curious about [pattern]. Can you tell me more?" - Store in
_HIPPOCAMPAL_PENDING_ASKvia the existing mechanism. - Quench:
intensity = 0.0,buffer = String[],quenched_at = time().
- After quenching, there's a cooldown:
CURIOSITY_COOLDOWN = 300.0seconds (5 minutes). - During cooldown, accumulation continues but overflow cannot fire.
- This prevents question-spam.
- In
AutoGrowth.accumulate_evidence!, after all evidence sources: call_accumulate_curiosity!(tokens, node_patterns, mlp_semantic_score, mlp_novelty_score). - In
Main.jl, after AutoGrowth call: checkAutoGrowth.check_curiosity_overflow(). If overflow, write to_HIPPOCAMPAL_PENDING_ASK. - Save/load: serialize
curiosity_accumulatorDict in the AutoGrowth save section.
- Missing conjunctions: "while", "whilst", "since" (temporal), "unless", "except", "apart from" (exclusion), "plus", "along with" (additive), "on the other hand" (contrastive)
- No sigil-boundary splitting: arithmetic expressions like "what is 2+3 and what is a dog" should split at the math boundary
- No EphemeralMLP-assisted decomposition: the MLP's
is_compoundflag exists but isn't used by the decomposer - Missing question markers: "can", "could", "would", "shall", "will", "do", "does", "did", "is", "are", "was", "were", "am"
- Missing command markers: "compare", "contrast", "analyze", "evaluate", "summarize", "determine", "identify", "convert", "translate"
# Add to _DEFAULT_SPLIT_CONJUNCTIONS:
"while", "whilst", "since", # temporal conjunctions
"unless", "except", # exclusive conjunctions
"plus", # additive ("what is X plus what is Y")
"independently", # "do X and independently do Y"
"separately", # "tell me X and separately tell me Y"# Add to _DEFAULT_COMPOUND_PAIRS:
"plus" => Set(["and", "also"]),
"while" => Set(["and", "also", "but"]),
"since" => Set(["and", "also"]),# Add to _DEFAULT_QUESTION_MARKERS:
"can", "could", "would", "shall", "will",
"do", "does", "did",
"is", "are", "was", "were", "am"# Add to _DEFAULT_COMMAND_MARKERS:
"compare", "contrast", "analyze", "evaluate",
"summarize", "determine", "identify",
"convert", "translate", "search", "lookup"
# Add to _DEFAULT_CONJUGATION_RULES:
"compare" => ["compares", "compared", "comparing"],
"contrast" => ["contrasts", "contrasted", "contrasting"],
"analyze" => ["analyzes", "analyzed", "analyzing"],
"evaluate" => ["evaluates", "evaluated", "evaluating"],
"summarize" => ["summarizes", "summarized", "summarizing"],
"determine" => ["determines", "determined", "determining"],
"identify" => ["identifies", "identified", "identifying"],
"convert" => ["converts", "converted", "converting"],
"translate" => ["translates", "translated", "translating"],
"search" => ["searches", "searched", "searching"],
"lookup" => ["lookups", "looked up", "looking up"],New splitting strategy that detects arithmetic/math sigil boundaries.
function _split_on_sigil_boundaries(input_text::String, config::DecomposerConfig)::Vector{String}
# GRUG: When input contains arithmetic expressions mixed with
# non-arithmetic content, split at the math boundary.
# "what is 2+3 and what is a dog" → ["what is 2+3", "what is a dog"]
# Already handled by conjunction "and" in most cases, but:
# "compute 5*3 tell me about dogs" → needs sigil boundary split
#
# Detection: look for &n/&op sigil regions in the tokenized input.
# If tokens transition from math-bound tokens to non-math tokens
# (or vice versa), that's a split point.
endThe MLP's is_compound flag is already computed in Main.jl. Pass it to the decomposer.
function decompose_input(input_text::String, config::DecomposerConfig;
mlp_is_compound::Bool=false)::Vector{DecomposedSubSubject}
# If MLP says compound but heuristics found no split,
# apply AGGRESSIVE splitting: try comma clauses with lower threshold,
# try clause-structure at every conjunction (not just split_conjunctions).
if mlp_is_compound && length(clauses) <= 1
clauses = _aggressive_split(input_text, config)
end
endCurrent _split_on_comma_clauses requires question markers on both sides of the comma. Enhance to also accept command markers and partial clause structure.
| Source # | Name | Signal | Target System | New? |
|---|---|---|---|---|
| 1 | silence_map | uncovered tokens | AutoGrowth | Existing |
| 2 | thesaurus_gap | uncovered synonyms | AutoGrowth | Existing |
| 3 | lobe_coverage | under-populated lobes | AutoGrowth | Existing |
| 4 | attachment | crystalized connectors | AutoGrowth | Existing |
| 5 | strain | MLP strain_energy | AutoGrowth | Existing (fix warrant) |
| 6 | time_gap | temporal keywords | AutoGrowth | Existing |
| 7 | sigil_gap | sigils with no expansion | AutoGrowth | Existing |
| 8 | co_occurrence | token co-occurrence | AutoGrowth | Existing |
| 9 | semantic_gap | MLP semantic_score < 0.35 | AutoGrowth | NEW |
| 10 | relevance_dropout | MLP relevance_score < 0.30 | AutoGrowth | NEW |
| 11 | disambiguation_pressure | MLP disambiguation > 0.65 | AutoGrowth | NEW |
| 12 | coherence_drop | ΔΦ < -0.15 | AutoGrowth | NEW |
| 13 | observer_pattern | SelfObserver recurring gap | AutoGrowth | NEW |
| 14 | flashcard_gap | arithmetic expr, no card | AutoGrowth | NEW |
| L1 | co_firing | same-cycle activation | AutoLinker | Existing |
| L2 | input_co_occurrence | same-input activation | AutoLinker | Existing |
| L3 | synonym_bridge | thesaurus synonyms | AutoLinker | Existing |
| L4 | opposing_lobe_co_act | cross-lobe co-fire | AutoLinker | Existing |
| L5 | strain_pair | co-stressed nodes | AutoLinker | Existing (FIX: populate) |
| L6 | attach_neighbor | bridge neighbor | AutoLinker | Existing |
| L7 | word_co_occur | word co-occurrence | AutoLinker | Existing |
| L8 | co_activation_pair | explicit CO_ACC | AutoLinker | Existing |
| L9 | disambiguation_bridge | MLP disambiguation > 0.65 | AutoLinker | NEW |
| L10 | relevance_cross_lobe | MLP relevance < 0.30 | AutoLinker | NEW |
| L11 | chatter_residual | ChatterResiduals pairs | AutoLinker | NEW |
"curiosity_accumulator"— in AutoGrowth section"flashcard_data"— per-lobe flashcard chunk data
# After existing autogrowth_evidence save:
if haskey(AutoGrowth._CURIOSITY, "buffer")
spec["curiosity_accumulator"] = AutoGrowth.serialize_curiosity()
end# After existing autogrowth evidence load:
if haskey(spec, "curiosity_accumulator")
AutoGrowth.deserialize_curiosity!(spec["curiosity_accumulator"])
end# In save_specimen:
fc_data = LobeTable.serialize_flashcards()
if !isempty(fc_data)
spec["flashcard_data"] = fc_data
end
# In load_specimen:
if haskey(spec, "flashcard_data")
LobeTable.deserialize_flashcards!(spec["flashcard_data"])
end/flashcard list [lobe_id]— show all flashcards (or for one lobe)/flashcard add <expression> <result>— manually add a flashcard/flashcard delete <expression>— remove a flashcard/flashcard stats— show flashcard hit counts and coverage
/curiosity status— show accumulator intensity and buffer/curiosity quench— manually quench the accumulator/curiosity clear— clear the buffer
/decomposer addQuestionMarker <marker>— add a question marker at runtime/decomposer removeQuestionMarker <marker>— remove a question marker/decomposer addSplitConjunction <conj>— already exists/decomposer aggressiveMode <on|off>— enable aggressive MLP-assisted decomposition
/autogrowth sources— show all 14 evidence sources with their current contribution stats/autogrowth mlpHeads— show current MLP head values and their evidence contributions
The implementation should follow this dependency order:
- LobeTable — Add
CHUNK_FLASHCARD+ flashcard API (foundation for everything else) - PettyLearner.jl — New module with classifier + dispatcher
- AutoGrowth — Add 5 new evidence sources (9-13) + flashcard_gap (14) + curiosity accumulator + 1 new growth type (:flashcard) + fix hippocampal_warrant_active
- AutoLinker — Add 3 new evidence sources (L9-L11) + fix strain_nodes
- InputDecomposer — Add conjunctions, markers, sigil-boundary splitting, MLP-assisted mode
- Main.jl — Wire all new kwargs, add PettyLearner dispatch, add curiosity overflow check, save/load for new state
- CLI commands — Add /flashcard, /curiosity, enhanced /decomposer, /autogrowth sources
New constants to add:
# In AutoGrowth.jl:
const SEMANTIC_GAP_THRESHOLD = 0.35 # below this = semantic gap
const RELEVANCE_DROPOUT_THRESHOLD = 0.30 # below this = relevance dropout
const DISAMBIGUATION_PRESSURE_THRESHOLD = 0.65 # above this = disambiguation pressure
const COHERENCE_DROP_THRESHOLD = -0.15 # below this = coherence drop
const FLASHCARD_EVIDENCE_INCREMENT = 0.3 # evidence per flashcard gap
const CURIOSITY_OVERFLOW_THRESHOLD = 0.85 # above this = overflow → question
const CURIOSITY_COOLDOWN = 300.0 # seconds after quench before next overflow
const CURIOSITY_PER_TOKEN = 0.05 # intensity per uncovered token
const CURIOSITY_NOVELTY_WEIGHT = 0.10 # novelty contribution
const CURIOSITY_SEMANTIC_WEIGHT = 0.08 # low-semantic contribution
const PETTY_MAX_UNCOVERED_TOKENS = 1 # only 1 uncovered → petty thesaurus path
const PETTY_SIMILARITY_FLOOR = 0.70 # SYNONYM_SEED_THRESHOLD for petty path
# In AutoLinker.jl:
const DISAMBIGUATION_BRIDGE_THRESHOLD = 0.65
const RELEVANCE_CROSS_LOBE_THRESHOLD = 0.30
const CHATTER_RESIDUAL_INCREMENT = 1.0