Skip to content

Commit 11227f4

Browse files
Document TXID, immutable columns, and indexed scans
1 parent 1680b73 commit 11227f4

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

docs/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ For file-backed databases, `SET DISK_LIMIT` persists in the database file and su
9292
| `.help` | `\?` | Show available commands. |
9393
| `.quit` / `.exit` | `\q` | Exit the REPL. |
9494
| `.tables` | `\dt` | List all table names. |
95-
| `.schema <table>` | `\d <table>` | Show table DDL and constraints. |
95+
| `.schema <table>` | `\d <table>` | Show table DDL and constraints. Per-column `IMMUTABLE` flags render on each flagged column alongside `NOT NULL` / `PRIMARY KEY`. |
9696
| `.explain <sql>` | | Show the query execution plan (useful for seeing whether vector search uses HNSW or brute-force). |
9797

9898
### Trace vs Explain

docs/query-language.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ SHOW DISK_LIMIT
134134
| `TIMESTAMP` | Stored as a Unix timestamp (`Value::Timestamp(i64)`); ISO 8601 text literals are also accepted on input | `NOW()` |
135135
| `JSON` | JSON value | `'{"key": "value"}'` |
136136
| `VECTOR(n)` | Fixed-dimension float vector | `[0.1, 0.2, 0.3]` |
137+
| TXID | Engine-issued transaction id (`Value::TxId`). Populate only via the library API with a bound parameter; SQL literals are rejected. Sync-apply advances the local TxId allocator past incoming peer values. | `Value::TxId(tx.id())` |
137138

138139
NULL values display as `NULL`. Vectors display as `[0.1, 0.2, ...]`.
139140

@@ -159,6 +160,39 @@ CREATE TABLE decisions (
159160
| `UNIQUE` | No duplicate values (single column). A duplicate INSERT on a `UNIQUE` column is a silent no-op (returns `Ok(rows_affected=0)`), matching the composite-uniqueness contract. |
160161
| `DEFAULT expr` | Default value for inserts |
161162
| `REFERENCES table(col)` | Foreign key — writes are rejected if the referenced row does not exist; in explicit transactions the error may surface at `COMMIT` |
163+
| `IMMUTABLE` | Column is audit-frozen — INSERT sets the value once; `UPDATE`, `ON CONFLICT DO UPDATE`, sync-apply mutations, and schema-altering DDL against the column are rejected with `Error::ImmutableColumn` |
164+
165+
### Audit-Frozen Columns
166+
167+
An audit-frozen column carries data that must not be silently rewritten by anyone, through any path. Declare it with `IMMUTABLE`:
168+
169+
```sql
170+
CREATE TABLE decisions (
171+
id UUID PRIMARY KEY,
172+
decision_type TEXT NOT NULL IMMUTABLE,
173+
description TEXT NOT NULL IMMUTABLE,
174+
reasoning JSON,
175+
confidence REAL,
176+
status TEXT NOT NULL DEFAULT 'active'
177+
) STATE MACHINE (status: active -> [superseded, archived])
178+
```
179+
180+
`decision_type` and `description` are provenance — set once at INSERT and never rewritten. `status` and `confidence` remain mutable. An `UPDATE decisions SET decision_type = '…'` returns `Error::ImmutableColumn`; the row is unchanged. Sync-apply across a NATS edge enforces the same rule on the peer: incoming row-changes that mutate a flagged column are rejected and surface in `ApplyResult.conflicts`. `ALTER TABLE ... DROP COLUMN`, `RENAME COLUMN`, and column-type-altering ALTER against a flagged column are refused.
181+
182+
Correction without rewrite — the supersede pattern. When a recorded decision turns out to be wrong, insert a new row with the corrected values and mark the original `superseded`:
183+
184+
```sql
185+
-- Original (frozen)
186+
INSERT INTO decisions (id, decision_type, description, status)
187+
VALUES ('…A', 'sql-migration', 'adopt contextdb', 'active');
188+
189+
-- Correction: a new row, not an update. Both rows remain queryable.
190+
INSERT INTO decisions (id, decision_type, description, status)
191+
VALUES ('…B', 'sql-migration', 'adopt contextdb (rev 2)', 'active');
192+
UPDATE decisions SET status = 'superseded' WHERE id = '…A';
193+
```
194+
195+
Nothing disappears. The audit trail shows both the original commitment and its correction.
162196

163197
### Composite Uniqueness
164198

docs/usage-scenarios.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ The `DAG('DEPENDS_ON', 'BASED_ON')` declaration means these specific edge types
7575

7676
**Problem:** Decisions have a lifecycle — draft, active, superseded, invalidated. Invalid transitions (draft directly to superseded) should be impossible.
7777

78+
**Correction-via-supersede.** Provenance columns — what was decided, what it was based on — are marked `IMMUTABLE`. A recorded decision is never silently rewritten. When a correction is needed, insert a *new* row with the corrected values and transition the original `status` to `superseded`. Nothing disappears from the audit trail.
79+
7880
```sql
7981
CREATE TABLE decisions (
8082
id UUID PRIMARY KEY,
81-
description TEXT NOT NULL,
83+
description TEXT NOT NULL IMMUTABLE,
8284
status TEXT NOT NULL,
8385
confidence REAL,
8486
context_id UUID,

0 commit comments

Comments
 (0)