@@ -5,6 +5,74 @@ Per `PLAN.md` §1 rule 6, every resolution of an ambiguity or deviation from
55
66---
77
8+ ## D17 — Write-path semantics the SPEC leaves open
9+
10+ ** Phase:** 6 · ** Status:** accepted
11+
12+ ` SPEC.md ` §4 defines the constraint set but not every edge of the write path.
13+ Phase 6 fixes these (each is a one-line change later if v2 decides otherwise):
14+
15+ - ** PK columns are immutable** — an update touching one is rejected
16+ (` PkImmutable ` ). Change-of-key is delete + insert.
17+ - ** Engine-managed columns reject explicit writes** : ` rowversion ` and
18+ ` on_update: now ` columns can never be set by the caller.
19+ - ** ` rowversion ` starts at 1** on insert and bumps by 1 on every update.
20+ - ** ` on_update: now ` also stamps on insert** (an ` updated_at ` is never NULL).
21+ - ** Explicit values on auto-increment columns are allowed** ; the sequence
22+ advances past them (` seq = max(seq, given + 1) ` ), so generated keys never
23+ collide. The sequence is a catalog entry — durable, gaps allowed, no reuse
24+ after crash/reopen.
25+ - ** ` add column ` ** requires nullable or a * constant* default; existing rows
26+ are padded lazily on read (generators cannot backfill), no rewrite.
27+ - ** UNIQUE ignores NULLs** (multiple NULLs allowed, SQL semantics).
28+
29+ ## D16 — UNIQUE enforced by a scan probe until Phase 7
30+
31+ ** Phase:** 6 · ** Status:** accepted (provisional)
32+
33+ ` SPEC.md ` §4.1 says UNIQUE is "enforced via a unique index", but ` index ` is
34+ Phase 7. Phase 6 enforces the constraint ** correctly but provisionally** with
35+ a full-table scan probe (one scan per write batch). Phase 7's unique indexes
36+ replace the probe with an index lookup; behavior is unchanged, only cost.
37+
38+ ## D15 — Provisional CHECK expressions with SQL three-valued logic
39+
40+ ** Phase:** 6 · ** Status:** accepted (provisional)
41+
42+ ` SPEC.md ` §4.1 allows ` CHECK(<expr>) ` over the row, but the expression
43+ language (§5.2) arrives with the query layer in Phases 8–9.
44+
45+ ** Decision:** Phase 6 ships a minimal ` CheckExpr ` — column-vs-literal
46+ comparisons, ` and ` /` or ` /` not ` , ` is_null ` /` is_not_null ` — validated at DDL
47+ (columns exist, literal kinds match) and stored in the catalog. Evaluation
48+ follows SQL 3VL: a CHECK is violated only when it is definitively ** false** ;
49+ NULL/unknown passes. The Phase 8/9 expression engine supersedes the enum
50+ (same precedent as Phase 3's provisional byte keys).
51+
52+ ## D14 — One published root: the catalog tree owns everything
53+
54+ ** Phase:** 6 · ** Status:** accepted
55+
56+ ` ARCHITECTURE.md ` §3.5 stores the system catalog "in B+trees referenced from
57+ the meta page" but leaves the multi-tree commit mechanics open.
58+
59+ ** Decision:**
60+ - The meta page's root ** is the catalog B+tree** ; every other tree hangs off
61+ it. Per table: ` ("tbl", name) ` → schema (changes on DDL), ` ("root", name) ` →
62+ data-tree root (changes on every write), ` ("seq", name) ` → auto-increment
63+ cursor. A write to table T updates T's tree, then T's root entry, producing
64+ one new catalog root — so one root install + one fsync pair commits schema
65+ and data atomically, and a snapshot pins both consistently.
66+ - ` txn ` generalizes to ** ` WriteJob ` /` WriteCtx ` ** : a job runs on the writer
67+ thread, edits any tree under the root, and returns a typed output delivered
68+ after durable commit. ` Db<B> ` is now an alias for ` JobDb<B, OpsJob> ` — the
69+ Phase 4 API and tests are unchanged. Jobs inherit D8's validate-then-apply
70+ contract; the writer classifies job errors ** by category** (` Io ` /
71+ ` Corruption ` fatal, everything else rejects just that transaction, with the
72+ root and freed-list restored defensively). Rejections cross the thread as
73+ ` TxnError::Rejected(Box<dyn CategorizedError>) ` and downcast back to the
74+ catalog's typed error at the API surface.
75+
876## D13 — No ` u64 ` value type; ` rowversion ` columns are ` i64 `
977
1078** Phase:** 5 · ** Status:** accepted (SPEC inconsistency, raised)
0 commit comments