Status: locked Proposed on: 2026-07-27 Statement: All new canonical intake starts in Short-term, one consolidation decision gives every pending item exactly one terminal route, and only an atomically receipted, graph-backed promotion may admit an item to Long-term. Default access collapses canonical lineage, while keyword, vector, compatibility, and shared-graph projections remain retryable derived views.
This rule and its guards must remain unchanged for seven days before a separate
PR may promote it to locked.
- Admit newly captured conversation, explicit-user, import, API, plugin, or integration input directly to Long-term or Archive. Historical migration/backfill is not new intake and remains governed by its explicit migration policy.
- Leave a pending Short-term item without exactly one consolidation route, or
apply more than one of
promote,archive,review, andrejectto it. - Treat the Short-term TTL alone as a terminal route or hide an expired active item before canonical apply records its disposition.
- Add a generic, batch/daily, call-site, or user-asserted fast-track promotion pass alongside the consolidation route.
- Commit a new active Short-term → Long-term transition without validating a server-authored promotion admission receipt and atomically writing the version-fenced per-memory graph assertion with the item, ledger head/commit, operation result, and outbox events.
- Return both a Short-term alias and its Long-term canonical survivor in a default list or search result.
- Treat keyword, vector, compatibility, or shared-graph projections as authoritative state.
- Send restricted memory content to a search, embedding, or vector provider.
- Acknowledge an outbox-backed projection event before its idempotent write succeeds and its post-write authoritative fence is reconciled.
- Canonical capture, maintenance, consolidation, and apply transactions
- Chat / agent / MCP memory retrieval
- Keyword, vector, compatibility, and graph projections
Coverage gap:
test_ws_i_write_convergence.py(1,398 lines) was deleted by5724a10084"converge universal memory and task authority" and this list was never updated. It is removed here so the remaining guards can be verified continuously; whether its coverage was absorbed elsewhere is unconfirmed and belongs to the memory owner.
backend/tests/unit/test_canonical_extraction_subject_wiring.pyandbackend/tests/unit/test_working_observations_extractor.py— conversation, observation, explicit, and external memory writes enter Short-termbackend/tests/unit/test_canonical_consolidation.py— pending work receives an exact one-route partition with authoritative subject/evidence validation; owner-rejected sources and near-duplicate negative examples cannot promotebackend/tests/unit/test_rejected_memory_feedback.py— negative examples are recent, bounded, sensitivity-safe, source-active, cached, and invalidatablebackend/tests/unit/test_canonical_maintenance_ordering.py— maintenance has one L2 route owner and blocked consolidation cannot fall through to generic promotionbackend/tests/unit/test_canonical_short_term_maintenance_cron.pyandbackend/tests/unit/test_validate_memory_maintenance_scheduler.py— the scheduled runtime invokes only the canonical maintenance owner, prioritizes expiry work independently of the registry/cooldown, and reports projection delivery and unadjudicated-expiry failuresbackend/tests/unit/test_atomic_apply.pyandbackend/tests/unit/test_memory_apply_store.py— promotion atomically writes the item, graph assertion, ledger state, operation result, and outbox; source replacement and privacy tombstones use the same journal boundarybackend/tests/unit/test_memory_replace_policy.pyandbackend/tests/unit/test_ws_j_delete_privacy.py— conversation reprocessing replaces its complete source set atomically, and privacy deletion closes over the complete canonical lineage under a control fencebackend/tests/unit/test_ws_m_atom_keyword_index.py— default retrieval collapses Short-term aliases into their Long-term canonical survivorbackend/tests/unit/test_memory_read_api.py— product access policy excludes restricted or otherwise ineligible canonical items from default readsbackend/tests/unit/test_canonical_memory_vectors.py— restricted canonical content is delete-only at the external vector boundarybackend/tests/unit/test_memory_graph_assertion_read.pyandbackend/tests/unit/test_knowledge_graph_canonical_mutation_routes.py— shared graph reads enforce the authoritative item privacy fence and public legacy mutations cannot replace retained canonical assertionsbackend/tests/unit/test_memory_outbox_worker.py— projection delivery reloads authoritative state, repairs reclaimed deliveries, retries, and acknowledges only successful convergence
backend/docs/epics/memory_normative_architecture.mdbackend/docs/memory/**backend/docs/canonical_memory_architecture.*backend/database/memory_*.pybackend/utils/memory/**backend/utils/memory_ingestion/**backend/utils/mcp_memories.pybackend/utils/conversations/process_conversation.pybackend/utils/llm/memories.pybackend/utils/llm/working_observations.pybackend/models/memory_*.pybackend/models/product_memory.pybackend/database/knowledge_graph.pybackend/routers/memories.pybackend/routers/memory_*.pybackend/routers/knowledge_graph.pybackend/modal/memory_maintenance_job.pybackend/deploy/runtime_env.yamlbackend/scripts/validate_memory_maintenance_scheduler.py.github/workflows/gcp_memory_maintenance_job*.ymlscripts/dev-harness/run-canonical-maintenance.pybackend/tests/unit/test_canonical_memory_vectors.pybackend/tests/unit/test_memory_graph_assertion_read.pybackend/tests/unit/test_knowledge_graph_canonical_mutation_routes.pybackend/tests/unit/test_validate_memory_maintenance_scheduler.pyscripts/dev-harness/tests/test_python_resolver.pyfirestore.rules
Name INV-MEM-4 in the PR body while this proposal is in scope. Proposed
invariants are design notes and are not CI-enforced until separately locked.