Files

11 KiB
Raw Permalink Blame History

Session handoff — 2026-05-24 (36)

Thirty-sixth handover. This session implemented ADR-0006 (undo/snapshot) end-to-end (§8 steps 18 + a /runda data-loss fix) and then drafted ADR-0035 — advanced-mode SQL DDL (Phase 4 of the ADR-0030 roadmap, status Proposed). The next session begins implementing ADR-0035, starting at sub-phase 4a. See §4.

§1. State at handoff

Branch: main. Tests: 1698 passing, 0 failing, 0 skipped, 1 ignored (the unchanged friendly/mod.rs doctest). Clippy: clean (cargo clippy --all-targets -- -D warnings).

Latest commit (local-only):

a079200 docs: ADR-0035 — advanced-mode SQL DDL (Phase 4)

origin/main is at df6aa69; 1 commit is local-only (a079200). The undo/snapshot work (through df6aa69) is already pushed. Unpushed commits are a normal working state; pushing is the user's step — do not prompt about it.

§2. What shipped this session

  • ADR-0006 (undo/snapshot) fully implemented — the U1/U2 half; the replay/journal half (U3/U4) had shipped via ADR-0034. Built across §8 steps 18 of the plan (docs/plans/20260524-adr-0006-undo-snapshots.md):
    • src/undo.rsSnapshotStore: a persisted undo ring + redo stack under <project>/.snapshots/ (index.yaml + per-snapshot payload dirs). Hybrid whole-project snapshot — db via the online backup API + project.yaml/data/*.csv copied; restore is text-first, db-last (ADR-0015 §6).
    • src/db.rssnapshot_then brackets all 19 mutating dispatch arms (stage→run→finalise/discard), gated on a user command source (internal ops like open-time rebuild are not snapshotted); BeginBatch/EndBatch (a replay/batch = one undo step); Undo/Redo/PeekUndo/PeekRedo handled in worker_loop with &mut conn.
    • undo/redo app commands + Modal::UndoConfirm confirm flow; --no-undo CLI flag; .snapshots/ git-ignored + export-excluded
      • temp-cleanup-allowlisted.
    • /runda found + fixed a silent data-loss bug: a committed mutation whose snapshot couldn't be staged left the redo stack stale (redo-clear was a side effect of finalize), so a later redo discarded the new work. Now clear_redo runs on that path (snapshot_then/end_batch); commit df6aa69, regression-tested.
    • ADR-0006 marked implemented (Amendment 1 + Implementation note); requirements.md U1/U2 → [x]; CLAUDE.md updated.
  • ADR-0035 drafted (docs/adr/0035-advanced-mode-sql-ddl.md, commit a079200, Proposed) — the next job (§3/§4).

§3. ADR-0035 design — settled with the user (do not re-litigate)

All user-confirmed through discussion this session.

  1. Own per-statement Sql* DDL commandsSqlCreateTable, SqlAlterTable, SqlDropTable, SqlCreateIndex, SqlDropIndex (granularity mirrors the DML Sql* set). Clarifies ADR-0030 §4: DDL gets its own advanced commands, but unlike DML they execute structurally, not verbatim — raw execution would lose the playground's types, named relationships, and STRICT. ("Verbatim" for DML was a convenience, not a rule.) Simple mode is untouched (additive). Handlers reuse the low-level schema/metadata helpers where the op matches simple mode, stand alone where the SQL surface is richer (multi-FK CREATE TABLE) — clarity over forced refactoring.
  2. Dispatch: create/drop reuse ADR-0033 Amendment 1's category-grouped, mode-aware dispatch (SQL-first in advanced, simple fallback); alter is a new advanced-only entry word.
  3. Type vocabulary (ADR-0030 §5): playground keywords + standard-SQL aliases mapped (integerint, varchartext, timestampdatetime, …); length args accepted-and-ignored; no engine type names in/out.
  4. FK → named relationships: inline REFERENCES + table-level FOREIGN KEY create the table and its relationship metadata in one command (= one undo step); ON DELETE/ON UPDATE → ADR-0013 actions; constraint name → relationship name.
  5. Column-type conversion — unified (ADR-0017 engine, mode policy): clean auto-converts both modes; incompatible + own-type-static cases refuse both modes; lossy refuses-by-default in simple mode (--force-conversion), but advanced mode performs it with a post-op loss note and relies on undo as the net (no force flag, no dropping to simple mode).
  6. Table rename (C1) — advanced-only ALTER TABLE … RENAME TO; new low-level op (rename table + its CSV file + the relationship metadata rows). No simple-mode form.
  7. Surface = full, no pre-emptive cuts; 9 sub-phases 4a4i (ADR §13), each with exit + DA gates.
  8. Integration is structural, not free of authoring (ADR §11): the walker mechanisms (highlighting, [ERR]/[WRN], usage skeleton, completion engine) come free; each node still authors the right IdentSource on schema-name slots, its hint/usage catalog keys, and DDL-specific walker diagnostics (the DDL peers of the DML ones ADR-0033 added).
  9. Replay: create/drop/alter are schema-write entry words, not in ADR-0034's app-lifecycle skip set, so SQL DDL replays as a write — no replay-filter change (unlike undo/redo).

§4. ADR-0035 implementation — the NEXT job

Begin Phase 4 at sub-phase 4a, test-first, following the ADR-0033 sub-phase model. Recommended first action: read ADR-0035 in full, then write a short plan doc (docs/plans/<date>-adr-0035-sql-ddl.md) and confirm any open micro-calls with the user before coding — exactly how ADR-0033/0034/ 0006 were run.

Sub-phases (ADR-0035 §13):

  • 4a — dispatch + CREATE TABLE core (columns + the §3 type map + column constraints + single/compound PRIMARY KEY); no FK yet.
  • 4b — FK in CREATE TABLE (inline + table-level) → relationships.
  • 4cDROP TABLE.
  • 4dCREATE [UNIQUE] INDEX / DROP INDEX.
  • 4eALTER TABLE add/drop/rename column.
  • 4fALTER TABLE … ALTER COLUMN TYPE (the §7 conversion model).
  • 4gALTER TABLE add/drop constraint, add FK.
  • 4hALTER TABLE … RENAME TO (the §6 new low-level op).
  • 4i — verification sweep (typing-surface/matrix, engine-neutral errors, undo parity, help/usage).

Concrete must-not-forget for the implementer:

  • Undo wiring for the new commands. Each Sql* DDL command becomes a new Request variant in src/db.rs and must be wrapped with snapshot_then like the existing 19 mutating arms (so it's one undo step). handle_request's exhaustive match will force you to handle each new variant — wrap it, don't reply.send it raw. create/ drop/alter need no is_app_lifecycle_entry_word change (they're writes, §3.9).
  • Grammar lives in src/dsl/grammar/ (CommandNode + the REGISTRY in mod.rs, tagged CommandCategory); mirror the ADR-0033 DML nodes (src/dsl/grammar/sql_*). CHECK/DEFAULT expressions reuse the ADR-0031 sql_expr fragment.
  • ALTER/column ops build on the ADR-0013 rebuild-table primitive (already used by drop/rename/change-column).
  • Catalog + keys lockstep (src/friendly/strings/en-US.yaml + src/friendly/keys.rs, validated by keys_validate_against_catalog): every new help_id/usage_id/diagnostic key needs both a catalog body and a keys.rs entry; engine-neutral wording (the vocab audit enforces it).
  • Tests: four tiers (ADR-0008). Per-sub-phase Tier-3 like tests/sql_insert.rs/sql_update.rs/sql_delete.rs, plus an end-to-end tests/sql_ddl_e2e.rs (mirror sql_dml_e2e.rs), plus typing-surface/matrix coverage. Add a DDL undo test (each statement = one undo step; CREATE TABLE with FK = one step).

Open micro-calls to escalate when reached (not yet decided):

  • CREATE UNIQUE INDEX — ADR-0025's index model may need a unique flag (ADR §4/§13 4d flags this).
  • Exact ALTER COLUMN … TYPE spelling, and whether IF [NOT] EXISTS is admitted or an ordinary parse error (ADR §12 leans OOS).
  • Status flip: ADR-0035 is Proposed; flip to Accepted once 4a validates the path end-to-end (the ADR-0033 lifecycle).

§5. Other tracked deferred items (nothing lost)

  • (A) App-lifecycle-command runtime-failure journalling (small ADR-0034 follow-up; recorded in ADR-0034's Implementation note).
  • M4 — execution-time mode side-channel (deferred by ADR-0033 Amendment 3; needs its own ADR).
  • blob value literal (src/dsl/value.rs) — pre-existing gap.
  • Undo residual edge (ADR-0006 Implementation note): if the entire .snapshots/ dir is unwritable, clear_redo can also fail and a stale redo could survive — accepted (whole undo subsystem is broken then).
  • CI / TT5, DSL→SQL teaching echo (ADR-0030 Phase 5), DDL as the last SQL phase before §6 polish.

§6. Process pins (unchanged, still binding)

  • Confirm every commit. Propose the message; wait for the go-ahead. (Every commit this session was user-approved.)
  • Push is the user's step. Never push; never prompt about it.
  • No AI attribution in commits (global rule).
  • Probe, don't reason. The /runda round this session found a real silent-data-loss bug by running a throwaway probe, not by reasoning. Reproduce/print before concluding; delete probes before committing.
  • Escalate ADR-vs-implementation mismatches and scope calls. The whole ADR-0035 design was settled by escalating (the reuse-vs-own-command question, the conversion model) rather than guessing — and corrected twice when the user pushed back.
  • Keep docs in lockstep. ADR status flips update docs/adr/README.md in the same edit; behaviour changes update requirements.md.
  • Terminology: the DSL is the one unified command grammar; the real axis is mode-availability (simple / advanced / both), not "DSL vs SQL". Avoid calling simple-mode commands "the DSL".

§7. How to take over

  1. Read, in order: this file → docs/adr/0035-advanced-mode-sql-ddl.md (the next job) → docs/adr/0030-advanced-mode-sql-surface.md (§4/§5 architecture) + docs/adr/0033-sql-dml-grammar.md (the dispatch + sub-phase precedent to mirror) → CLAUDE.mddocs/requirements.md (Q4/C1).
  2. Baseline:
    cargo test    # expect 1698 passing / 0 failing / 0 skipped / 1 ignored
    cargo clippy --all-targets -- -D warnings   # clean
    
  3. Start ADR-0035 per §4: read the ADR, draft a short plan, confirm the open micro-calls with the user, then implement 4a test-first.
  4. Escalate anything not settled in ADR-0035; the user wants mismatches and scope calls surfaced, not silently decided.