feat(types)!: drop the blob column type (ADR-0005 Amendment 2)
blob was a dead-end: declarable but never fillable (no literal in either mode, seed-unsupported), so a blob column could only ever hold NULL. Remove Type::Blob + Value/CellValue::Blob + the base64 CSV path + the grammar slot + completion/render/type-change/seed handling + the binder refusal (whose message also carried a user-facing "DSL" copy-rule bug). The vocabulary is now nine types; base64 stays (clipboard OSC-52). Backward compat is the ADR-0015 migration framework's first real use: a v1->v2 format bump (CURRENT_SCHEMA_VERSION across serializer/parser/skeleton) with a migrator that rewrites `type: blob` -> `type: text`, and a forced .db rebuild from the migrated text when a blob column was actually converted (the stale .db keeps a STRICT BLOB engine column). Conversion to text is non-destructive and CSV-free. Covered by a full-stack integration test and a Tier-4 PTY test that opens a real legacy v1-blob project. Also sweeps the nine-type vocabulary through CLAUDE.md, requirements.md, the website (type reference, seed doc, highlight grammar), and the ADR-0030/0033/ 0035 cross-references; CHANGELOG Removed entry; handoff-79. BREAKING CHANGE: the `blob` column type is removed. Existing projects that declared a blob column are migrated on first open (the column becomes text; the original project.yaml is kept as a .v1.bak).
This commit is contained in:
@@ -172,7 +172,7 @@ representation; the SQL surface does not round-trip through it.
|
||||
|
||||
### 5. Type vocabulary — the playground's, not the engine's
|
||||
|
||||
Advanced-mode DDL uses the playground's own ten-type
|
||||
Advanced-mode DDL uses the playground's own nine-type
|
||||
vocabulary (ADR-0005). There is **no fallback to engine
|
||||
storage types**: a column created in advanced mode is a
|
||||
first-class `serial` / `decimal` / `date` / … exactly as a
|
||||
@@ -373,7 +373,7 @@ ADR when taken up (ADR-0026-style).
|
||||
- ADR-0002 — the engine is an implementation detail; "no
|
||||
engine name in user-facing strings" — §7 extends it.
|
||||
- ADR-0003 — the simple / advanced mode model this builds on.
|
||||
- ADR-0005 — the ten-type vocabulary advanced DDL uses (§5).
|
||||
- ADR-0005 — the nine-type vocabulary advanced DDL uses (§5).
|
||||
- ADR-0009 — the DSL conventions; the DSL stays usable in
|
||||
advanced mode.
|
||||
- ADR-0012 / ADR-0013 — the metadata tables the `Command` core
|
||||
|
||||
@@ -1649,7 +1649,7 @@ more.
|
||||
|
||||
## See also
|
||||
|
||||
- ADR-0005 — the ten-type vocabulary INSERT works with.
|
||||
- ADR-0005 — the nine-type vocabulary INSERT works with.
|
||||
- ADR-0006 — the auto-snapshot before destructive ops.
|
||||
- ADR-0014 — the DSL DML model + cascade-summary precedent.
|
||||
- ADR-0015 — the persistence write-through path.
|
||||
|
||||
@@ -58,7 +58,7 @@ Two things from the earlier phases shape this one:
|
||||
executed as-is, the engine would make the table, but the
|
||||
playground would lose what the user meant: that `id` is `serial`,
|
||||
that a `REFERENCES` clause is a *named relationship*, that `STRICT`
|
||||
applies, that the ten-type vocabulary governs. Recovering that
|
||||
applies, that the nine-type vocabulary governs. Recovering that
|
||||
needs the parsed statement either way.
|
||||
|
||||
ADR-0030 §4 said "DDL → a `Command` … run the typed executor." That
|
||||
@@ -92,7 +92,7 @@ mode. Unlike the DML `Sql*` commands they **execute structurally**:
|
||||
the handler reads the parsed structure and performs the schema change
|
||||
through the playground's metadata-maintaining machinery — writing
|
||||
`__rdbms_playground_columns` / `__rdbms_playground_relationships`,
|
||||
applying `STRICT`, using the ten-type vocabulary — so an
|
||||
applying `STRICT`, using the nine-type vocabulary — so an
|
||||
advanced-mode-created object is a first-class playground object,
|
||||
identical to a simple-mode-created one (ADR-0030 §5).
|
||||
|
||||
@@ -772,5 +772,5 @@ honouring it is not the lesson.
|
||||
- **ADR-0017** — the column type-change classification §7 shares.
|
||||
- **ADR-0029** — column constraints; **ADR-0025** — indexes;
|
||||
**ADR-0011** — FK column-type compatibility; **ADR-0005** — the
|
||||
ten-type vocabulary.
|
||||
nine-type vocabulary.
|
||||
- **ADR-0006** — undo; each DDL statement is one undo step (§10).
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Session handoff — 2026-06-22 (79)
|
||||
|
||||
A long session continuing the open-issue sweep (handoff-77/78). Cleared the
|
||||
**help** issue (#36) and the **schema-cache** bug (#39) earlier; this note
|
||||
mainly records the big piece: **dropping the `blob` column type** (ADR-0005
|
||||
Amendment 2), which grew out of a one-line copy-rule fix.
|
||||
|
||||
## §1. State
|
||||
|
||||
**Branch `main`.** Commits this session so far (all on `main`, **not pushed**):
|
||||
`07575da` (#39 gate) · `e88fa79` (handoff-77 + changelog rule) · `3ad4aff`
|
||||
(#36 help) · `64818c0` (handoff-78) · `1a2002d` (**ADR-0005 Amendment 2** —
|
||||
the blob-drop decision record).
|
||||
|
||||
**Uncommitted: the blob-removal implementation** (39 files) — staged for review,
|
||||
commit proposed at session end (see §4). **Full suite green: 2520 passed / 0
|
||||
failed / 1 ignored** (1810 lib + 7 e2e_pty + 503 it + 200 typing).
|
||||
`clippy --all-targets -D warnings` + `fmt --check` clean.
|
||||
|
||||
**Closed this session:** #36, #39. **Open:** #37 (clause hints), #38
|
||||
(diagnostic route — needs a do/defer/close call), #40 (winget release notes).
|
||||
|
||||
## §2. What shipped — drop `blob` (ADR-0005 Amendment 2)
|
||||
|
||||
**Why** (recorded in the ADR): `blob` was a dead-end type — declarable but
|
||||
never fillable (no literal in either mode, `seed`-unsupported), so a blob
|
||||
column could only ever hold NULL. It rode along as the engine's fourth
|
||||
storage class and never got the pedagogical scrutiny UUIDs (excluded) and
|
||||
compound PKs (defended) did. The vocabulary is now **nine types**.
|
||||
|
||||
**Discovered via:** the `value.rs:106` binder message *"…not supported in DSL
|
||||
yet"* — a user-facing copy-rule violation (it `passthrough`es to the user via
|
||||
`DbError::InvalidValue`). Rather than reword, we removed the type; the message
|
||||
is deleted outright.
|
||||
|
||||
**Implementation (test-first throughout):**
|
||||
- **Removal** (compiler-guided): `Type::Blob` + its `keyword`/`sqlite`/`all()`/
|
||||
`from_sql_name` alias arms; `Value::Blob`; `CellValue::Blob(Vec<u8>)` + the
|
||||
base64 CSV encode/decode; the `BLOB_SLOT` grammar slot; completion's `blob`
|
||||
candidate; `output_render`'s `BLOB`; the type-change `↔ blob` static refusal;
|
||||
the seed blob arms; the binder refusal. User-facing strings: dropped `blob`
|
||||
from `help.types_reference` and removed the `hint.value_slot_blob` slot hint.
|
||||
`base64` **stays** (clipboard OSC-52).
|
||||
- **Backward-compat migration** (the ADR-0015 framework's **first real use**):
|
||||
a **v1→v2 format bump**. `parse_schema` hard-pinned the version to 1, so this
|
||||
rippled into a `CURRENT_SCHEMA_VERSION = 2` constant used by the serializer +
|
||||
parser + skeleton, the first registered migrator (`migrate_v1_to_v2`:
|
||||
rewrites `type: blob`→`type: text` + bumps the version), and ~30 `version: 1`
|
||||
test fixtures. The runtime (already wired to `ensure_project_yaml_migrated`)
|
||||
**forces a `.db` rebuild** from the migrated text **only when a blob column
|
||||
was actually converted** (`body_declares_blob_column` pre-read at both open
|
||||
sites) — the stale `.db` keeps a `STRICT … BLOB` engine column + `"blob"`
|
||||
metadata it would otherwise use as-is. Conversion target **text** (not drop)
|
||||
was the user's call (non-destructive, CSV-free, PK/FK-safe).
|
||||
- **Tests:** migrator unit tests (incl. a column *named* `blob` + a `blob`
|
||||
substring in a CHECK left untouched); a **full-stack** integration test
|
||||
`tests/it/blob_removal_migration.rs` (v1 blob project → migrate → `text`
|
||||
column + row data preserved + `.bak`); a **Tier-4 PTY** end-to-end test
|
||||
`e2e_pty::opens_a_legacy_v1_blob_project_by_migrating_to_text` (the real
|
||||
binary opens a seeded legacy v1-blob project via `--resume` → migrate +
|
||||
rebuild + `text` column) — added in the implementation `/runda` pass to
|
||||
cover the runtime's migrate-on-open glue; updated all-types tests to nine;
|
||||
regenerated 5 typing-surface snapshots (reviewed — only the `blob`/`data`
|
||||
candidate vanished).
|
||||
- **Docs:** ADR-0005 Amendment 2 (committed `1a2002d`) + README index; swept
|
||||
`ten-type`→`nine-type` / removed `blob` from CLAUDE.md, `requirements.md`,
|
||||
the website (`reference/types.md`, the seed doc's stale `not null blob`
|
||||
bullet, the `rdbms.mjs` highlight grammar), and the cross-reference counts in
|
||||
ADR-0030/0033/0035. CHANGELOG `[Unreleased] → Removed`.
|
||||
|
||||
## §3. Decisions & notes for next time
|
||||
|
||||
- **convert-to-text, not drop-the-column** (user, 2026-06-22): drop would force
|
||||
rewriting every `data/*.csv` past the rebuild's strict header check — not
|
||||
worth it for a few-days-old, few-users tool.
|
||||
- **Full v2 framework migration, not parse-time leniency** (user): the proper
|
||||
recorded migration with `.bak`, exercising the dormant framework.
|
||||
- **`BlobLit` grammar terminal deliberately left** — a pre-existing,
|
||||
`#[allow(dead_code)]` speculative token never used by any grammar; orthogonal
|
||||
to the type vocabulary. Its "blob literal" string is unreachable. Removing it
|
||||
is a separate optional cleanup (touches the grammar core).
|
||||
- **Known assumption:** the migrator + `body_declares_blob_column` match the
|
||||
serializer's *inline* column format (`- { name: …, type: … }`). A
|
||||
hand-written *block-style* `project.yaml` with `type: blob` wouldn't convert
|
||||
(and would then fail to parse). `project.yaml` is always machine-serialized
|
||||
inline, so this is fine in practice — noted in case a future format change
|
||||
moves away from inline columns.
|
||||
- **Other ADRs (0030/0035) keep their historical `blob` content** (type-change
|
||||
matrix, `binary`/`varbinary` aliases) per the project's supersede-don't-rewrite
|
||||
ADR philosophy; ADR-0005 Amendment 2 is the authoritative record.
|
||||
|
||||
## §4. Process pins / next
|
||||
|
||||
- Commits user-confirmed, no AI attribution, append-only, on `main`; **push is
|
||||
the user's step** (everything this session is unpushed).
|
||||
- **`/runda` was run on both the ADR (design) and the implementation.** The
|
||||
implementation pass found one real gap — the runtime's migrate-on-open glue
|
||||
was untested — closed with the new Tier-4 PTY test. It also verified the
|
||||
import path migrates (extract→migrate→rebuild) and the non-migration
|
||||
`parse_schema` callers fail-safe.
|
||||
- Proposed commit split for the implementation: (1) `feat(types)!` — code +
|
||||
tests + CHANGELOG; (2) `docs` — the CLAUDE.md/requirements/website/ADR-x-ref
|
||||
sweep; (3) `docs(handoff-79)`.
|
||||
- Consider a `cargo sweep` at this milestone.
|
||||
- **Next open issues:** #37 (clause hints, on-mission), #38 (escalate
|
||||
do/defer/close first), #40 (winget release notes). Plus: blob removal means a
|
||||
`cargo sweep`-worthy build and a good moment to push.
|
||||
@@ -404,7 +404,7 @@ since ADR-0027.)
|
||||
referenced column), then `ALTER TABLE … ALTER COLUMN TYPE` (4f —
|
||||
runtime-decomposed to `change_column_type` with `ForceConversion`, the
|
||||
§7 advanced policy: lossy converts with a note, incompatible + static
|
||||
refusals (`↔ blob`, non-`int → serial`) refuse, `int → serial` allowed;
|
||||
refusals (non-`int → serial`) refuse, `int → serial` allowed;
|
||||
the internal-`__rdbms_*` guard folded into `do_change_column_type`),
|
||||
then `ALTER TABLE` add/drop constraint + add FK (4g — `ADD [CONSTRAINT
|
||||
<name>] (CHECK | UNIQUE | FOREIGN KEY)` + `DROP CONSTRAINT <name>`;
|
||||
@@ -430,7 +430,7 @@ since ADR-0027.)
|
||||
refused with an engine-neutral message naming the construct.
|
||||
Implementation pending.)*
|
||||
- [x] **Q3** User-facing simplified types map transparently to
|
||||
SQLite STRICT types in generated DDL. *(All ten types implemented
|
||||
SQLite STRICT types in generated DDL. *(All nine types implemented
|
||||
and tested.)*
|
||||
- [x] **Q4** Supported SQL subset specification — **ADR-0030**.
|
||||
Advanced mode is a standard-SQL surface, engine-neutral; the
|
||||
@@ -462,10 +462,11 @@ since ADR-0027.)
|
||||
|
||||
## Type system (per ADR-0005)
|
||||
|
||||
- [x] **T1** All ten user-facing types implemented: `text`,
|
||||
`int`, `real`, `decimal`, `bool`, `date`, `datetime`, `blob`,
|
||||
- [x] **T1** All nine user-facing types implemented: `text`,
|
||||
`int`, `real`, `decimal`, `bool`, `date`, `datetime`,
|
||||
`serial`, `shortid`. *(Mapping to SQLite STRICT covered by
|
||||
ADR-0005; FK target type rule by ADR-0011.)*
|
||||
ADR-0005; FK target type rule by ADR-0011; `blob` dropped by
|
||||
ADR-0005 Amendment 2.)*
|
||||
- [x] **T2** `shortid` generation: base58, 10–12 characters,
|
||||
omits ambiguous characters; generated client-side at insert.
|
||||
*(Implemented per ADR-0014; auto-fills omitted shortid
|
||||
|
||||
Reference in New Issue
Block a user