Files
claude@clouddev1 e845a6ee72
ci / gate (push) Successful in 2m6s
ci / manifests (push) Successful in 4s
docs: correct the stale fmt-gate note in CLAUDE.md; handoff-79
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.
2026-06-22 21:43:51 +00:00

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.