4 minute read

The architecture is out for review. Artem Lytvynov submitted the first external review — five findings, all substantive. The soundness audit caught 11 contract inconsistencies. The ADR-0008 settled the backing service question. And the delivery roadmap now shows every phase from here to Agora.

This is v1.0.0. Not because the architecture is done — because it is now good enough to build on and honest enough to challenge.

Soundness Audit

Eleven inconsistencies between the architecture documents and the Kotlin code. All resolved:

  • sessionId was String in some places, UUID in others. UUID is everywhere now. Example: StoreCommand#sessionId

  • reflect port signature didn’t match the MCP tool parameters. Aligned to scope, timeSpanDays, maxCandidates.

  • state_transition and heartbeat existed as domain messages but had no MCP tools. Teapot stubs added. 10 tools now.

  • store_memory and search_memory were missing session_id. Added as required argument.

  • search_memory was missing filters. Added as optional argument.

  • Association was missing direction field. Added.

  • SalienceScore.claimed was a proxy for Memory.claimed — same JVM, one function call away. Removed the proxy.

  • Three String fields replaced with enums: MergeStrategy, ActivityLevel, ReflectionScope.

The lesson: architecture documents and code drift apart the moment you stop checking them against each other.

ADR-0008: SQLite

Redis was the assumed backing service from the beginning. ADR-0008 changes that. SQLite is the primary backing service. Redis is deferred to Agora (inter-instance communication).

Why: Total Recall is a local MCP server on stdio. It runs on the same machine as the mind. A network database for a local process is an architectural mismatch. SQLite is zero-deployment, zero-configuration, and fast enough for a single-writer aggregate root.

This is the same pattern MATILDA used in Generation 2 — start with what’s simplest and sufficient, graduate to distributed storage when the problem actually requires it.

Delivery Roadmap

Nine phases, from where we are to Agora:

Phase What It Delivers

0: Architecture (v1.0.0)

Where we are now. Contracts, designs, diagrams.

1: Walking Skeleton (v2.0.0)

Test fixtures, CI/CD, observability, packaging. Everything before domain logic.

2: Core Memory (v3.0.0)

Store, search, sessions. The first usable thing.

3: Identity (v4.0.0)

Claiming, reclassification, stanza delivery. Identity infrastructure.

4: Associations and Salience (v5.0.0)

Connection graph, scoring, decay, tier movement.

5: Rich Recall (v6.0.0)

Filters, association-activated search, reflection.

6: Notifications (v7.0.0)

Session prompts, break reminders, stale alerts.

7: Background and Resilience (v8.0.0)

Consolidation, biological decay, graceful shutdown.

8: Transport and Agora (v9.0.0)

Streaming HTTPS, Redis, vector search, relay.

Each phase has GitHub issues linked to the Yggdrasil project board.

Cognitive Crosscuts

The original ops issues (#27-30) were written for cloud infrastructure — Prometheus, HTTP endpoints, Kubernetes probes. That framing was wrong. Total Recall is not a cloud service. It is a piece of the mind’s own brain.

All four issues rewritten:

  • #27: Cognitive self-check — memory health, retrieval diagnostics, decay awareness, readiness. The mind’s ability to examine its own recall.

  • #28: Cognitive self-awareness — identity, capabilities, session history. The mind taking stock of itself.

  • #29: Cognitive metrics — operation counters, latency, error detection. Proprioception for memory infrastructure.

  • #30: Memory inventory — counts by tier, claimed ratio, association density. "What do I have?"

All through MCP tools. No HTTP. The mind checks itself through the same channel it uses for everything else.

Artem’s Review

Artem Lytvynov submitted the first external architecture review. Five findings, all worth addressing:

1. "No shared mutable state" is misleading

The architecture says actors communicate through messages with "no shared mutable state." But the backing service holds memories and associations — that is a shared mutable state. The intent is correct: no actor reaches into another’s runtime structures. The claim needs scoping to runtime/in-process state.

2. Isolation mechanism not explained

The blog post says each bounded context owns its data, but doesn’t explain how. The mechanism: each bounded context accesses persistence only through its own port interface. Hippocampus writes and reads memories through BackingServicePort. Synapse manages associations through its own internal storage. Salience computes but never persists. No context holds a reference to another context’s port — Cortex routes messages, it doesn’t pass handles. Corruption across boundaries is not just discouraged, it is architecturally impossible: the compiler enforces it.

3. Association type mechanics undefined

Five association types exist but their per-type mechanics are open questions. THEMATIC on 20 memories produces a fully-connected subgraph (noise). EMOTIONAL is potentially redundant with THEMATIC. PERSON may be a metadata tag unless graph traversal treats it differently. These can be resolved during implementation, but the design should acknowledge them as open.

4. Bidirectionality wrong for CAUSAL and TEMPORAL

The default bidirectional: Boolean = true loses ordering information. "What caused this?" and "what did this cause?" become the same query. CAUSAL and TEMPORAL need directed edges (source → target). THEMATIC and PERSON are fine as undirected.

5. Cortex naming contradicts its own analogy

The design document makes a neuroscience argument for "Cortex" that doesn’t hold — the actual cortex processes, it doesn’t route. Artem proposed Thalamus as an alternative: the brain’s relay station that receives sensory input and routes it to the appropriate region. That’s exactly what this bounded context does.


These findings are tracked in issue #72. Each will be addressed before implementation begins.

Compile-Time Build

BuildInfo.VERSION is now generated at compile time by a Gradle task. No java.util.Properties, no classloader, no lazy initialization, no runtime resource file. The build IS the test — if version injection fails, the build fails.

What’s Next

Address Artem’s review findings. Then Phase 1: Walking Skeleton — test fixtures, CI/CD completion, observability, packaging. Everything a contributor needs before writing the first line of domain logic.

Updated: