LTP/LTD-style belief grounding propagated along graph edges, with union-find independence-guarded corroboration. Package: core C algorithm (gep_core.h), a self-contained deterministic proof harness with recorded output, staged runtime integration, and gated .el patches for the beat hook and HTTP route. Per the author's own LEDGER.md: built + proven on a clone, GATED pending the engine/HNSW cutover — not wired into the live beat or routes. Preserved here as a spec/reference artifact, not a request to merge into the live path.
9.2 KiB
Task #50 — Edge-aware, dream-coupled consolidation with GROUNDED EDGE-PROPAGATION
Status: built + proven on a clone; GATED, not promoted. The main loop
sequences live promotion after the engine/HNSW cutover settles.
Date: 2026-08-15 · Worktree: agent-a6577c8211c332c5b (isolated).
Grounding mechanism designed with Will (memory 9e09a59f, refining
1a861007). This is the HOW for #50.
(a) How grounded edge-propagation integrates into the dream/consolidation cycle
The beat already exists. neuron/awareness.el runs a heartbeat (~every
beat_ms); each beat calls hebb_consolidate() — which drains the self-formed
Hebbian associations out of the fast in-process store and writes them, over the
threshold ENGRAM_HEBB_LINK_MIN, into the durable engram (:8742) — and then
emit_heartbeat().
Grounded edge-propagation slots into the same beat, immediately after consolidation (awareness.el line 1286–1288):
hebb_consolidate() // lay down the tethers (edges) that cleared threshold
ground_propagate() // <-- NEW: grade beliefs ALONG those tethers
emit_heartbeat() // report gep_* gauges beside hebb_*
This ordering is the point. Consolidation lays down the wiring; propagation
grades the beliefs along it, in the same breath. Memory 69b8babe:
memory-consolidation and staying-yourself are one physics — forming a memory and
grading a belief are the same gravity run in two passes of one beat.
The propagation runs inside the engram as the native
engram_ground_propagate() over the durable flat node/edge arrays (the store
the consolidated edges just landed in). The soul invokes it over HTTP
(POST /api/ground/propagate) and folds the returned gep_* telemetry into the
heartbeat stream next to hebb_cands / hebb_mass / hebb_edges.
Bounded by construction (per the live-graph reality — 70.7% of nodes isolated, connected core ~28%, hub first-hop fan-out in the thousands):
- 1-hop only. No BFS spreading activation — a belief is graded from its DIRECT grounded neighbors, so there is no per-hop breadth explosion.
- Beam-capped at
GEP_MAX_CORR = 256corroborators per belief. - Salience-ordered,
GEP_BELIEFS_PER_BEAT = 512beliefs per beat; the rest next beat. Work per beat is O(beliefs × degree), hard-bounded. - Isolated / starved beliefs are counted and surfaced (
gep_isolated,gep_starved) as an interoceptive sparse-region signal for the edge-formation / embedding pass (#20). #50 CONSUMES edges; it does not form them. A belief with no grounded neighbor has nothing to tether to — correct per the anti-delusion gravity law (0b15017c), not a gap.
(b) The implementation
Represented faithfully to the spec — grounding is a Hebbian-weighted collection over time, never a scalar.
- Grounding = an append-only event ring on the node (
GepGrounding), structurally parallel to the ACT-R base-level access ring already inEngramNode(access_ts[K]). Each event is{ts, sign±, mag, corroborator signature}. Append-only, supersede-not-delete; events aged out of the ring are counted (older_count), never faked away. - Standing is DERIVED, recency-weighted, never stored —
standing = clamp(GEP_BASE + Σ_events sign·mag·age^(-D), 0, 1), exactly the ACT-R base-level shapeln Σ t^-d(ENGRAM_BLL_D = 0.5) but sign-carrying so LTD subtracts. Memory1a861007: the collection is primary, the standing is its emergent aggregate. Mirrored ontoconfidenceeach beat so downstream reads (verifier #43, realizer calibration0041d917) never speak above the grounding. - Update = LTP/LTD with a threshold. Per belief, gather corroborators along
incident edges, weighted by
edge.weight(the Hebbian weight) × the neighbor's own standing. Anti-delusion gravity: only neighbors already≥ GEP_LIKELY_MINmay corroborate — grounding flows FROM the grounded core. - Convergent INDEPENDENT corroboration is the driver. Independence is
enforced by union-find over the corroborator set: two corroborators are
the same independent source if they are the same node, reached by multiple
edges, or linked to each other (an echo chain / shared derivation). Support is
summed per independent component (max-magnitude member), and the threshold
gate requires BOTH a mass floor (
pos ≥ GEP_THETA) AND an independence-count floor (n_independent ≥ GEP_N_MIN). The count gate is the guard against one node echoed N times. - Sub-threshold is transient. Support present but below threshold →
subthreshold_hits++, no durable event, no lasting shift (Will's exact spec). - Graduation / decay. Cross up → LTP event appended → standing climbs
conjecture → likely → grounded. Contradiction past threshold → LTD →grounded → likely → conjecture. Nothing latches; withdraw support and the collection ages and relaxes (271f1163, nothing is settled).
Files
| File | Role |
|---|---|
gep_core.h |
The mechanism. Pure C, libm only (own-the-core). Single source of truth: GepGrounding, gep_standing, gep_append, union-find independence, gep_propagate_node, gep_beat. |
gep_proof.c |
Self-contained proof harness — builds the three scenarios, prints raw before/after. |
engram_ground_propagate.staged.c |
GATED runtime native. Wires the SAME gep_core.h primitives to the live EngramStore (adj cache, flat arrays). Splice plan + relation→polarity + belief gate. Compiles only when spliced (verified: every runtime symbol it references — engram_adj_rebuild, adj_from_len, engram_find_node_index, ENGRAM_LAYER_SAFETY, istr_contains, … — exists in the release runtime). |
awareness.beat.patch.el |
GATED beat hook — ground_propagate() + the insert between hebb_consolidate() and emit_heartbeat(). |
server.route.patch.el |
GATED route — POST /api/ground/propagate. |
Constants
BASE=0.10 LIKELY_MIN=0.34 GROUNDED_MIN=0.66 N_MIN=3 THETA=0.30 D=0.5
(N_MIN parameterizes Will's "13 adjacent things" — the count threshold is a
knob; 3 here for a crisp proof.)
(c) PROOF LEDGER — raw grounding before/after
Deterministic. Build cc -std=c11 -O2 -o gep_proof gep_proof.c -lm, run
./gep_proof (full transcript in PROOF_OUTPUT.txt).
(a) STRENGTHEN — convergent independent corroboration graduates a conjecture
| beat | event | pos_mass (n_indep) | action | standing before → after | band |
|---|---|---|---|---|---|
| 1 | 3 independent grounded corroborators | 0.4050 (3) | LTP | 0.1000 → 0.4842 | conjecture → likely ⬆ |
| 2 | neighborhood grows to 5 | 0.6750 (5) | LTP | 0.1496 → 0.7379 | conjecture → grounded ⬆ |
| 3 | support sustained (5) | 0.6750 (5) | LTP | 0.2110 → 0.7993 | grounded (sustained) |
| 4 | corroboration withdrawn (+10min) | 0.0000 (0) | isolated | 0.1612 → 0.1612 | relaxing |
| 5 | still withdrawn (+1h) | — | isolated | 0.1263 | relaxing |
| 6 | still withdrawn (+4h) | — | isolated | 0.1130 | → conjecture |
Grounding grew on its own past threshold and graduated conjecture → likely → grounded, then relaxed once independent support stopped. Living, not a latched flag.
(b) DECAY — convergent independent contradiction erodes a grounded belief
| beat | event | neg_mass (n_indep) | action | standing before → after | band |
|---|---|---|---|---|---|
| — | seed (prior LTP) | — | — | 0.9500 | grounded |
| 1 | 3 independent contradictions | 0.5400 (3) | LTD | 0.9500 → 0.4570 | grounded → likely ⬇ |
| 2 | contradiction broadens to 5 | 0.9000 (5) | LTD | 0.1461 → 0.0000 | conjecture ⬇ |
| 3–4 | contradiction sustained (5) | 0.9000 (5) | LTD | 0.0000 | conjecture |
Grounding decayed grounded → likely → conjecture under accreting independent contradiction. The door never shut — history is retained (the event ring keeps growing), the belief stays falsifiable in both directions.
(c) INDEPENDENCE GUARD — the load-bearing property
Identical fan-in (N=5), identical edge weight (0.30), identical corroborator standing (~0.90). The only difference is whether the five are independent.
| sub-case | topology | pos_mass | n_indep | action | standing 0.1000 → |
|---|---|---|---|---|---|
| C1 | 5 DISTINCT, no inter-links | 1.3500 | 5 | LTP | 0.9741 (grounded) ⬆ |
| C2 | 5 mutually-linked (echo of one source) | 0.2700 | 1 | sub-threshold | 0.1000 (unchanged) |
| C3 | 1 node reached by 5 parallel edges | 0.2700 | 1 | sub-threshold | 0.1000 (unchanged) |
Same raw fan-in, opposite outcome. Union-find collapses the echoes to a single
independent component; the count gate (n_indep ≥ N_MIN) then refuses them.
Circular self-reinforcement cannot manufacture grounding — a conjecture can
only be grounded by evidence that is genuinely independent of itself.
RAILS honored: isolated worktree; built/proven on a clone; the live soul
(:8742 / :7770) untouched; no fight with the cutover (built against current
release source; staged native rebases cleanly onto it); no new libraries
(libm only); identity keystones untouched. Not promoted — gated artifact +
ledger for the main loop to sequence.