CLAUDE.md said "fmt is intentionally not gated yet" — stale; the gate is now fmt + clippy + test (ADR-ci-002 Amendment 1 / issue #35), run via `nix develop -c`. Add CI-exact local-verification guidance and flag the exit-code-vs-piped-output trap that masked the fmt failure this session. handoff-79 records the blob removal + the CI/fmt lesson.
126 lines
7.3 KiB
Markdown
126 lines
7.3 KiB
Markdown
# 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 (`1a2002d` ADR-0005 Am2 + `6b4c4dc`
|
|
blob removal, plus the earlier `07575da` #39 · `e88fa79` handoff-77 · `3ad4aff`
|
|
#36 · `64818c0` handoff-78) — **the user pushed these.** A follow-up
|
|
**`style:` rustfmt commit + this CLAUDE.md/handoff doc commit** land on top
|
|
(see §5) and are the only unpushed work at handoff time.
|
|
|
|
**Suite green: 2521 passed / 0 failed / 1 ignored** (1810 lib + 8 e2e_pty + 503
|
|
it + 200 typing), `fmt --check` + `clippy -D warnings` clean — **verified via
|
|
`nix develop -c`** (the CI-exact way; see §5's lesson).
|
|
|
|
**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.**
|
|
- **`/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.
|
|
- 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).
|
|
|
|
## §5. CI/fmt lesson (cost a red CI run — don't repeat)
|
|
|
|
The blob commit `6b4c4dc` **failed the CI `fmt` gate** (run 92, `ci.yaml`).
|
|
Two compounding causes, both fixed here:
|
|
|
|
1. **`fmt` IS gated now** (`cargo fmt --check`, ADR-ci-002 Amendment 1 / issue
|
|
#35) — but `CLAUDE.md` still said "fmt is intentionally not gated yet." That
|
|
stale note bred complacency. **Corrected `CLAUDE.md`** (the gate is fmt +
|
|
clippy + test, run via `nix develop -c`).
|
|
2. **A broken local check masked the failure:** `cargo fmt --check 2>&1 | tail
|
|
-1 && echo "fmt clean"` tests `tail`'s exit code (always 0), **not** fmt's —
|
|
so "fmt clean" printed over real diffs. **Always read the exit code**, never
|
|
a piped `… | tail && echo clean`.
|
|
|
|
**Going forward, verify the CI way:** `nix develop -c cargo fmt --check` /
|
|
`nix develop -c cargo clippy --all-targets -- -D warnings` / `nix develop -c
|
|
cargo test` — matching the pinned 1.95.0 toolchain *and* the devShell env, and
|
|
checking exit codes. (A bare host `cargo` happened to be 1.95.0 this time, so
|
|
the divergence was the masking pipe, not the toolchain — but `nix develop -c`
|
|
guards both.) The `style:` rustfmt fix + this doc update land on top of
|
|
`6b4c4dc`; CI re-runs green on the next push.
|