diff --git a/packages/chord/docs/next/decisions.md b/packages/chord/docs/next/decisions.md index f200cdace..5440aa7bf 100644 --- a/packages/chord/docs/next/decisions.md +++ b/packages/chord/docs/next/decisions.md @@ -1637,7 +1637,8 @@ validation and copies the v2 kernel added around Delta. purpose of this slice"):** `StoreStorage` declares conversations, entries, tasks, submissions and `record_ids` as `defineTable`s, writes them with `put` (Durable replaces complete records), and reads them with the store's queries; the outbox, export, import, the applier and later `evolveTable` versions handle them as every table. The partial - head index becomes an index on `(conversation_id, has_head, id)`; indexed strings that must stay lossless keep + head index becomes a table `entry_heads` (one row per entry with a head; build, 2026-10-27, faster than an index on + `(conversation_id, has_head, id)`); indexed strings that must stay lossless keep Durable's JSON encoding. - **Slice 6b D3: one id counter per store (owner, 2026-10-27: "a"):** the store's counter (`next_document_id`, renamed `next_id`; the archive manifest's `nextDocumentId` becomes `nextId`) numbers every id in the store: Durable's diff --git a/packages/chord/docs/next/slice-6b.md b/packages/chord/docs/next/slice-6b.md index 32e1eb69b..837a4ceff 100644 --- a/packages/chord/docs/next/slice-6b.md +++ b/packages/chord/docs/next/slice-6b.md @@ -174,13 +174,16 @@ app owns it). Every row carries the record's indexed columns and the whole record as `json(unknown(), { version: 1 })`; indexed strings that must stay lossless (`kind`, `request_id`) hold Durable's JSON encoding; index columns are non-`opt`, so absent values take sentinels that no encoded value can be (`0` for an absent owner id, ids start at 2; `""` for an -absent request id, JSON-encoded strings start with `"`). +absent request id, JSON-encoded strings start with `"`). SQLite's partial head index is the table `entry_heads` +(builder, 2026-10-27: an index on `(conversation_id, has_head, id)` cost about 5.5 µs per commit; the table is written +only for entries with a head and is faster on both paths). | Table | Key | Columns | Indexes | | --- | --- | --- | --- | | `record_ids` | `id` | `record_type str` | | | `conversations` | `id` | `owner_conversation_id int`, `owner_task_id int`, `record` | `(owner_conversation_id, id)`, `(owner_task_id, id)` | -| `entries` | `id` | `conversation_id int`, `has_head int` (0/1), `commit_seq int` (stamped), `record` | `(conversation_id, id)`, `(conversation_id, has_head, id)` | +| `entries` | `id` | `conversation_id int`, `commit_seq int` (stamped), `record` | `(conversation_id, id)` | +| `entry_heads` | `id` | `conversation_id int` (one row per entry with a `head`, written with it) | `(conversation_id, id)` | | `tasks` | `id` | `conversation_id int`, `kind str`, `status str`, `abort_requested int`, `background int`, `record` | `(status, id)`, `(conversation_id, id)`, `(kind, id)`, `(abort_requested, id)`, `(background, id)` | | `submissions` | `id` | `conversation_id int`, `request_id str`, `status str`, `record` | `(conversation_id, request_id)`, `(conversation_id, id)`, `(status, id)` |