Files
rdbms-playground/docs/handoff/20260622-handoff-79.md
T
claude@clouddev1 6b4c4dcea4
ci / gate (push) Failing after 35s
ci / manifests (push) Successful in 3s
website / deploy (push) Successful in 35s
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).
2026-06-22 21:25:38 +00:00

6.4 KiB

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 passthroughes 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: blobtype: 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-typenine-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.