Canonadr

ADR-2026-08-31-02 — Three continuity scopes

Status: Accepted
Date: 2026-08-31
Gap: G-01
Related: ADR-2026-08-31-01, ADR-2026-08-31-03

Context

packages/hermes-spine-memory models memory as two scopes:

export type MemoryScope = "personal" | "org";   // types.ts:29

The namespace header describes personal:user:{id} as holding "twin chat history, personal
notes"
— one namespace holding two participants' continuity. routeTwinMemory() can only route
Twin into personal or org, so AI has no continuity of its own: its working memory is
stored inside the human's private namespace.

This violates the canon invariant directly. Personal Memory and AI Memory are supposed to be
separate from each other, and neither automatically becomes organizational truth. Today the first
half of that is untrue.

It also blocks Spine Agents (G-05), which cannot have per-agent memory
namespaces while the scope enumeration has no slot for a non-human participant.

Decision

Memory has three scopes, matching the three continuity domains:

ScopeHoldsOwner
orgBusiness Context / Organizational Memory — shared organizational reality and durable knowledgeOrganization
personalPersonal Contextual Memory — the human's private continuityHuman
aiAI Continuity Memory — AI's own continuing working memoryTwin, Spine Agents

Twin's continuity moves out of the human's private namespace into its own.

The ai scope is subject-addressed like the others, so a Twin and each Spine Agent get distinct
namespaces rather than sharing one AI pool.

Governed promotion is the only path between scopes. Nothing crosses implicitly. This half is
already correct in code: services/pipeline/src/memory-promoter.ts never auto-promotes
AI-sourced writes into organizational memory — they land in staging pending approval. That
behaviour is preserved unchanged.

Implementation status — landed 2026-08-31

Implemented in packages/hermes-spine-memory:

  • MemoryScope widened to "personal" | "org" | "ai", with MemorySubjectType naming the
    subject each scope addresses (user / tenant / agent).
  • resolveNamespace and the new subjectIdForScope resolve the subject per scope and throw
    when it is absent. A fallback would write one participant's continuity into another's database,
    so absence is refused rather than defaulted.
  • routeTwinMemory now defaults Twin to its own ai continuity when an agentId is known,
    instead of falling into personal or org.
  • The ai scope is subject-addressed, so a Twin and each Spine Agent get distinct namespaces.
  • 27 tests added (namespaces.test.ts) — the package previously had none.

Round-trip bug fixed in passing. The path grammar was inconsistent: resolveNamespace produced
personal:user:{id} but parseNamespacePath treated user as part of the subject id, so
dbNameFromPath(ns.path) returned iw_mem_personal_user_abc while ns.dbName was
iw_mem_personal_abc — two different databases for one namespace. The grammar is now uniformly
{scope}:{subjectType}:{subjectId} and round-trips are asserted for all three scopes.

No migration is required — correcting an earlier assessment

An earlier draft of this ADR stated that a data migration was required, on the assumption that
existing personal:user:{id} namespaces held commingled human notes and Twin chat history. That
was wrong.
Verified:

  • packages/hermes-spine-memory has zero consumers — only its own package.json and
    index.ts reference it. Nothing has ever written through it.
  • services/continuity no longer uses CouchDB. Its wrangler.toml binds env.DB (D1)
    exclusively, and src/couchdb.ts no longer exists. The COUCHDB_* secrets in its README.md
    and in SERVICE_ARCHITECTURE_REPORT.md are stale documentation.
  • apps/web/lib/core/twin-memory/store.ts is an in-memory Map implementation, headed
    "Production: Replace with Supabase or database backend."

So no CouchDB memory databases are provisioned, and AI continuity has no persistent home today
at all
. This substrate is designed but unwired.

That makes now the cheapest possible moment to correct the scope model: the design is being fixed
before anything depends on it, at zero migration risk. It also reframes the gap — the problem was
never "AI memory sits in the wrong live namespace," it was "the three-domain model was designed
into a substrate that was never wired, with only two domains in it."

Consequences

  • The privacy boundary is now structural: a human's personal namespace cannot accumulate AI
    working state, because the ai scope refuses to resolve against a userId.
  • Unblocks G-05 — Spine Agents can hold identity plus an addressable
    memory namespace.
  • A migration becomes required the moment this substrate is wired to a live store. This ADR
    records that it is not required now; that changes as soon as anything writes through it.
  • Stale CouchDB references in services/continuity/README.md and SERVICE_ARCHITECTURE_REPORT.md
    should be corrected, so the next reader does not conclude a CouchDB deployment exists.

Not decided here

Promotion rules between the three scopes — what qualifies AI continuity or personal context for
promotion into organizational memory, and under whose authority. The existing seven promotion
signals cover Spine → Org Memory. Scope-to-scope promotion needs its own decision.