dc5dc94d79
Multi-channel retrieval sidecar over Universal Memory Protocol: - 3-channel RRF (UMP FTS5 + Qdrant vector + knowledge graph) - ACT-R re-ranking (Anderson 1983) with access tracking - Co-occurrence graph edges (Phase 6) for dense traversal - Memory lifecycle decay (Phase 4) with per-kind confidence - MCP shim routes recall through sidecar, falls back to canonical UMP Architecture: - src/server.js HTTP sidecar on port 4380 - src/graph.js 2592-node / 111-edge graph from UMP (or +cooccur: 13k+) - src/actr.js A_i = -d*ln(age) + beta*log1p(freq) + epsilon*conf - src/access_log.js per-URN counter + last_accessed_at - src/ump-recall-mcp.js MCP shim (recall via sidecar, others passthrough) Eval results (851-record UMP corpus): - 2ch RRF over baseline: +50pp recall@10 - 3ch RRF (+graph): +60pp, 12 unique wins - ACT-R re-rank: 4/20 #1 changes, 84% top-5 retention Tests: 76/76 passing across graph (27), actr (27), access_log (28), decay (20), mcp-shim (sidecar + fallback). Run with: npm test Inspired by AIAppsAPI/adaptive-recall but built from scratch against existing DNS2 infrastructure (UMP at :4317, Qdrant at :6333, Ollama at :11434). No paid SaaS, MIT-licensed.
86 lines
2.6 KiB
Markdown
86 lines
2.6 KiB
Markdown
# UMP memory.ump.json — actual schema (verified 2026-07-12)
|
|
|
|
**File:** `/root/.openclaw/agents/main/workspace/state/ump-local/memory.ump.json`
|
|
**Format:** JSON array, 851 records
|
|
**Total records:** 851 (not 846 — was 768 in Qdrant backfill, 846 in watcher's last run; real total is 851)
|
|
|
|
## Top-level fields per record
|
|
|
|
```jsonc
|
|
{
|
|
"ump": "0.1", // schema version (string)
|
|
"id": "urn:ump:jzbhzerwqn23hfzre...", // URN string (not "urn"!)
|
|
"kind": "procedural", // see kinds below
|
|
"body": {
|
|
"subject": "...", // short title
|
|
"text": "..." // full content
|
|
},
|
|
"scope": {
|
|
"owner": "did:key:z6Mk...", // actor DID
|
|
"project": "openclaw/workspace",
|
|
"visibility": "private",
|
|
"tags": ["..."]
|
|
},
|
|
"time": {
|
|
"created": "2026-06-06T21:49:57.806Z", // ISO 8601
|
|
"modified": "...",
|
|
"observed": "...",
|
|
"valid_from": "...",
|
|
"valid_to": null
|
|
},
|
|
"lifecycle": { // NESTED, not flat!
|
|
"status": "active", // see statuses below
|
|
"confidence": 0.6 // 0.0 - 1.0
|
|
},
|
|
"superseded_by": [], // array or null
|
|
"provenance": {...},
|
|
"integrity": {...}
|
|
}
|
|
```
|
|
|
|
## Kinds (distribution)
|
|
|
|
| kind | count |
|
|
|---|---|
|
|
| procedural | 245 |
|
|
| semantic | 231 |
|
|
| identity | 152 |
|
|
| episodic | 152 |
|
|
| note | 42 |
|
|
| working | 29 |
|
|
|
|
(Total: 851)
|
|
|
|
## Lifecycle statuses (distribution)
|
|
|
|
| status | count | meaning |
|
|
|---|---|---|
|
|
| active | 708 | normal, queryable |
|
|
| candidate | 53 | pending promotion |
|
|
| archived | 42 | kept but deprioritized |
|
|
| tombstoned | 48 | deleted logically — skip in retrieval |
|
|
|
|
## Critical corrections vs spec
|
|
|
|
- Field is **`id`**, NOT `urn`
|
|
- `lifecycle.status` is **nested** in `lifecycle.status`, NOT flat `status`
|
|
- `lifecycle.confidence` is **nested**, NOT flat
|
|
- `kind` values include `note` (in addition to standard 5)
|
|
- Status values: `active`, `candidate`, `archived`, `tombstoned` (not just `active`/`archived`)
|
|
- No `topic` field — uses `scope.project` and `scope.tags`
|
|
- No `access_count` or `last_accessed_at` fields yet (would need to be added)
|
|
|
|
## Code patterns
|
|
|
|
```js
|
|
import fs from 'node:fs';
|
|
const data = JSON.parse(fs.readFileSync(UMP_FILE, 'utf-8'));
|
|
for (const r of data) {
|
|
const urn = r.id; // NOT r.urn
|
|
const text = r.body?.text ?? r.body?.subject ?? '';
|
|
const kind = r.kind; // procedural|note|semantic|working|identity|episodic
|
|
const status = r.lifecycle?.status ?? 'active';
|
|
const confidence = r.lifecycle?.confidence ?? 1.0;
|
|
const createdAt = r.time?.created ?? null;
|
|
}
|
|
``` |