# 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)` + 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.