Skip to main content

Single Source of Truth

One SOAT project can be the record for a system where many orchestrations, triggers and agents write reports as documents and facts as memories, and read each other's, with no external store beside it.

This page maps what such a record needs to the module that provides it. The module pages hold the definitions; nothing is re-defined here. Single Source of Truth walks the write half against one project.

What the record needs​

NeedMechanismWhere
One address per recordproject_id + path is unique on documentsDocuments
One fact stored onceDedup and supersession on write; a declared supersedesMemories
Access control on every read and writeIAM policies, tag conditions, boundary_policyIAM, Agents
A write that cannot be lostversion counter, expected_version / If-Match, 409 VERSION_CONFLICTConcurrent Writes
Every past state readableAppend-only document versions; restore appendsDocuments
Withdraw without losing historyTombstone version; ?include_withdrawn=trueDocuments
Retire a fact that stopped holdinginvalidated_at; retracted assertionMemories
Who claimed what, through which doorMemory assertion ledger, source_typeMemories
Typed fields, not labelsmetadata beside tags, one line between themIAM
One shape every writer is held toMetadata schema per path prefix, 400 VALIDATION_FAILEDMetadata Schemas
Query the record by its fieldsEquality, in, ordering on ?metadata= (documents, tasks) and in knowledge searchDocuments
Say what a document is to anotherderived_from, supersedes, cites; ?related_to=Documents
Retrieval with citationsHybrid search over documents and memories, source_type on every hitKnowledge
Every change reaches its subscribersDurable event triggers, webhooksTriggers, Webhooks
An operational ledger nothing rewritesAudit log, activity, usageAudit Log, Activity, Usage
The corpus as a fileNDJSON export, oldest firstExport

Writes​

Every document and memory carries a version. A write may state the version it read; a write against any other version is refused whole, and two writes that race on one record are serialized whether or not either stated one. Concurrent Writes is the definition.

A document write that changes content, title, path, metadata, tags or chunk configuration archives the state it replaced, so a run can cite the version it read and a later reader can fetch exactly that. Restore appends a new version rather than rewinding, and runs through the ordinary update path, so the restored content is re-chunked and re-embedded.

A memory write is recorded twice: the memory is state, and each write attempt is an assertion naming the principal, the mechanism and the outcome, including the writes that changed nothing.

Removal​

Neither a document nor a memory needs to be deleted to leave the record.

DocumentMemory
OperationPOST /api/v1/documents/{document_id}/withdrawPOST /api/v1/memories/{memory_id}/retract
Stored asA tombstone versioninvalidated_at with superseded_by_memory_id null, plus a retracted assertion
LeavesListings and knowledge search; chunks drop from the indexListings, dedup and knowledge search
Still readableBy id, with every versionBy id, with its assertions
Comes back throughRestoring a content versionA new write; dedup never matches a retired fact
Eventdocuments.withdrawn, documents.restoredmemories.retracted

DELETE stays permanent on both.

Structure​

A record carries two annotation bags. tags are flat string labels the platform reads for authorization and scoping. metadata is typed JSON the platform stores, validates and filters, and never reads for itself. The line between them is defined once, in Tags and metadata.

A metadata schema declares what documents under a path prefix must carry, and every write path that stores the bag is judged by it: the REST routes, a formation, a restore. Documents already stored are not re-judged until their path or metadata is next written.

The same metadata object filters GET /api/v1/documents and POST /api/v1/knowledge/search, with equality, in and gt / gte / lt / lte, matched by type: {"revision": 3} and {"revision": "3"} are different filters. A filter narrows what the caller's policy already allows.

A relation is a typed edge one document asserts about another. Asserting it is a write of the asserting document alone, and ?related_to= finds neighbours on either side.

Delivery​

An event trigger writes its firing before the target is touched, so a process that dies mid-dispatch leaves a row another process redelivers. Delivery is at-least-once and deduplicated per (event, trigger), so an event target must be idempotent. Webhooks deliver the same events outside the platform. The names are listed in Webhook Events.

Export​

Each export streams newline-delimited JSON, oldest first, one object per line, in the shape the module's listing returns for the same caller. Each is its own IAM action, separate from the listing.

ExportNarrowed byAction
GET /api/v1/documents/exportpath_prefix; withdrawn documents and /.system/ left outdocuments:ExportDocuments
GET /api/v1/memory-stores/{memory_store_id}/export?tags=; include_invalidated=true adds retired factsmemories:ExportMemories
GET /api/v1/activity/exportThe listing's filtersactivity:ExportActivity
GET /api/v1/audit-log/exportThe listing's filtersaudit:ExportAuditEntries

Scope​

A write precondition covers one record. There is no transaction across records: two writes to two documents are two writes, and where several must move as one, the step is an idempotent orchestration, as Concurrent Writes states.