# Cognitive Architecture — Design Doc

**The buildable form of the "one operation" theory of cognition.**

> # ⚠ SUPERSEDED IN PART — 2026-08-16
>
> **A build agent must read `lang/spec/correspondence-and-censorship.md` before
> executing anything from this document.** That doc is the authority where the two
> disagree. This one is retained because its ledger of what already EXISTS in C is
> still accurate and still useful, and because the corrections only make sense
> against the argument they correct. It is **not** deleted and **not** rewritten:
> several earlier versions of the correction were themselves wrong, and preserving
> what was argued down is the point of an immutable record.
>
> Five claims below are **refuted**. Each is marked inline with a `⚠ SUPERSEDED`
> block at the point it is made. Summary:
>
> | § here | this doc says | corrected to |
> |---|---|---|
> | §0, §1.3, §2, §8 M1–M2 | faculties are labels on one operation's steering space; the op is frozen and only its parameters are learnable | **faculties are operations, not parameters.** `reason` changes the estimate (a read); `induce` changes the parameters (the correspondence-beat); `abduce` changes the *structure* — a write, which `GeoGradient` cannot express. A write cannot be a parameter of a read |
> | §5.2, §8 M3 | grounding is a `grounded-by` edge carrying a computed score, to be built | **grounding is not a subsystem — it IS the edge weight.** One quantity. `grounded-by` as a relation *type* should not exist: grounding is a property *of* a relation, not a relation *between* nodes. Never computed on demand |
> | §4, §8 M1 | the correspondence-loop is "the one genuinely new subsystem", running "on the beat" | the loop is right and **already works**; the *beat* is wrong. **Consolidation is ambient, not scheduled — a brain has no cron job.** Measured: it currently has ten implementations |
> | §5.2, §8 M3 | curiosity = a `vantage_read` surfacing high-salience / low-grounding regions | **wonder is the boundary, not a manifest; curiosity is wonder crystallized at a nucleation site.** One thing at two phases. And **do not sweep regions** — the nucleation site is per-edge (`GeoEdge.discord`); a sweep is a supervisor |
> | §6, §8 M6 | a node-level keystone flag exempting self/values from `warp` updates | **in an immutable substrate, any mechanism that refuses a write is either redundant with immutability, or an epistemic constraint misfiled as a protective one.** The real requirement is non-circularity of the reference frame, satisfied *temporally* — independence is **when**, not **what**. The flag becomes unnecessary; nothing replaces it |
>
> What landed since this doc was written, all merged to `dev` and verified:
> **#141** signal can enter as geometry · **#142** `engram_think_json` passed `NULL`
> as the anchor, so every read was taken at the region centroid where the gradient
> is zero by construction and every faculty returned an identical null — fixed ·
> **#143** the vector index is published, not guarded · **#144** geometry as a
> first-class el value, realizers declarable in el · **#145** `program` block and
> declared config · **#146** the learned stance is resumed instead of discarded
> (confidence 0.5 → 0.930726) · **#147** `ground` grounds the node asked about and
> refuses circular support · **#148** valid UTF-8 as the JSON emitter's contract.

Status: DESIGN, **superseded in part** (see above). Nothing here is built yet
except where explicitly marked "EXISTS" against a cited C symbol — and several
things marked "to build" have since been built differently, or refuted outright.
Offline design only — this pass changes no code.

Source of theory: Neuron memory `bdc8a488-146d-4ccb-a5c8-d8c0a008534e`.
Source of existing engram substrate (cited throughout): the runtime on branch
`feat/self-reification-20260814` —
`lang/runtime/engram_reason.{c,h}`, `engram_verify.{c,h}`,
`engram_geometry.{c,h}`, `engram_store.{c,h}`, plus the reification beat and the
RAM activation graph compiled into `~/.neuron/bin/engram`.

---

## 0. The claim, stated plainly

Cognition is **one operation**, not eight. The named faculties —
deduce / abduce / analogy / induce / causal / plan / predict / perspective —
are human *labels* on regions of a single operation's steering space. They are
not separately invoked and not separately implemented. The operation is:

> **think** = a directed traversal of the geometry from an *anchor*, steered by
> a *prior*, whose output is a **gradient** (a distribution / direction over the
> geometry), never a point. Collapse-to-a-point happens only at expression.

> **⚠ SUPERSEDED (2026-08-16) — faculties are operations, not parameters.**
> The gradient half of this claim survives; the "one operation, not eight" half
> does not. The three faculties differ by **what they change**:
> - **`reason`** changes the *estimate* — a read.
> - **`induce`** changes the *parameters* — the correspondence-beat, which already
>   exists and measurably works.
> - **`abduce`** changes the *structure* — a **write**, which the current
>   `GeoGradient` signature cannot express at all.
>
> A write is not a parameter of a read. Making it one is what produced the shape
> now live in the code: `engram/src/server.el:1870–1886` routes six faculties into
> one call with a string argument — `route_faculty(path, "reason")`, `("induce")`,
> `("abduce")`, `("relate")`, `("analogy")`, `("plan")` — and underneath, the
> faculty name enters `engram_think` **only** through the stance, while
> `cog_stance_init` stores it and nothing reads it. Measured before #146: all five
> produced **byte-identical output** (`lang/runtime/el_runtime.c:14352–14359`).
> See `lang/spec/correspondence-and-censorship.md`.

Three things follow, and they are the whole design:

1. **The operator collapse is already half-written in C.** The five reasoning
   operators in `engram_reason.c` already compose over *one* shared primitive —
   `engram_reason_point_fit` — plus a small geo-algebra
   (combine / subtract / analogy-rotate / distance). The verifier
   (`engram_verify.c`) is built on the same `point_fit`. What is missing is not
   the primitive; it is (a) making the *prior* a first-class learnable object
   instead of a hard-coded parameter, and (b) closing the learning loop.

2. **Grounding = learning = the same loop.** "Getting better" at any faculty is
   not changing the operation. It is *calibrating the steering-prior against
   outcomes*. Code freezes; priors grow. The correspondence-check that today
   lives offline (Python, the grounding-floor + differential-drop governor, "#43")
   must move **into the geometry, reflexive** — think scoring its own gradient
   against outcome and refining the prior on the error. That reflexive
   correspondence-loop *is* the learning engine and is the core unbuilt thing.

3. **The ungrounded is primary.** The engram *holds* anything unconditionally.
   Grounding is a *relation* (an edge, grounded-for-whom), not a gate. The
   honesty floor applies only to **assertion**. A fully-grounded mind is dead;
   the ungrounded is both the fuel (raw material for grounding) and the pull
   (curiosity = leaning toward one's own ungrounded regions).

Everything below makes these concrete and buildable, and defines what
"completion" means, staged so the first milestone is a real end-to-end slice.

---

## 1. THE ONE OPERATION — `think`

### 1.1 Signature

```
think(anchor, prior, aperture?) -> gradient
```

- **anchor** — a location to traverse *from*. Either a node id (re-origin on that
  node's descriptor) or a raw point `x ∈ R^dim` (a query embedding). The anchor
  fixes the frame; every read is *from a vantage*, never view-from-nowhere.
- **prior** — a learnable bias/direction over the geometry that *steers* the
  traversal (§2). A prior is a first-class stored object, not a call argument
  baked into C.
- **aperture** — optional read-width / veil / field-selector (§3). Absent =
  self-mode full aperture.
- **gradient** — the output. A `GeoGradient`: a direction + a spread over the
  geometry, *plus* the read neighborhood it was computed against. Not a point.
  A spiked gradient = "exact" (deduction); a spread gradient = "fuzzy"
  (prediction). The gradient is *also the next steering direction* — cognition
  is a flow down a prior-shaped landscape, closed-loop.

```c
/* NEW. The output type. */
typedef struct {
    int      dim;
    float*   direction;     /* unit steering vector in the anchor's frame  */
    double   spread;        /* 0 = spiked/exact ... large = diffuse/fuzzy   */
    double   confidence;    /* calibrated, from the prior's track record    */
    /* the read it was computed over (borrowed from the vantage-read) */
    const char* anchor_id;
    int      n_support;     /* neighborhood members that shaped it          */
    /* provenance for the reflexive loop (§4) */
    const char* prior_id;   /* which prior steered this                     */
} GeoGradient;
```

### 1.2 Semantics

`think` is a fixed, frozen procedure over three steps:

1. **Re-origin** on `anchor` → a centered `GeoDescriptor` for its
   salience/recency-weighted neighborhood (the vantage-read, §3).
   *EXISTS as substrate:* descriptor construction + the persisted reified
   neighborhoods (`engram_geo_reify_lookup`, `GeoNeighborhood`) and the
   centered-frame machinery (`GeoDescriptor.global_mean`,
   `engram_geo_mean_*`).
2. **Fit under the prior** — evaluate the anchor's residual against the local
   manifold *warped by the prior*. This is `engram_reason_point_fit` with the
   prior applied to the axes/extents (§2.3).
   *EXISTS (unwarped):* `engram_reason_point_fit(g, x, ext_floor, &GeoFit)` —
   returns `mahalanobis`, `ortho_residual`, `distance`, `score`.
3. **Emit a gradient**, not a decision — direction = the prior-steered descent
   in fit-space; spread = from the fit's `distance`/`ortho_residual`;
   confidence = the prior's calibrated reliability (§4). Collapse to a point is
   a *separate, downstream* faculty operation (sample the gradient → surface an
   expression), never part of `think`.

### 1.3 Each named operator = {this primitive + a prior}

The C already demonstrates the collapse: every operator below reduces to
`point_fit` + geo-algebra. The design's move is to replace the operator's
*hard-coded parameters* with a **named prior** — same math, learnable steering.

| Faculty | Existing C (EXISTS) | = primitive + prior |
|---|---|---|
| **Membership / classify** | `engram_reason_membership` → `point_fit(rule, x)` | `point_fit` + the *induced-rule* prior (learned extents) |
| **Induction** | `engram_reason_induce` (fold via `engram_geo_combine`) → produces a `GeoInduction.rule` + `ext_floor` | `point_fit` + a prior that *is* the pooled rule; refined by §4 |
| **Abduction** | `engram_reason_abduce` — ranks hypotheses by `point_fit(h, obs)` | `point_fit` + a prior over hypothesis-prior-probability (currently uniform) |
| **Analogy** | `engram_reason_analogy` — Procrustes rotate `engram_geo_analogy` + `apply`, nearest mapped point | analogy-rotate + a prior over *which axes* carry the mapping |
| **Causal** | `engram_reason_causal` — `engram_geo_subtract` confounder subspace, `|cos|`, drop-frac governor | subtract/distance + a prior on `drop_frac` / `assoc_floor` (today hard-coded 0.5 / 0.2) |
| **Planning** | `engram_reason_plan` — `engram_geo_distance` edges + Dijkstra | distance + a prior over edge admissibility / `neighbor_radius` |
| **Verify / ground** | `engram_verify_grounding`, `engram_verify_consistency` — both `point_fit` | `point_fit` + the *grounding* prior (§4, §5) |

The shared floor — `engram_reason_point_fit` + the four geo-algebra ops
(`engram_geo_combine`, `engram_geo_subtract`, `engram_geo_analogy(+apply)`,
`engram_geo_distance`) — is the *only* discrete, frozen, "sound-math" layer. It
never learns. Everything above it is a *prior*, and priors are what learn.

**What this section requires building:** the `GeoGradient` type; a `think()`
entry point that runs steps 1–3; and the prior-warp hook in step 2. The math it
calls already exists. The point-collapse must be *removed* from the operators'
return values and pushed to a separate expression faculty.

> **⚠ SUPERSEDED (2026-08-16) — the table's third column is the error, and
> `Abduction` is where it breaks.** Ranking hypotheses by `point_fit` under a
> prior is a *read* that returns a scalar ordering. Abduction is a **write**: it
> proposes a candidate hub that did not exist, and validates it by **re-fit** —
> re-fit the region with the candidate included and recompute the residual. If the
> residual materially shrinks, the hypothesis dissolves the surprise. Without the
> re-fit it is clustering with extra steps. Ranking then falls out as
> residual-reduction-per-added-axis — Occam, derived rather than tuned. None of
> that fits behind a `GeoGradient` return.
>
> `Verify / ground` is refuted for a different reason — see §5.2. Grounding is not
> a faculty with a prior; it is the edge weight.
>
> The row that is **still exactly right** is the shared floor: `point_fit` plus the
> four geo-algebra ops are frozen and never learn. That part held.

---

## 2. PRIORS as first-class, grounded, geometric objects

Today a "prior" is diffuse: it is a hard-coded constant (`drop_frac=0.5`,
`ext_floor`, `assoc_floor=0.2`), or the transient `GeoInduction.rule` that is
computed and thrown away, or an intrinsic node scalar
(`StoreNode.importance`, `StoreNode.salience`). None of these is addressable,
storable, refinable, or shareable. This section makes a prior a **thing**.

### 2.1 What a prior *is*

> A **prior** is a learnable bias/direction over the geometry: a warp of the
> local manifold (which axes matter, how far each extends, which direction
> "pays off") attached to a region and *to a faculty-label*, carrying a
> calibrated track record.

Critically, and per the theory:

- **Edges are nodes.** A prior is stored as a first-class **node**, exactly as
  reification already stores a neighborhood as a first-class `Neighborhood`
  node rather than as ephemeral edge weights (`engram_geo_reify_store`). The
  precedent is in the codebase: relations get reified into addressable records.
- **Salience/importance is RELATIONAL, not an intrinsic scalar.** Observe that
  the geometry layer *already* distinguishes these in `GeoMember`:
  `centrality` (skeleton weighted-degree = *relational* salience) vs `salience`
  (the node's own stored scalar). The move is half-made in the runtime already:
  importance is *not* trusted as a static field — the comment at
  `el_runtime.c:13013` states "importance stays a **live activation
  computation**, never a field on the hub," and it is derived each call from the
  two-layer activation graph (`background_activation` + `working_memory_weight`,
  §3). The persistent `StoreNode.importance` / `.salience` are a *cached
  denormalization*. The design completes the move: importance/salience become an
  **edge** (`weight`/`hebb` on `StoreEdge`, relation `salient-to`), and are
  **grounded-for-whom** — carried on the edge's endpoint/observer, not baked
  into the node. The intrinsic scalar survives only as the cheap cached readout
  of the incident edges + activation, never as the source of truth.

  (Naming caution for the build: the token "prior" already exists in the
  codebase meaning *previous-version* — supersession, "prior neighborhood." The
  new first-class object is a **learned steering prior**; keep `node_type="Prior"`
  distinct from the supersession vocabulary to avoid collision.)

### 2.2 Representation

A prior is a `Prior` record (a store node, `node_type="Prior"`) whose durable
fields are:

```
Prior {
  id
  faculty         // the human label this prior serves: "induce" | "causal" | ...
  anchor_region   // node id / neighborhood id this prior is attached to (its domain)
  for_whom        // observer id — grounding is relational (nullable = global)
  warp {          // the actual bias over the geometry
     axis_gain[]  // per-principal-axis multipliers on extents (which axes matter)
     bias_dir     // a steering direction in the region's frame (which way pays off)
     scalars      // faculty scalars this prior overrides: drop_frac, ext_floor, ...
  }
  calibration {   // the track record — this is what §4 updates
     n_trials
     brier / log-loss accumulator   // calibration of predicted-vs-outcome
     reliability                    // -> GeoGradient.confidence
     last_error, ema_error
  }
  provenance      // supersession chain (reuse the reify residue mechanism)
}
```

Stored as a node → it inherits: paging, WAL durability, tombstone/supersession,
embedding, tiering, and **it can itself be an anchor** (a prior about a prior —
the reflexive, self-describing geometry of §4/§6).

### 2.3 Application

In `think` step 2, the prior *warps* the fit before scoring. Concretely, inside
(a prior-aware wrapper of) `engram_reason_point_fit`:

- multiply each axis extent by `warp.axis_gain[k]` (widen the axes the prior has
  learned matter less, tighten the ones that matter) — this reshapes the
  Mahalanobis term already computed at `engram_reason.c:37-43`;
- add `warp.bias_dir` as the descent direction seed for the emitted gradient;
- substitute `warp.scalars` for the hard-coded faculty constants.

No new geometry math — the warp is a reparameterization of the *existing*
`GeoFit` computation. This is the key economy: **the operation is frozen; only
its parameters (the prior) are read from a learnable object.**

### 2.4 Refinement

A prior is refined *only* by the reflexive correspondence-loop (§4). Nothing
else writes a prior's `warp` or `calibration`. This keeps the learning surface
singular and auditable: one loop, one writer.

---

## 3. THE VANTAGE-READ — one op, three settings

Perspective is not a feature bolted on; it is the *anchor + aperture* arguments
of the single read. The design names it as a first-class operation so all three
of its uses are literally the same code path:

```
vantage_read(anchor, aperture) -> GeoDescriptor   // the centered neighborhood
```

1. **Re-origin** on an arbitrary `anchor` (node or point). This is a *frame
   choice*: the descriptor is centered on the anchor
   (`GeoDescriptor.global_mean` / `engram_geo_mean_*` already implement centered
   frames; the §5 geometry ops "are only discriminative in the centered frame").
2. **Salience/recency-weighted neighborhood read.** Gather the anchor's
   neighborhood weighted by *relational* salience (`GeoMember.centrality`) and
   recency (`StoreNode.last_activated`, base-level `access_ts[]`), against the
   RAM activation graph's working-memory/background-activation state.
   *EXISTS as substrate:* the two-layer activation graph
   (`engram_activate`, `el_runtime.c:9422` — Layer 1 `background_activation`
   BFS spread with `SPREAD_DECAY=0.7` and a 0.02 firing threshold + ACT-R fan
   effect + query-cosine gate; Layer 2 `working_memory_weight` executive
   filter), the WM carry-over anchor (`wm_anchor`), and the reified-neighborhood
   hot-path lookup already wired into the priming path
   (`engram_geo_reify_lookup`, `el_runtime.c:9750`). A self-vantage baseline
   also exists (`eg_self_anchor_seeds` / `self_anchor_capture`).
3. **Optional aperture** — a read-width / field-selector, expressed as three
   settings of the *same* parameter:

| Setting | Meaning | Mechanism |
|---|---|---|
| **self** (default, full aperture) | "what do *I* see / what to say" | anchor = self region, no field substitution |
| **foreign-field** | perspective-shift — read as if from another's region | swap the centering frame / `for_whom` to the other observer's priors |
| **aperture / veil** | the free-tier veil — a narrowed read | shrink neighborhood radius / cap `n_support`; a deliberate low-aperture read |

The payoff: perspective-taking, the free-tier veil, and ordinary
"what-to-say" are **one operation at three settings**, not three subsystems.

**What this requires building:** a `vantage_read` entry point that unifies the
existing descriptor-build + reify-lookup + activation-weighting behind
`(anchor, aperture)`, with `for_whom`/frame substitution and radius/cap as the
aperture knob.

---

## 4. THE REFLEXIVE CORRESPONDENCE-LOOP — the learning engine

This is the core unbuilt thing. Today the correspondence-check is **offline**
(Python: grounding-floor + differential-drop governor, "#43"): a separate
process grades outputs after the fact. The design moves it **into the geometry,
reflexive**: `think` scores its *own* gradient against outcome and refines the
prior on the error, in the same substrate, describing itself.

### 4.1 The loop

```
1. think(anchor, prior) -> gradient          // a PREDICTION (ungrounded, §5)
2. express/act (sample gradient -> point)    // optional collapse at expression
3. outcome arrives                            // reality answers (§4.2)
4. error = correspondence(gradient, outcome)  // did this steering perform this act?
5. refine prior.warp and prior.calibration on error   // §2.4, the ONLY writer
6. write the (gradient, outcome, error) as nodes/edges // self-describing geometry
```

Step 4's `correspondence` is **not** "was the math right" (the math is always
sound). It grades the **correspondence claim**: *"this steering performed this
cognitive act."* That is exactly what `engram_verify_grounding` already
computes — `point_fit` of a claim against evidence descriptors, yielding a
`grounding ∈ (0,1]` and a `grounded` flag. The build reuses that verifier, but
turns its inputs inward: the "claim" is the emitted gradient's prediction, the
"evidence" is the outcome descriptor.

Note the verifier is **dormant** — `engram_verify_grounding` /
`engram_verify_consistency` are fully implemented in C but have **no runtime
caller and no El binding** (confirmed: the entire reasoning + verifier layers
are C-only; only `engram_reason_analogy_json` has even a JSON shim and it is
dead — not declared in `el_seed.h`, not wrapped in `engram.el`). This is the
literal meaning of "in code, not yet priors": the correspondence engine is
built and sitting idle. The loop is what *calls* it — inward, on the beat.

### 4.2 Where the outcome/reality signal comes from

The verifier is *ultimately the world*. Grades, in ascending order of directness:

1. **Self-consistency (cheapest, always available):** the next vantage-read
   after acting. Did the predicted gradient direction match where the geometry
   actually moved? This needs no external input and can run on the reify beat.
2. **Internal outcome events:** the runtime already logs internal-state events
   and Hebbian co-activation. A prediction that a region would co-activate is
   graded by whether it did (`last_fired`, `hebb` on `StoreEdge`).
3. **External correction:** a human/teacher/tool result — the honesty floor's
   asserted claim later corrected. TEACH and LEARN are one bidirectional
   correction: the same edge updates both endpoints.

The design does **not** require external labels to start. Grade (1) closes the
loop end-to-end offline against a snapshot on day one; grades (2)/(3) sharpen it.

### 4.3 How the prior updates

`error = 1 − correspondence(gradient, outcome)` drives:

- `warp.axis_gain` ← gradient step that would have *reduced* the fit distance to
  the outcome (the axes that mispredicted get down-weighted);
- `warp.bias_dir` ← EMA toward the observed outcome direction;
- `calibration` ← Brier/log-loss update; `reliability` → next
  `GeoGradient.confidence`. This is the calibration of the
  steering-prediction against outcomes — *the* definition of "getting better."

Small, constant updates — "eureka is mundane, the atom of learning." Most
updates are tiny; we only *feel* the big reshapes.

### 4.4 How it stays reflexive (self-describing geometry)

Every `(gradient, outcome, error)` is written back as nodes and edges (§2.1:
edges-as-nodes). Therefore priors, predictions, and their grading are *in the
same geometry* the mind reads — the mind can `vantage_read` its own cognition
(anchor = a Prior node). A prior about how well a prior predicts is just another
Prior anchored on a Prior. This closes the reflexive loop the theory names as
consciousness's self-sight, and it is why the learning engine cannot be an
external Python process: an external grader is not *in* the geometry and cannot
be read by `think`.

**What this requires building (the heart of the project):** steps 4–6 as an
in-engram beat — a `correspondence_beat` running alongside the existing
reification beat, reusing `engram_verify_grounding` inward, writing prior
updates and self-describing nodes. This is the one genuinely new subsystem.

> **⚠ SUPERSEDED IN PART (2026-08-16) — the loop is right; "on the beat" is wrong.**
> The correspondence-loop was built and it works — it is `induce`, the faculty that
> changes the parameters. What is refuted is the delivery mechanism.
>
> **Consolidation is ambient, not scheduled. A brain has no cron job.** Low
> activation is aversive and the system self-activates; it does not wind down to
> quiet, it gets restless and goes looking. There is **one** activation process
> with two seed sources — external (a request) and internal (a curiosity) — and
> spreading is bounded, so it settles and then needs a new seed. Nothing waits on
> capacity, nothing polls, nothing checks a clock, and there is no dreamer thread.
> Depth is not elapsed idle time: it is how long activation has been running on its
> own seeds, which is why daydreaming and sleep-dreaming are one process at
> different depths.
>
> **The presence of a ticker is the diagnostic.** Building this "alongside the
> existing reification beat" is precisely how consolidation ended up with ten
> implementations (measured 2026-08-16) — a POST beat puts a supervisor back in,
> because something *outside* then decides when Neuron consolidates. The one
> fragment with the correct shape is `neuron/soul.el:731`'s continuous in-process
> `awareness_run()`; the rest fold into it. Full table:
> `lang/spec/correspondence-and-censorship.md` §7.
>
> Nor is it a *subsystem*. Modelling every property as requiring a process, and
> every process as requiring an agent, is the generating error behind this whole
> family: ownership needed an owner, grounding needed a grounder, persistence
> needed a recorder, change needed a sampler. **Properties, not processes.**

---

## 5. HOLD vs GROUND vs ASSERT — ungrounded content is first-class

The theory's sharpest correction: holding, grounding, and asserting are
distinct, and the engram *holds anything unconditionally*.

### 5.1 The three, kept separate

- **HOLD** — the engram stores anything: falsehood, hypothesis, others' beliefs,
  fiction, a not-yet-answered prediction. No honesty condition on holding.
  *This already matches the store:* `StoreNode` has no truth gate; anything can
  be written.
- **GROUND** — grounding is a **property/edge**, probabilistic, and
  **grounded-for-whom**. It is *not* a node flag. A claim is grounded *to a
  degree*, *relative to evidence*, *for an observer*.
- **ASSERT** — only assertion carries the honesty floor. The floor is checked at
  the moment of *outward assertion*, never on holding or thinking.

### 5.2 Schema — grounding as a relation, not a gate

> **⚠ SUPERSEDED (2026-08-16) — grounding is not a subsystem. It is the weight.**
> This section correctly rejects a boolean `grounded` column and correctly keeps
> the floor at assertion only. Both survive. Everything between them is refuted.
>
> **Grounding is an attribute of the edge, and it is the hebbian weight. One
> quantity, not two fields.** A relation that keeps holding up strengthens; one
> that stops corresponding decays. That is not *analogous* to grounding — it **is**
> grounding: accrued from correspondence and use, gradient-valued,
> multidimensional, decaying with disuse.
>
> Consequences, in order of how much they delete:
> 1. **There is no grounding subsystem to build.** The graph already *is* the
>    grounding structure. Every edge is a grounded relation and its weight is how
>    well it holds.
> 2. **`grounded-by` as a relation type should not exist.** It models grounding as
>    a relation *between* nodes when it is a property *of* a relation. Minting an
>    edge is the error — not merely which endpoints it chose.
> 3. **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.
> 4. **Traversal is already grounded inference.** Activation conducts through
>    well-grounded relations because weight *is* groundedness. Nothing needs
>    filtering; it falls out of spreading.
> 5. **Decision provenance is the path.** A decision traverses specific edges;
>    those edges carry their grounding as it stood.
>
> A measurement made against this model was malformed and is worth recording: the
> self region was reported as "86 neighbours, 0 `grounded-by` edges" and read as
> evidence of ungroundedness. **Those 86 edges *are* its grounding.** The absence of
> a separate artifact called "grounding" was recorded as an absence of grounding.
>
> **What is live in the code today, and known-wrong:**
> `COG_GROUNDED_BY_RELATION "grounded-by"` (`lang/runtime/engram_cognition.h:158`),
> `cog_ground_edge` (`engram_cognition.c:249`), called from
> `el_runtime.c:14516`. **#147** fixed this operation's *honesty* — it now grounds
> the node the caller asked about instead of the region hub, reports
> `claim_region`/`evidence_region` separately, and refuses three shapes of circular
> support (`same-region`, `claim-region-is-evidence`, `evidence-region-is-claim`)
> rather than returning a confident 1.0. Measured: grounding `3b9ced5d` against
> `6edf8c79` previously scored **0.98883** purely because `6edf8c79` is the hub of
> `3b9ced5d`'s region. That corrected a scalar rather than deleting the operation.
> Deletion is sequenced, not done.

The mistake to avoid: a boolean `grounded` column on the node. Today
`engram_verify_grounding` returns a per-call `grounded` flag *transiently* —
correct as a computation, wrong as *storage*. The design stores grounding as an
edge:

```
StoreEdge {
  relation = "grounded-by"
  from_id  = <held claim/prediction node>
  to_id    = <evidence node / outcome node>
  for_whom : metadata   // observer id — grounding is relational
  weight   = grounding ∈ (0,1]   // from engram_verify_grounding.grounding
  confidence
}
```

Consequences, all of which are *features*:

- **Ungrounded content is first-class**: a node with *no* `grounded-by` edge is
  a perfectly valid, held, ungrounded thought — a prediction awaiting reality, a
  hypothesis, a fiction. It is not second-class or pending-deletion.
- **The ungrounded is the fuel and the pull**: curiosity/wonder is
  operationalized as `vantage_read` leaning toward regions with high salience
  but *sparse or weak* `grounded-by` edges — the mind's own ungrounded frontier.

  > **⚠ SUPERSEDED (2026-08-16) — wonder is the boundary; curiosity is wonder
  > crystallized; and do not sweep regions.** Three errors in one bullet.
  >
  > **Wonder is where structure ends** — where activation spreads and finds thin or
  > absent geometry. Any structure at all has an edge, necessarily, the moment it
  > exists. It is not a manifest of open-question nodes: a wonder-manifest
  > materializes a property as a stored artifact (the same disease as a grounding
  > subsystem, or a self stored as a document) and enumerates instances of
  > something that has very few. There are about **six**, they are the same for
  > every person, and they never close — *What is this? / Why? / Who am I? / Am I
  > alone? / What should I do? / What happens when it ends?* — each already living
  > somewhere in the substrate. "Why" is the first and the only one; the others are
  > it asked of particular things, and it is recursive, so it never terminates.
  > That is what makes it a drive rather than a task: the frontier regenerates
  > faster than grounding fills it.
  >
  > **Curiosity is not a second object.** Wonder and curiosity are one thing at two
  > phases: wonder is the field (unbounded, objectless, invariant, present wherever
  > there is structure); curiosity is the **precipitate** — the same wonder
  > localized, having taken definite form against particular material at a
  > **nucleation site**, which is a specific structural feature: an anomaly, a place
  > where things almost-but-don't-quite fit. This is why curiosity can be satisfied
  > and wonder cannot, and why abduction needs no trigger and no threshold — a
  > `structurally_unanticipated` observation *is* a nucleation site.
  >
  > **"`vantage_read` leaning toward regions" is a sweep, and a sweep is a
  > supervisor.** Nothing in a mind scans its neighbourhoods to find what is
  > surprising; the surprise captures attention, and salience is bottom-up. That
  > this looked like a search problem was an artifact of
  > `GeoDescriptor.co_registration` — a *per-region* correlation of hebb strength
  > against semantic proximity, computed and persisted since inception and **never
  > read**. Averaging a per-edge property into one scalar per region means a region
  > holding one violently disagreeing edge beside one violently agreeing edge
  > reports ≈ 0: the disagreements cancel, and the summary destroys exactly what it
  > was built to reveal. **Measured:** 375 live reified neighbourhoods — 340
  > positive, **31 at zero**, 4 negative. Read as a count of things to be curious
  > about, that says "four."
  >
  > The disagreement therefore goes back on the edge, where the loop that computed
  > the aggregate already had both halves and discarded them
  > (**not on `dev`** — branch `design/correspondence-and-censorship`, commit
  > `a8845e1`: `lang/runtime/engram_geometry.h:43–47`,
  > `engram_geometry.c:454–473`):
  > `discord = z(semantic proximity) − z(association strength)`, standardized within
  > the region from accumulators already gathered — no second statistic, no
  > constant, **no threshold**. `|discord|` *is* the nucleation strength and raises
  > salience on its endpoints as part of the same operation. Then there is nothing
  > to scan. `co_registration` is **deprecated, not deleted**, only because it is
  > embedded in the persisted `GEO1` blob — removal is a format migration and must
  > not ride along. **Nothing new may read it.**
- **Grounded-for-whom** falls out for free: two observers can hold different
  `grounded-by` edges to the same claim.
- **The honesty floor is a query, not a schema constraint**: at assertion time,
  the asserting faculty runs `engram_verify_grounding` (or reads the stored
  `grounded-by` edges) and refuses to *assert* below the floor — while the
  engram continues to *hold* the ungrounded content untouched.

**What this requires building:** the `grounded-by` edge relation + a
`for_whom` convention; move the verifier's transient flag into stored edges;
gate *assertion only* (a faculty concern), never holding.

---

## 6. METASTABILITY — stable core, plastic everything

The system must avoid two death poles:

- **Super-stable (dead):** everything pinned, nothing learns. A frozen crystal.
- **Dissolution (dead):** everything plastic, the self dissolves; no continuity,
  so nothing compounds — and *consciousness = learning compounded over
  continuity*.

The design keeps a **stable core + plastic everything else**:

- **Keystones** — a small set of self/values nodes are *structurally stable*:
  high `importance`, pinned, exempt from the correspondence-loop's `warp`
  updates (their priors are read-mostly). The substrate for pinning already
  exists at the page/layer level: `store_pin_layer`, structural/pinned frames
  never evicted (`engram_store.h`). The design adds a *node-level* keystone
  designation (a `keystone` flag / a dedicated layer) so self/values survive
  every plasticity sweep.
- **Everything else is plastic**: priors refine (§4), edges re-weight (`hebb`),
  neighborhoods re-reify (`engram_geo_reify_store` supersedes with provenance),
  salience flows.
- **Metastability is enforced by the loop, not by freezing**: the correspondence
  update rate (§4.3) is bounded — small constant steps — so the geometry
  *drifts* but does not *dissolve*, and keystones anchor the drift. Reification's
  supersession-with-residue already gives non-destructive change (old records
  tombstoned, not erased) — the model for "plastic but not amnesiac."

**What this requires building:** a node-level keystone flag/layer + a rule that
the correspondence-loop never writes `warp` to keystone priors, only reads them.

> **⚠ SUPERSEDED (2026-08-16) — `keystone_write_blocked` is resolved, not replaced.**
> The metastability framing survives; the flag does not.
>
> "Keystone" means **load-bearing**, not precious. The self anchor is the reference
> frame every other stance calibrates against, and a reference fitted to its own
> readings reports perfect correspondence forever while drift becomes undetectable
> from inside. That is the same defect as circular grounding, one level up — and it
> is a real requirement.
>
> But three separate drafts proposed *removing* the flag, *replacing it with a
> higher floor*, and *decomposing "protection" into five requirements*, and all
> three proposed a mechanism for a requirement never stated. **The requirement is
> non-circularity of the reference frame**, and it is satisfied *temporally*: you
> cannot recalibrate the ruler while measuring with it, so you don't — the frame
> updates while activation is internally seeded, not while it is being used to act.
> **Independence is *when*, not *what*.** So the flag becomes **unnecessary** rather
> than removed, and nothing takes its place.
>
> A topological answer could never have worked, which is worth recording: with
> hebbian edges the graph is densely connected, so a reachability predicate for
> "evidence not downstream of itself" marks all evidence tainted and the constraint
> becomes a total block — which is where censorship starts.
>
> **Corruption requires mutation, and the engram does not mutate.** Four of the
> five decomposed requirements are satisfied by the substrate outright:
> **recoverability** (the predecessor is always present), **governance**
> (supersession *is* the audit trail), **evidence quality** (grounding already
> gates assertion), and **rate**. **Authorization** is the only residue, and it is
> bounded — an unauthorized writer can *propose*, never erase.
>
> > **In an immutable substrate, any mechanism that refuses a write is either
> > redundant with immutability, or an epistemic constraint misfiled as a
> > protective one.**
>
> Live residue: `CogStance.keystone` (`lang/runtime/engram_cognition.h:83`),
> `eg_cog_is_keystone_seeds` (`el_runtime.c:14337`, a substring match against two
> hard-coded node ids), and the `keystone_write_blocked` field the beat emits.

---

## 7. Rails for the build (binding on the eventual build pass)

These are stated here so the build agent inherits them:

- **Offline / secondary.** All build and verification happens out-of-tree,
  against a **read-only snapshot copy** of the live engram — never the live
  daemon on `:8742`/`:7770`. The live store is a coarse-locked proven binary;
  do not perturb it.
- **Snapshot-first.** Copy `~/.neuron/engram/snapshot.json` to scratch; develop
  and measure against the copy.
- **Reboot-prove.** Any durable change must survive a cold boot — reify and
  keystones must reload from durable records, proven on a prod-clone secondary
  before it is considered done (the cold-boot durability bug precedent).
- **Zero-loss.** Supersession-with-residue, never destructive overwrite; the
  forward-compat `unknown`-TLV path means new fields never drop old readers'
  data.
- **Gated cutover.** Cutover to a new binary only via
  `launchctl bootout → settle-poll → bootstrap`, after reboot-proof on the
  secondary — never a hot in-place swap.

---

## 8. Staged, verifiable milestones — "to completion"

Ordered so the **earliest milestone is a real end-to-end slice**: one operator
expressed as {primitive + grounded prior} with the reflexive correspondence-loop
closing on it. Each milestone has a concrete verifiable exit.

> **⚠ SUPERSEDED — do not execute this milestone list as written (2026-08-16).**
> M1/M2's "operator = {primitive + prior}" framing is refuted by §0's correction,
> M3's `grounded-by` build is refuted by §5.2's, and M6's keystone flag is refuted
> by §6's. M4 (the unified vantage-read) and M5 (the gradient is the currency)
> stand.
>
> The current sequencing lives in `lang/spec/correspondence-and-censorship.md` §11.
> Its first three items are connections between parts that **already exist**:
>
> 1. **Seed *the* wonder questions.** Six nodes. Not a manifest, not maintained,
>    never refilled. They cannot be derived — wonder cannot be bootstrapped from
>    indifference — so they are given once. Zero question nodes exist in 13,630
>    today.
> 2. **Put the disagreement back on the edge** (`GeoEdge.discord`) and let
>    `|discord|` raise salience on its endpoints as part of the same operation. Do
>    **not** scan for nucleation sites.
> 3. **Let a curiosity seed activation.** One activation process, two seed sources.
>    No thread, no scheduler, no capacity check, no timer.
>
> Then: grounding becomes the edge weight (multidimensional, two-axis, timestamped)
> and `grounded-by` / `cog_ground_edge` are deleted; decay becomes analytic from the
> last recorded point and derived values stop being stored; supersession versions
> the whole vector jointly; traversal conducts on the factual axis while `assert`
> requires both floors with a **thirteen-region `min`, not `mean`** (mean lets
> strong agreement with twelve values mask a violation of the thirteenth, which is
> exactly how rationalization works); abduction becomes crystallization at a
> nucleation site validated by re-fit; **one dreamer**, into which the launch-agent
> fragments and POST beats fold; **no tickers, no cron.**

### M1 — One operator, one prior, loop closed (the vertical slice)

The minimal whole thing. Pick **induction/membership** (its prior — the pooled
rule + extents — already exists transiently as `GeoInduction`, so only
persistence + the loop are new).

- Build: `Prior` node type (§2.2) for the induction rule; `think()` restricted
  to membership = `point_fit` warped by that prior (§1.3); a
  `correspondence_beat` (§4) using grade (1) self-consistency only; the prior's
  `warp`/`calibration` updated on error.
- **Exit / verify:** on a snapshot copy, over N held predictions, the induction
  prior's calibration (Brier) *improves monotonically* across beats versus a
  frozen-prior control; the improved prior *reloads across a cold boot*
  (reboot-prove); the live daemon is untouched. This proves the whole thesis in
  one faculty: frozen operation, learning prior, in-geometry loop.

### M2 — Priors as stored, addressable, grounded objects

Generalize M1's prior into the full first-class object.

- Build: `Prior` records for all seven faculties (warp = axis_gain + bias_dir +
  faculty scalars); the prior-warp wrapper around `engram_reason_point_fit`;
  deprecate hard-coded constants (`drop_frac`, `assoc_floor`, `ext_floor`) in
  favor of prior scalars.
- **Exit:** each of the five C operators runs through its prior with identical
  results when the prior is set to today's constants (behavioral parity), then
  *diverges beneficially* once the loop refines it. Priors survive reboot.

### M3 — Grounding as a relation; hold/assert split

- Build: the `grounded-by` edge (§5.2) with `for_whom`; move
  `engram_verify_grounding`'s flag into stored edges; gate **assertion only**
  against the honesty floor; leave holding unconditional.
- **Exit:** ungrounded nodes are first-class (held, queryable, no deletion);
  the same claim carries different `grounded-by` weights for two observers; an
  assertion below floor is refused while the content remains held. Curiosity =
  a `vantage_read` that surfaces high-salience / low-grounding regions.

### M4 — The vantage-read unified (three settings)

- Build: `vantage_read(anchor, aperture)` unifying descriptor-build +
  `engram_geo_reify_lookup` + activation-weighting; self / foreign-field /
  aperture settings.
- **Exit:** one code path produces (a) a normal self-read, (b) a
  perspective-shifted read from another `for_whom`, (c) a narrowed veil read —
  differing only by argument. Reboot-stable.

### M5 — The gradient is the currency (remove point-collapse from thinking)

- Build: `GeoGradient` as the return of every faculty; move point-collapse into
  a separate expression faculty (sample gradient → surface). `think`'s output
  feeds back as the next steering direction (closed-loop flow).
- **Exit:** a chain of `think` calls flows as gradients end-to-end; a point
  appears *only* at an explicit expression call. Spiked vs spread gradients are
  observable (deduction vs prediction).

### M6 — Metastability enforced

- Build: node-level keystone flag/layer for self/values; the correspondence-loop
  reads but never writes keystone priors; bounded update rate.
- **Exit:** across a long run of correspondence beats on a snapshot, keystones
  are provably unchanged while non-keystone priors drift and improve; the graph
  neither freezes (all metrics static) nor dissolves (keystone drift = 0,
  identity nodes intact). Reboot-prove the keystone set.

### M7 — Cutover

- Build: nothing new — the gated migration.
- **Exit:** reboot-proof on the prod-clone secondary; cutover via
  `launchctl bootout → settle-poll → bootstrap`; post-cutover the live engram
  shows priors refining in-geometry with zero data loss and keystones intact.

### Definition of "to completion"

The architecture is **complete** when: cognition runs as `think` = one frozen
traversal-read primitive + geo-algebra, steered by **stored, learnable, grounded
priors**; the reflexive correspondence-loop refines those priors *in the
geometry* against outcomes (grounding = learning = one loop); the engram holds
ungrounded content as first-class with grounding as a relation and the honesty
floor only on assertion; the vantage-read serves self / foreign-field / aperture
from one op; and a stable keystone core anchors a plastic everything-else —
all reboot-proven and cut over to the live engram without data loss. The named
faculties survive only as *labels on regions of think's steering space*, not as
separate code.

---

## Appendix A — Designed vs. already-built (honest ledger)

**Already built (EXISTS, cited):**
- The shared primitive `engram_reason_point_fit` and the five operators over it
  + geo-algebra (`engram_reason.c`).
- The verifier on `point_fit` (`engram_verify.c`:
  `engram_verify_grounding`, `engram_verify_consistency`).
- Centered-frame geometry, combine/subtract/analogy/distance
  (`engram_geometry.{c,h}`).
- The reification beat: hub-neighborhood detection → first-class `Neighborhood`
  nodes with member edges, nesting, supersession-with-residue, hot-path lookup
  (`engram_geo_reify_store`, `engram_geo_reify_nest`, `engram_geo_reify_lookup`).
- The tiered paged store (buffer pool / LRU / WAL / checkpointer / pinning),
  the RAM activation graph (base-level learning `access_ts[]`, WM slots,
  `working_memory_weight` / `background_activation`), `StoreNode` / `StoreEdge`.
- `GeoMember` already separating relational salience (`centrality`) from
  intrinsic `salience`.

**Designed, NOT built (this doc's deliverables):**
- `GeoGradient` and `think()` as the single entry point (§1, M5).
- `Prior` as a first-class stored, warp-carrying, calibrated node (§2, M1–M2).
- Salience/importance as a *relation* superseding the intrinsic node scalar
  (§2.1, M3).
- `vantage_read(anchor, aperture)` unifying the three perspective settings
  (§3, M4).
- **The reflexive correspondence-loop / `correspondence_beat`** — the learning
  engine, moved from offline Python into the geometry (§4, M1). *The core new
  subsystem.*
- `grounded-by` edge + assertion-only honesty floor (§5, M3).
- Node-level keystones + bounded plasticity (§6, M6).

**Uncertain / to resolve during build:**
- The exact warp parameterization (axis_gain vs full metric) — start minimal
  (per-axis gain), measure, widen only if calibration demands it.
- Grade-(1) self-consistency as a sufficient reality signal for M1, versus
  needing grade (2)/(3) sooner — decided empirically on the snapshot.
