diff --git a/docs/DOMAIN_MODEL.md b/docs/DOMAIN_MODEL.md index 72ead64b1..efb43754a 100644 --- a/docs/DOMAIN_MODEL.md +++ b/docs/DOMAIN_MODEL.md @@ -133,6 +133,61 @@ projections. They exist to retrieve and traverse knowledge efficiently. - Search results point back to entities and notes; they do not become independent documents. - Deleting or rebuilding an index must not mutate canonical content. +### Accepted Change Journal + +`RuntimeAcceptedProjectNoteChange` is the canonical temporal record of one accepted note mutation +inside a project partition, and `Project.partition_position` is the strictly ordered per-project +watermark those records advance. + +- An accepted change is replay-complete evidence: operation, paths, accepted content version and + checksum, actor, source, and acceptance time. It is recorded with the accepted mutation, not + reconstructed later from derived state. +- Consumers that need ordering, coalescing, or idempotency — projectors, routines, temporal + reads — consume the journal watermark. Human-facing feeds are presentations, never the + ordering substrate; today's recent-activity feed still derives from search state rather than + journal reads (see Event Surfaces And Derivation). +- Materialization settling records when durable storage caught up with an accepted position. A + consumer that must not run ahead of durable files (the Wiki Projector, portable logs) holds + behind unsettled positions instead of guessing. +- The journal is note-scoped and project-partitioned today. A fuller event envelope (causation, + correlation, depth, workspace scope) grows this record; it does not introduce a second journal + beside it. +- Scope today: only DB-first accepted note mutations reach the journal + (`accepted_note_mutation_runner`). File-first reconciliation — observed file indexing and + external delete handling — converges derived state without journal evidence yet. Journaling + those reconciliation paths is the intended direction; until it lands, journal consumers see + DB-first mutations only, and file-first changes surface through reindex and reconciliation. + +### Event Surfaces And Derivation + +Every event-shaped surface is the journal, a projection of it, ingress toward it, or a separate +family that must not be mistaken for it: + +```text +storage notifications / webhooks ingress evidence + -> reconciliation commands + -> accepted change journal canonical time + -> wiki projections index.md, log.md, navigation + -> search / graph / vector retrieval projections + -> activity feeds, live updates human presentation and transient delivery + -> temporal reads (bm log) CLI/API views over the journal +``` + +- A projection may lag the journal and must be rebuildable from it plus canonical Markdown. +- The diagram is the target architecture; two edges run ahead of the code today. Ingress: + reconciliation of external file changes does not yet advance the journal (see the journal's + scope bullet above), so the top edge holds only for DB-first accepted mutations. Activity: + the current recent-activity feed is built from search state (`ContextService.build_context`), + not from journal reads — its edge names where that feed converges, not what it reads today. +- Delivery events (webhook attempts, storage notifications, SSE publishes) prove delivery, not + acceptance; they are never the canonical semantic log. +- Run ledgers (projection runs, index runs) record operational work, and product telemetry + (usage, subscription, journey events) records behavior. Neither is a knowledge event, and + neither derives from the journal. + +POSIX-shaped reads describe memory space; the accepted change journal describes time; the +knowledge graph describes meaning; runtimes describe behavior. + ## Source Of Truth And Authority "Markdown is the source of truth" describes the product representation. Operational authority diff --git a/src/basic_memory/indexing/wiki_projector.py b/src/basic_memory/indexing/wiki_projector.py index 861581aca..fe6105270 100644 --- a/src/basic_memory/indexing/wiki_projector.py +++ b/src/basic_memory/indexing/wiki_projector.py @@ -10,6 +10,8 @@ from pathlib import PurePosixPath, PureWindowsPath import unicodedata +from basic_memory.runtime.project_partition import RuntimeProjectNoteOperation + OKF_VERSION = "0.2" WIKI_PROFILE = "wiki/1" WIKI_PROJECTOR_VERSION = "wiki/1.0.0" @@ -32,13 +34,9 @@ class WikiProjectionReason(StrEnum): manual_rebuild = "manual_rebuild" -class WikiChangeOperation(StrEnum): - """Accepted note operation represented in generated Wiki logs.""" - - created = "created" - updated = "updated" - moved = "moved" - deleted = "deleted" +# Wiki logs present the accepted-change journal, so they reuse its operation vocabulary +# instead of maintaining a twin enum that can drift from the journal it renders. +WikiChangeOperation = RuntimeProjectNoteOperation class WikiProjectionState(StrEnum):