# Task #50 — Edge-aware, dream-coupled consolidation with GROUNDED EDGE-PROPAGATION

**Status:** built + proven on a clone; **GATED, not promoted.**
**Do not promote as designed** — see the block below.
**Date:** 2026-08-15 · **Worktree:** `agent-a6577c8211c332c5b` (isolated).

> # ⚠ DO NOT PROMOTE — SUPERSEDED IN PART (2026-08-16)
>
> This work is gated, which limits the blast radius, and its measurements are
> retained. But four of its structural commitments were refuted the day after it
> was written. Authority: `lang/spec/correspondence-and-censorship.md`. Read it
> before any promotion decision.
>
> | this ledger | corrected to |
> |---|---|
> | grounding is an **append-only event ring on the node** (`GepGrounding`), propagated by a dedicated `engram_ground_propagate()` | **grounding is not a subsystem and not a per-node structure — it IS the edge weight.** One quantity. A relation that keeps holding up strengthens; one that stops corresponding decays. That is not analogous to grounding, it *is* grounding. The ledger is **half-right**: it correctly rejects the scalar (§(a) "never a scalar"), but then builds a *second* structure beside the weight instead of recognising the weight |
> | the soul invokes propagation over HTTP, **`POST /api/ground/propagate`** | **grounding is never computed on demand.** An operation may *read* the grounding of a path; computing-and-writing a score makes reads write, which is the `eg_vindex_sync` defect (`lang/spec/runtime-ownership.md` §2) one level up. A POST also puts a supervisor back in — something *outside* deciding when Neuron consolidates |
> | **`GEP_BELIEFS_PER_BEAT = 512`** beliefs per beat, salience-ordered, the rest next beat | **the presence of a ticker is the diagnostic.** Consolidation is ambient, not scheduled — a brain has no cron job. A per-beat quota is a rate-limiter on an intrinsic rhythm that was replaced by an external clock. Measured 2026-08-16: consolidation already has **ten implementations**; this would be the eleventh |
> | grounding **mirrored onto `confidence` each beat** so downstream reads never speak above it | **confidence is derived, therefore never stored.** Confidence is high grounding *and* low volatility. Storing it separately is precisely how `confidence: 0.5` ends up sitting beside a zero vector, asserting something nothing computed |
>
> **What survives, and it is the valuable half:** the insight in memory `69b8babe`
> that *memory-consolidation and staying-yourself are one physics* — forming a
> memory and grading a belief are the same operation, not two passes. That is
> right, and it is stronger than this ledger's own framing: they are not two passes
> of one beat, they are **one event**. When neurons fire together the synapse
> changes — one physical event, not "fire, then write." No supervisor reads the
> weight, compares it to a threshold, and decides to persist. **Potentiation *is*
> the firing**, so there is no sampling rate and no `BELIEFS_PER_BEAT` to tune. A
> relation changes in exactly two ways, neither requiring observation on a clock:
> by **use** (an event — there is no interval during which something happened
> unnoticed, because the event is what happening consists of) and by **decay** (a
> pure function of the last recorded point and elapsed time — **analytic**, known
> in closed form between any two versions).
>
> The generating error, named: modelling every property as requiring a process, and
> every process as requiring an agent. Ownership needed an owner, grounding needed
> a grounder, persistence needed a recorder, change needed a sampler. **Properties,
> not processes.**

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 = 256` corroborators per belief.
- **Salience-ordered, `GEP_BELIEFS_PER_BEAT = 512`** beliefs 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 in
  `EngramNode` (`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 shape `ln Σ t^-d` (`ENGRAM_BLL_D = 0.5`) but sign-carrying so
  LTD subtracts. Memory `1a861007`: the collection is primary, the standing is
  its emergent aggregate. Mirrored onto `confidence` each beat so downstream
  reads (verifier #43, realizer calibration `0041d917`) 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_MIN` may 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.
