Files
el/engram/spec/cognitive-architecture.design.md
T
bigmerge e239f2894c docs: carry the correspondence corrections, because a stale doc builds the wrong thing
The docs described a mind made of subsystems — a grounding subsystem, a wonder
manifest, a dreamer on a beat, faculties as arguments to one call. Each of those
is a supervisor invented for something that should be a property of the
substrate, and two of the documents carrying them are load-bearing for a build
agent: cognitive-architecture.design.md says "a build agent executes from this
doc", and tools/api-reshape/README.md marks the refuted shapes PROVEN on a live
clone.

Corrections carried, per lang/spec/correspondence-and-censorship.md (PR #149)
and lang/spec/runtime-ownership.md:

- Grounding is not a subsystem — it IS the edge weight. 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.
- Faculties are operations, not parameters. reason changes the estimate, induce
  changes the parameters, abduce changes the structure — a write, which
  GeoGradient cannot express. A write is not a parameter of a read.
- Wonder is the boundary, not a manifest. Curiosity is wonder crystallized at a
  nucleation site: one thing at two phases. Removed wonder from the operator
  table in AGENTS.md.
- Consolidation is ambient, not scheduled. A brain has no cron job. The presence
  of a ticker is the diagnostic.
- co_registration is deprecated — it averaged a per-edge property into a region
  scalar, so opposing sites cancelled. GeoEdge.discord replaces it. Nothing new
  may read it.
- 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 two design docs are marked superseded-in-part with the refutation at the
point each claim is made, not rewritten. Preserving what was argued down is the
point of an immutable record.

Also measured and corrected while verifying the above: engram/README.md
documented a Rust engram-core crate on sled with "flat cosine scan until scale
demands HNSW" — there is no Rust in engram/ and HNSW is the index; lang/releases/
no longer exists, so both README.md and AGENTS.md pointed at a deleted path for
the authored runtime; language.md listed the engram_* and http_* runtimes as
stubs. Added language.md §20 for geometry-as-a-value, realizers and transduce
(#144), which had landed with no spec coverage.

Documentation only. No .c, .h, or .el file is touched.
2026-08-16 15:49:44 -05:00

48 KiB
Raw Blame History

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 M1M2 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-20260814lang/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:18701886 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:1435214359). 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.
/* 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_membershippoint_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_causalengram_geo_subtract confounder subspace, ` cos
Planning engram_reason_planengram_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 13; 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 dormantengram_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 46 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 (lang/runtime/engram_geometry.h:4347, engram_geometry.c:454473): 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, M1M2).
  • 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.