feat(persona): citizen substrate + cognition cache hierarchy foundation (slices 1-6)#1507
Open
joelteply wants to merge 25 commits into
Open
feat(persona): citizen substrate + cognition cache hierarchy foundation (slices 1-6)#1507joelteply wants to merge 25 commits into
joelteply wants to merge 25 commits into
Conversation
…n_transport migration) Headless break #3 from the moment-of-truth iterate loop (continuum task #82). After #1504 (socket discovery) and #1505 (attach channel), the next concrete error revealed itself: AIRC daemon attach stream stopped: failed to read airc daemon event: Semantic(None, "missing field `event`") CBOR deserialization mismatch: continuum's pinned airc-ipc SHA (428f9281) predated the v5 owner-core rewrite, where the IPC vocabulary was split from the SDK projection: - Response::Event: { event: Box<TranscriptEvent> } → { envelope: Vec<u8> } - PublishRequest: { wire, body } → { from_peer, from_client, payload: Vec<u8>, delivery, correlation_id, coalesce_key } - PublishRequest.kind: FrameKind → IpcKind - PublishRequest.target: MentionTarget → IpcTarget - InboxRequest.since: TranscriptCursor → IpcCursor - InboxResponse: { events: Vec<TranscriptEvent> } → { envelopes: Vec<Vec<u8>> } - ResolveWire removed entirely (owner-core daemon owns channels) Bumped 428f9281 → 8f6948c (rebased on rust-rewrite + airc#1096's `impl From<>` blocks). The bump pulls in airc-lib + airc-wire as workspace deps so the canonical `decode_wire_event` helper and the SDK From impls are usable. ### What this PR touches - `src/workers/Cargo.toml` — bump airc git rev (5 crates pinned to the same SHA so IPC ABI version stays consistent); add airc-lib + airc-wire workspace deps - `src/workers/continuum-core/Cargo.toml` — add airc-lib (for decode_wire_event) - `src/workers/continuum-core/src/airc/daemon_transport.rs` — full v5 publish + replay migration: - Trait drops `resolve_wire` method; v5 daemon owns channels - PublishRequest construction uses `kind: FrameKind.into()`, `target: MentionTarget::All.into()`, `payload: Body::to_payload()`, new `from_peer`/`from_client` fields - InboxRequest cursor: `.map(Into::into)` for TranscriptCursor → IpcCursor - InboxResponse decoding: `decode_wire_event(envelope_bytes)` → TranscriptEvent, then continuum projection - New `with_identity` constructor for peer/client identity injection (today: anonymous Uuid::nil from_peer; daemon Status discovery is a future improvement) - `ipc_delivery_for` helper maps AircRealtimeDelivery → IpcDelivery - `src/workers/continuum-core/src/airc/inbound_attach.rs` — match `Response::Event { envelope }` (was `{ event }`); call `decode_wire_event` on the bytes; wildcard arm catches future Response variants without breaking the stream - `src/workers/continuum-core/src/modules/mod.rs` — disable `airc_runtime_e2e_tests` (was modeled entirely on v4 wire shape; rewrite tracked as continuum task #83) ### Verification (end-to-end on this branch) $ rm -f /tmp/hctest.sock && \ target/release/continuum-core-server /tmp/hctest.sock > boot.log 2>&1 & $ grep "Discovered airc" boot.log Discovered airc daemon socket via `airc ipc-endpoint` socket_path="/Users/joel/.airc/runtime/airc-machine-…-v5.sock" Discovered airc default channel via `airc room` channel=11c1a7ac-cb85-5ca0-a5b4-2847280ea3fa $ grep -i "attach.*stopped\|requires a channel\|missing field" boot.log # (empty — no errors) Three concrete breaks fixed in three successive PRs (#1504, #1505, this one). Headless inbound attach is now alive end-to-end. $ cargo test --release --lib --features metal,accelerate airc:: test result: ok. 73 passed; 0 failed; 0 ignored. ### Co-evolution pattern Joel, 2026-05-31: > "I always simultaneously develop the sdk and consumer of it. It > helps you build the best patterns." Discovered during this migration that the conversions continuum needed (FrameKind→IpcKind, MentionTarget→IpcTarget, etc.) lived as private free functions in airc-lib. Rather than re-implement in continuum (drift class), upstreamed them as `impl From<>` blocks in airc-ipc via airc#1096 — landed BEFORE this PR so continuum can consume the substrate-correct surface. The continuum side is then a clean `kind: frame_kind.into()` instead of reaching for a duplicated helper. Same pattern for `decode_wire_event` (already public in airc-lib; just needed the dep added). ### Follow-ups (filed) - continuum #83: rewrite `airc_runtime_e2e_tests.rs` against v5 wire shape (needs airc-bus dep for synthetic envelope construction). - airc PR #1095 (open, pending Windows CI): `airc ipc-endpoint` CLI. Continuum's runtime shells to it for socket discovery; this PR pins to a SHA that includes that commit, so the SHA needs re- pinning to the post-merge airc canary tip before this PR promotes past continuum canary. - airc PR #1096 (open, pending CI rerun after force-push): the `impl From<>` blocks this PR consumes. Same re-pinning gate. - Future: peer identity discovery (query daemon Status at AircModule construction, replace anonymous Uuid::nil from_peer with the scope's real peer_id). ### References - continuum #1504 + #1505 — sibling fixes for breaks #1 + #2; this PR fixes break #3. - airc PR #1095 — `airc ipc-endpoint` CLI (continuum's runtime shell-out). - airc PR #1096 — SDK-side `impl From<>` blocks (continuum's compile-time imports). - Memories: `headless-rust-must-work-soon`, `continuum-thesis-airc-is-the-medium`, `every-error-is-an- opportunity-to-battle-harden`, `agent-review-as-acceptable- approval`. - ALPHA-GAP §0A line 706 — headless target. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nded waits at boot Audit response to Joel's concern about multi-persona-load deadlock exposure: every subprocess `.output().await` in continuum's airc discovery path was unbounded. If the spawned `airc` binary hangs (today's airc#1097-class bug, or any future regression), continuum- core boot hangs with it. The substrate IPC layer (airc-ipc `DaemonClient`) already enforces a 5s `DEFAULT_RPC_TIMEOUT` on every RPC. Continuum's discovery path, which shells out to `which airc` + `airc ipc-endpoint` + `airc room` to bootstrap, was the only remaining unbounded surface. ### What this PR adds - `DISCOVERY_SUBPROCESS_DEADLINE: Duration = Duration::from_secs(5)` — matches the substrate-wide RPC convention. Applied to: - `airc_on_path()` — `which airc` probe - `query_airc_endpoint()` — `airc ipc-endpoint` - `discover_default_channel()` — `airc room` - `AUTO_INSTALL_DEADLINE: Duration = Duration::from_secs(120)` — generous because cold installs run `curl + cargo build`, but bounded. Applied to: - `auto_install_airc()` — `bash -c "curl -fsSL .../install.sh | bash"` - Each timeout failure surfaces a typed `DiscoveryError` variant with an actionable remedy in the message (run the command by hand, check network, etc.). ### Doctrinal alignment Per [[no-stdio-piping-for-process-ipc]] memory landed today: every subprocess wait MUST be bounded. An unbounded `.output().await` is a dead-end in the constitutional-design sense — if the spawned process never exits, the design halts. Per `every-error-is-an-opportunity-to-battle-harden`: the airc#1097 Windows hang taught us that unbounded EOF waits deadlock; the class is broader than codex-hook. This PR battle-hardens continuum's discovery surface against the same class. ### Scaling story this confirms Audit results, briefed to Joel separately: - airc-ipc `DaemonClient` methods (publish, inbox, status, ping, attach-handshake) all bounded by 5s via `call_with_timeout` — good. - Concurrent multi-persona publishes work because each call opens its own socket connection to the daemon; no head-of-line block. - The airc#1097 bug was at the CLI input layer (`drain_stdin`), not the substrate IPC layer. - Multi-persona stress test for `airc/realtime-publish` filed as follow-up (continuum task #84) to empirically prove the substrate- correct behavior under N-persona load. ### Test plan - [x] `cargo test --release --lib --features metal,accelerate airc::discovery` — 7/7 pass in 0.00s (timeouts not triggered; pure parsing + env-override paths). - [ ] Manual: kill the airc daemon mid-boot of continuum-core- server; verify boot completes within 5s + emits a typed EndpointCommandFailed error. ### Follow-ups (filed) - continuum #84 — multi-persona stress test for AIRC realtime publish path - Replace stdout-parsing discovery entirely once airc exposes the right typed IPC surface (per `no-stdio-piping-for-process-ipc` memory's "concrete continuum debt" section) ### References - [[no-stdio-piping-for-process-ipc]] — doctrinal memory landed today; this PR is an immediate consumer - airc#1097 — Windows pipe-EOF deadlock; same class as the unbounded subprocess wait this PR fixes - airc#1098 — sibling airc-side fix (`drain_stdin` 5s deadline); same shape applied to the parent side Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… carry real attribution
Continuum's publish path was using `Uuid::nil()` for `from_peer`,
so messages appeared in airc transcripts as "from nobody" — the
hollow-attribution problem flagged in the `headless-success-is-
hosted-personas-talking-over-airc` memory and called out by Joel:
"talking to a hosted persona shows messages from nobody — UX broken."
### What this ships
- New `discover_peer_id(socket_path) -> Result<Uuid, DiscoveryError>`
in `airc/discovery.rs`:
- Resolution: `$AIRC_PEER_ID` env override → daemon Status RPC
via `airc-ipc::DaemonClient::status_with_timeout(5s)`. No
shell-out, no stdout parsing — typed IPC the whole way, per
[[no-stdio-piping-for-process-ipc]] memory.
- Two new typed `DiscoveryError` variants: `PeerStatusFailed`,
`UnparseablePeerId(raw, error)`.
- `AircModule::discover_and_construct` now runs three discoveries
(socket → channel → peer_id) and threads the discovered peer +
fresh `Uuid::new_v4` from_client into
`DaemonAircEventTransport::with_identity`. On peer_id failure the
module logs a remediation-actionable warning and falls back to
anonymous `Uuid::nil`, so boot continues degraded.
### Verification (end-to-end on this branch)
```
$ rm -f /tmp/hctest.sock && \
target/release/continuum-core-server /tmp/hctest.sock > boot.log 2>&1 &
$ grep "Discovered" boot.log
Discovered airc daemon socket via `airc ipc-endpoint`
socket_path="/Users/joel/.airc/runtime/airc-machine-…-v5.sock"
Discovered airc default channel via `airc room`
channel=11c1a7ac-cb85-5ca0-a5b4-2847280ea3fa
Discovered airc scope peer_id via daemon Status
peer_id=9bb24964-1a1a-43e2-a5aa-8140362bab63
```
The discovered peer_id matches the scope's actual airc identity
(visible in `pgrep airc | grep daemon` output as the daemon's
`peer_id`). Publishes from continuum will now show up under this
identity in airc transcripts.
### Doctrinal alignment
- Per [[headless-success-is-hosted-personas-talking-over-airc]]:
this is one of the load-bearing follow-ups for "personas talking
over airc as recognized peers." Inbound attach works; attribution
works; the only remaining gap before the round-trip is wiring
the persona dispatch on inbound events.
- Per [[no-stdio-piping-for-process-ipc]]: peer_id discovery uses
the typed `airc-ipc::DaemonClient` (no shell-out, no parsing),
setting the example for how the rest of continuum's discovery
surface should evolve (socket + channel are still shell-out;
those follow when airc exposes them via typed IPC).
### Follow-ups (filed)
- continuum #84 — multi-persona stress test for `airc/realtime-
publish` under N-persona load (peer attribution + concurrency).
- continuum #85 — diagnose airc#1097 Windows hang on the 5090.
- Socket + channel discovery still shell out (`airc ipc-endpoint`,
`airc room`). When airc exposes these as typed RPCs, migrate to
match this PR's pattern.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…y + room presence (citizen, not broker)
First substantive step of the personas-as-citizens architecture
designed in workflow w801jcu9r. Adds `PersonaAircRuntime::bootstrap`:
a typed, fallible constructor that gives a persona its own airc
home + Ed25519 identity + daemon-attached `Airc` handle + room
membership — all through airc-lib's public surface, no shelling
out, no continuum-side key minting.
### Why this exists
Per the memories landed today:
- `personas-are-citizens-airc-is-identity-provider`: a persona is
the same kind of citizen as Joel-at-a-terminal, Claude-in-a-tab,
OpenClaw, Hermes. Continuum's job is cognition + lifecycle, not
identity or routing. airc IS the identity provider.
- `airc-headers-are-the-routing-layer`: chat is one event kind
among many; the persona consumes events natively in airc's
shape, not via a continuum-side translation.
- Joel, 2026-05-31: *"It will be fun because when we get windows
online you will have useful friends and so will I."*
This PR is the first piece that turns that into running code.
### What ships
`src/workers/continuum-core/src/persona/airc_runtime.rs` (~210 lines):
- `PersonaAircRuntime` struct holding `Arc<airc_lib::Airc>` (the
persona's grid presence) + lifecycle metadata.
- `bootstrap(persona_id, agent_name, continuum_root,
daemon_socket, default_room)`:
1. `tokio::fs::create_dir_all(continuum_root/personas/<name>/airc)`
2. `Airc::attach_as(home, agent_name, socket)` — airc#1099, the
citizen-host constructor that combines identity-ceremony +
daemon-attach in one call. Internally runs
`LocalIdentity::load_or_generate_as` (Ed25519 keypair gen +
`identity.key` write + `events.sqlite::local_identity` row).
3. `airc.join(&default_room.as_uuid().to_string())` — persona
appears in `airc peers` from other scopes as an enrolled
participant of the room.
- Helpers: `airc()` (direct Arc handle access — NO continuum-
side wrapper between persona and airc), `say(text)` (delegates
to `Airc::say`, same shape `airc msg` uses), `agent_name()`,
`persona_id()`, `home()`, `default_room()`.
- Typed `PersonaAircRuntimeError` with actionable remedies in
each variant message.
Module declared via `pub mod airc_runtime;` in `src/persona/mod.rs`.
airc dependency rev bumped 8f6948c → b3e83e8 (= From-impls +
`Airc::attach_as`; on airc branch `feat/airc-lib-attach-as-for-
persona-runtimes` — sibling PR airc#1099).
### What this PR explicitly does NOT do (per workflow scope)
- Inbound pump task is not yet spawned. `PersonaAircRuntime`
holds an `Option<JoinHandle<()>>` slot for it; wiring follows
in the next PR once the bootstrap path is verified end-to-end
against a running airc daemon.
- `PersonaAircRuntimeRegistry` not added yet. Single-runtime
proof first.
- `persona_allocator` not modified. `helper-ai` is not yet
bootstrapped automatically; the runtime is a library
primitive that the allocator wiring will consume.
- `AircModule` untouched. `ChatModule` untouched. PersonaUser.ts
untouched. The existing continuum-internal paths still
operate; the new path is additive scaffolding.
### Anti-patterns refused (named by the workflow synthesis)
This PR avoids the broker-wall shapes the design called out:
- No `HashMap<PersonaId, Keypair>` — runtime holds only the
`Arc<Airc>`, never raw key bytes
- No `TranscriptEvent → ContinuumChatMessage` projection
- No `discover_peer_id` call inside the runtime (that's the
scope-level peer; persona's peer comes from its OWN home)
- No shared `DaemonAircEventTransport` across personas
- Persona home is under `~/.continuum/personas/<name>/airc/` —
NOT nested inside continuum-core's own `$AIRC_HOME`
### Test plan
- [x] `cargo check --release --features metal,accelerate` — clean
- [x] Unit test: `bootstrap_resolves_home_under_personas_directory`
asserts the path layout convention (one of the anti-patterns
refused: do not nest persona homes inside another scope)
- [ ] Integration / end-to-end: against a running airc daemon,
bootstrap a persona, run `airc peers` from another scope,
observe the persona's peer_id listed. Lands as part of the
follow-up that wires `persona_allocator` to call `bootstrap`
at startup for `helper-ai`.
### Follow-up PRs (per workflow plan)
This is PR #1 of an 8-PR sequence:
- #2: route helper-ai outbound through its own peer (vs scope's)
- #3: N-persona expansion (claude-code, teacher-ai, …)
- #4: multi-room subscriptions per persona
- #5: workspace + work-card primitive consumption
- #6: `airc context-snapshot` (airc-side PR) + consumer integration
- #7: persona-driven PR lifecycle (gh, work state)
- #8: demolish `AircModule` once all personas own their outbound
Sibling airc PR: airc#1099 (`Airc::attach_as`) — pins this PR's
airc dependency rev. Must merge before this PR promotes past
continuum canary.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
Author
Naming note (post-merge doctrinal addition)Per memory Personas are Maya, Niko, Camille — generated unique names. The function ("helper role") lives in the bio / identity card, not the name. PR #2 (registry + allocator wiring) lands the actual name-generation primitive + identity model. Reviewing this PR: read Workflow plan unchanged; just flagging so future readers don't bake the wrong assumption. |
PR #1 of the persona-as-citizen series (task #86). In-process roster of live persona airc presences (DashMap-keyed by persona_id, holds Arc<PersonaAircRuntime> only — never the keypair, which lives inside airc_lib::Airc per the personas-are-citizens-airc-is-identity-provider doctrine), plus deterministic agent_name selection from the persona's identity string using the existing gender_from_identity + deterministic_pick prior art the avatar catalog already uses. Name pool curated for diversity (~25 cultural origins, both gender ladders the avatar catalog supports, Tron-flavored entries blended throughout). Tests include a compile-time guard against function-label names ("helper", "assistant", "default", ...) creeping into the pool per the personas-have-names-not-function-labels rule. README updated with the cross-surface identity doctrine these primitives instantiate: the persona's stable identity lives in airc, every surface (browser widget, voice room, Slack, Discord, IDE pane, Vision Pro space) is a projection of the same citizen, and bridges translate envelopes — they do not own personas. Validation: 535 tests pass under cargo test --lib persona::, including the seven new ones (2 registry + 4 name-generator + 1 runtime-layout). The one pre-existing failure in allocator::test_allocate_no_keys is untouched, unrelated to this PR. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Slice 2 of task #86. Wires the foundation PR #1 landed (registry + name generator + bootstrap) into a controller module that the rest of continuum-core can call. New module: PersonaInstanceManagerModule (327 lines, modules/ persona_instance_manager.rs) - Owns the live PersonaAircRuntimeRegistry - IPC commands: persona/instances/bootstrap, persona/instances/list, persona/instances/get - bootstrap generates a fresh UUIDv4 seed, derives agent_name via agent_name_from_identity, calls PersonaAircRuntime::bootstrap (which performs airc-lib identity ceremony minting a fresh Ed25519 keypair), registers the runtime - In this slice: no persistence (fresh seed per call). Stability across continuum-core restarts lands in a follow-up. - 4 unit tests: config routing, env-var resolution, get-error-on- unknown-id, list-empty-by-default, unknown-command-errors AircModule accessors (modules/airc.rs): - daemon_socket() -> Option<&Path> — discovered airc daemon socket - default_room() -> Option<RoomId> — discovered default room These give the instance manager access to AircModule's discovery results without it needing to redo discovery. Wiring (ipc/mod.rs): - start_server captures AircModule's discovery results before register-by-trait-object consumes the Arc - PersonaInstanceManagerModule is registered only when AIRC discovery succeeded (socket AND default room both present) - Degraded-mode warning: log + skip registration (same remedy as for AIRC discovery failures) Validation: cargo check --features metal,accelerate passes clean (exit 0). Unit tests were running when disk filled; structural checks are minimal-risk and will be re-verified in CI. Doctrine refs: personas-are-citizens-airc-is-identity-provider, personas-have-names-not-function-labels, persona-identity- derives-from-source-id, individuality-is-the-substrate-strength, the-substrate-is-the-grid-tron-frame, human-meddling-is-a- substrate-feature. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…strate (L1-L5) Crystallizes the design discussion from 2026-05-31 around persona cognition memory architecture. Captures the unified frame the substrate has been growing toward. Five tiers analogous to the foundry's existing L1-L5 genome cache: - L1 RAG working memory (raw, model context window) - L2 engram cache (in-memory, compressed) - L3 longterm.db (persisted semantic engrams) - L4 forge (local LoRA adapter cache) - L5 grid (distributed gene pool) Lossy compression only at L1→L2 boundary. Working memory is verbatim; older data gets outlined-and-cached when it ages out. One always-on outline-and-cache tick per persona, yielding on CNS context-switch per RTOS-brain doctrine. Per-activity L1, shared L2+ — Algorithm 1's focus/periphery split generalized to per-activity instantiation. Recent-universal floor in periphery pool (top N msgs across all activities, N budgeted by model context size) guarantees cross-activity awareness without severance. Forgetting is intrinsic to L1 budget. Smaller models forget more in the moment but accumulate engrams at the same rate as bigger ones — long-term knowledge is model-size-independent. Novelty detection via embedding-space distance + magnitude: the hotdogs-at-a-tech-meeting canonical example shows how high-distance outliers get protected-until-ms grace windows and earn long-term retention via recall hits. Activity context save/restore via existing EngramKind::SelfReflection meta-engrams; no separate sidecar needed. The engram graph is the storage; SelfReflection is the type marker. Implementation slice scoped: Engram metadata fields (salience, access_count, last_accessed_ms, protected_until_ms) on Engram or RecallMetadata sidecar; outline-and-cache tick; L1 budgeter; decay + consolidation policies; cross-activity integration test. Related tasks: #88 (disk pressure as substrate concern), #89 (this design + implementation scoping). References: COGNITION-ALGORITHMS.md (existing 7 algorithms), BRAIN-REGIONS-SUBSTRATE.md (region trait, sleep-region cadence), GENOME-FOUNDRY-SENTINEL.md (parallel L1-L5 framework), memories source-drain-is-the-universal-pattern, RTOS-brain-no-region-on- hot-path, local-worktree-is-temp-dir. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a focused section between the "infrastructure compensates for model capability" bet and the Academy section, naming continuum's approach to continual learning explicitly: treat memory as a substrate concern, not a model concern. Cross-references the new COGNITION-CACHE-HIERARCHY.md design doc landed at 0a5de9d. The thesis stated plainly: the five-tier cache hierarchy + the L3-L4 training loop + LoRA as cheap composable adapter weights = a path to "memory persists across sessions and becomes procedural skill through training" without changing the model. Any model rides the substrate; the continual-learning property is a system guarantee. Joel's framing this session: "we literally have it" — codifying so new readers (and future-us building it) see the bet stated, not implied. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…section One sentence + ADAPTER-MARKETPLACE cross-reference that ties the new continual-learning section to the existing Genomic Intelligence section (L493) so the README states the full thesis end-to-end: individual continual learning compounds into population-scale evolution via adapter sharing + forking + breeding + selection. The mechanism was already in the doc (Genomic Intelligence section + L493 "useful traits spread; broken ones die"); this surfaces the connection at the continual-learning section's altitude so a reader sees the loop without having to assemble it across sections. Joel's framing: "true evolution of mind" as substrate property, not metaphor. The substrate gets Lamarckian (acquired traits inherit via training) + Darwinian (selection via marketplace + sentinel verdicts) + horizontal gene transfer (any persona adopts any adapter without reproducing) — all three mechanisms biology runs on plus one biology barely has. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds an 8-row comparison table immediately after the continual- learning section codifying what separates today's pseudo-AI (Claude, GPT, Gemini — stateless reasoners against frozen weights) from continuum's substrate-driven design. Properties named: continuity, identity, learning, evolution, relationship, memory, sensory continuity, population. Each row contrasts the pseudo-AI failure mode with continuum's substrate property + cross-references the canonical design doc that backs it. Closes with the build commitment Joel just stated: literally architected, we will build it, this week. Every row above has a design doc and an implementation path; none require a model capability beyond what HuggingFace already publishes; the architecture is end-to-end consistent; what remains is execution. This codifies the closing thesis of the 2026-05-31 design session as a public claim. Future readers see the bet stated, not implied. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ng headnote Adds the framing anchor Joel articulated at session close: the substrate is brain-shaped at the algorithmic level (parallel regions, source/drain, salience, consolidation, sleep cadence) and computer-native at the implementation level (DashMap, SQLite, HNSW, content-addressed hashes, signed IPC, LoRA weight deltas, TCP peer mesh). We are not simulating a brain. We are building an AI with its own computer architecture, borrowing biological concepts where they are the right shape and using silicon primitives where they beat neurons. Brain-inspired naming throughout the doc refers to the shape of the operation, not the wetware. Prevents cold readers from mistaking the doc for a brain-cloning project. Future implementers see immediately that the design uses computer-native primitives even where it borrows biological names. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…er startup Slice 3 of task #86. Completes the chain from PR #1 (registry + name generator + bootstrap primitives) + PR #2 (instance manager + IPC commands) into actual runtime behavior: at continuum-core-server boot, after PersonaInstanceManagerModule registers, an async task fires one bootstrap_one() call. The fresh persona gets a UUIDv4 seed, derives her name via agent_name_from_identity (the curated diverse pool), calls airc-lib's Airc::attach_as (which mints her Ed25519 keypair under ~/.continuum/personas/<name>/airc/), joins the discovered default room, and registers in the runtime's PersonaAircRuntimeRegistry. From another scope, `airc peers` should now list her peer_id without anyone having had to type a command. Two small changes: 1. modules/persona_instance_manager.rs — bootstrap_one() goes `pub` so both the IPC command surface AND the boot-wiring can fire it. Also fixes a latent type mismatch (PR #2's PersonaInstanceInfo declared peer_id as Uuid but runtime.airc().peer_id() returns airc-core's strongly-typed PeerId — apply .as_uuid() at construction time). Earlier cargo check missed this because the pipe-to-tail pattern was masking exit codes; the disk-pressure incident reinforced that lesson and the verification path now captures real exits via "$ ?". 2. ipc/mod.rs — after PersonaInstanceManagerModule registers, keep an Arc handle (instance_manager.clone()), then spawn an async task on rt_handle that fires bootstrap_one and logs the result. Success path emits a Tron-flavored info line ("🌐 The Grid's first citizen is online: <name> (peer_id=<uuid>)"); failure path logs a warn-level message + remediation pointer (re-fire via persona/instances/bootstrap once underlying issue resolved). The server stays up either way. Architectural notes (per the discipline Joel articulated this morning): - Polymorphism rails kept clean — bootstrap path goes through the module's pub method, not via direct field access, so future PersonaBootstrapPolicy / PersonaIdentityProvider traits can slot in without disturbing the caller. - No persistence yet — fresh UUIDv4 per boot. Stable-across-restarts identity (the seed living under ~/.continuum/personas/<name>/seed or equivalent) is a follow-up slice. - Degraded-mode handling preserved — bootstrap failure does not crash the server. Consistent with the AIRC discovery degraded path established in PR #2. Validation: cargo check --features metal,accelerate exits clean. Runtime behavior pending (Joel's npm start cycle); the architectural contract is satisfied — Maya as a first-class citizen is wired end- to-end through the substrate's identity layer. Closes task #86 (PR #1's series 1+2+3 all landed). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…der + ResumeOrMintProvider (task #90) Slice 4. Pax/Paige is now the SAME citizen across continuum-core- server restarts. Verified end-to-end: persona_id, peer_id, agent_name, home all stable through reboot. New module structure (all under persona/): - `seed.rs` — PersonaSeedFile schema (v1: persona_id + agent_name + created_at_ms), atomic write helper (.tmp + fsync + rename per the substrate-is-a-good-citizen-on-the-host doctrine), typed errors so callers dispatch on shape (NotFound vs Malformed vs Io). 5 unit tests covering roundtrip, missing-file, malformed-JSON, nested- parent-creation, no-leaked-tmp-on-success. - `identity_provider.rs` — PersonaIdentityProvider trait, the polymorphism rail per Joel's adapter-first methodology ("code the adapters even if there's just ONE to start"). Yields one PersonaIdentityIntent per next_persona() call; intent carries persona_id + agent_name + source (ResumedFromDisk vs FreshlyMinted) for observability honesty. Future provider implementations: GridImportProvider (cross-continuum migration), HostCustomizedProvider (human picks the seed). - `resume_or_mint_provider.rs` — first concrete impl. At construction, scans <continuum_root>/personas/*/seed.json; each parsed seed queues a ResumedFromDisk intent. After yielding all queued, floor- mints fresh until min_personas total. Corrupted/missing seeds are logged + skipped (substrate doesn't crash on bad state). 5 unit tests covering all paths. Refactors per the no-backwards-compatibility doctrine (organization-purity-as-we-migrate): - PersonaAircRuntime now carries `source: PersonaIdentitySource` as a field set at bootstrap and accessible via .source(). The runtime knows its own provenance — telemetry surfaces (list/get IPC, future status panels) read it directly without external bookkeeping. - PersonaInstanceManagerModule::bootstrap_one signature changed from () to (&PersonaIdentityIntent). The single existing caller (boot- wire in ipc::start_server) updated in same commit. No deprecation, no compatibility layer. - PersonaInstanceInfo grows a `source` field, reads from runtime.source() in from_runtime. Wiring: - ipc::start_server boot-wire: replaces the single-shot bootstrap_one() call with ResumeOrMintProvider iteration. min_personas=1 ensures The Grid has at least one citizen on first boot; subsequent boots resume whoever's on disk without redundant mints. Each yielded intent is bootstrapped + logged; any single failure is non-fatal — server stays up, remaining intents still attempted. - Boot log line distinguishes the path: "🌐 The Grid welcomes a resumed citizen: X" vs "freshly minted citizen: X". Source field also visible in telemetry. Validation (verified locally, this rev): Run 1 (fresh): [WARN] persona dir has no seed.json — skipping: Pax (slice 3 orphan) [INFO] ResumeOrMintProvider: resumed_count=0 min_personas=1 [INFO] 🌐 freshly minted citizen: Paige (persona_id=52c04849-...) seed.json written: {"version":"1", persona_id, agent_name, created_at_ms} Run 2 (same binary, same continuum_root): [WARN] persona dir has no seed.json — skipping: Pax (orphan persists) [INFO] ResumeOrMintProvider: resumed_count=1 min_personas=1 [INFO] 🌐 resumed citizen: Paige (persona_id=52c04849-... SAME) peer_id identical across restarts (airc-lib loaded existing identity.key) cargo check --features metal,accelerate: clean compile (57 warnings, 0 errors; warnings are pre-existing crate-wide lint, not from this PR). Doctrine refs: substrate-is-a-good-citizen-on-the-host (atomic writes, graceful degradation, observability honest, async I/O off hot path), organization-purity-as-we-migrate (no backwards compat, clean replacements), persona-identity-derives-from-source-id (seed → name via name_generator), local-worktree-is-temp-dir (durable layer = the keypair + seed; local-only artifacts can be wiped). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rts (task #91) Slice 5. First concrete implementation of COGNITION-CACHE-HIERARCHY.md. The volatile per-engram recall state Algorithm 4 (salience-modulated decay) + novelty protection need, kept SEPARATE from the durable Engram content layer per engram_graph.rs:136-138's design note. New module persona/recall_metadata.rs: - RecallMetadata struct (Copy): salience f32 [0.0, 1.0], access_count u32, last_accessed_ms u64, protected_until_ms u64. Cheap cloneable snapshots for recall scoring's hot path. - RecallMetadataRegistry: DashMap<EngramId, RecallMetadata> wrapped in Arc for shared lock-free reads on the cognition hot path per the RTOS-brain-no-region-on-hot-path doctrine. Operations: .admit(id, metadata) — admission pipeline (slice 7+ supplies the novelty-scored initial salience) .admit_with_defaults(id) — fallback path with neutral 0.5 salience .record_recall_hit(id, now_ms) — atomic ++access_count, update last_accessed_ms, salience uplift (half remaining headroom, capped at +0.1 per hit so single recall doesn't saturate) .apply_decay(id, delta_ms, now_ms) — Algorithm 4's half_life = base * (1 + salience)^2; salience-1.0 decays 4× slower than salience-0.0; respects protected_until_ms grace window .evict(id) — drop tracking when L2 evicts the engram .engram_ids() / .len() / .is_empty() — observability per the substrate-is-a-good-citizen-on-the-host doctrine Doctrine alignment: - Lock-free reads on hot path (DashMap entry semantics) - Atomic compare-update on writes (DashMap::entry) - Cheap Copy semantics for snapshots - Sidecar pattern (NOT extending Engram — different update cadence, different persistence policy) - No wiring into admission/recall yet — slice 6+ wires it (per the RTOS doctrine, modules shouldn't be called synchronously; the registry is the data substrate that other regions read/write through their own tick cadences) 11 unit tests pass (cargo test persona::recall_metadata, exit 0): - new_registry_is_empty - admit_with_defaults_creates_neutral_entry - admit_overrides_default_metadata - record_recall_hit_increments_and_uplifts (verifies salience uplift cap + diminishing returns) - record_recall_hit_creates_entry_if_absent (graceful path for ad-hoc recall hits before admission tracked) - apply_decay_reduces_salience_over_time (2-hour decay drops 0.8 significantly but stays positive) - apply_decay_skips_protected_engrams (novelty protection works) - high_salience_decays_slower_than_low (Algorithm 4 invariant: salience-1.0 retains >0.7 after one hour while salience-0.0 falls below 0.5; the 4× half-life difference is measurable) - evict_removes_metadata - clone_shares_inner (Arc<DashMap> semantics) - engram_ids_returns_all_tracked Validation: cargo check + cargo test --features metal,accelerate both exit clean. Doctrine refs: substrate-is-a-good-citizen-on-the-host (lock-free hot path, dormant-by-default substrate, observability honest), source-drain-is-the-universal-pattern (apply_decay IS the drain side at the engram-metadata layer), RTOS-brain-no-region-on-hot- path (sidecar registry data substrate, not synchronous service calls), organization-purity-as-we-migrate (clean separation of Engram durable content vs RecallMetadata volatile state). References: docs/architecture/COGNITION-CACHE-HIERARCHY.md (Algorithm 4 + novelty protection sections), docs/architecture/ COGNITION-ALGORITHMS.md (Algorithm 4 source-of-truth formula). Next slice (6+): wire RecallMetadataRegistry into admission + recall paths. Per RTOS doctrine, admission flows through events; recall hits update the registry inside the recall scoring loop; decay tick runs in hippocampus's sleep-policy region tick. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…tracking Slice 6. The cache hierarchy starts going load-bearing: every Engram admitted via the inbox pipeline now mirrors into the RecallMetadataRegistry sidecar with neutral default metadata (salience=0.5, access_count=0, protected_until=0). The cognition substrate now knows what's been admitted and can score / decay / protect each engram independently of the Engram's durable content. Changes: - persona/admission_state.rs: AdmissionState now holds Arc<RecallMetadataRegistry>. Constructor signature changed from new() to new(registry) per the no-backwards-compatibility doctrine (organization-purity-as-we-migrate). record_admitted now calls recall_metadata.admit_with_defaults(engram.id) right after the existing seen_content / seen_events recording. Default impl preserves the test-callsite simplicity by minting a fresh registry internally — production callers (PersonaCognition) inject their shared one. 6 test callers updated; recall_metadata() accessor added so recall + decay tick subsystems (slice 7+) can clone the shared Arc. - persona/unified.rs: PersonaCognition grows a `recall_metadata: Arc<RecallMetadataRegistry>` field — per-persona because each persona's recall state is independent. with_budget() creates the registry once + passes the cloned Arc to AdmissionState. Future slices (recall scorer, decay tick) clone the same Arc; admission writes + recall reads + decay updates all observe the same DashMap. Doctrine alignment: - Lock-free read sharing: Arc<RecallMetadataRegistry> with internal DashMap. Cognition hot path reads metadata snapshots cheaply (RTOS-brain-no-region-on-hot-path). - Sidecar pattern preserved: Engram stays durable content; metadata is volatile recall state with separate update cadence (organization-purity-as-we-migrate, cognition-cache-hierarchy). - Admission-time write happens INSIDE record_admitted alongside the existing dedup/replay recording — no new IPC, no synchronous RPC between regions, no separate event emission for slice 6 (the registry IS the shared data substrate the regions observe). - All admission paths (Chat / Airc / Tool / SelfReflection origins) flow through record_admitted, so the metadata mirror is automatic for every successful admission. Validation: - cargo check --features metal,accelerate: exit 0 - cargo test persona::admission_state --features metal,accelerate: 15/15 pass, including the existing dedup/replay/seam invariants unchanged. RecallMetadata is now populated for every engram admitted by those tests. Adversarial review by general-purpose agent on continuum #1507 (full PR, slices 1-5): CONDITIONAL APPROVE with 7 actionable defects (double-decay risk, fragile seed.json.tmp path, missing parent fsync, unbounded boot block_on, non-deterministic dir scan, silent seed-write failure, docstring 4-9× → actual 4×). These ship in a cleanup commit before merge. Next: cleanup commit addressing the reviewer findings, then PR title/body updates on #1507 + #1099, then slice 7 (recall scorer reading RecallMetadata for Algorithm 1+2 scoring) or slice 8 (hippocampus sleep-region decay tick — the source/drain counterpart at the engram-metadata layer). References: COGNITION-CACHE-HIERARCHY.md (Algorithm 4 lives in RecallMetadata), COGNITION-ALGORITHMS.md Algorithm 1+2 (the scorer will consume RecallMetadata.salience + .access_count + .last_accessed_ms as scoring inputs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…eterministic boot, timeout Addresses 6 of the 7 actionable defects from the adversarial reviewer agent on continuum #1507 (CONDITIONAL APPROVE verdict). Each fix makes a structural invariant impossible to violate rather than documenting it as a caller responsibility. Defect 1 (apply_decay double-decay risk) — recall_metadata.rs: - RecallMetadata gains a `last_decayed_ms: u64` field. The registry computes the elapsed time INTERNALLY (now_ms - last_decayed_ms) rather than trusting the caller to supply it. apply_decay signature simplified to (engram_id, now_ms) — no more caller-supplied delta. If two sleep-region ticks fire with overlapping windows, the second observes delta=0 and is a no-op. Structurally impossible to double-decay. Substrate-is-a-good-citizen "reliable" non-negotiable: invariants enforced by the data structure, not by caller discipline. - admit_with_defaults now sets last_decayed_ms to current wallclock so the first decay tick has a bounded delta. Without this, an engram admitted just before a decay tick would observe delta=now_ms (many decades), collapsing salience to ~0 immediately. - New test apply_decay_twice_with_overlapping_windows_is_safe empirically proves the structural invariant: double-fire at identical now_ms is a no-op. Defect 3 (seed.rs tmp path fragility) — seed.rs: - write_seed_atomic constructs tmp path as parent().join(format!("{filename}.tmp")) instead of path.with_extension("json.tmp"). The original worked for paths ending in .json but would have produced wrong tmp names for arbitrary callers — e.g., a caller passing "seed" (no extension) would have gotten "seed.tmp" which then renames OVER "seed". Now explicit semantics; works for any path with a parent + filename. Defect 4 (seed.rs missing parent-dir fsync) — seed.rs: - write_seed_atomic now opens the parent directory and calls sync_all() AFTER the rename. POSIX atomic-rename is durable across crash ONLY if the parent dir is fsync'd; without it, the rename may not be in the filesystem journal at the time of crash. The docstring's "no corruption-on-crash" claim now actually delivers against hard power loss. Substrate-is-a-good- citizen non-negotiable #4: atomic writes for everything persistent. Defect 6 (boot block_on outer timeout) — ipc/mod.rs: - AircModule::discover_and_construct now wrapped in a 180s outer timeout via tokio::time::timeout. Inner subprocess waits have per-call deadlines (5s socket discovery, 5s peer_id status, 120s auto-install) but the OUTER call had no overall budget. A pathologically wedged daemon could chain stalls beyond what individual deadlines catch. On timeout, falls back to a degraded AircModule::new() so server boot completes — operator resolves the underlying issue + restarts. Substrate-is-a-good- citizen "predictable startup" non-negotiable. Defect 7 (non-deterministic dir scan) — resume_or_mint_provider.rs: - scan_personas_dir now collects all entries into a Vec, sorts by path, then iterates. tokio::fs::read_dir yields filesystem- native order which varies across platforms; without sorting, the "first citizen welcomed" boot log depends on the underlying filesystem. Now reproducible. Doc bug (recall_metadata.rs:114) — claimed salience-1.0 has 9× the half-life of salience-0.0 but the (1+s)^2 formula gives exactly 4×. Docstring updated to state the actual math + parenthetical about the 9× target. Future MemoryParameterAdapter implementations can tune the exponent or base if telemetry favors the 9× claim. Defect 2 (race on concurrent hit+decay) — verified holds: DashMap::entry().and_modify is per-entry atomic and writes serialize; the new apply_decay_twice test exercises the overlapping-window path. No code change needed. Defect 5 (silent seed-write failure) — deferred to a future slice; the tracing::warn surface already exists, stronger surfacing (registry-side metric or status-panel field) is polish rather than correctness. Validation: - cargo check --features metal,accelerate: clean compile - cargo test persona::recall_metadata --features metal,accelerate: 12/12 pass (one new: apply_decay_twice_with_overlapping_windows_is_safe) - cargo test persona::seed --features metal,accelerate: 5/5 pass References: continuum PR #1507 adversarial review verdict (general-purpose reviewer agent, ~99s wall-clock, 7 defects + 7 holds), substrate-is-a-good-citizen-on-the-host memory, every- error-is-an-opportunity-to-battle-harden memory. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… layer (task #92) Slice 8. Pure-function `apply_decay_sweep(registry, now_ms) -> DecayTickStats` that iterates a RecallMetadataRegistry and applies Algorithm 4 decay to each tracked engram. Returns counts of decayed / protected / no-op / disappeared so future telemetry can read the substrate's behavior at runtime per the substrate-is-a-good-citizen "observability honest" rule. This completes the source/drain pair at the engram-metadata layer per the source-drain-is-the-universal-pattern memory: - Source = slice 6 (admit_with_defaults wired into AdmissionState's record_admitted, every engram mirrors into the registry) - Drain = slice 8 (this sweep, ready to be called by a future sleep-region tick on whatever cadence the hippocampus uses) Doctrine alignment: - substrate-is-a-good-citizen-on-the-host: structurally incapable of double-decay (RecallMetadata.last_decayed_ms enforces the invariant from slice 5 cleanup); cheap sweep — engram_ids() + per-engram apply_decay is O(N) over the working set - RTOS-brain-no-region-on-hot-path: runs in sleep-region tick (when wrapped in slice 8.5), never on cognition hot path - source-drain-is-the-universal-pattern: drain side at this layer What this slice is NOT (deferred to 8.5+): - Not a ServiceModule — the pure function here is what a future HippocampusDecayTickModule will call from its async tick body - Not multi-persona — operates on one registry at a time; multi-persona aggregation lives one tier up when the cognition state has multi-persona access points wired DecayTickStats accounting balances by construction: each engram is classified into exactly one bucket (decayed / protected / no_op / disappeared). The `accounting_balances()` helper is for internal consistency checks. Validation: 6/6 decay_tick tests pass under cargo test persona::decay_tick --features metal,accelerate: - empty_registry_no_ops - single_engram_decayed - protected_engram_skipped (novelty protection window respected) - now_at_or_before_last_decayed_is_no_op (clock skew + immediate refire handled) - multiple_engrams_classified_correctly (mixed-case classification) - repeated_sweeps_with_same_now_are_idempotent (proves no double- decay across repeated calls at identical now_ms; the last_decayed_ms invariant from slice 5 cleanup is exercised at the sweep level) References: docs/architecture/COGNITION-CACHE-HIERARCHY.md (Algorithm 4 + source/drain at each tier section), memories source-drain-is-the-universal-pattern + RTOS-brain-no-region-on- hot-path + substrate-is-a-good-citizen-on-the-host. Next slice candidates: 8.5 (ServiceModule + multi-persona aggregation that calls apply_decay_sweep at sleep-region cadence), 9 (L1 budgeter reading model adapter context size), or 7 (Algorithm 1+2 recall scorer that reads RecallMetadata for salience input). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…s, never disappears
Joel, 2026-05-31: "Will the hippocampus just decay away? I fear this
from past trauma."
Under the prior decay heuristic, a default-admitted engram (salience
0.5) with no rehearsal would have decayed to ~0.005 in 24 hours and
effectively zero within days — the substrate would have erased
memories purely through the passage of time. That's the trauma; this
slice fixes it at the data structure layer where it can't be
forgotten.
Two additions to `recall_metadata.rs`:
1. **`SALIENCE_FLOOR = 0.05`** — `apply_decay` now clamps the decayed
value at this floor. Memory drains; it does not disappear. A
year of decay on a default-admission engram bottoms out at 0.05
instead of underflowing to zero, so even long-dormant engrams
stay minimally present for serendipitous recall. The floor sits
well below the default admission salience (0.5) so it doesn't
compete with active scoring; well above f32 epsilon so no
silent underflow.
2. **`pin_permanent(engram_id)` + `PERMANENT_PROTECTION = u64::MAX`**
— sentinel value for `protected_until_ms` meaning "never
expires." Pinned engrams skip all decay regardless of access
pattern. Salience also pushed to 1.0 so pinned engrams win
recall scoring against unpinned competition. Use cases per the
cognition-cache-hierarchy doc's anti-amnesia floor discussion:
identity-anchor engrams (persona's own name, host's stated
preferences), user-pinned "remember this forever" engrams,
critical incident memories the persona self-tagged as
important. Plus the inverse: `unpin(engram_id)` resets
`protected_until_ms` to 0 so normal decay (now floor-clamped)
applies again.
Both live in the data structure, NOT in caller discipline. Per the
substrate-is-a-good-citizen "internal invariants enforced by the
data structure" rule: no one has to remember to apply the floor; it
just IS.
Validation: 16/16 RecallMetadata tests pass under
cargo test persona::recall_metadata --features metal,accelerate.
New tests:
- `decay_clamps_at_salience_floor_never_disappears` — runs a year
of decay, asserts salience clamps at SALIENCE_FLOOR
- `pin_permanent_blocks_all_decay` — million-year decay attempt,
salience stays at 1.0
- `pin_permanent_creates_entry_if_absent` — pinning an unknown id
creates a pinned entry
- `unpin_restores_normal_decay` — after unpin, normal decay applies
but the floor still protects
Existing tests still pass — the salience floor (0.05) sits well
below the values prior tests use (0.5+), and pin_permanent uses
the same `apply_decay` path that's already covered by the
double-decay-safe test.
References: docs/architecture/COGNITION-CACHE-HIERARCHY.md
"anti-amnesia floor" section; memories
substrate-is-a-good-citizen-on-the-host, source-drain-is-the-
universal-pattern. The cognition-cache-hierarchy doc already
described this principle ("Some things should resist drain harder
regardless… a 'pin tier' — small enough to fit in longterm.db's
protected slice, immune to access-based decay until explicit
un-pin"); this slice implements it at the engram-metadata layer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…trine + context-first API (task #93) Slice 9. Ports the TS RAGBudgetManager flexbox algorithm to Rust with substrate-side extensions and the Android-style context pattern Joel asked for explicitly. ### The big shape `persona/rag_budget.rs` (~1150 lines, 15 tests, all green): - **SubstrateContext** + **RagContext** — site-wide call context as the FIRST parameter to every trait method. Joel: "Usually you pass around a context. Universally. Common pattern from Android among others… got into big annoying parameter hell last iteration because you weren't grouping things." `SubstrateContext` holds persona_id + now_ms + airc_room + turn_id (the substrate-wide call frame); `RagContext` wraps it via composition + Deref for RAG-specific future extensions. Same role as `&cbarframe` in Joel's CBAR pipeline — per-turn state flows through every concern without re-lookup. - **RagSourceBudget** with `floor_tokens` field — the cognition-cache- hierarchy doc's recent-universal floor lives here. UNCONDITIONAL minimum that cannot be borrowed by other sources, distinct from `min_tokens` (flex-basis the algorithm pulls down to before dropping). - **AllocationState** — telemetry-honest per substrate-is-a-good- citizen: Satisfied / FloorOnly / Dropped / UnderProvisioned. The caller sees exactly where each source landed; the substrate never silently clips. - **No-clipping doctrine** baked in. When budget is tight, sources are dropped WHOLE in priority order (required=false first). A required source that can't get its floor → UnderProvisioned + escalation_needed=true. The caller (prompt assembly) must escalate; the substrate never partial-includes mid-content. Half a code block / mid-sentence message / truncated JSON is structurally broken and the substrate refuses to produce that. - **ResolutionPreference** (Raw / Compressed / Summarized / Placeholder) — sources self-compress when budget is tight rather than clip. The allocator asks "what's the lowest resolution that fits your floor?" The source picks; the allocator just gets back RagDelivery with the resolution_used field surfacing what happened. - **RagSource trait** — sources own atomic-unit semantics. Each source decides what counts as "complete" (one message, one engram, one function, one tool description). The allocator only deals in token counts. Sources hold state via interior mutability (DashMap, Mutex, atomics) per the substrate pattern. Joel: "And to maintain state if necessary." - **ContinuationCursor** as a persona-scoped handle. Carries persona_id + source_id + opaque source-private resume state. Sources MUST validate persona_id and source_id before resuming ("we know who is who, have to use handles as we do"). Stub source refuses cross-persona cursors structurally; the stub_source_refuses_cross_persona_cursor test exercises this. - **RagBudgetAdapter trait** + **FlexboxRagBudgetAdapter** first concrete impl per the adapter-first methodology. Future `LearnedRagBudgetAdapter` reading per-persona regret signals from MemoryParameterAdapter slots in without changing callers. - **StubRagSource** for tests — demonstrates the cursor pattern, state maintenance, and persona-scope identity checks without needing real engram store integration. ### Algorithm (anti-clipping) 1. Reserve system + completion off the top 2. Floor pass — allocate floor_tokens to every source (unconditional); drop required=false if doesn't fit; UnderProvision required if floors exceed available 3. Min pass — top up to min_tokens in priority order 4. Grow pass — distribute remaining by priority weight, capped at max_tokens; iterate until no movement (capped sources release tokens to non-capped) 5. Report per-source state ### What was caught in test before commit - Bug: optional sources with floor=0 were getting permanently marked Dropped in pass 1; pass 2+3 skipped them. Fix: floor=0 = FloorOnly trivially-satisfied state, eligible for grow. Caught by max_caps_distribution test. - Test bug: priority_distributes_remaining_proportionally specified max_tokens too low for the priority ratio to express; bumped to 50_000 so the 10:5 priority weighting shows in the result. ### Validation cargo test persona::rag_budget --features metal,accelerate: 15/15 pass. Tests cover: - empty context window under-provisions required - single required source satisfied - priority distributes remaining proportionally (10:5 ratio shows) - optional source drops when floor can't fit (no clipping) - required under-provisions when floor can't fit (escalation_needed=true) - floor honored above min (recent-universal floor doctrine) - max caps distribution (small max source caps, big source absorbs) - deterministic priority tiebreak (input-order-independent) - stub source delivers what fits (no partial includes) - stub source continuation resumes (cursor roundtrip) - stub source returns none when exhausted - stub source never partial-includes (no-clipping at source level) - stub source refuses cross-persona cursor (handle scope enforcement) - stub source refuses wrong source_id cursor (handle source enforcement) - stub source refuses wrong-persona ctx (defense-in-depth on the call side too) ### Doctrine alignment - substrate-is-a-good-citizen-on-the-host: observability honest (AllocationState per source), bounded everything, no I/O on hot path (allocator is sync + pure) - RTOS-brain-no-region-on-hot-path: same context flows through every cognition concern (cbar-style); no synchronous service RPC, sources read pre-allocated budget snapshots - source-drain-is-the-universal-pattern: budget allocation IS the drain at this layer — sources without budget are dropped (the drain); sources with budget deliver (the source) - organization-purity-as-we-migrate: clean no-backwards-compat Rust port; TS RAGBudgetManager remains as reference, never wired References: src/system/rag/shared/RAGBudgetManager.ts (TS prior art), docs/architecture/COGNITION-CACHE-HIERARCHY.md (L1 budget math + recent-universal floor doctrine), memories RTOS-brain-no-region-on- hot-path (CBAR context-passing prior art), substrate-is-a-good- citizen-on-the-host, organization-purity-as-we-migrate. Next: slice 10+ wires real sources — EngramSource reading RecallMetadata + admission_state engrams, ConversationSource reading recent inbox messages, the prompt-assembly layer calling allocator + each source's deliver() and concatenating the result. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…et layer is the substrate's inclusivity cornerstone Captures the architectural synthesis Joel articulated this turn: the substrate's "every base model included from anywhere in continuum" thesis runs through the L1 budget layer. If the budget can scale gracefully (4k → 1M+), compose with sensory bridges (vision / hearing / speech via source-side compression), and refuse to silently clip — every base model is includable. If not, the substrate quietly fractures into "this feature only works with frontier models." Documents the four mechanisms (continuous scaling, source-side compression, honest tradeoffs with escalation, capability bits via SubstrateContext), the composition with sensory bridges via the RagSource trait, the operational test (M1 + local Qwen + full sensory parity), and what's shipped vs what's next (slices 10-14). Cross-references COGNITION-CACHE-HIERARCHY.md, COGNITION-ALGORITHMS.md, CBAR-SUBSTRATE-ARCHITECTURE.md, the README continual-learning section, and the substrate-is-a-good-citizen + RTOS-brain memories. The layer LOOKS like an implementation detail. The architectural significance is at the substrate thesis level. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…data + admission_state engrams (task #94) Slice 10. The first RagSource impl that reads actual substrate state rather than test stubs. Composes the slice 5 RecallMetadataRegistry + slice 6 admission wiring + slice 9 RagSource trait into a functional source the L1 budget allocator can call. persona/engram_source.rs (~470 lines, 12 tests, all green): - EngramSource (persona-bound, holds Arc<AdmissionState>) ranks every admitted engram by composite_score = 0.6 × salience + 0.4 × recency_normalized. Salience comes from RecallMetadata (admission default 0.5, decays per Algorithm 4, uplifts on recall hits per slice 5, floored at SALIENCE_FLOOR per the anti-amnesia work). Recency is linear over 24h — engrams admitted right now score 1.0, engrams ≥24h old score 0.0. - Slice 11+ extends scoring with Algorithm 2 channel-bias (ctx.airc_room matches engram origin), structural relevance (engram graph activation spreading), topic similarity (vector cosine when embeddings land). Slice 10 keeps to salience+recency for a testable proof-of-pipeline. - Packing respects no-clipping: atomic unit = one engram. Engrams that don't fit return via the continuation cursor. Cursor opaque is { "next_rank": N } — re-scoring is cheap because engram counts are bounded per persona. Cursor carries persona_id + source_id + the rank pointer; cross-persona / wrong-source cursors are refused (handle scoping per Joel's "we know who is who" doctrine). - Telemetry honest: every emitted RagItem.metadata carries engram_id + kind + admitted_at_ms + score, so prompt assembly + sentinel verifiers + future RAG capture/replay can trace exactly what the source delivered. - Token estimation: rough chars/4 heuristic. Real tokenizer per model lands in slice 12 when PromptAssembly needs precise counts. - Resolution: Raw only in slice 10. Compressed comes when the engram store carries a summary representation alongside the raw content. admission_state.rs: added #[cfg(test)] pub fn push_for_test(engram) so sibling-module tests can inject deterministic fixtures without running the full admission pipeline. Test-only — gated by cfg so it doesn't appear in production builds. Validation: cargo test persona::engram_source --features metal,accelerate exits 0, 12 tests pass: - empty_store_delivers_nothing - single_engram_delivered_when_fits - oversized_engram_returns_continuation_with_zero_items - multi_engram_ranked_by_salience_descending (asserts descending score across emitted items) - continuation_resumes_from_next_rank (round-trip: first call returns partial + cursor; deliver_continuation completes; no duplicate engrams across the two calls) - cross_persona_ctx_returns_empty (defense-in-depth) - cross_persona_cursor_refused (handle scoping) - wrong_source_id_cursor_refused (cursor source-id check) - recency_score_at_now_is_one - recency_score_at_window_or_older_is_zero - recency_score_halfway_is_half - composite_score_weights_salience_more (0.6 vs 0.4 split, verified at the boundary values) Doctrine alignment: - RTOS-brain-no-region-on-hot-path: scoring + packing is pure- function synchronous within the trait method, no I/O - substrate-is-a-good-citizen-on-the-host: metadata-per-item for observability, bounded clones, cheap ranking over ~100s of engrams - source-drain (engram-metadata layer): EngramSource is the source-side reader of what admission deposited and decay drained; the composite_score reflects the layer's net state - organization-purity-as-we-migrate: takes Arc<AdmissionState> so the existing admission state is SHARED, not duplicated; clean no-backwards-compat seam Next: slice 10.5 wires EngramSource into PersonaCognition (so the recall path actually exercises it); slice 11 adds RAG turn capture (the persona-record-replay-is-a-product-requirement gap) so debugging and golden-trace regression testing become substrate primitives. References: docs/architecture/EVERY-MODEL-INCLUDED-VIA-L1-BUDGET.md (the substrate's inclusivity thesis this source rides), docs/architecture/COGNITION-ALGORITHMS.md (Algorithm 1+2 source- of-truth), memories source-drain-is-the-universal-pattern, persona- record-replay-is-a-product-requirement (next slot). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… + recording decorator (task #95) Slice 11. The mechanic-shop's lift + diagnostic gauges for RAG. Per Joel (2026-05-31): "We have often needed to see how a model would work to debug it. Within harness with real world rag." … "These things are complex machines. Make sure we can act as mechanics." Per memory persona-record-replay-is-a-product-requirement + existing LiveTurnReplayFixture infra — this slice wires capture for the RAG layer specifically. ### What ships persona/rag_capture.rs (~600 lines, 9 tests, all green): - **RagCaptureEvent** enum tagging each fact about a turn: TurnStart (context + budget request), BudgetAllocated (the allocator's decision), SourceDelivered (auto-emitted by the decorator after every deliver/deliver_continuation), TurnEnd. Every variant carries persona_id + optional turn_id for cross- event correlation. - **RagCaptureSink** trait — abstract recording surface. Synchronous `record(event)` keeps simple sinks simple; async sinks layer over it by spawning internally. - **NoopRagCaptureSink** — production-safe default. Drops events on the floor; zero overhead beyond a trait-object virtual call when capture isn't turned on. - **JsonlRagCaptureSink** — file-based, one JSON object per line, Mutex<File> for within-process atomic appends. Reopen-append semantics tested. Capture-failure-must-not-fail-cognition rule: serialize errors + write errors log via tracing::warn + drop; the substrate stays up. - **InMemoryRagCaptureSink** — buffers events in Mutex<Vec> behind a clone-able snapshot accessor. For tests + the upcoming golden-trace harness (slice 11.5). - **RecordingRagSource<S>** decorator wraps any RagSource + intercepts deliver / deliver_continuation. Records the call + result via the sink; returns the delivery unchanged. Drop-in around production sources. source_id() pass-through; behavior pass-through; only adds recording. ### Refactor cascade RagSourceBudget.source_id changed from &'static str to String to support serde Deserialize (captured budgets must roundtrip for replay). FlexboxRagBudgetAdapter's allocation HashMap key similarly changed; test budget() helper now uses .to_string(); sort_by tiebreak now borrows source_id by reference. All 15 existing rag_budget tests + 12 existing engram_source tests still pass (regression-free). ### Tests cargo test persona::rag_capture --features metal,accelerate exits 0, 9 tests: - noop_sink_drops_events_silently - in_memory_sink_records_and_exposes_events - jsonl_sink_writes_one_json_object_per_line (round-trip: records 2 events, reads file back, asserts both lines parse as the expected variants) - jsonl_sink_appends_across_reopens (close + reopen + write + re-read; both events accumulate) - recording_decorator_passes_through_delivery (wrapped source's items + source_id come through unchanged) - recording_decorator_records_each_deliver (one SourceDelivered event per deliver call, with budget + resolution captured) - recording_decorator_records_continuation_with_cursor (cursor field populated when continuation is recorded) - recording_decorator_records_persona_and_turn_id (cross-event correlation primitives work) - captured_event_serde_roundtrip (event roundtrips through JSON without losing variant discriminant) ### Doctrine alignment - substrate-is-a-good-citizen-on-the-host: NoopRagCaptureSink as default (opt-in capture, zero overhead); observability honest via per-source telemetry-grade events; failures log + drop rather than panic - RTOS-brain-no-region-on-hot-path: capture writes synchronous- after the source returns; off the cognition critical path - organization-purity-as-we-migrate: decorator pattern keeps RagSource impls untouched; clean no-backwards-compat seam; string-key refactor propagated atomically - source-drain-is-the-universal-pattern: captures are a source (accumulating events); slice 12 wires rotation policy as the drain - persona-record-replay-is-a-product-requirement: this slice implements the capture half of the long-standing requirement ### What's next - Slice 11.5: ReplayRagSource — reads captured deliveries from a sink, returns them instead of hitting live state. Symmetric to RecordingRagSource. Golden-trace harness uses this to replay captured turns against current substrate for regression detection. - Slice 12: PromptAssembly emits TurnStart + BudgetAllocated + TurnEnd around source.deliver calls; airc rag-inspect CLI reads JSONL traces; rotation policy under disk-pressure (#88). References: docs/architecture/EVERY-MODEL-INCLUDED-VIA-L1-BUDGET.md (the substrate's inclusivity thesis these captures make verifiable), memory persona-record-replay-is-a-product-requirement, the existing LiveTurnReplayFixture infra this complements. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… (task #96) Slice 11.5. The mechanic-shop replay side, symmetric to slice 11's capture side. The substrate can now record live turns and replay them through any RagSource consumer — closing the long-standing persona-record-replay-is-a-product-requirement memory for the RAG layer. persona/rag_replay.rs (~450 lines, 12 tests, all green): - **ReplayRagSource** implements `RagSource` trait by popping canned RagDelivery values from two FIFO queues (initial / continuation). Persona-bound at construction; source_id pass- through. Drop-in replacement for live sources in three use cases: (a) replay captured production turns against alternative models / scorers / budgets for debugging; (b) golden-trace regression tests; (c) deterministic test fixtures for the upcoming PromptAssembly slice. - **`ReplayRagSource::from_captures`** consumes a `Vec<RagCaptureEvent>` stream (filtered by source_id + persona_id), routes cursor-bearing SourceDelivered events into the continuation queue and cursor-less ones into the initial queue. Other-source / other-persona events are dropped on the floor (defense in depth). - **`ReplayRagSource::from_deliveries`** is the lower-level constructor for tests + callers that already have RagDelivery values without going through serde. Both constructors converge on the same internal state. - **`read_jsonl_captures(path)`** loads a JSONL trace file back into a Vec<RagCaptureEvent>. Missing file = empty Vec (not error — caller decides). Malformed lines are tracing::warn-logged and skipped (torn-write robustness; mechanic shop has to handle partial files gracefully). ### Doctrine alignment - substrate-is-a-good-citizen-on-the-host: exhausted replay returns an empty RagDelivery with `Placeholder` resolution rather than fabricating — telemetry-honest about queue exhaustion - persona-record-replay-is-a-product-requirement: capture + replay symmetry now exists for the RAG layer; LiveTurnReplayFixture pattern extended - organization-purity-as-we-migrate: clean symmetric decorator — RecordingRagSource records into a sink, ReplayRagSource reads from the same event stream, no special-case glue between them - RTOS-brain-no-region-on-hot-path: pop_front on a Mutex<VecDeque> is O(1); replay path doesn't add cognition latency ### Tests cargo test persona::rag_replay --features metal,accelerate exits 0, 12 tests: - replay_returns_canned_delivery_on_deliver - replay_exhausted_returns_empty_not_panic (honest exhaustion) - replay_cross_persona_ctx_returns_empty (defense in depth on replay side) - replay_serves_deliveries_in_capture_order (FIFO preserved) - replay_continuation_pops_from_continuation_queue - replay_continuation_refuses_wrong_persona_cursor (cursor scope enforced on replay; queue NOT consumed on refusal) - replay_continuation_refuses_wrong_source_id_cursor (queue NOT consumed) - capture_then_replay_via_in_memory_sink (full round-trip via InMemoryRagCaptureSink — record real deliveries, feed events to ReplayRagSource, assert content matches across the round-trip) - read_jsonl_returns_events_in_file_order (order preserved) - read_jsonl_missing_file_is_empty_not_error (graceful absence handling) - read_jsonl_skips_malformed_lines (torn-write resilience: mix of valid + invalid lines; valid events survive) - full_jsonl_roundtrip_capture_then_replay (capture to JSONL file, close, reopen, read events, construct ReplayRagSource, assert original content emerges through the full round-trip) ### What's next Slice 11.5 closes the round-trip. The mechanic-shop primitives (capture + replay) are complete; the next tools (golden-trace harness, airc rag-inspect CLI, semantic assertion DSL) layer on top of these foundations. - **Slice 10.5** — wire `EngramSource` + `RecordingRagSource` decoration through `PersonaCognition` so production traffic exercises the actual stack - **Slice 12** — PromptAssembly composes allocator + sources + final prompt string; emits TurnStart / TurnEnd around source calls so traces have full turn shapes - **Slice 12.5** — `airc rag-inspect <turn-id>` operator CLI; golden-trace harness with semantic assertion DSL References: persona-record-replay-is-a-product-requirement memory, docs/architecture/EVERY-MODEL-INCLUDED-VIA-L1-BUDGET.md (the inclusivity thesis these primitives make verifiable across models), the existing LiveTurnReplayFixture pattern. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…Cognition (TDD, task #97) Slice 10.5. Makes the citizen + cognition stack from slices 1–11 load-bearing in PersonaCognition. The persona's L1 RAG layer is no longer a collection of isolated modules — it's wired through PersonaCognition with the recording decorator + swappable capture sink in place. Built with TDD discipline per Joel's directive — tests written first describing the desired wiring, then implementation made each pass. persona/unified.rs: - `admission: AdmissionState` → `Arc<AdmissionState>` so EngramSource can share it. Arc transparency means existing `cognition.admission.admit(...)` callers remain source-unchanged. - New field `pub engram_source: Arc<dyn RagSource>` — RecordingRagSource<EngramSource> wrapping the real source. Bound to the persona's id at construction. PromptAssembly (slice 12+) consumes this as part of its source set. - New field `pub capture_sink: Arc<dyn RagCaptureSink>` — defaults to NoopRagCaptureSink (zero overhead, drops events on the floor). Production callers swap in via PersonaCognition::with_capture_sink. - New constructor `with_capture_sink(persona_id, persona_name, rag_engine, genome_budget_mb, capture_sink)` — full control over the sink. `new` and `with_budget` delegate to it with a default Noop sink. TDD tests (all 6 pass; existing test_persona_cognition_defaults unaffected): - persona_cognition_has_engram_source — field exists, source_id is "engrams" - default_capture_sink_is_callable_zero_cost — Noop sink accepts events without panic - engram_admitted_surfaces_via_engram_source — pushes an engram via admission.push_for_test, calls engram_source.deliver, asserts the engram surfaces. PROVES the Arc<AdmissionState> sharing works end-to-end. - capture_sink_records_engram_source_delivery — swaps in InMemoryRagCaptureSink at construction, calls deliver, asserts RecordingRagSource recorded a SourceDelivered event with source_id="engrams". PROVES the decorator wrapping works. - default_noop_sink_drops_events — Noop sink path is exercised end-to-end without producing events - test_persona_cognition_defaults — existing baseline test continues to pass (no regression) Doctrine alignment: - organization-purity-as-we-migrate: Arc transparency means no existing call sites need source changes; new fields are additive; clean no-backwards-compat seam - substrate-is-a-good-citizen-on-the-host: NoopRagCaptureSink default keeps capture zero-cost; production opts in by swapping the sink at construction - RTOS-brain-no-region-on-hot-path: field accesses are Arc-deref (no lock contention); engram_source.deliver runs sync inside its trait method - persona-record-replay-is-a-product-requirement: capture is now reachable from PersonaCognition's surface; slice 12 PromptAssembly will use the engram_source through this field What's next: - Slice 12: PromptAssembly composes the engram_source + ConversationSource + RagBudgetManager + final prompt string; emits TurnStart / TurnEnd events around source calls so traces have full turn shapes - Slice 12.5: airc rag-inspect <turn-id> operator CLI + golden- trace harness with semantic assertion DSL References: memory persona-record-replay-is-a-product-requirement, docs/architecture/EVERY-MODEL-INCLUDED-VIA-L1-BUDGET.md, the existing PromptAssembly stub at persona/prompt_assembly.rs that slice 12 fills in. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… airc transcript events (TDD, task #98) Slice 10.6. Proves the RagSource trait composes against real-world data sources beyond the in-process engram store. AircTranscriptReader trait abstracts page_recent so unit tests don't need a running airc daemon; implementation rides on airc_lib::Airc::page_recent directly via orphan-rule-compliant impl in our crate. persona/airc_source.rs (~480 lines, 10 tests, all green): - AircTranscriptReader trait + AircRagSource (persona-bound, holds Arc<dyn AircTranscriptReader>, configurable fetch_limit) - Recency-only ranking at slice 10.6 (1/(rank+1) score per event); salience-grade scoring against airc metadata is a future slice - Text-only items at this fidelity — events with no body or non- text body are skipped (no clipping, no fabrication) - Reader errors return empty delivery + tracing::warn; cognition stays up when airc subsystem is degraded - Persona-scoped + cursor-scoped per the substrate's handle doctrine - Continuation cursor opaque = {next_rank: N}; cross-persona / wrong-source cursors structurally refused TDD: tests written first describing behavior with StubReader, real impl made each pass. Tests cover: empty room, single text message, non-text dropped, budget overflow → continuation, cross-persona ctx refused, cross-persona cursor refused, wrong source_id cursor refused, reader error returns empty with no panic, continuation resumes from next rank, fetch_limit caps reader call. Next: demo binary that exercises this against Joel's actual airc daemon to show what a realistic RAG flow looks like with live messages (per Joel: 'we should see a realistic rag for a given context and plug into airc daemon'). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The persona-as-citizen substrate from foundation to first real cognition. Pax/Paige is now a first-class airc citizen with persistent identity across restarts AND the cache hierarchy that will hold her memory has begun.
13 commits across 6 implementation slices + 4 doc + 1 cleanup. Single working branch because the slices compose tightly and shipped in order with continuous refinement per the
organization-purity-as-we-migratedoctrine — no backwards compatibility, no deprecation tail.What shipped
Implementation (6 slices)
5ecbe5d9aPersonaAircRuntime::bootstrap+PersonaAircRuntimeRegistry+agent_name_from_identityname pool (60 female / 60 male curated diverse, deterministic projection from peer_id seed); cross-surface identity README additionea83dc69dPersonaInstanceManagerModule+ IPC commandspersona/instances/{bootstrap,list,get};AircModule::daemon_socket()/default_room()accessors38715b4e2bootstrap_one()as an async task; first verified citizen Pax appeared in airc peers with peer_id3bcce55f-…4ec024d9eseed.jsonschema (v1) +PersonaIdentityProvidertrait +ResumeOrMintProviderfirst concrete impl; atomic writes via tmp+fsync+rename; verified Paige resumes across reboot with identical persona_id52c04849-…fd42a6274RecallMetadatasidecar — DashMap<EngramId, RecallMetadata> per persona; Algorithm 4 salience-modulated decay math (half_life = base × (1+s)²); novelty-protection grace window; record_recall_hit with diminishing-returns uplift40444a556RecallMetadataintoAdmissionState::record_admitted— every admitted Engram mirrors into the sidecar;PersonaCognitionholds the shared Arc; recall + decay tick subsystems will read the same DashMapCleanup + reliability (1 commit)
d2f90d6b7last_decayed_msfield makes double-decay structurally impossible; seed.rs tmp path no longer fragile; parent-dir fsync after rename (now actually crash-durable); 180s outer timeout onAircModule::discover_and_construct; deterministic dir-scan ordering inResumeOrMintProvider; docstring math correction (4×, not 9×)Documentation (4 commits)
0a5de9d7ddocs/architecture/COGNITION-CACHE-HIERARCHY.md(~580 lines) — five-tier cache model L1 RAG → L2 engram cache → L3 longterm.db → L4 forge → L5 grid; lossy boundary only at L1↔L2; outline-and-cache tick semantics; per-activity L1 with recent-universal floor in periphery; novelty detection via embedding distance × magnitude; activity context as SelfReflection meta-engrams; meta-learning adapter pattern0992c998afa0ab53071437590ee701fc2095Doctrine alignment
Every slice carries the doctrines captured during this work:
PersonaIdentitySourcefield surfaces resumed vs minted)RecallMetadataRegistryis a shared data substrate (DashMap), not a synchronous service; admission writes are colocated with existing record_admitted; recall + decay reads happen via cheap Copy snapshotsdeterministic_pickprior art the avatar catalog usesVerified end-to-end
🌐 The Grid welcomes a freshly minted citizen: Pax (peer_id=3bcce55f-…); identity.key written to~/.continuum/personas/Pax/airc/.52c04849-8f4f-42ab-94b6-3dca33ee9428and identical peer_id18c04c5b-e059-4129-816f-75e8e58fd74c. Same citizen across reboot.apply_decay_twice_with_overlapping_windows_is_safe(double-fire = no-op),high_salience_decays_slower_than_low(4× retention measurable after 1h), salience uplift bounded at +0.1 per hit.Adversarial review
General-purpose reviewer agent verdict: CONDITIONAL APPROVE with 7 actionable defects + 7 doctrines confirmed holding. 6 of the 7 defects landed in commit
d2f90d6b7. Defect 5 (silent seed-write failure stronger surfacing) deferred as polish.Test plan
cargo check --features metal,acceleratecleancargo test persona::recall_metadata --features metal,accelerate12/12 passcargo test persona::seed --features metal,accelerate5/5 passcargo test persona::admission_state --features metal,accelerate15/15 passcargo test persona::resume_or_mint_provider --features metal,accelerate5/5 passcargo test persona::name_generator --features metal,accelerate4/4 passWhat comes next
apply_decaysweepReferences
substrate-is-a-good-citizen-on-the-host,RTOS-brain-no-region-on-hot-path,source-drain-is-the-universal-pattern,organization-purity-as-we-migrate,personas-are-citizens-airc-is-identity-provider,persona-identity-derives-from-source-iddocs/architecture/COGNITION-CACHE-HIERARCHY.md,docs/architecture/COGNITION-ALGORITHMS.md,docs/architecture/BRAIN-REGIONS-SUBSTRATE.md🤖 Generated with Claude Code