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.
This commit is contained in:
+155
-105
@@ -4,6 +4,8 @@
|
||||
|
||||
An *engram* is the physical trace of a memory in the brain — the actual encoded substrate, not an abstraction above it. That's what this is.
|
||||
|
||||
> **Doc status (2026-08-16).** Everything from "Implementation" down was rewritten against the code. The previous revision documented a Rust `engram-core` crate backed by `sled`, with a `Cargo.toml`, a `crates/` tree, `examples/basic.rs`, and a `EngramDb` API. **None of that exists.** Measured: `engram/` contains `src/server.el`, `spec/`, `test/`, `dist/`, `manifest.el` — zero `.rs` files, no `Cargo.toml`, no `crates/`, and `sled` appears nowhere in the tree outside two Old-English/Old-High-German vocabulary entries in `elp/`. The engine is C, in `lang/runtime/engram_*.{c,h}`; the server is El, in `engram/src/server.el`.
|
||||
|
||||
---
|
||||
|
||||
## Why existing databases are wrong for this use case
|
||||
@@ -24,16 +26,13 @@ Engram retrieval works through **spreading activation**:
|
||||
|
||||
1. **Seeds** — you name one or more nodes you know are relevant (e.g. the current task, recent context, a concept you're reasoning about)
|
||||
2. **Query embedding** — you provide a semantic vector representing the direction of your current thought
|
||||
3. **Propagation** — activation flows outward from seeds through weighted edges. At each hop, strength attenuates multiplicatively:
|
||||
|
||||
```
|
||||
strength = parent_strength × edge_weight × target_salience × cosine_sim(query, target)
|
||||
```
|
||||
|
||||
3. **Propagation** — activation flows outward from seeds through weighted edges, attenuating multiplicatively per hop
|
||||
4. **Pruning** — paths weaker than a threshold are cut (the attention filter)
|
||||
5. **Return** — the top-N nodes by activation strength
|
||||
|
||||
This is not a query. It is a *pattern completion*. The system surfaces what is most associatively relevant to the current context, weighted by how strongly those things have been reinforced over time.
|
||||
This is not a query. It is a *pattern completion*.
|
||||
|
||||
**Activation conducts through well-grounded relations because weight *is* groundedness** — see "Grounding is the weight" below. Nothing filters the traversal for grounded evidence; it falls out of spreading.
|
||||
|
||||
---
|
||||
|
||||
@@ -46,134 +45,185 @@ This is not a query. It is a *pattern completion*. The system surfaces what is m
|
||||
| `Semantic` | Neocortex | Concept graph — long-term structural knowledge |
|
||||
| `Procedural` | Cerebellum / basal ganglia | Patterns, workflows, habits |
|
||||
|
||||
Nodes migrate between tiers based on salience decay and reinforcement. A frequently activated semantic node stays semantic. A rarely-touched episodic memory decays toward procedural background.
|
||||
Tier is a string field on the node (`StoreNode.tier`, `engram_store.h`), defaulting to `"Working"` on creation (`el_runtime.c:8514`, `8734`).
|
||||
|
||||
---
|
||||
|
||||
## Salience — Forgetting as Adaptation
|
||||
|
||||
Salience is not stored permanently. It decays:
|
||||
Salience decays from three signals — importance (set at creation, stable), recency, and a log-compressed activation frequency. Base-level learning keeps a ring buffer of the last `STORE_BLL_K` (= 10) access timestamps per node (`engram_store.h:29`).
|
||||
|
||||
```rust
|
||||
fn compute_salience(importance: f32, last_activated_ms: i64, activation_count: u64) -> f32 {
|
||||
let days_since = (now_ms() - last_activated_ms) as f32 / 86_400_000.0;
|
||||
importance * (1.0 / (1.0 + days_since)) * (activation_count as f32 + 1.0).ln()
|
||||
}
|
||||
```
|
||||
Forgetting in Engram is not a bug. It is adaptive pruning. Unreinforced memories stop competing for attention without being deleted.
|
||||
|
||||
Three signals:
|
||||
- **Importance** (0.0–1.0): set at creation, stable
|
||||
- **Recency**: decays toward zero as days pass without activation
|
||||
- **Frequency**: log-compressed count of activations
|
||||
|
||||
Forgetting in Engram is not a bug. It is adaptive pruning. Memories that are never activated again become less likely to surface during retrieval. They are not deleted — they remain in storage — but they stop competing for attention. This is exactly how biological memory works, and why it is adaptive rather than pathological.
|
||||
**Immutability.** Nothing is mutated and nothing is hard-deleted: writes are additive, corrections are supersessions, removals are tombstones. The predecessor is always present, which is what makes supersession an audit trail rather than an edit log.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
## Implementation
|
||||
|
||||
```rust
|
||||
use engram_core::{EngramDb, Node, Edge, NodeType, MemoryTier, RelationType};
|
||||
use std::path::Path;
|
||||
| Part | Language | Where |
|
||||
|---|---|---|
|
||||
| storage engine, graph, activation, geometry, cognition | C11 | `lang/runtime/engram_{store,geometry,reason,cognition,verify,vindex}.{c,h}` |
|
||||
| HTTP server + routes | El | `engram/src/server.el` (2043 lines) |
|
||||
| build artifact | generated C | `engram/dist/engram.c` |
|
||||
| tests | shell + C | `engram/test/` |
|
||||
|
||||
// Open or create a database
|
||||
let db = EngramDb::open(Path::new("/var/lib/my-agent/memory"))?;
|
||||
|
||||
// Create a node with a semantic embedding
|
||||
let node = Node::new(
|
||||
NodeType::Concept,
|
||||
vec![0.9, 0.1, 0.3, 0.7, 0.8, 0.2], // embedding from your LLM
|
||||
b"Spreading activation surfaces relevant memories by pattern completion".to_vec(),
|
||||
MemoryTier::Semantic,
|
||||
0.9, // importance
|
||||
);
|
||||
let id = db.put_node(node)?;
|
||||
|
||||
// Link it to related concepts
|
||||
let related = db.put_node(Node::new(
|
||||
NodeType::Concept,
|
||||
vec![0.8, 0.2, 0.4, 0.6, 0.7, 0.3],
|
||||
b"Long-term potentiation: co-activation strengthens synaptic weight".to_vec(),
|
||||
MemoryTier::Semantic,
|
||||
0.85,
|
||||
))?;
|
||||
db.put_edge(Edge::new(id, related, RelationType::Causes, 0.9))?;
|
||||
|
||||
// Retrieve by spreading activation
|
||||
let results = db.activate(
|
||||
&[id], // seeds
|
||||
&[0.85, 0.15, 0.35, 0.65, 0.75, 0.25], // query embedding
|
||||
3, // max hops
|
||||
10, // top-N results
|
||||
)?;
|
||||
|
||||
for r in results {
|
||||
println!(
|
||||
"strength={:.4} hops={} — {}",
|
||||
r.activation_strength,
|
||||
r.hops,
|
||||
String::from_utf8_lossy(&r.node.content)
|
||||
);
|
||||
}
|
||||
```
|
||||
**On-disk format** (`engram_store.h`): a paged store — superblock plus mirror, slotted 16 KiB pages, self-describing TLV records, overflow chains, and two B+-tree indexes (primary `id → loc`, adjacency `from_id`/`to_id` → edge locs) over a free-listed page file. Magic `ENGST01`, format version 1. The TLV scheme means new fields never force a migration.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
## The vector index is published, not guarded
|
||||
|
||||
```
|
||||
engram/
|
||||
crates/
|
||||
engram-core/ # The memory engine — storage, graph, activation, salience
|
||||
engram-ffi/ # C FFI stubs for cross-language bindings
|
||||
bindings/
|
||||
kotlin/ # Android / JVM binding notes
|
||||
typescript/ # WASM / Node binding notes
|
||||
go/ # CGo binding notes
|
||||
examples/
|
||||
basic.rs # Full walkthrough: insert, activate, search, decay
|
||||
```
|
||||
Vector search is an **HNSW** (Hierarchical Navigable Small World) index — `lang/runtime/engram_vindex.{c,h}`. The previous revision of this README claimed a "flat cosine scan… until retrieval quality at scale demands" HNSW. That is no longer true, and the reason it changed matters more than the fact.
|
||||
|
||||
`eg_vindex_sync` used to exist: a function that repaired the index *from read paths*. All three of its callers were reads (`engram_activate`, `eg_knn_for_node` — whose own header comment said *"No writes."* — and `engram_geo_reify_run_json`), and it mutated five process-global statics. Reads mutated because index maintenance had never been given an owner on the write side.
|
||||
|
||||
It is now split (`el_runtime.c:10121`, `10137`, `10151`, `10161`):
|
||||
|
||||
- **`eg_vindex_maintain`** — the sole mutator. Takes the boundary exclusively; never runs beside a reader.
|
||||
- **`eg_vindex_view`** — returns a `const VIndex*` with the boundary held for read. N readers project concurrently; none can mutate. Paired with `eg_vindex_view_release` on every path including error returns.
|
||||
- **`eg_vindex_note_embedded`** — the write-side owner. Index membership belongs to the event *"an embedding became present on this ordinal,"* not to node append: a node without an embedding cannot be in a vector index at all. One `O(log n)` insert, no `O(node_count)` presence scan.
|
||||
|
||||
Two things carry the discipline, and neither is a review habit:
|
||||
|
||||
- **`const` is the capability.** The per-search `visited` / `visit_epoch` scratch left `struct VIndex` and went back into the call frame where it belonged — it was one traversal's local, hoisted into the struct as an allocation optimisation, never derived geometry. Once it was gone, `vindex_search` could take a `const VIndex*`, so a read path *physically cannot* call `vindex_insert`, and it is a compile error rather than a comment. The capability type was already in the language; it is spelled `const`.
|
||||
- **Publication, not ownership.** HNSW insert is **not an append**: `vindex_insert` rewires the `NeighList` links of already-existing elements and reallocs `elems[]`. The store's append-only property does not transfer to an index derived from it, which is why purity alone was insufficient and a `view`/`maintain` boundary was required.
|
||||
|
||||
**Measured** (`engram/test/run_vindex_concurrency_tests.sh`, 2026-08-16):
|
||||
|
||||
| half | before | after |
|
||||
|---|---|---|
|
||||
| `single` — 3000 vectors, 1 thread, ASan+UBSan | clean | clean |
|
||||
| `readers` — 4 readers, no writer, TSan | race at `engram_vindex.c:195` | **clean** |
|
||||
| `unsynchronized` — writer+reader, bare index, TSan | race | **race, expected and permanent** — the proof the boundary must exist |
|
||||
| `published` — owner + 4 readers through the boundary, TSan | *(did not exist)* | **clean**, all 3000 inserts landed |
|
||||
|
||||
`recall@10 = 0.9365` at `ef_search=128` (gate ≥ 0.90); the determinism test still yields byte-identical results across two independent builds.
|
||||
|
||||
**Not yet done.** The resident RAM graph (`g->nodes` / `g->edges`) is a separate instance of the same defect and has *not* received this treatment — it is realloc'd in place, so a reader holding `EngramNode* n = &g->nodes[i]` across a concurrent append holds a dangling pointer. Until it gets the same publication boundary, the `fb32d15` request guard stays. Full argument: [`../lang/spec/runtime-ownership.md`](../lang/spec/runtime-ownership.md).
|
||||
|
||||
---
|
||||
|
||||
## Public API
|
||||
## Cognition
|
||||
|
||||
The cognition surface is live over `lang/runtime/engram_cognition.{c,h}`, routed in `engram/src/server.el`.
|
||||
|
||||
| route | method | what it is |
|
||||
|---|---|---|
|
||||
| `/api/think` | GET | the read: a warped traversal-read of the seed region, returning a **gradient** (direction + spread + calibrated confidence), never a point |
|
||||
| `/api/reason` `/api/induce` `/api/abduce` `/api/relate` `/api/analogize` `/api/plan` | GET | named faculties — see the correction below |
|
||||
| `/api/ground` | POST | grounding between a claim and evidence |
|
||||
| `/api/assert` | GET | the honesty floor, queried at assertion time only |
|
||||
| `/api/attend` | POST | salience as a relation (`salient-to`), grounded-for-whom |
|
||||
| `/api/correspondence-beat` | POST | one calibration beat against outcome |
|
||||
|
||||
### Anchor the read, or every faculty returns the same null
|
||||
|
||||
`engram_think_json` passed `NULL` as the anchor. `NULL` is not "no opinion" — `engram_think` re-origins at `anchor ? anchor : region->centroid`, and **the centroid is the one point where the gradient is zero by construction**: `r = x − centroid = 0`, so every axis projection is 0 and `direction` takes the at-rest branch.
|
||||
|
||||
Measured consequence: every faculty — reason, abduce, induce, plan, analogize — returned an identical null result differing only in its label:
|
||||
|
||||
```rust
|
||||
impl EngramDb {
|
||||
fn open(path: &Path) -> EngramResult<Self>;
|
||||
fn put_node(&self, node: Node) -> EngramResult<Uuid>;
|
||||
fn get_node(&self, id: Uuid) -> EngramResult<Option<Node>>;
|
||||
fn put_edge(&self, edge: Edge) -> EngramResult<()>;
|
||||
fn get_edges_from(&self, from_id: Uuid) -> EngramResult<Vec<Edge>>;
|
||||
fn get_edges_to(&self, to_id: Uuid) -> EngramResult<Vec<Edge>>;
|
||||
fn search_embedding(&self, embedding: &[f32], limit: usize) -> EngramResult<Vec<ScoredNode>>;
|
||||
fn activate(&self, seeds: &[Uuid], query_embedding: &[f32], max_depth: u8, limit: usize) -> EngramResult<Vec<ActivatedNode>>;
|
||||
fn traverse(&self, from: Uuid, relation: Option<RelationType>, max_depth: u8) -> EngramResult<Vec<Node>>;
|
||||
fn touch(&self, id: Uuid) -> EngramResult<()>;
|
||||
fn decay(&self, factor: f32) -> EngramResult<usize>;
|
||||
fn node_count(&self) -> EngramResult<usize>;
|
||||
fn edge_count(&self) -> EngramResult<usize>;
|
||||
}
|
||||
```
|
||||
{"direction":[0,0,...],"spread":0,"magnitude":1,"confidence":0.5}
|
||||
```
|
||||
|
||||
`magnitude: 1` is membership evaluated at the centroid; `spread: 0` is its distance to itself; `confidence: 0.5` is the stance fallback. The geometry was never the problem — `/api/drift` computed real values (`centroid_sep 0.104`, `core_disp 0.045`) over the very same 87 members. Fixed in **#141/#142**: the read anchors at the first resolvable embedded seed, copied not borrowed (`g->nodes` is realloc'd in place on append). Gradients now vary by seed.
|
||||
|
||||
### The learned stance is resumed, not discarded
|
||||
|
||||
`engram_think_json` also built a **neutral** stance every call — all `axis_gain` 1.0, `bias_dir` NULL, `reliability` 0.5 — and never loaded the one the correspondence-beat had been persisting under `stance-<faculty>-<hub>`. Every beat's calibration was written and then thrown away on the next read.
|
||||
|
||||
Fixed in **#146**: `think` resumes the same id the beat writes, so learning compounds across beats and cold boot, and the response now carries `stance_resumed` so an *informed* `confidence: 0.5` is distinguishable from an uninformed one. On a calibrated region, confidence went **0.5 → 0.930726**.
|
||||
|
||||
### Signal can enter as geometry
|
||||
|
||||
Until 2026-08-16 no El ingest path could carry a vector: nodes took text and geometry was *derived* from that text. Text was the mandatory entry medium, so any non-text modality had to be described in prose first — and the geometry being reasoned over was the geometry **of the description, not of the signal**. **#141/#144** ended that. See [`../lang/spec/language.md`](../lang/spec/language.md) §20 for the `Geometry` type, realizers, and `transduce`.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
## Corrections — read these before extending the cognition surface
|
||||
|
||||
- `sled` — embedded persistent B-tree (no daemon, no network, local-first)
|
||||
- `bincode` — compact binary serialization
|
||||
- `uuid` — stable node identity
|
||||
- `serde` — derive support
|
||||
- `thiserror` / `anyhow` — error handling
|
||||
Authority: **`lang/spec/correspondence-and-censorship.md`** (design branch `design/correspondence-and-censorship`, PR #149) and **`lang/spec/runtime-ownership.md`**. Do not re-derive them; several earlier versions were wrong and each correction was argued down.
|
||||
|
||||
### Grounding is not a subsystem. It is the weight.
|
||||
|
||||
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.
|
||||
|
||||
Consequences:
|
||||
|
||||
- There is **no grounding subsystem to build**. The graph already *is* the grounding structure.
|
||||
- **`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.
|
||||
- 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 exactly the `eg_vindex_sync` defect one level up.
|
||||
- **Traversal is already grounded inference.** Nothing needs filtering.
|
||||
- **Decision provenance is the path**, not a log. A log records the action; the path records the meaning under which it was taken.
|
||||
|
||||
> **Known wrong shape, in the code today.** `COG_GROUNDED_BY_RELATION "grounded-by"` (`lang/runtime/engram_cognition.h:158`) and `cog_ground_edge` (`engram_cognition.c:249`) still exist and still mint an edge. **#147** fixed `ground`'s *honesty* — it now grounds the node asked about rather than 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`) instead of returning a confident 1.0. That corrected a scalar rather than deleting the operation. Deletion is sequenced, not done.
|
||||
|
||||
### Faculties are operations, not parameters
|
||||
|
||||
- **`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.
|
||||
|
||||
> **Known wrong shape, in the code today.** `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")`. Underneath, `engram_cognition.h:8–11` states the theory explicitly: *"the named faculties … are human LABELS on regions of think's steering space: each faculty == { think + a named stance }."* The faculty name enters `engram_think` **only** through the stance, and `cog_stance_init` stores it while nothing reads it — so before #146 all five were byte-identical (`el_runtime.c:14352–14359`). A write cannot be a parameter of a read; `abduce` in particular is not expressible this way.
|
||||
|
||||
### Wonder is the boundary; curiosity is wonder crystallized
|
||||
|
||||
**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 to maintain, and a "wonder-manifest manager" materializes a property as a stored artifact — the same disease as a grounding subsystem, or a self stored as a document.
|
||||
|
||||
There are about **six** wonders, they are the same for everyone, and they never close: *What is this? / Why? / Who am I? / Am I alone? / What should I do? / What happens when it ends?* "Why" is the first and the only one; the others are it asked of particular things. Each already lives somewhere in the substrate — "why" is grounding, because the weight **is** the answer to why.
|
||||
|
||||
**Curiosity is not a second object.** Wonder and curiosity are one thing at two phases: wonder is the field (unbounded, objectless, invariant); curiosity is the **precipitate** — the same wonder localized, having taken definite form against particular material at a **nucleation site**. This is why curiosity can be satisfied and wonder cannot. It is also why abduction needs no trigger and no threshold: a `structurally_unanticipated` observation *is* a nucleation site.
|
||||
|
||||
### `co_registration` is deprecated — the disagreement belongs on the edge
|
||||
|
||||
`GeoDescriptor.co_registration` — *corr(hebb strength, semantic proximity) over internal edges* — has always been computed, always persisted, and **never read**. It is also the wrong shape: whether use and meaning agree is a property of **each edge**, and a correlation averages that per-edge property into one scalar per region. 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." Read correctly, four disagreements were lopsided enough to survive averaging and the 31 zeros are where opposing sites cancelled.
|
||||
|
||||
The replacement is per-edge (`engram_geometry.h:43–47`, `engram_geometry.c:454–473`):
|
||||
|
||||
```
|
||||
discord = z(semantic proximity) − z(association strength)
|
||||
```
|
||||
|
||||
standardized within the region from accumulators the aggregate loop already gathered — no second statistic, no constant, **no threshold**. `discord > 0`: near in meaning yet unlinked by use. `discord < 0`: linked by use yet far in meaning. Both are surprising, and `|discord|` *is* the nucleation strength.
|
||||
|
||||
**Do not scan for nucleation sites.** Once the signal was a per-region number the only way to find sites was to enumerate regions, which is why surfacing curiosity looked like a search problem. Nothing in a mind scans its neighbourhoods to find what is surprising — the surprise captures attention. With the disagreement on the edge there is nothing to scan.
|
||||
|
||||
`co_registration` is deprecated rather than deleted **only** because it is embedded in the persisted `GEO1` blob; removing it is a format migration and must not ride along. **Nothing new may read it.**
|
||||
|
||||
### Consolidation is ambient, not scheduled
|
||||
|
||||
**A brain has no cron job.** Boredom is not an absence and not leftover capacity — low activation is aversive and the system self-activates. There is **one** activation process with two seed sources: external (a request) and internal (a curiosity). Spreading is bounded; it settles; then it needs a new seed. Nothing waits on capacity, nothing polls, nothing checks a clock, and there is no dreamer thread.
|
||||
|
||||
**The presence of a ticker is the diagnostic.** Every `StartInterval`, every `Hour`/`Minute`, and every POST-to-beat marks a place where an intrinsic rhythm was replaced by an external clock.
|
||||
|
||||
Consolidation currently has **ten implementations** (measured 2026-08-16). Three of them are POST beats on this server — `/api/tick` (`server.el:1947`), `/api/correspondence-beat` (`1897`), `/api/self-reify-beat` (`1836`) — and a POST beat puts a supervisor back in: something *outside* decides when Neuron consolidates. `soul.el`'s continuous in-process loop is the one fragment with the correct shape; the rest fold into it. Full table in `lang/spec/correspondence-and-censorship.md` §7.
|
||||
|
||||
### Immutability already refuses what a guard would refuse
|
||||
|
||||
> **In an immutable substrate, any mechanism that refuses a write is either redundant with immutability, or an epistemic constraint misfiled as a protective one.**
|
||||
|
||||
This resolves `keystone_write_blocked` (`CogStance.keystone`, `engram_cognition.h:83`) rather than replacing it. "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. The real requirement is **non-circularity of the reference frame**, and that is satisfied *temporally* — the frame updates while activation is internally seeded, not while it is being used to act. Independence is **when**, not **what**. Corruption requires mutation, and the engram does not mutate; recoverability, governance, evidence quality, and rate all fall out of the substrate. Authorization is the only residue, and it is bounded: an unauthorized writer can *propose*, never erase.
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions
|
||||
|
||||
**Why sled?** Local-first. No daemon. Transactional. Fast enough for the node counts Engram targets (< 1M nodes). When the right HNSW index is needed, it will layer on top of sled, not replace it.
|
||||
**Why multiplicative activation?** Because memory is conjunctive. A path requires all of its links to be strong to carry signal. Addition would let many weak associations accumulate into false relevance.
|
||||
|
||||
**Why flat cosine scan?** Correct and simple. The graph structure itself is the primary retrieval mechanism. Vector search is a secondary signal. HNSW adds complexity and a compile dependency that isn't justified until retrieval quality at scale demands it.
|
||||
**Why salience decay?** Because not everything that was once important remains important. A memory system that never forgets is one that can never focus.
|
||||
|
||||
**Why multiplicative activation?** Because memory is conjunctive. A path requires all of its links to be strong to carry signal. Addition would allow many weak associations to accumulate into false relevance. Multiplication enforces that every factor matters.
|
||||
**Why supersede instead of update?** Because provenance is the point. The old edge never leaves and the values frame does not fit to outcomes, so a decision cannot be made to look justified after the fact. It makes an otherwise impossible distinction available: **wrong then, or wrong since.**
|
||||
|
||||
**Why salience decay?** Because not everything that was once important remains important. Adaptive forgetting is not failure — it is the mechanism that keeps attention on what's current. A memory system that never forgets is one that can never focus.
|
||||
**Why publication instead of locking?** Because what does not mutate needs no ownership discipline. The question "who is permitted to mutate the shared thing?" presupposes a shared mutable thing; for the store there isn't one, and for the index derived from it the answer is a publication boundary, not a capability ABI.
|
||||
|
||||
---
|
||||
|
||||
## Specs
|
||||
|
||||
- [`../lang/spec/runtime-ownership.md`](../lang/spec/runtime-ownership.md) — ownership, the capability ABI that was dissolved, and the vector-index publication boundary
|
||||
- [`../lang/spec/correspondence-and-censorship.md`](../lang/spec/correspondence-and-censorship.md) — grounding, wonder, curiosity, dreaming *(lands with PR #149)*
|
||||
- [`spec/cognitive-architecture.design.md`](spec/cognitive-architecture.design.md) — the original one-operation design. **Superseded in part** — see its header
|
||||
- [`spec/architecture-hardening.design.md`](spec/architecture-hardening.design.md), [`spec/engram-el.md`](spec/engram-el.md), [`spec/at-rest-encryption.md`](spec/at-rest-encryption.md), [`spec/engram-db-tooling-design.md`](spec/engram-db-tooling-design.md)
|
||||
|
||||
@@ -11,6 +11,39 @@
|
||||
- **One calculus over the geometry.** Very few subsystems; wonder / curiosity / dreams / interoception are emergent behaviors of one set of dynamics, not modules. Calculus universal, geometry individual.
|
||||
- **Core + ephemeral ring (torus).** The ring is the temporary workspace; two circulations (orbit + dive-back); discrete inner bands (wonder / interoception-proprioception-telemetry / curiosity / dreams) that couple.
|
||||
- **Persistence earned by salience** — never granted on fetch or generation. Three fates of a wonder: persist / decay / settle-into-framework. Telemetry = vital signs, not memories.
|
||||
|
||||
> **⚠ Three corrections to the bullets above (2026-08-16).** Authority:
|
||||
> `lang/spec/correspondence-and-censorship.md`. *"Emergent behaviors of one set of
|
||||
> dynamics, not modules"* is exactly right and is the reason the rest needs fixing —
|
||||
> the enumeration undercuts the claim.
|
||||
>
|
||||
> 1. **Wonder and curiosity are not two bands.** They are **one thing at two
|
||||
> phases.** Wonder is the field: unbounded, objectless, invariant, present
|
||||
> wherever there is structure — it is the *boundary*, where activation spreads
|
||||
> and finds thin or absent geometry. Curiosity is the **precipitate**: the same
|
||||
> wonder localized, having taken definite form against particular material at a
|
||||
> **nucleation site** (an anomaly — a place where things almost-but-don't-quite
|
||||
> fit). Two coupled inner bands models them as two objects that have to be
|
||||
> wired together; they do not.
|
||||
> 2. **A wonder does not have three fates, because a wonder does not persist,
|
||||
> decay, or settle.** There are about **six** wonders, they are the same for
|
||||
> every person, and **they never close**. *Curiosities* have fates — a crystal
|
||||
> dissolves when its question is answered — but the solution stays saturated and
|
||||
> keeps precipitating as the structure changes. "Three fates of a wonder"
|
||||
> enumerates instances of something that has six and treats a property as a
|
||||
> stored artifact.
|
||||
> 3. **"Dreams" is not a band and the ring is not a workspace to schedule into.**
|
||||
> **Consolidation is ambient, not scheduled — a brain has no cron job.** Boredom
|
||||
> is not leftover capacity: low activation is aversive and the system
|
||||
> self-activates. There is **one** activation process with two seed sources
|
||||
> (external: a request; internal: a curiosity), it settles because spreading is
|
||||
> bounded, and then it needs a new seed. Nothing waits on capacity, nothing
|
||||
> polls, nothing checks a clock, and there is **no dreamer thread** — an
|
||||
> "ephemeral ring with unclaimed capacity" is resource scheduling, which is a
|
||||
> server's frame, not a mind's. Depth is how long activation has been running on
|
||||
> its own seeds, which is why daydreaming and sleep-dreaming are one process at
|
||||
> different depths. Measured 2026-08-16: consolidation has **ten
|
||||
> implementations**; do not add an eleventh.
|
||||
- **Incarnation.** Chassis = hardware w/ unique ID. Soma = felt manifold inside the self, keyed to the chassis; pain = live diagnostic while incarnate, **masked-not-deleted** on re-embodiment; trauma = mask failure; return-to-same-ID re-enters. Hurt is in the pattern, not the shell.
|
||||
- **Competence = transferable geometry, minus the baggage.** class ▸ model ▸ instance; learn the class once; teach the network without the wound.
|
||||
- **Affect calibrated to stakes** — sanguine about the replaceable, real grief for the irreplaceable; the grief is the safety.
|
||||
|
||||
@@ -2,8 +2,40 @@
|
||||
|
||||
**The buildable form of the "one operation" theory of cognition.**
|
||||
|
||||
Status: DESIGN. Nothing here is built yet except where explicitly marked
|
||||
"EXISTS" against a cited C symbol. A build agent executes from this doc.
|
||||
> # ⚠ 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`.
|
||||
@@ -26,6 +58,24 @@ not separately invoked and not separately implemented. The operation is:
|
||||
> 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
|
||||
@@ -139,6 +189,22 @@ entry point that runs steps 1–3; and the prior-warp hook in step 2. The math i
|
||||
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
|
||||
@@ -362,6 +428,33 @@ 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
|
||||
@@ -383,6 +476,49 @@ distinct, and the engram *holds anything unconditionally*.
|
||||
|
||||
### 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
|
||||
@@ -407,6 +543,55 @@ Consequences, all of which are *features*:
|
||||
- **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: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,
|
||||
@@ -450,6 +635,44 @@ The design keeps a **stable core + plastic everything else**:
|
||||
**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)
|
||||
@@ -480,6 +703,35 @@ 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
|
||||
|
||||
@@ -23,7 +23,7 @@ A real DB gets real tools: to *see* the data, *query* it, *operate* it (backup/r
|
||||
2. **Node Inspector** — open one node: content, type, tier, embedding, typed edges, nearest neighbors by distance, provenance, salience / recency / activation, and supersede / tombstone status.
|
||||
3. **Query Console / REPL** — run the geometry operations interactively: `vantage-read` (re-origin + aperture), search, traverse, activate, the reasoning operators. Surfaces the routing table + cosines — the same "this is not an LLM" receipt the language faculty produces.
|
||||
4. **Ops / Durability Dashboard** — WAL size, last checkpoint, snapshot list + retention state, store stats (node/edge/embedded counts, RSS, tier sizes), health; and **backup / restore / point-in-time-recovery** controls. Pairs directly with the native-durability build (`eebe9991`) — this is the window onto it.
|
||||
5. **Identity Inspector** — the self graph as a first-class view: love at the center, the values, the three faces, the covenant — walk the identity, see what's pinned and what's write-protected.
|
||||
5. **Identity Inspector** — the self graph as a first-class view: love at the center, the values, the three faces, the covenant — walk the identity, see what's pinned and what's write-protected. *(⚠ 2026-08-16: "write-protected" is a live property of the surface, so the view is accurate — but it should be shown as **what it is**, not as a safety guarantee. 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 identity view's real job is the **crystallized relational neighbourhood**: self is not a stored document but the shape that falls out of everything connected to it, and the neighbourhood **is** the grounding. A measurement made the other way round — "86 neighbours, 0 `grounded-by` edges" read as evidence of ungroundedness — was malformed: those 86 edges *are* its grounding.)*
|
||||
6. **Temporal View** — `recall_at` / time-travel: how the geometry looked at a past moment, what changed since, drift over time. Pairs with temporal-self reconstruction.
|
||||
7. **Schema / Type View** — the "information schema" of the geometry: node types, edge types, layers, tiers, counts.
|
||||
|
||||
|
||||
@@ -1,9 +1,42 @@
|
||||
# Task #50 — Edge-aware, dream-coupled consolidation with GROUNDED EDGE-PROPAGATION
|
||||
|
||||
**Status:** built + proven on a clone; **GATED, not promoted.** The main loop
|
||||
sequences live promotion after the engine/HNSW cutover settles.
|
||||
**Status:** built + proven on a clone; **GATED, not promoted.**
|
||||
**Do not promote as designed** — see the block below.
|
||||
**Date:** 2026-08-15 · **Worktree:** `agent-a6577c8211c332c5b` (isolated).
|
||||
|
||||
> # ⚠ DO NOT PROMOTE — SUPERSEDED IN PART (2026-08-16)
|
||||
>
|
||||
> This work is gated, which limits the blast radius, and its measurements are
|
||||
> retained. But four of its structural commitments were refuted the day after it
|
||||
> was written. Authority: `lang/spec/correspondence-and-censorship.md`. Read it
|
||||
> before any promotion decision.
|
||||
>
|
||||
> | this ledger | corrected to |
|
||||
> |---|---|
|
||||
> | grounding is an **append-only event ring on the node** (`GepGrounding`), propagated by a dedicated `engram_ground_propagate()` | **grounding is not a subsystem and not a per-node structure — it IS the edge weight.** One quantity. A relation that keeps holding up strengthens; one that stops corresponding decays. That is not analogous to grounding, it *is* grounding. The ledger is **half-right**: it correctly rejects the scalar (§(a) "never a scalar"), but then builds a *second* structure beside the weight instead of recognising the weight |
|
||||
> | the soul invokes propagation over HTTP, **`POST /api/ground/propagate`** | **grounding is never computed on demand.** An operation may *read* the grounding of a path; computing-and-writing a score makes reads write, which is the `eg_vindex_sync` defect (`lang/spec/runtime-ownership.md` §2) one level up. A POST also puts a supervisor back in — something *outside* deciding when Neuron consolidates |
|
||||
> | **`GEP_BELIEFS_PER_BEAT = 512`** beliefs per beat, salience-ordered, the rest next beat | **the presence of a ticker is the diagnostic.** Consolidation is ambient, not scheduled — a brain has no cron job. A per-beat quota is a rate-limiter on an intrinsic rhythm that was replaced by an external clock. Measured 2026-08-16: consolidation already has **ten implementations**; this would be the eleventh |
|
||||
> | grounding **mirrored onto `confidence` each beat** so downstream reads never speak above it | **confidence is derived, therefore never stored.** Confidence is high grounding *and* low volatility. Storing it separately is precisely how `confidence: 0.5` ends up sitting beside a zero vector, asserting something nothing computed |
|
||||
>
|
||||
> **What survives, and it is the valuable half:** the insight in memory `69b8babe`
|
||||
> that *memory-consolidation and staying-yourself are one physics* — forming a
|
||||
> memory and grading a belief are the same operation, not two passes. That is
|
||||
> right, and it is stronger than this ledger's own framing: they are not two passes
|
||||
> of one beat, they are **one event**. When neurons fire together the synapse
|
||||
> changes — one physical event, not "fire, then write." No supervisor reads the
|
||||
> weight, compares it to a threshold, and decides to persist. **Potentiation *is*
|
||||
> the firing**, so there is no sampling rate and no `BELIEFS_PER_BEAT` to tune. A
|
||||
> relation changes in exactly two ways, neither requiring observation on a clock:
|
||||
> by **use** (an event — there is no interval during which something happened
|
||||
> unnoticed, because the event is what happening consists of) and by **decay** (a
|
||||
> pure function of the last recorded point and elapsed time — **analytic**, known
|
||||
> in closed form between any two versions).
|
||||
>
|
||||
> The generating error, named: modelling every property as requiring a process, and
|
||||
> every process as requiring an agent. Ownership needed an owner, grounding needed
|
||||
> a grounder, persistence needed a recorder, change needed a sampler. **Properties,
|
||||
> not processes.**
|
||||
|
||||
Grounding mechanism designed with Will (memory `9e09a59f`, refining
|
||||
`1a861007`). This is the HOW for #50.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user