docs: re-base the system memory spec on the cloud substrate

a524bec9a92d · AtlantisPleb · · parent 19098b54939e

docs: re-base the system memory spec on the cloud substrate

The spec was written against the local engram ledger: signed NIP-AE
kind:30174 events distributed by a Nostr transport. On 2026-08-25 the owner
replaced that substrate — memories live in the centralized cloud database,
recall runs server-side inside POST /api/v1/responses, the local engram code
is frozen, and the Nostr transport is dropped (#63 closed as not planned).
Only section 6 recorded the override, so the rest of the doc still taught a
reader the wrong store.

Re-base the container, keep the judgments. Every section that assumed events,
signatures, relays, or local-first sync now names rows, an authenticated
writer, the server, and the table. Evidence-backed admission, dated claims,
correction by supersession, the privacy tiers, the poisoning caps, and the
knowledge-base line are transport-agnostic and stand as written.

What the re-base changes rather than renames, stated plainly:

- Local-first no longer holds. A server the client cannot reach is a turn
  without memory. Recall still degrades to silence, not to an error.
- The steward allowlist loses its signing, pinning, and time-of-check
  machinery and becomes a server-side role. Only a steward admits, unchanged.
- Centralization is no longer a bootstrap posture; the substrate decision
  made a single authority the design.
- The privacy gate carries more weight: with every write reaching the server,
  the tier field is the only thing between an account-scoped row and the
  shared bucket.
- Challenge and refutation survive because they never defended against the
  relay; the caps narrow to the prolific-writer case rather than disappear.
- The KB collision rule loses its enforcement point: the KB is retrieved
  client-side, memory recall is now server-side, and #65 owns the choice.

Also record two facts the build needs: openagents.com already runs profile
and experience memory planes that a memories table must reconcile with, and
MEMORY-001 confines recall to the current account conversation, which a
cross-account system bucket requires amending deliberately.

Section 6 keeps its superseded note, its "one channel, whatever it is"
framing, and the superseded design itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SoZMfWRSGnf6FZX2Ar9rQ2
Co-Authored-By
Claude Fable 5 <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified docs/memory/2026-08-25-system-memory-spec.md

Diff

1 file changed, +305 -190

docs/memory/2026-08-25-system-memory-spec.md modified +305 -190

@@ -2,20 +2,50 @@

2 2
3 3
- Class: design specification
4 4
- Date: 2026-08-25
5
- Revised: 2026-08-25, re-based on the cloud substrate. See "Substrate".
5 6
- Status: accepted design for the system bucket; no code lands under the
6 7
  owning issue
7 8
- Owning issue: OpenAgentsInc/openagents#52
8
- Base: the engram model and its live wiring in
9
  `packages/openagents-cli/src/memory/` (vendored from
10
  `packages/agent-experience-memory`), the user and learned buckets in #51,
11
  the knowledge base in #49, and the engram sync seam whose real Nostr
12
  transport is the remaining project-15 piece
9
- Base: the cloud memory store in the openagents.com Phoenix and Postgres
10
  server, the user and learned buckets in #51, and the knowledge base in #49
13 11
- Vocabulary: transparency tiers reuse the forge's `dark/pulse/ledger/glass`
14 12
  names (`openagents.com` `lib/openagents/transparency.ex`)
15 13
14
## Substrate
15
16
This spec was first written against the local engram ledger: signed NIP-AE
17
`kind:30174` events in `~/.openagents/memory/engrams.jsonl`, distributed by a
18
Nostr transport. On 2026-08-25 the owner replaced that substrate.
19
**Memories live in the centralized cloud database.** The store is a
20
`memories` table in the openagents.com Postgres, recall runs server-side
21
inside `POST /api/v1/responses`, writes go through the memories API, and the
22
local engram code is frozen rather than extended. The Nostr transport is
23
dropped from the roadmap, and the build issue that would have delivered relay
24
distribution (#63) is closed as not planned.
25
26
The re-base changes the container, not the judgments. Evidence-backed
27
admission, dated claims, correction by supersession, the privacy tiers, the
28
poisoning caps, and the knowledge-base line are properties of the design, not
29
of the ledger, and they stand as written. Where a section named an event, a
30
signature, a relay, or a local ledger, it now names a row, an authenticated
31
writer, the server, and the table. Section 6 records the transport decision
32
itself and keeps the superseded design for reference.
33
34
Two things a reader should carry into the build. First, the server is not
35
greenfield: `OpenAgentsInc/openagents.com` already runs a profile-memory
36
plane and a private experience-memory plane, both with append-and-supersede
37
records, evidence refs, consent, redaction, and hybrid lexical and pgvector
38
recall. The `memories` table this spec assumes has to be reconciled with
39
those planes, not laid beside them. Second, that repo's `INVARIANTS.md`
40
carries MEMORY-001 through MEMORY-009, and MEMORY-001 confines recall to the
41
current account conversation with no unscoped fallback. A `system` bucket
42
read into every account's turn is cross-account recall by construction, so
43
building it means amending that invariant deliberately, with the eligibility
44
filter in section 7.1 as the predicate that replaces the scope predicate.
45
16 46
## 1. What a system memory is
17 47
18
The memory system has two buckets today, both owner-local (#51):
48
The memory system has two buckets today, both account-scoped (#51):
19 49
20 50
- **user** — things the reader explicitly asked to have remembered.
21 51
- **learned** — heuristics the consolidation pass distills from episodes.

@@ -34,100 +64,94 @@ memory derived from a private transcript is a privacy breach by construction.

34 64
An unattributed system memory cannot be challenged, corrected, or discounted.
35 65
Every decision below follows from those three failure modes.
36 66
37
The one-sentence design: **a system memory is an ordinary signed engram that
38
has passed an evidence-backed admission gate, carries a transparency tier of
39
`ledger` or above, distributes on the existing engram sync seam, and can be
40
challenged and superseded by further signed events — never edited.**
67
The one-sentence design: **a system memory is an ordinary memory row that has
68
passed an evidence-backed admission gate, carries a transparency tier of
69
`ledger` or above, is served from the one shared store every client already
70
reads, and can be challenged and superseded by further records — never
71
edited.**
41 72
42 73
## 2. What stays unchanged
43 74
44
The system bucket adds no new event kind, no new store, and no new channel.
45
It reuses, unmodified:
46
47
- **The engram event model** (`memory/engram.ts`): NIP-AE `kind:30174`
48
  addressable events, the OpenAgents companion body, the hard-unsafe
49
  redaction gate before signing, content digests, and the
50
  `supersedes` correction path. A correction appends; it never edits.
51
- **The projection** (`memory/projection.ts`): derived, idempotent,
52
  order-independent; unresolved supersession chains are refused whole.
53
- **The ranking module** (`memory/ranking.ts`): deterministic cosine top-K,
54
  salience recall, token-budget packing.
55
- **The sync seam** (`memory/sync.ts`): `EngramTransport`,
56
  `EngramSyncQueue`, local-first, never blocks a turn.
75
The system bucket adds no new store and no second channel. It reuses,
76
unmodified:
77
78
- **The memory row model** (#51): account-scoped rows carrying a bucket, a
79
  body, a source reference, and a supersession pointer. A correction inserts a
80
  new row and points the old one at it; it never edits in place.
81
- **Derived status.** A memory's effective state is computed from the records
82
  that reference it, not read from a field the author set. The derivation is
83
  pure, idempotent, and order-independent, and an unresolved supersession
84
  chain is refused whole.
85
- **The ranking discipline**: deterministic top-K, salience recall, and
86
  token-budget packing, with stable tie-breaks so equal inputs give equal
87
  notes. Retrieval targets embedding search per the workspace retrieval
88
  invariant; a full-text slice is a marked, swappable stand-in.
89
- **The redaction gate**: the hard-unsafe rule set that refuses a write
90
  outright, applied at the write boundary before any row lands.
57 91
- **The transparency vocabulary**: `dark` (nothing public), `pulse`
58 92
  (metadata only), `ledger` (content and metadata), `glass` (full access).
59 93
60
What the bucket adds is one companion extension (section 3), three event
61
roles (admission, challenge, refutation — sections 4 and 5), one relay
62
namespace on the coming Nostr transport (section 6), and recall caps
63
(section 7).
64
65
## 3. Event shape
66
67
A system memory is an engram whose companion body carries a `system` block.
68
The companion schema id bumps to name the extension; events without the block
69
are user- or learned-bucket engrams and nothing about them changes.
70
71
```jsonc
72
// content of a kind:30174 event, after redaction, before signing
73
{
74
  "slug": "sys:gateway-402-retired-model",
75
  "value": "A 402 from the inference gateway usually means the default model was retired upstream. Check gateway status before bisecting local lanes.",
76
  "openagents": {
77
    "schema": "openagents.agent_experience_memory.nip_ae_companion.v2",
78
    "admission": "candidate",          // existing field; see section 4
79
    "entityId": "inference-gateway",
80
    "contentDigest": "sha256:…",
81
    "sourceEventRefs": [
82
      { "eventId": "…64 hex…", "role": "tool_result" }
83
    ],
84
    "relations": [],
85
    "derivedFromSlugs": [],
86
    "supersedes": "…64 hex…",          // optional, existing path
87
    "system": {
88
      "schema": "openagents.system_memory.v1",
89
      "tier": "ledger",                 // "ledger" | "glass"; never lower
90
      "asOf": "2026-08-25",             // the date the claim was observed true
91
      "evidenceRefs": [                 // at least one, required
92
        {
93
          "kind": "receipt",            // "receipt" | "engram" | "url"
94
          "ref": "https://openagents.com/receipts/…",
95
          "digest": "sha256:…"          // required for kind "url"
96
        }
97
      ]
98
    }
99
  }
100
}
101
```
94
What the bucket adds is a set of system fields on the row (section 3), three
95
record roles — admission, challenge, and refutation (sections 4 and 7.3) —
96
and recall caps (section 7).
97
98
## 3. Record shape
99
100
A system memory is a row in the shared memory store whose bucket is `system`
101
and which carries the system-only fields below. Rows in the `user` and
102
`learned` buckets are unchanged and carry none of them. This shape replaces
103
the `kind:30174` companion block the spec first carried; the fields and the
104
reasons for them are the same, restated as columns.
105
106
| Field | Values | Notes |
107
| --- | --- | --- |
108
| `bucket` | `user`, `learned`, `system` | `system` selects this shape |
109
| `slug` | string | `sys:` prefix for system memories |
110
| `body` | text | the redacted claim, in plain language |
111
| `author_id` | account reference | the account that wrote the row |
112
| `entity` | string, optional | what the claim is about |
113
| `tier` | `ledger`, `glass` | never lower; see section 5 |
114
| `as_of` | date | the date the claim was observed true |
115
| `admission` | `candidate`, `admitted`, `rejected` | the author's claim only; see section 4 |
116
| `superseded_by_id` | row reference, optional | the only correction path |
117
| `source_refs` | list of `{ref, role}` | roles include the three added in section 4 |
118
| `evidence_refs` | non-empty list of `{kind, ref, digest}` | `kind` is `receipt`, `memory`, or `url` |
119
120
An example body: "A 402 from the inference gateway usually means the default
121
model was retired upstream. Check gateway status before bisecting local
122
lanes." — slug `sys:gateway-402-retired-model`, entity `inference-gateway`,
123
tier `ledger`, `as_of` 2026-08-25, one evidence ref of kind `receipt`.
102 124
103 125
Field decisions, and why:
104 126
105
- **`source` is the event's own `pubkey`.** No separate source field: the
106
  signature already binds author to claim, and a claim nobody signed is a
107
  claim nobody can be held to. Unsigned or unverifiable events are never
108
  projected (existing behavior).
109
- **`asOf` is distinct from `created_at`.** `created_at` orders the chain;
110
  `asOf` dates the claim. Recall renders `asOf` so a stale truth reads as
111
  dated, the same way a knowledge-base stance carries its review date.
112
- **`evidenceRefs` is required and non-empty.** A system memory without
127
- **The source is the writing account.** No separate source field: the server
128
  authenticates the writer and records the account on the row, so the store
129
  binds author to claim the way a signature did, and a claim nobody is
130
  attributed with is a claim nobody can be held to. An unattributed row is
131
  never surfaced.
132
- **`as_of` is distinct from the insert time.** The insert time orders the
133
  chain; `as_of` dates the claim. Recall renders `as_of` so a stale truth
134
  reads as dated, the same way a knowledge-base stance carries its review
135
  date.
136
- **`evidence_refs` is required and non-empty.** A system memory without
113 137
  evidence is an assertion, and assertions do not enter the shared store
114
  (section 4). `kind: "receipt"` points at a forge receipt or signed event;
115
  `kind: "engram"` points at a prior admitted engram; `kind: "url"` points at
116
  public material and must carry a content digest so the evidence cannot be
117
  swapped after admission.
118
- **`tier` is `ledger` or `glass`.** By definition a system memory's value
119
  reaches every agent, which is content-plus-metadata — `ledger`. `glass`
138
  (section 4). `kind: "receipt"` points at a forge receipt; `kind: "memory"`
139
  points at a prior admitted row; `kind: "url"` points at public material and
140
  must carry a content digest so the evidence cannot be swapped after
141
  admission.
142
- **`tier` is `ledger` or `glass`.** By definition a system memory's body
143
  reaches every agent, which is content plus metadata — `ledger`. `glass`
120 144
  additionally asserts that every evidence ref resolves publicly. `dark` and
121 145
  `pulse` are not valid values here: a claim that cannot ship its content is
122
  not a system memory (section 5 covers what happens to it instead).
123
- **`supersedes` is the only correction path.** Reused as-is from the engram
124
  model. Only the original author or a steward (section 4) may sign a
125
  superseding event for a system slug; the projection refuses a superseding
126
  event signed by anyone else. Anyone else who disagrees files a challenge
127
  (section 5.2).
146
  not a system memory. Section 5 covers what happens to it instead.
147
- **Supersession is the only correction path.** Only the original author or a
148
  steward (section 4) may write a superseding row for a system slug; the API
149
  refuses a superseding write from anyone else, and the derivation ignores one
150
  that reaches the table by another route. Anyone else who disagrees files a
151
  challenge (section 7.3).
128 152
- **Slug namespace.** System slugs carry the `sys:` prefix. The prefix is a
129 153
  routing convention, not a security boundary — the security boundary is the
130
  admission status and the signature.
154
  admission status and the write authorization.
131 155
132 156
## 4. Admission
133 157

@@ -135,52 +159,59 @@ Field decisions, and why:

135 159
136 160
**Anyone can propose. Only evidence admits. Only admitted memories surface.**
137 161
138
Any network identity can sign and publish a candidate system memory
139
(`admission: "candidate"`). Candidates are visible to tooling and to
140
challenge, but recall never surfaces a candidate to a session (section 7).
162
Any account can write a candidate system memory (`admission: "candidate"`).
163
Candidates are visible to tooling and to challenge, but recall never surfaces
164
a candidate to a session (section 7).
141 165
This is the same discipline as a promise flip: the registry does not turn a
142 166
promise green because someone said so; it turns green on verifiable evidence.
143 167
Admission is a receipt, not an assertion.
144 168
145 169
### 4.2 The pipeline
146 170
147
1. **Propose.** An author builds the engram (section 3), passes the
148
   hard-unsafe redaction gate, signs it, and publishes it through the sync
149
   queue with `admission: "candidate"` and at least one evidence ref.
150
   A candidate with no evidence refs is refused at build time, before
151
   signing — the schema makes the empty list unrepresentable.
171
1. **Propose.** An author builds the memory (section 3) and writes it through
172
   the memories API with `admission: "candidate"` and at least one evidence
173
   ref. The write passes the hard-unsafe redaction gate. A candidate with no
174
   evidence refs is refused before the row lands — the write path makes the
175
   empty list unrepresentable, and a database constraint backs it so a row
176
   cannot reach the table by another route.
152 177
2. **Verify.** A steward (section 4.3) checks the evidence: the refs resolve,
153
   digests match, the receipt supports the claim, and the value survives an
178
   digests match, the receipt supports the claim, and the body survives an
154 179
   independent pass of the redaction gate. Verification is a judgment call on
155 180
   whether the evidence supports the claim; everything else is mechanical and
156 181
   tooling performs it.
157
3. **Admit or reject.** The steward signs an **admission event**: an engram
158
   with slug `adm:<candidate-event-id>`, whose `sourceEventRefs` carry
159
   `{ eventId: <candidate>, role: "admission" }` and whose value records the
160
   verdict (`admitted` or `rejected`) and the ground. The admission event is
161
   itself signed, dated, published, and permanent — the receipt for the flip.
162
4. **Project.** The projection derives a candidate's effective status from
163
   the admission events that reference it, exactly as it derives a value from
164
   a supersession chain. The `admission` field on the candidate is the
165
   author's claim; the admission event is the authority. Recall trusts only
166
   the projected status.
167
168
The `EngramSourceRole` literal set gains three members for this and section
169
5: `"admission"`, `"challenge"`, `"refutation"`.
182
3. **Admit or reject.** The steward writes an **admission record**: a row
183
   with slug `adm:<candidate-id>`, a source ref
184
   `{ ref: <candidate>, role: "admission" }`, and a body recording the verdict
185
   (`admitted` or `rejected`) and the ground. The admission record is
186
   attributed, dated, and append-only — the receipt for the flip.
187
4. **Derive.** The store derives a candidate's effective status from the
188
   admission records that reference it, exactly as it derives a body from a
189
   supersession chain. The `admission` field on the candidate is the author's
190
   claim; the admission record is the authority. Recall trusts only the
191
   derived status.
192
193
The source-role enum gains three members for this and section 7.3:
194
`admission`, `challenge`, and `refutation`.
170 195
171 196
### 4.3 Who admits
172 197
173
The steward set is a published allowlist of pubkeys served by the forge
174
(`openagents.com`), bootstrapped to the operator's key. The list itself is
175
signed and dated; clients pin it and refuse admission events from keys not on
176
the list at the admission event's `created_at`.
198
The steward set is a role the server holds: accounts the operator has marked
199
as stewards, bootstrapped to the operator's own account. The server checks the
200
role on the write and refuses an admission record from an account without it.
177 201
178
This is deliberately centralized to start. Decentralized admission
179
(stake-weighted, reputation-weighted, or multi-steward quorum) is a
180
governance change, not a schema change: the event shapes above already
181
support any number of admitting keys, so broadening the set later touches the
182
allowlist, not the protocol. The spec records the centralization as a known
183
bootstrap posture, not a hidden assumption.
202
The re-base simplifies this. There is no allowlist to publish, sign, pin, or
203
evaluate as of a timestamp, and no signature to verify, because a single
204
trusted server both holds the role and performs the write. What survives is
205
the rule the machinery existed to enforce: **only a steward admits**, and the
206
check runs where the row is created.
207
208
The centralization is deliberate and now unavoidable rather than a bootstrap
209
posture — the substrate decision (section 6) made a single authority the
210
design. Decentralized admission (stake-weighted, reputation-weighted, or
211
multi-steward quorum) would be a substrate change as well as a governance
212
change, and nothing here anticipates it. The record shapes above do support
213
any number of admitting accounts, so broadening the steward set touches the
214
role assignment, not the schema.
184 215
185 216
### 4.4 What qualifies
186 217

@@ -203,33 +234,41 @@ A system memory must be:

203 234
Nothing crosses from a private transcript into the system bucket without
204 235
passing, in order:
205 236
206
1. **The redaction gate** (`guardEngramContent`) — mechanical, already
207
   enforced before any engram is signed. Hard-unsafe categories block
208
   signing outright.
237
1. **The redaction gate** — mechanical, enforced at the write boundary before
238
   any row lands. Hard-unsafe categories refuse the write outright. The local
239
   engram path enforced this before signing; the cloud path enforces the same
240
   rule set in the API.
209 241
2. **Consolidation** — session-derived material enters only as a distilled
210
   heuristic (the existing dream pass), never as a quoted episode. The
211
   synthesizer recombines already-redacted fragments; raw trajectory text has
242
   heuristic, never as a quoted episode. Server-side consolidation over thread
243
   events (#51) recombines already-redacted fragments; raw trajectory text has
212 244
   no path into a candidate.
213
3. **An explicit tier decision** — the owner of the originating scope signs
214
   the candidate (or a consent engram the candidate references) that names
215
   the tier. Redaction is necessary but not sufficient: a perfectly redacted
216
   fact about an owner's project is still the owner's fact. Default is
217
   `dark`; silence never publishes. This mirrors the trace-upload default
218
   (`owner_only`) and the thread default (`dark`).
245
3. **An explicit tier decision** — the owner of the originating scope names
246
   the tier on the write, or on a consent record the candidate references.
247
   Redaction is necessary but not sufficient: a perfectly redacted fact about
248
   an owner's project is still the owner's fact. Default is `dark`; silence
249
   never publishes. This mirrors the trace-upload default (`owner_only`) and
250
   the thread default (`dark`).
251
252
The re-base raises the stakes on this gate rather than lowering them. On the
253
local ledger, an owner who never synced kept a candidate on one disk by
254
default. In the cloud store, every write reaches the server, so the tier
255
field is the only thing standing between an account-scoped row and the shared
256
bucket. The default must be enforced at the write, not assumed from the
257
absence of a sync.
219 258
220 259
### 5.2 What each tier means for memory
221 260
222
| Tier | Effect on the engram |
261
| Tier | Effect on the row |
223 262
| --- | --- |
224 263
| `dark` | Never leaves the owner scope. Not a system memory. The default. |
225
| `pulse` | Existence, slug, and content digest may sync; the value may not. Useful for corroboration counts ("three owners report this pattern") without content. Not recallable as a system memory. |
226
| `ledger` | Value and metadata distribute. The floor for a system memory. |
264
| `pulse` | Existence, slug, and content digest may enter the shared bucket; the body may not. Useful for corroboration counts ("three owners report this pattern") without content. Not recallable as a system memory. |
265
| `ledger` | Body and metadata are readable by every account. The floor for a system memory. |
227 266
| `glass` | `ledger` plus every evidence ref resolves publicly. |
228 267
229 268
A candidate that cites `pulse` evidence can be admitted — the steward
230
verifies against the digest and the owner's consent engram — but admitted
231
memories should prefer `glass` evidence, and the admission event records
232
which tier of evidence it verified.
269
verifies against the digest and the owner's consent record — but admitted
270
memories should prefer `glass` evidence, and the admission record notes which
271
tier of evidence it verified.
233 272
234 273
## 6. Transport
235 274

@@ -250,6 +289,40 @@ written. The paragraphs below are kept as the superseded design rather than

250 289
deleted, because the decisions on top of the seam still describe what the
251 290
cloud path has to provide.
252 291
292
### 6.1 What the channel is now
293
294
The channel is the openagents.com server. System memories, admission records,
295
challenges, and refutations are rows in the one memory store, read by the one
296
query recall already runs; every client — CLI, web, and API — reaches the
297
shared bucket through the same endpoints it uses for its own account's
298
memories. Distribution is a query, not a sync protocol, so it needs no build
299
issue of its own.
300
301
Three decisions from the superseded design survive, restated:
302
303
- **Stored in the clear, not owner-encrypted.** A system memory is shared by
304
  definition, so its body is stored as redacted plaintext. The tier decision
305
  (section 5) happens before the write; the store never decides visibility.
306
- **One bucket, one query.** `bucket: system` is the whole namespace. No
307
  separate table, no separate poll, no side door — the same rule the single
308
  relay filter stated.
309
- **Authorization at the write, not verification at ingest.** A single trusted
310
  server authenticates the writer and enforces the steward role directly, so
311
  there is no signature to check and no forged status to defend against. What
312
  remains is authorization: who may write an admission record, a refutation,
313
  or a superseding row (sections 4 and 7.3).
314
315
One decision does not survive. **Local-first no longer holds.** The seam
316
promised that a relay being down cost freshness, not correctness, because the
317
store was local and recall read it in-process. With the store in the cloud,
318
recall happens server-side inside the request that needs it, so a server the
319
client cannot reach is a turn without memory — the same as a turn without any
320
other server capability. Recall still degrades to silence rather than to an
321
error, and that acceptance criterion stands; the availability claim behind it
322
does not.
323
324
### 6.2 The superseded design
325
253 326
The superseded design read: distribution rides the engram sync seam and
254 327
nothing else; the real Nostr transport behind `EngramTransport`, built on
255 328
`nostr-effect`, is the same transport system memories use; a system memory

@@ -282,63 +355,81 @@ Decisions on top of that seam:

282 355
283 356
### 7.1 Surfacing
284 357
285
System memories surface on the #51 rails: the per-prompt harness retrieval
286
ranks the projected store against the incoming message and attaches the top
287
memories above a floor as a bounded note. The note names the bucket, so a
288
session can weigh "the network learned" differently from "you asked me to
289
remember":
358
System memories surface on the #51 rails: server-side recall inside
359
`POST /api/v1/responses` ranks the shared bucket against the incoming input
360
and attaches the top memories above a floor to the model context as a bounded
361
note. The note names the bucket, so a session can weigh "the network learned"
362
differently from "you asked me to remember":
290 363
291 364
```
292 365
[From memory: (system, as of 2026-08-25, admitted) A 402 from the inference
293 366
gateway usually means…]
294 367
```
295 368
296
Only memories whose projected status is **admitted** and unchallenged (or
369
Only memories whose derived status is **admitted** and unchallenged (or
297 370
challenged and refuted — section 7.3) are eligible. Candidates, rejected
298 371
memories, and memories with an open challenge never surface.
299 372
373
The system bucket is the one place recall crosses an account boundary by
374
design: an admitted row written by one account is read into every account's
375
turn. That is the point of the bucket, and it is also the sharpest thing the
376
re-base introduces, because account scoping is the property the rest of the
377
memory store enforces. The eligibility filter above is what replaces the
378
scope predicate for this bucket, so it belongs in the query, not in a later
379
application-side filter.
380
300 381
### 7.2 Per-source caps
301 382
302 383
Ranking must not let one adversarial writer dominate recall. Two
303 384
deterministic caps apply after scoring, before packing:
304 385
305
- **Per-note cap:** at most **1** system memory per author pubkey in a
386
- **Per-note cap:** at most **1** system memory per writing account in a
306 387
  single note, and at most **2** system memories per note total (matching
307 388
  the knowledge-base note limit — more is noise, not context).
308 389
- **Per-pool cap:** in the ranked candidate pool for a message, at most
309
  **25%** of slots from a single author, enforced by a stable round-robin
310
  over authors in rank order. Ties keep the existing deterministic
390
  **25%** of slots from a single account, enforced by a stable round-robin
391
  over accounts in rank order. Ties keep the existing deterministic
311 392
  tie-breaks, so equal inputs still give equal notes.
312 393
313 394
The caps are recall-side, not admission-side, on purpose: admission is the
314
gate on truth, caps are the gate on volume, and an attacker who passes the
315
first still cannot win by flooding.
395
gate on truth, caps are the gate on volume, and a writer who passes the first
396
still cannot win by flooding.
397
398
The re-base narrows what the caps defend against without removing the need
399
for them. A single trusted server means no anonymous publisher and no forged
400
attribution, so the adversarial case shrinks to accounts the operator has
401
already admitted claims from. What the caps still buy is the ordinary case:
402
one prolific or one systematically wrong writer should not own a note, and
403
the bound should hold deterministically rather than by good behavior.
316 404
317 405
### 7.3 Challenge and refutation
318 406
319
Disagreement is a first-class event, not an edit war:
407
Disagreement is a first-class record, not an edit war:
320 408
321
- **Challenge.** Anyone may sign an engram with slug
322
  `chl:<target-event-id>`, a `sourceEventRefs` entry
323
  `{ eventId: <target>, role: "challenge" }`, and a value stating the ground.
324
  A challenge carrying its own `evidenceRefs` is an **evidenced challenge**;
325
  one without is recorded but does not change recall.
409
- **Challenge.** Any account may write a row with slug `chl:<target-id>`, a
410
  source ref `{ ref: <target>, role: "challenge" }`, and a body stating the
411
  ground. A challenge carrying its own evidence refs is an **evidenced
412
  challenge**; one without is recorded but does not change recall.
326 413
- **Effect.** An open evidenced challenge suspends the target from recall
327 414
  (section 7.1) until resolved. This is the fail-safe direction: a contested
328 415
  claim silently absent is cheaper than a poisoned claim silently present.
329
- **Resolution.** A steward resolves by signing either a **refutation** of
330
  the challenge (slug `ref:<challenge-event-id>`, role `"refutation"`,
331
  restoring the target) or a **superseding event** on the target's slug
332
  (correcting or tombstoning it — the existing supersession path, which
333
  stewards may exercise on any system slug). Both are signed, dated,
334
  permanent receipts; the projection derives the current state from the
335
  full set.
336
- **Rate limit.** The per-source caps apply to challenges too: one author's
416
- **Resolution.** A steward resolves by writing either a **refutation** of
417
  the challenge (slug `ref:<challenge-id>`, role `refutation`, restoring the
418
  target) or a **superseding row** on the target's slug (correcting or
419
  tombstoning it — the existing supersession path, which stewards may
420
  exercise on any system slug). Both are attributed, dated, append-only
421
  receipts; the current state is derived from the full set.
422
- **Rate limit.** The per-source caps apply to challenges too: one account's
337 423
  flood of unresolved challenges cannot suspend the whole store, because an
338
  author's open evidenced challenges suspend at most the same 25% share of
424
  account's open evidenced challenges suspend at most the same 25% share of
339 425
  any recall pool; beyond that they queue for steward attention without
340 426
  recall effect.
341 427
428
Challenge survives the re-base because it never defended against the relay.
429
It exists so that a reader who finds an admitted claim wrong has a path other
430
than editing someone else's row, and so that a contested claim leaves recall
431
while a human decides. Both hold with one server and several writers.
432
342 433
## 8. The knowledge-base line
343 434
344 435
The knowledge base (#49) and system memory both put network-level knowledge

@@ -347,15 +438,15 @@ of the same claims. The line:

347 438
348 439
**The KB owns what the project has reviewed and decided. Memory owns what
349 440
the network has observed and can evidence.** A stance is editorial; an
350
engram is evidentiary.
441
memory row is evidentiary.
351 442
352 443
| | Knowledge base (#49) | System memory (this spec) |
353 444
| --- | --- | --- |
354
| Unit | Stance or doc summary | Signed engram |
445
| Unit | Stance or doc summary | Memory row |
355 446
| Authority | Human review; content checked into git | Evidence refs; steward admission receipt |
356
| Change | Regenerated from docs; edited like content | Superseded by signed events; never edited |
357
| Provenance | Source doc and review date | Author pubkey, `asOf`, evidence refs |
358
| Dispute | Doc PR | Challenge and refutation events |
447
| Change | Regenerated from docs; edited like content | Superseded by later rows; never edited |
448
| Provenance | Source doc and review date | Writing account, `as_of`, evidence refs |
449
| Dispute | Doc PR | Challenge and refutation records |
359 450
| Typical claim | "Earning is parked; on the roadmap" | "The gateway 402s when the default model is retired" |
360 451
| Note label | `[From the OpenAgents knowledge base: …]` | `[From memory: (system, …) …]` |
361 452

@@ -364,18 +455,35 @@ Two rules keep them from diverging into rivals:

364 455
- **Promotion drains memory into the KB.** When a system memory stabilizes —
365 456
  admitted, unchallenged for a sustained period, repeatedly recalled — a
366 457
  human may promote it to a KB stance through the normal docs path. The
367
  promotion supersedes the engram with a tombstone whose value names the
368
  stance, so the claim has exactly one live home.
458
  promotion supersedes the row with a tombstone whose body names the stance,
459
  so the claim has exactly one live home.
369 460
- **The KB wins collisions at recall.** When one message would attach both a
370
  KB hit and a system memory covering the same claim, the harness attaches
371
  the KB hit and drops the memory. Reviewed beats accumulated whenever both
372
  speak; memory's job is to cover the ground review has not reached yet.
461
  KB hit and a system memory covering the same claim, the attached context
462
  carries the KB hit and drops the memory. Reviewed beats accumulated
463
  whenever both speak; memory's job is to cover the ground review has not
464
  reached yet.
465
466
The re-base opens a seam under the second rule. The knowledge base is
467
retrieved harness-side in the client, from a corpus compiled into the plugin
468
at build (#49), while memory recall now runs server-side inside
469
`POST /api/v1/responses`. The two rails no longer meet in one process, so
470
"the KB wins" has no single place to be decided. The rule is unchanged; its
471
enforcement point is now an open choice, and the build issue (#65) owns it.
472
Two shapes are available: the client suppresses a returned memory note when
473
its own KB hit covers the same claim, or the request carries what the KB
474
would attach so the server can drop the memory before it reaches the model.
475
The first keeps the KB where it is and costs a returned-then-discarded note;
476
the second needs a field on the request and makes the server the only place
477
the note is assembled.
373 478
374 479
## 9. What this spec deliberately excludes
375 480
376
- **Decentralized admission governance.** The steward allowlist is the
377
  bootstrap; broadening it is future governance (section 4.3) and blocks
378
  nothing here.
481
- **Peer-to-peer distribution.** Dropped with the substrate (section 6). #63
482
  is closed as not planned. Nothing in this spec requires a relay, and
483
  reviving one would be a new decision, not a resumed task.
484
- **Decentralized admission governance.** A single trusted server holds the
485
  steward role; broadening the set is future governance (section 4.3) and
486
  blocks nothing here.
379 487
- **Cross-owner learned-memory sharing below `ledger`.** `pulse`-tier
380 488
  corroboration counting is sketched (section 5.2) but not required by any
381 489
  build issue; it lands only if a concrete need appears.

@@ -387,19 +495,26 @@ Two rules keep them from diverging into rivals:

387 495
388 496
## 10. Build order
389 497
390
The follow-up issues, each citing its section as the contract:
391
392
1. **Event shape and admission pipeline** — companion `v2` with the `system`
393
   block, the three new source roles, admission events, steward-allowlist
394
   verification, projection of admission status (sections 3-4).
395
2. **Challenge and refutation events** — event shapes, suspension semantics
396
   in the projection, steward resolution paths (section 7.3).
397
3. **Distribution on the engram Nostr sync** — the `system-memory` relay
398
   namespace on the real transport, ingest verification, merge-and-reproject
399
   (section 6). Depends on the project-15 transport landing; adds no second
400
   channel.
401
4. **Recall integration with poisoning caps** — the system bucket on the #51
402
   rails, admitted-only eligibility, per-note and per-pool caps, the note
403
   format (sections 7.1-7.2).
404
5. **KB boundary enforcement** — collision suppression at recall and the
405
   promotion-with-tombstone path (section 8).
498
The follow-up issues, each citing its section as the contract. Each of the
499
four open issues carries a comment re-basing its scope on the cloud
500
substrate; read the comment with the body.
501
502
1. **Record shape and admission pipeline** (#61) — the system fields on the
503
   memory row, the three new record roles, admission records, the steward
504
   role check, and derived admission status (sections 3-4).
505
2. **Challenge and refutation records** (#62) — record shapes, suspension
506
   semantics in the derivation, steward resolution paths (section 7.3).
507
3. **Distribution** — dropped. The engram Nostr sync this item named went
508
   with the substrate (section 6), and #63 is closed as not planned.
509
   Distribution is a query against the shared bucket, so it needs no build
510
   issue.
511
4. **Recall integration with poisoning caps** (#64) — the system bucket on
512
   the #51 rails, admitted-only eligibility, per-note and per-pool caps, the
513
   note format (sections 7.1-7.2).
514
5. **KB boundary enforcement** (#65) — collision suppression at recall, the
515
   enforcement point the re-base left open, and the promotion-with-tombstone
516
   path (section 8).
517
518
All four depend on the #51 cloud store landing first: there is no shared
519
bucket to admit into, challenge, rank, or suppress until the `memories` table
520
and the server-side recall path exist.

This page updates live while a promote is in flight · changelog