Records layer
Status: Supported
Milestone: 5a — Records projection
Spec: Core concepts §3, Journal §4, Query §9
Package: internal/records, internal/journal, internal/query, internal/modules
Goal
Introduce a rebuildable record index projected from an append-only revision log
(apply and delete operations). Records are the primary MCP query surface;
revisions remain the audit/rebuild source of truth.
See records concept for vocabulary.
Interfaces
Write — AppendRevision
Appends a record-scoped journal revision and materializes the record projection in
one transaction (RPC, HTTP, module Core).
POST /records
{
"operation": "apply",
"record_ref": "01JREC...",
"type": "trove://type/note/quick/1",
"source": "shortcuts",
"payload": { "text": "hello" },
"transforms": [{ "op": "add", "path": "/tags/-", "value": "photo" }],
"blob_ref": "sha256-..."
}
| Operation | record_ref |
Purpose |
|---|---|---|
apply |
Optional (server allocates on create) | Create or amend record |
delete |
Required | Tombstone; body retained |
Response: { revision_id, record_ref, version, completeness, operation }
gRPC: AppendRevision(AppendRevisionRequest) returns (AppendRevisionResponse) on CoreServices.
Read — internal RPC / MCP
get_record(record_ref, version?) -> Record
search_records(query, filters...) -> []Record
list_incomplete_records(source?, limit?) -> []Record
MCP tools: get_record, search_records, list_incomplete_records.
Data model
Journal (revisions)
| Column | Notes |
|---|---|
operation |
apply | delete |
record_ref |
Always persisted; server assigns on first apply |
type |
Record type when set (nullable) |
payload |
Merge-patch fragment (apply); {} for delete |
transforms |
RFC 6902 JSON Patch array (apply only) |
blob_ref |
Primary content (apply only) |
Projection
record_heads— current folded state perrecord_refrecord_revisions—(record_ref, version)→revision_idrecords_fts— FTS5 on type, source, body
Completeness: incomplete | complete | deleted
Fold order (apply)
- Merge
payloadinto previous body (RFC 7396) - Apply
transforms(RFC 6902) against the body object - Set
type/content_reffrom revision fields - Validate folded body against TTD when type set
- Write
record_heads+ FTS
Delete: set completeness = deleted; retain body, type, content_ref.
Implementation notes
- Materializer in
internal/records; same SQLite txn as revision append - TTDs describe record body, not journal envelope
- Legacy
eventsdatabases migrate torevisionsonjournal.Open retention_dayscascades to record projection tables- Processor routing:
consumeson type; modules guardoperationinProcess/Handle - Rebuild:
trove records rebuildreplays all revisions
Acceptance criteria
Core
- [x]
AppendRevisionapplywithoutrecord_refcreates record at version 1 - [x]
AppendRevisionapplywithrecord_refincrements version - [x]
AppendRevisiondeletesets completenessdeletedand retains body - [x] Fold order: merge payload → transforms → type/blob_ref → validate
- [x] Materialization in same txn as revision append
- [x]
trove records rebuildreproduces identicalrecord_heads
Query
- [x] MCP
get_record,search_records,list_incomplete_records - [x] FTS on
records_fts; deleted excluded from default search
Sources
- [x]
POST /recordshandlesapplyanddelete - [x] MQTT one-message-one-record
- [x] Telegram classify uses
record_ref - [x] capture-classifier module removed
Retention
- [x]
PruneBeforecascades torecord_heads,record_revisions, andrecords_fts
Dependencies
- Blocks: record-centric embeddings
Open questions
| Item | Decision |
|---|---|
| Delete body | Retain previous body |
search_records body shape |
TBD — full body vs summary |
See also
- Records concept
- Revisions concept
- Type catalog
- Revision rename
- References and URIs — planned link/unlink, attachments