Commit Graph
100 Commits
Author SHA1 Message Date
claude@clouddev1 c84a640259 docs(website): document the hint feature with a cast (ADR-0053)
getting-help gains a "Hints" section — F1 for a tier-3 teaching hint on the
live input, `hint` to explain the most recent error — with the real rendered
block and a cast showing both: the live-input hint (via the demo-mode
Ctrl-G→[F1] alias, since autocast can't send F1) and `hint` on an error.
the-assistive-editor points at F1. Page converted to .mdx to embed the cast;
CtrlG added to the cast generator's key map.
2026-06-15 21:49:29 +00:00
claude@clouddev1 407408ec29 Merge branch 'main' into website 2026-06-15 21:44:22 +00:00
claude@clouddev1 4016c3e5cd feat(demo): Ctrl-G as a demo-mode F1 alias for casts (ADR-0047 Amendment 1)
ci / gate (push) Successful in 3m3s
The contextual hint overlay (ADR-0053) opens on F1, but F1 is an escape
sequence the autocast recorder can't emit — so casts (and presenter /
teacher sessions) couldn't trigger the most teaching-relevant overlay.

In demo mode only, Ctrl-G now aliases F1: it runs the same hint logic and
badges AS [F1], so a recording is visually identical to a real F1 press.
Ctrl-G is the only fit — Ctrl+digit (e.g. Ctrl-1) isn't encodable in a
legacy terminal (arrives as a bare `1`), and the kitty protocol that would
encode it needs escape sequences autocast can't send (and the app doesn't
enable keyboard-enhancement flags). Demo-gated, so the shipped keymap
stays F1-only; outside demo mode Ctrl-G is inert.

- app.rs: hint_key guard gains the demo-gated Ctrl-G disjunct;
  demo_badge_label maps Ctrl-G -> [F1]; 3 Tier-1 tests + badge assertion.
- ADR-0047 Amendment 1 + README index; also removed two stray
  </content> / </invoke> lines accidentally committed in the ADR file.

docs: drop three more stale "deferred" entries from CLAUDE.md — readline
shortcuts (I1b, ADR-0049), tab completion (I3), and syntax highlighting
(I4) are all implemented; only multi-line input (I1) remains open.
2026-06-15 21:30:37 +00:00
claude@clouddev1 1feb803aab chore(website): re-record all casts against the current app
pnpm casts refresh so every cast reflects the merged app — the
context/state-aware keybinding strip, the readline keys, year/choice-set
seeding, and the DDL-confirmation changes. The .cast files are
regenerable artifacts.
2026-06-15 20:59:49 +00:00
claude@clouddev1 93a40970c3 docs(website): landing — Wordmark replaces the plain title heading
Hide the splash hero's redundant <h1> (kept in the DOM for SEO/a11y,
landing-scoped via a title-only hero) and render the Wordmark + tagline +
buttons in the body, so the brand lockup sits where the heading was and
the content rises above the fold (it was nearly hidden on an iPad).
Styles in global.css; doc-page headings are unaffected.
2026-06-15 20:59:49 +00:00
claude@clouddev1 96b9581089 docs(website-adr): record website CI as implemented (ADR-website-001 §4)
The Gitea Actions → Cloudflare Pages pipeline shipped; update §4 from
"No CI yet" to the implemented workflow, the `relplay` project, the
branch→environment mapping, and the required secrets.
2026-06-15 20:59:49 +00:00
claude@clouddev1 b60c0bb0ec ci: skip the crate gate for website-only changes
ci / gate (push) Successful in 3m0s
Add website/** and the website workflow to ci.yaml's paths-ignore, so a
push confined to the website subproject (built + published by
website.yaml) no longer runs clippy+test. A push that also touches crate
code still gates (paths-ignore skips only when all files match).
2026-06-15 20:24:46 +00:00
claude@clouddev1 c2baf6923b ci(website): Cloudflare Pages deploy via Gitea Actions
ci / gate (push) Successful in 3m5s
website / deploy (push) Successful in 1m47s
New .gitea/workflows/website.yaml: on a push to main or website that
touches website/**, build the Astro site with pnpm and deploy
website/dist to the `relplay` Cloudflare Pages project via wrangler —
--branch selects production (main) vs preview (website). Runs on the
bare ci-public runner (node present; pnpm via corepack). Pin pnpm with
package.json's packageManager for deterministic corepack installs.

Requires repo Actions secrets CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID.
2026-06-15 20:04:48 +00:00
claude@clouddev1 1660a6a17c docs: handoff 72 — H2 hint corpus verified (4 fixes + parse guard)
ci / gate (push) Successful in 2m59s
2026-06-15 19:03:13 +00:00
claude@clouddev1 ea38e7a151 docs(website): update seed (year + choice-sets) and readline keys for the merge
build-ci-image / build (push) Successful in 11m19s
ci / gate (push) Successful in 3m8s
Seed page reflects #33/#34: year-as-int columns, built-in value sets
(priority/severity/rating), advisory now status-only; output blocks
re-captured and the seed cast re-recorded. Assistive-editor documents
the #29 readline shortcuts (Ctrl-A/E/W/K/U, Esc) and #30 cross-mode
history recall; multi-line stays the only planned item.
2026-06-15 18:59:50 +00:00
claude@clouddev1 5a37437055 fix(hint): correct H2 corpus errors + add parse guard (handoff-71)
Semantic verification pass over the tier-3 `hint` corpus (ADR-0053).
Four content errors corrected in src/friendly/strings/en-US.yaml:

- cmd.create_table: the example `with pk id(serial), name(text),
  email(text)` declares a 3-column COMPOUND primary key, not a PK
  plus regular columns (every `with pk` column is a key member,
  ADR-0005). Rewritten to a single-column PK + `add column` for the
  rest; what/concept aligned.
- cmd.save: `save as my-shop` does not parse — `save as` takes no
  inline name, it opens a path-entry prompt. Example -> `save as`;
  what no longer implies inline naming; added a temp-vs-named concept.
- cmd.import: target `shop-copy` does not parse — the `as <target>`
  slot is a NewName ident that rejects hyphens. -> `shop_copy`.
- err.foreign_key.child_side: dropped the bogus `on delete set
  null/cascade` remedy — that governs the parent direction; a
  child-side violation is fixed by inserting the parent first
  (matches the tier-1 hint).

Adds every_cmd_hint_example_parses_in_its_mode — a catalog-driven
guard that parses every hint.cmd.* example in its taught mode,
backstopping syntactic drift (it caught the save and import errors).
Registers the new hint.cmd.save.concept key.

docs: drop two stale "deferred" entries from CLAUDE.md — project
storage (export/import, --resume, input history, migration scaffold)
and m:n convenience (C4) are all implemented (ADR-0015/0045); record
the verification pass on requirements.md H2.
2026-06-15 18:59:38 +00:00
claude@clouddev1 3fe62af886 Merge branch 'main' into website 2026-06-15 17:22:46 +00:00
claude@clouddev1 b4441507e2 docs: handoff 71 — hint content needs a semantic verification pass
User smoke-test found hint.cmd.create_table is semantically wrong: the
example `create table Customers with pk id(serial), name(text),
email(text)` reads as a 3-column table but actually declares a compound
PK (id, name, email) — everything after `with pk` is the PK column list
(ADR-0005). Root cause: Phase C examples were syntax-checked but some
were extrapolated, not verified to *do* what what/concept claims. Handoff
specifies a full per-block semantic pass (run each example / check the
ADR) + a ready-to-apply create_table fix.
2026-06-15 17:14:22 +00:00
claude@clouddev1 8ae0eedd44 Merge branch 'ci'
ci / gate (push) Successful in 3m7s
release / test (push) Successful in 2m43s
release / build (aarch64-pc-windows-gnullvm) (push) Successful in 4m17s
release / build (aarch64-unknown-linux-musl) (push) Successful in 4m15s
release / build (x86_64-pc-windows-gnu) (push) Successful in 4m48s
release / build (x86_64-unknown-linux-musl) (push) Successful in 4m10s
2026-06-15 16:57:18 +00:00
claude@clouddev1 5f28de8ac3 docs(ci): move CI handoff into docs/ci/handoff (avoid main collision)
main independently wrote its own docs/handoff/20260615-handoff-70.md the
same day, so my global-sequence handoff-70 was an add/add conflict waiting
to merge. Relocate it to docs/ci/handoff/20260615-handoff-ci-01.md (its own
namespace, like docs/ci/adr) + a README index. main's handoff-70 is
untouched; the merge becomes conflict-free.
2026-06-15 16:56:50 +00:00
claude@clouddev1 888be16090 docs: handoff 70 — ADR-0052 follow-up + H2 hint shipped (ADR-0053)
ADR-0052 vestigial-source unwind; H2 contextual hint (F1 keybinding +
`hint` command) fully implemented Phases A–D, closing A1 + H2. 4 issues
filed (#35–#38, incl. 3 hint/help deferrals). CI branch merged into main
mid-session (D1 release work now on main). 2499 pass / 1 ignored, clippy
clean.
2026-06-15 16:47:18 +00:00
claude@clouddev1 329adfc935 fix(hint): labelled tier-3 block format + snapshot (ADR-0053 /runda)
Final /runda found the rendered block was three bare unlabelled lines,
deviating from the approved exemplar format. Fix:
- emit_tier3_block now renders a `Hint` heading + aligned `What:` /
  `Example:` / `Concept:` lines (hint.block.* labels); concept stays muted
- lock the format with an insta snapshot (hint_block_insert)
- amend ADR-0053 D2/D4 + exemplars: drop the `Next:` line (tier-2 ambient
  already owns live position-awareness — user-confirmed), align exemplars
  to the shipped format

2499 pass / 1 ignored, clippy clean.
2026-06-15 16:45:47 +00:00
claude@clouddev1 447112b17f feat(hint): H2 Phase D — coverage gate, F1 strip, status flips (ADR-0053)
Completes H2:
- comprehensiveness coverage tests: every REGISTRY command form has a
  hint_id resolving to a hint.cmd.* block, and every runtime error class
  resolves to a hint.err.* block (enforces ADR-0053 D6)
- ADR-0051 keybinding strip advertises F1 in the editing (leads) and
  default states; +shortcut.hint label; 12 full-panel snapshots
  re-accepted (status-bar line only)
- flip ADR-0053 -> implemented, requirements H2 + A1 -> [x], README

2498 pass / 1 ignored, clippy clean.
2026-06-15 16:34:10 +00:00
claude@clouddev1 984bc30256 docs: record CI branch work — D1/D2 done, TT5 partial, handoff 70
requirements.md: D1 (all six cross-platform binaries) and D2 (no-runtime-
deps, per-platform) done; D3 noted (binaries shipped, package managers
pending); TT5 partial (gate + macOS test live; Windows build-only; Tier-4
unwired). CLAUDE.md: add the CI/release decision (-> docs/ci/adr) + update
the deferred list. Adds handoff 70 summarising the pipeline + follow-ups
(incl. the versioning gap).
2026-06-15 16:31:58 +00:00
claude@clouddev1 417cbc8df9 docs(hint): defer pre-submit-diagnostic route + diagnostic.* blocks (ADR-0053)
Phase C scope decision: Diagnostic carries no class key, so the F1
diagnostic route would need a class field threaded through every
diagnostic site (broad change) for marginal value — tier-2 already
surfaces diagnostics and many duplicate the runtime error classes. Defer
the route + the ~33 diagnostic.* tier-3 blocks to issue #38. v1 ships
command-form hints + 9 runtime error-class hints (comprehensive for
those). Updates ADR-0053 D2/D6/Status/OOS + README.
2026-06-15 16:28:54 +00:00
claude@clouddev1 b6b98ad30f feat(hint): H2 Phase C batch 5 — runtime error-class tier-3 hints (ADR-0053)
what/example(fix recipe)/concept for the 9 runtime error classes:
foreign_key parent_side (child_side was the exemplar), unique, not_null,
check, type_mismatch, not_found, already_exists, generic, invalid_value.
Keyed by friendly::error_hint_class; catalogue + keys.rs registered.
+1 spot test; 2496 pass / 1 ignored, clippy clean.
2026-06-15 16:16:49 +00:00
claude@clouddev1 97970f2a2c feat(hint): H2 Phase C batch 4 — advanced-mode SQL tier-3 hints (ADR-0053)
Distinct SQL-syntax hints for the 11 advanced-mode forms: sql create
table / alter table / create index / drop index / drop table / insert /
update / delete, select, with, explain. hint_ids wired on all 11 nodes.

Hardened hint_key_for_input_in_mode for shared entry words: a bare
multi-form entry word defers to tier-2; when the second token isn't a
form word (insert into / update … set), it falls back to the
mode-primary key — so advanced mode resolves to the SQL form and simple
mode to the DSL form. catalogue + keys.rs registered. +2 spot tests +
grammar mode-disambiguation asserts; 2495 pass / 1 ignored, clippy clean.
2026-06-15 16:14:23 +00:00
claude@clouddev1 9c4d520d5c feat(hint): H2 Phase C batch 3 — DML tier-3 hints (ADR-0053)
Per-form hints for querying/changing data: update, delete, show
data/table/tables/relationships/indexes, seed, explain, replay
(insert was the Phase-B exemplar). hint_ids wired on UPDATE/DELETE/
SHOW/SEED/EXPLAIN/REPLAY; catalogue + keys.rs registered. +2 spot
tests (incl. multi-form SHOW disambiguation); 2493 pass / 1 ignored,
clippy clean.
2026-06-15 16:08:57 +00:00
claude@clouddev1 47a08166a4 merging ci branch
build-ci-image / build (push) Successful in 10m58s
ci / gate (push) Successful in 3m8s
2026-06-15 16:07:10 +00:00
claude@clouddev1 6429b56443 feat(hint): H2 Phase C batch 2 — DDL tier-3 hints (ADR-0053)
Per-form hints for the schema-shaping commands: create table, create
m:n, add column/index/constraint, drop table/column/relationship/
index/constraint, rename column, change column (add_relationship was
the Phase-B exemplar). Examples verified against the canonical usage
templates. hint_ids wired on CREATE/CREATE_M2N/DROP/RENAME/CHANGE;
catalogue + keys.rs registered. +2 spot tests (incl. multi-form DROP
disambiguation); 2491 pass / 1 ignored, clippy clean.
2026-06-15 16:05:41 +00:00
claude@clouddev1 4bdfce6250 feat(hint): H2 Phase C batch 1 — app-command tier-3 hints (ADR-0053)
Per-form hints for the 14 app-lifecycle commands (quit/help/hint/
rebuild/save/new/load/export/import/mode/messages/undo/redo/copy),
reference-leaning what/example with concept where it teaches (rebuild,
mode, messages, undo, export, help). hint_ids wired, catalogue + keys.rs
registered. +1 spot test; 2489 pass / 1 ignored, clippy clean.
2026-06-15 16:01:39 +00:00
claude@clouddev1 138e766817 Merge branch 'main' into ci
ci / gate (push) Successful in 3m5s
Bring main's latest (ADRs 0049-0053 + their features) onto the CI branch so
the gate runs against current main before CI lands on main. Clean merge —
ci and main touched disjoint files.
2026-06-15 16:01:09 +00:00
claude@clouddev1 aeb92f56a7 docs(ci): record macOS implementation in ADR-ci-003 (D1 complete)
ci / gate (push) Successful in 3m23s
macOS is no longer deferred — built natively on a Tart (Apple-Silicon)
runner (real hardware → licensed SDK, no grey area). Amendment documents
release-macos.yaml (dispatch-only, needs main), the libiconv de-nix +
ad-hoc re-sign, the runner-label `:host` backend nuance, generation-based
cache pruning, and D2-on-macOS (system libs only). All six D1 targets now
produce artifacts. Updates the deferred list + index entry.
2026-06-15 15:56:38 +00:00
claude@clouddev1 4a5fd1b5c1 feat(hint): H2 Phase B — per-form keying + the three exemplars (ADR-0053)
The first exemplar (`add 1:n relationship`) showed per-node keying is
too coarse for multi-form commands, so revise the mechanism to per-form.

- CommandNode `hint_id: Option<&str>` -> `hint_ids: &[&str]` (mirrors
  usage_ids); hint_key_for_input_in_mode reuses a factored-out
  pick_form_key (shared digit/m:n/suffix form disambiguation with
  usage_key_for_input_in_mode)
- wire INSERT + ADD (all four forms) with hint_ids
- author the three approved exemplars: hint.cmd.insert,
  hint.cmd.add_relationship, hint.err.foreign_key.child_side
  (what/example/concept) + keys.rs registration
- revise ADR-0053 D3 to per-form; record clause-concept hints as a
  deferred extension (issue #37); update README + plan
- +5 tests; 2488 pass / 1 ignored, clippy clean
2026-06-15 12:18:41 +00:00
claude@clouddev1 050b36391e feat(hint): H2 Phase A — hint command + F1 keybinding skeleton (ADR-0053)
The mechanism for the contextual hint, with tier-2 fallback; the
tier-3 corpus lands in later phases.

- new CommandNode `hint_id` field (all None for now)
- AppCommand::Hint + HINT grammar node + REGISTRY + dispatch
- F1 read-only overlay in handle_key (buffer/cursor/memo untouched)
- note_hint* renderers; hint_id_for_input_in_mode (shared selection
  helper refactored out of usage_keys_for_input_in_mode)
- last_error_hint_key + friendly::error_hint_class classifier
- catalogue: help.app.hint / parse.usage.hint / hint.getting_started
- +12 tests; 2483 pass / 1 ignored, clippy clean
2026-06-15 10:36:51 +00:00
claude@clouddev1 9868442889 docs(plan): H2 contextual hint implementation plan (ADR-0053)
Phased build plan: mechanism skeleton with tier-2 fallback first
(hint_id field, AppCommand::Hint, F1 read-only overlay, last_error_hint_key,
note_hint* renderer), then catalogue + the three approved exemplars,
then comprehensive content in batches, then polish. Reuses the existing
command_for_entry_word / usage_keys_for_input_in_mode lookups for
command identification. Test spine includes the comprehensiveness
coverage test that gates "comprehensive for v1".
2026-06-14 22:18:59 +00:00
claude@clouddev1 309d2e0b3f ci: release-macos workflow (dispatch); retire macOS smoke-test
The macOS release leg: workflow_dispatch (tag input) on the Tart runner —
test → build both *-apple-darwin targets → rewrite nix libiconv to /usr/lib
+ ad-hoc re-sign → upload binary + .sha256 to the tagged release (idempotent
create-or-get) → prune the nix store by generation. Composed entirely of
parts the smoke-test proved green, so the smoke-test is removed.

Dispatch-only fits the intermittent runner and keeps the 4-target Linux/
Windows release independent. Becomes triggerable once CI is on the default
branch (workflow_dispatch is default-branch-only in Gitea).
2026-06-14 22:18:02 +00:00
claude@clouddev1 e16ad50aa7 docs(adr): ADR-0053 — contextual hint command + F1 keybinding (H2)
Settles the `hint` slot ADR-0003 left pending; closes the last open
piece of A1. Two surfaces (F1 → live-input hint; `hint` command →
last-error expansion), no topic arg, and a new tier-3 teaching corpus
keyed on a new CommandNode `hint_id` so advanced-SQL forms get distinct
mode-correct content. Comprehensive content for v1, authored
exemplars-first. Refines ADR-0003; references ADR-0019/0021/0022/0049/
0051. Files #36 for the parallel help-side gap.
2026-06-14 22:14:11 +00:00
claude@clouddev1 60dbb903cc ci: macOS smoke-test — run tests + nix-store generation pruning
macos-build-test / build (push) Successful in 2m59s
ci / gate (push) Successful in 3m6s
- Add `cargo test` before the darwin builds (gate is Linux-only; the macOS
  leg is test-then-build) — a full dry-run of release-macos bar the upload.
- Add an `if: always()` prune step. The runner wipes the workspace each run,
  so cargo target/ never accumulates (no sweep). The persistent cache is the
  nix store: record the current toolchain in a persistent profile, keep the
  2 newest generations (nix-env --delete-generations +2), reclaim the rest
  (nix-collect-garbage). Pairs with min-free/max-free in the runner nix.conf.
2026-06-14 22:07:48 +00:00
claude@clouddev1 9a126782f1 ci: de-nix macOS binary libiconv via install_name_tool + re-sign
macos-build-test / build (push) Successful in 2m11s
build-ci-image / build (push) Successful in 9m49s
ci / gate (push) Successful in 2m50s
libiconv is the only /nix/store dep the darwin stdenv bakes in (everything
else is system frameworks + libSystem/libobjc). The smoke-test now rewrites
that load path to /usr/lib/libiconv.2.dylib (ABI-compatible, present on
every Mac), re-signs ad-hoc (install_name_tool breaks the sig; arm64
requires a valid one), then verifies no /nix/store paths remain, the
signature is valid, and the native binary launches. Flake comment updated
to reflect the propagated-libiconv reality.
2026-06-14 21:43:01 +00:00
claude@clouddev1 4d004f5847 ci: drop nix libiconv from darwin build (portable macOS binary)
macos-build-test / build (push) Failing after 1m36s
build-ci-image / build (push) Successful in 9m45s
ci / gate (push) Successful in 2m59s
The smoke-test caught the aarch64 binary linking a /nix/store libiconv.dylib
— non-portable (won't exist on a user's Mac). The Apple SDK already provides
a system libiconv stub, so removing pkgs.libiconv makes the linker resolve
-liconv to /usr/lib instead. The smoke-test now fails if any /nix/store dylib
is linked.
2026-06-14 21:36:08 +00:00
claude@clouddev1 d5fb47bcc8 ci: macOS build smoke-test + flake darwin support
macos-build-test / build (push) Successful in 3m52s
build-ci-image / build (push) Successful in 10m3s
ci / gate (push) Successful in 2m52s
Add the two *-apple-darwin targets to rust-toolchain.toml and apple-sdk +
libiconv to the flake devShell (darwin only) so the nix toolchain links
AppKit; make cargo-zigbuild/zig Linux-only (macOS builds natively). Repoint
the throwaway macOS workflow to actually build both darwin targets through
the flake on the Tart runner — the first real check of the macOS leg, which
can't be verified locally. Delete once release-macos lands.
2026-06-14 21:28:41 +00:00
claude@clouddev1 0878c6df19 ci: target the macOS runner by label name macos (not macos:host)
macos-probe / probe (push) Successful in 57s
ci / gate (push) Successful in 2m46s
In act_runner a label is `<name>:<backend>`; `:host` is the execution-
backend schema (run on host, no container), not part of the label. The
runner registered as `macos:host` therefore has the label `macos`, which
is what runs-on must reference.
2026-06-14 21:21:13 +00:00
claude@clouddev1 52815f1a76 ci: trigger macos-probe on push (workflow_dispatch needs default branch)
ci / gate (push) Successful in 2m48s
macos-probe / probe (push) Has been cancelled
Gitea only exposes workflow_dispatch for workflows on the default branch
(main); our CI is on `ci`, so the manual-run button/API isn't available.
Add a push trigger (filtered to the probe file) so we can drive the macOS
runner test from the ci branch. workflow_dispatch kept for post-merge.
2026-06-14 21:18:25 +00:00
claude@clouddev1 2721bd8d04 ci: macOS (Tart) runner probe — throwaway diagnostic
ci / gate (push) Successful in 3m1s
Manual-dispatch probe on runs-on macos:host to confirm the runner picks up
jobs and report arch / macOS version / Xcode SDK / toolchains (nix, rustup,
cargo) / git+node, before wiring the macOS release leg. Delete once done.
2026-06-14 21:11:28 +00:00
claude@clouddev1 e8fa859ab9 refactor(db): unwind vestigial worker source plumbing (ADR-0052 follow-up)
ADR-0052 moved success journaling out of the worker to the dispatch
layer, leaving the `source` that handlers threaded purely for the
worker's old history.log write dead. Remove it:

- drop `_source` from finalize_persistence and do_rebuild_from_text
- inline + delete the three read-only *_request wrappers
- drop the now-unused `source` param from the ~30 forwarding worker
  handlers (leaf + composite), compiler-guided
- remove the `source` field from the DescribeTable/QueryData/RunSelect
  requests and their DatabaseHandle methods (call sites updated)

The only worker `source` left is the snapshot/undo label
(snapshot_then / stage_pre_mutation / begin_batch). Purely mechanical,
no behaviour change. 2471 pass / 0 fail / 1 ignored, clippy clean.
2026-06-14 13:47:49 +00:00
claude@clouddev1 ae73a4be85 docs: handoff 69 — four issues closed (#27/#28/#29/#30) + ADRs 0049–0052; tracker empty 2026-06-14 12:08:24 +00:00
claude@clouddev1 4aeea55984 feat(history): mode-tagged history + top-of-chain journaling (#30)
Record the submission mode per history entry so advanced commands are
reusable in simple mode, and fix the bug where a ':'-one-shot command
lost its ':' across sessions (ADR-0052, closing #30).

Format: the history.log status token gains an optional ':adv' suffix
(ok / ok:adv / err / err:adv); 'source' stays last and canonical, so
replay is unaffected. The in-memory ring (still Vec<String>) stores
advanced entries ': '-prefixed; recall strips the ':' in advanced mode
and keeps it in simple; hydration reconstructs the prefix from the tag.

Journaling moved from the worker to the dispatch layer (spawn_dsl_-
dispatch / run_replay / app-command sites), where the mode is in scope
with no worker plumbing; finalize_persistence writes only yaml/csv
(commit-db-last still atomic for state). The journal write is now
best-effort (command already committed), consistent with the failure
path. App commands journal simple, so they recall bare. Journaling is
now uniform (every successful command, per ADR-0034) — closing a gap
where show tables/relationships/explain didn't journal.

Amends ADR-0034 (status tag + journaling location), ADR-0015 §6
(history.log out of the worker tx), ADR-0040 (journal-write best-effort).
15 worker-level journaling tests retired, re-covered at the new layer
(history.rs format, app.rs recall matrix, iteration6 cross-session
regression, replay). 2471 pass / 0 fail / 0 skip, clippy clean.
2026-06-14 11:20:55 +00:00
claude@clouddev1 5869eec4f4 docs(ci): ADR-ci-003 — cross-platform release builds (D1 matrix)
Record the multi-platform build strategy as its own decision: cargo-zigbuild
for the four non-macOS targets, the static/standalone posture per platform,
the Windows synchronization stub, the test->build matrix workflow, and the
macOS deferral with its licensing rationale (the public CI image can't carry
the SDK). Shrinks the ci-001 amendment to a pointer; updates the index.

Runtime-verified by the user: Linux x86_64 + Windows aarch64 run correctly.
2026-06-13 19:11:29 +00:00
claude@clouddev1 eceedc19b7 feat(ui): context- and state-aware bottom keybinding strip (#27)
Per ADR-0051 (closing issue #27): the bottom status line is now a
keystrokes-only, state-selected strip. A pure status_bar_bindings()
picks the binding set by priority (first match wins):

  sidebar focus   → Ctrl-O next pane · ↑↓/PgUp/PgDn scroll · Esc input
  completion live → Tab/Shift-Tab cycle · Esc cancel · Enter run
  history nav     → ↑↓ browse · Esc clear · Enter run
  editing         → Esc clear · Ctrl-A/E home/end · Ctrl-W del word · Enter run
  default (empty) → Ctrl-O sidebar · Tab complete · ↑ history · Enter run

The editing state surfaces the #29 readline keys (ADR-0049's deferred
advertisement). Typed-command words (mode advanced/simple, the ':'
one-shot) and Ctrl-C quit leave the strip; simple mode's empty-input
hint gains a '`mode advanced` for SQL' pointer (advanced mode shows
none — a switcher knows the way back, and help covers it).

Mechanism: status_bar_bindings + a thin renderer (unit-testable);
App::is_browsing_history() exposes the private history_cursor; the mode
pointer lives in resolve_hint_lines. Catalog: 12 new shortcut labels +
panel.hint_mode_advanced (en-US.yaml + keys.rs, validator 1:1), 5 dead
strip strings removed.

Forks user-chosen: editing state shows #29 keys; quit omitted; no
width-drop machinery (longest strip ~65 cols fits; a width-budget test
keeps it lean). Modal-aware strip is OOS (pre-existing). Tests: 9
Tier-1 unit (per-state key sets, width budget, mode pointer), 1 Tier-3
rewritten, 15 full-panel snapshots re-accepted (reviewed). 2467 pass /
0 fail / 0 skip, clippy clean.
2026-06-13 12:18:37 +00:00
claude@clouddev1 298475b326 ci: D1 release matrix over the four non-macOS targets
build-ci-image / build (push) Successful in 9m56s
ci / gate (push) Successful in 2m47s
release / test (push) Successful in 2m18s
release / build (aarch64-pc-windows-gnullvm) (push) Successful in 3m31s
release / build (aarch64-unknown-linux-musl) (push) Successful in 3m52s
release / build (x86_64-pc-windows-gnu) (push) Successful in 4m14s
release / build (x86_64-unknown-linux-musl) (push) Successful in 3m25s
release.yaml becomes test (once, host) -> build (matrix) over the four
cargo-zigbuild targets; each matrix job uploads its binary + .sha256 to
the shared release (idempotent create-or-get). Records the expansion in
ADR-ci-001 (2026-06-13 amendment); macOS stays deferred.
2026-06-13 12:14:49 +00:00
claude@clouddev1 04ebd83f08 build: D1 cross-compile via cargo-zigbuild (4 non-macOS targets)
Replace the single-target musl cc with cargo-zigbuild + zig in the flake
devShell — one universal cross cc/linker (incl. rusqlite's bundled SQLite
C) for all four non-macOS D1 targets, added to rust-toolchain.toml:
  x86_64/aarch64-unknown-linux-musl              (static, D2)
  x86_64-pc-windows-gnu, aarch64-pc-windows-gnullvm  (standalone .exe)

Windows links -lsynchronization (std WaitOnAddress), which rust-overlay's
toolchain and zig's mingw don't ship; the symbols are forwarded by
kernel32, so an empty stub libsynchronization.a (ci/winstub/, wired via
.cargo/config.toml for the windows targets only) satisfies the linker.
Verified: all four build; linux static; windows valid PE32+.
2026-06-13 12:14:49 +00:00
claude@clouddev1 8ac3537df0 feat(render): incidental-DDL confirmations show structure only, no relationships (#28)
Per ADR-0050 (closing issue #28): the confirmation echo after an
incidental structural edit — create table, add/drop/rename/change
column, add/drop index — now renders the structure only (header +
column box + indexes + constraints) and no longer appends the
References:/Referenced by: relationship block.

Rationale: a confirmation reports the change just made, not the
table's relationships, which the user didn't touch. Relationship info
is still one `show table <T>` away, and the relationship-subject
surfaces (show table, add/drop relationship) keep their ADR-0044
diagrams unchanged.

Scope is all incidental DDL (user-confirmed). Mechanism: drop the
relationship-block call from render_structure (all its callers are
incidental DDL); the handle_dsl_success diagram-vs-structure routing
is unchanged. The orphaned relationship_prose_lines + cols_disp
helpers are deleted (the prose format survives in ADR-0016 §5 + git
history for a future OOS-7 always-prose setting).

ADR-0050 supersedes ADR-0044 §1's incidental-DDL prose clause and the
relationship-block half of ADR-0016 §5 (both annotated). Tests: prose-
presence unit test + snapshot removed; new unit test locks structure-
only with inbound+outbound relationships present; the misnamed add-
column integration test inverted + renamed. 2458 pass / 0 fail / 0
skip, clippy clean.
2026-06-12 22:45:18 +00:00
claude@clouddev1 18d08642d7 ci: skip the gate for docs-only changes
ci / gate (push) Successful in 2m31s
Add paths-ignore (docs/**, **/*.md) to the gate's push + pull_request
triggers so markdown/docs-only changes don't run a full clippy+test that
can't change the outcome. Mixed code+docs pushes still gate (not all
files are ignored); flake/toolchain changes are deliberately not ignored.
Also refresh a stale ADR-0049 -> ADR-ci-002 comment reference.
2026-06-12 22:42:50 +00:00
claude@clouddev1 da8bfebc36 docs(ci): establish docs/ci/adr namespace (ci-001 pipeline, ci-002 flake)
ci / gate (push) Successful in 2m33s
Records the CI/release pipeline as ADR-ci-001 and relocates the nix-flake
ADR from main's ADR-0049 to ADR-ci-002 (content unchanged, history note
added). Both live in docs/ci/adr/ with a README index — a dated,
ci-segmented namespace disjoint from main's integer ADR sequence, the
same split the website subproject uses to avoid cross-branch number
collisions. Drops the ADR-0049 entry from docs/adr/README.

ci-001 covers the runner model, the baked nix CI image, the clippy+test
gate, the static-musl release on tag, trigger hygiene, auth, and scope.
2026-06-12 22:38:34 +00:00
claude@clouddev1 66c8bdaa65 feat(input): readline keymap — Esc-clear + Ctrl-A/E/W/K/U (#29)
Implement the deferred I1b readline shortcuts in the command input
field (ADR-0049, closing issue #29):

  Esc      clear a partly-typed command (only when no completion memo)
  Ctrl-A   cursor to line start (Home alias)
  Ctrl-E   cursor to line end (End alias)
  Ctrl-W   delete the previous word (readline-style, UTF-8 safe)
  Ctrl-K   kill to end of line
  Ctrl-U   kill to start of line

Esc precedence is preserved: a live Tab-completion memo still wins
(Esc undoes the completion first, ADR-0022); Esc clears only when no
memo is alive. While a sidebar panel is focused (Ctrl-O), Esc exits
navigation mode upstream and never clears the input draft. Cursor-only
keys leave history navigation intact like Home/End; buffer-mutating
keys end it like Backspace.

New helpers clear_input / delete_prev_word / kill_to_end /
kill_to_start in src/app.rs. 22 new Tier-1 tests (2458 pass / 0 fail
/ 0 skip, clippy clean). ADR-0049 amends ADR-0046's OOS list;
requirements.md I1b marked done.
2026-06-12 22:12:08 +00:00
claude@clouddev1 89b9392c25 ci: release job — test before publish, pin bash, fix diagnostic
release / release (push) Successful in 3m59s
build-ci-image / build (push) Successful in 7m27s
ci / gate (push) Successful in 2m27s
- Run cargo test before the build so a tag never publishes untested code.
- Pin shell: bash on the scripted steps; the runner defaults to dash,
  which rejected `set -o pipefail` and failed run 22's package step.
- Swap `file` (absent in the slim image) for `ls -l`.
2026-06-12 22:11:24 +00:00
claude@clouddev1 bba24120f1 ci: scope gate + image-build to branch pushes (skip tags)
Tag pushes ignore paths: filters, so a release tag spuriously rebuilt
the unchanged CI image and re-ran the gate on a commit the branch push
already gated. Add branches: ['**'] to both push triggers — tag pushes
no longer fire them (release.yaml owns tags). Pushing commits + a tag
together still gates the commits via the branch push.
2026-06-12 22:11:24 +00:00
claude@clouddev1 88145225cc ci: release workflow — static binary to Gitea releases on tag
build-ci-image / build (push) Has been cancelled
ci / gate (push) Successful in 2m32s
release / release (push) Failing after 3m2s
On a v* tag, builds the x86_64-unknown-linux-musl binary in the CI image
and publishes it (+ .sha256) to a Gitea release via the API and the
auto GITEA_TOKEN. x86_64 Linux only for now; rest of the D1 matrix and
D3 packaging layer on later. Correctness comes from the branch gate.
2026-06-12 21:43:23 +00:00
claude@clouddev1 8e3208528e build: static musl release build capability
rust-toolchain.toml gains the x86_64-unknown-linux-musl target; the
flake devShell gains a musl cc (pkgsCross.musl64) + CC/linker env so a
`cargo build --target …-musl` compiles rusqlite's bundled SQLite C and
links fully static (D2: single static binary, no runtime deps). Cargo
release profile strips symbols (13MB -> 10MB). Verified locally: the
musl binary is static-pie, statically linked, stripped, runs standalone.
2026-06-12 21:43:23 +00:00
claude@clouddev1 862ab21202 docs: handoff 68 — six issues closed (#25/#26/#31/#32/#33/#34) + open-issue map 2026-06-12 21:38:57 +00:00
claude@clouddev1 ee3ccd8d77 feat(hint): advertise the optional seed count in the hint panel (#26)
At `seed <table> ▮` the hint showed only the `set`/`--seed` chips and
never mentioned the optional row count — a bare positional number with no
candidate, on an already-complete command, so neither the candidate
ladder nor the resolver surfaced it. (A prior IntroProse attempt was
reverted: pending_hint_mode is cleared by the trailing optionals.)

Carry a skipped Optional's IntroProse hint: walk_optional stashes the
inner's key into a new WalkContext.surviving_intro_hint (key + position)
before the empty match clears pending_hint_mode; the snapshot keeps it
only when the skip position is the cursor (so it never leaks past a
later-consumed `set …` clause, nor once the count is given); the
resolver returns it ahead of the empty-expected short-circuit. The seed
count is wrapped Hinted{IntroProse("hint.seed_count")}; the prose names
the count (default 20), the `.column` column-fill form, and `set` /
`--seed`. Tab still cycles the keywords.

Only IntroProse is carried; ProseOnly/ForceProse and the CREATE-TABLE
element (a required Repeated) are untouched. No AmbientHint/renderer
change. Fires in both modes.

ADR-0022 Amendment 7; +3 tests.
2026-06-12 21:34:48 +00:00
claude@clouddev1 9d8161218a ci: gate workflow + CI-image build/push, drop probe
build-ci-image / build (push) Successful in 6m18s
ci / gate (push) Successful in 3m19s
- build-ci-image.yaml: builds .gitea/ci-image/Dockerfile via DinD and
  pushes git.lazyeval.net/oli/rdbms-playground-ci:latest (REGISTRY_*
  secrets); triggers on image-input changes + manual dispatch.
- ci.yaml: the gate — runs inside that image, clippy -D warnings +
  cargo test, on push/PR. fmt intentionally not gated (ADR-0049).

Removes ci-probe.yaml; it answered the runner questions (jobs run in
containers, host nix unreachable, custom container: works).
2026-06-12 21:08:04 +00:00
claude@clouddev1 dc63ed66f1 ci: nix CI toolchain image (node-slim base + warmed flake)
Job-container image the gate runs in. node:22-bookworm-slim satisfies
the act_runner contract (sleep/bash/node) far more cheaply than the
catthehacker images; single-user nix installed on top (pre-create /nix
+ empty build-users-group so it installs as root in a container) with
the flake's devShell pre-warmed — CI enters a ready 1.95.0 toolchain in
~1.4s. Verified by local build. ~5.5GB (rust toolchain closure); dep/
target caching is a noted follow-up.
2026-06-12 21:08:04 +00:00
claude@clouddev1 deb0948d6c feat(seed): year-as-int + conventional choice-set heuristics (#33, #34)
Two additive D7 catalogue rules, surfaced while writing the website seed
docs. No change to the type fallback, executor, or grammar.

#33 — year-like int columns. `published`/`birth_year` were just `int`, so
they fell to the unbounded int path and produced nonsense (`9419`). Add an
int-gated year rule (after the quantity rule, so `year_count` stays a
count): `year`/`*_year`/`published`/`founded` -> a bounded 1950-2025 year
(new `YearRecent`), or the dob-style birth window 1945-2007 for
`birth`/`born`/`dob` (new `YearBirth`). Plain int; not added to the D9
named-generator vocabulary.

#34 — conventional choice sets. A few enum-ish names have a near-canonical
small set that reads far better than lorem text. Add a type-gated PickFrom
lookup (reusing the existing generator): priority/prio, severity,
rating/stars. `status` is deliberately excluded (values too
domain-specific) and keeps the D12 advisory; a user IN-CHECK still wins.
`priority` leaves ENUM_TOKENS.

ADR-0048 Amendment 1; +8 tests (incl. a column-fill integration test that
also closes a pre-existing gap on that path).
2026-06-12 20:36:20 +00:00
claude@clouddev1 c7ac0c9877 ci: add throwaway runner-probe workflow
ci-probe / host (push) Failing after 54s
ci-probe / nix-container (push) Failing after 1m12s
Diagnostic to determine how the ci-public runner executes jobs and
where the nix toolchain is reachable (host vs default container vs a
custom container:), so the real gate is built on facts. Delete once
the gate lands.
2026-06-12 20:35:39 +00:00
claude@clouddev1 9189740028 build(nix): reproducible dev + build env via a flake (ADR-0049)
Root flake with two outputs: devShells.default (pinned 1.95.0
toolchain via rust-toolchain.toml + rust-overlay, plus cargo-sweep)
and packages.default (rustPlatform.buildRustPackage from the committed
Cargo.lock; doCheck=false). flake.lock pins nixpkgs nixos-26.05 /
rust-overlay / flake-utils. .envrc (use flake) for direnv parity.

Single source of toolchain for dev and the upcoming CI, so they can't
drift. Verified through the flake: nix build yields a working binary,
clippy clean, 2424 tests pass / 0 fail / 1 intentional ignored doctest.
First step toward requirements.md TT5 + D1/D2/D3.
2026-06-12 20:35:39 +00:00
claude@clouddev1 fde50ce3bf fix(ui): mark sidebar focus with an accent colour, not bold (#25)
The focused sidebar panel border (ADR-0046 DC3) was bright `fg` plus
`Modifier::BOLD`. Bold box-drawing glyphs render as broken/gapped
line-art in the asciinema cast player and are fragile in some terminals.

`panel_border_style` now marks focus with a non-bold accent colour
(`theme.mode_simple`, blue); the unfocused border stays muted. Bold is
untouched on text spans (titles, key hints) — the constraint is
specifically that box-drawing borders carry no bold attribute.

Pure style change: the Tier-2 snapshots are text-only so none needed
re-accepting; the Tier-1 assertion was updated and a render-level test
now checks the rendered border cells carry the accent and no bold.

ADR-0046 Amendment 1.
2026-06-12 15:01:26 +00:00
claude@clouddev1 3d4a0fd45e fix(render): trim IEEE-754 noise from displayed decimal arithmetic (#32)
`decimal` is stored as exact TEXT, but SQLite has no native decimal type,
so arithmetic/aggregation implicitly coerces it to an IEEE-754 double.
The computed result carries no playground type, so `sum(price * qty)`
rendered the double's full noise — `298.59999999999997` for `298.60` — a
confusing, off-topic float lesson for a teaching tool.

Add `format_real_display`: round REAL values to 15 significant figures
(a double's reliable precision) then take the shortest round-tripping
form, collapsing `298.59999999999997` to `298.6`. Wired into `format_cell`
(result-set / `show data` cells) only — the sole surface where the noise
appears, since it arises from arithmetic.

Every other f64->string path keeps full precision for semantic, not
cosmetic, reasons: CSV persistence stays byte-exact for round-trip;
`render_value` is a canonical identity key for the uniqueness dry-runs
(dry_run_unique, check_uniqueness_collisions), where rounding would
report collisions the exact-valued engine wouldn't; FK-key matching and
EXPLAIN-SQL literals likewise stay exact.

ADR-0005 Amendment 1; +7 tests.
2026-06-12 14:42:22 +00:00
claude@clouddev1 77c55fa669 docs(website): document the seed command, with cast (ADR-0048)
New Reference page "Generating sample data" (captured output + a
two-table seed cast showing generation, FK sampling context, and a
`set` override); cross-links from inserting-and-editing-data and
columns; seed added to the rdbms highlight grammar;
querying/sql-queries renumbered. Cast stance in STYLE.md revised to
"justify the absence". Refs #33, #34.
2026-06-12 14:41:37 +00:00
claude@clouddev1 7e4bc122be fix(completion): treat a bare in-scope table alias as an alias, not an unknown column (#31)
A bare table alias typed where a column is expected — `… GROUP BY o`,
with `o` aliasing `FROM Orders o` — was a blind spot: completion offered
nothing for `o`, and the hint panel called the in-scope alias an unknown
column (`no such column o on table Orders, ...`).

Completion now offers each FROM source's qualifier (alias-if-present-else
table-name) at a bare sql_expr_ident slot, folded into the column
candidate list; on an exact-qualifier partial the alias source steps
aside so the diagnostic can surface. The bare-reference diagnostic arm
emits a targeted `alias_used_as_column` / `table_used_as_column` hint
("`o` is a table alias — write `o.<column>` ...") after the
projection-alias check, so ORDER-BY alias refs still win and a genuine
unknown column still reports `unknown_column`.

Two guards keep the qualified-form advice correct: SQL only (role
`sql_expr_ident`, so the DSL `expr_column` path keeps `unknown_column`
since the DSL has no `table.column` syntax) and effective-qualifier
match (alias-if-present-else-table, so an aliased source referenced by
its shadowed real name falls through rather than being advised as
`name.<column>`). The diagnostic is a drop-in replacement for
`unknown_column` at the same span/Error severity, so verdict/overlay/hint
paths are unchanged.

ADR-0032 Amendment 3; +10 tests.
2026-06-12 14:03:00 +00:00
claude@clouddev1 4691d7950a Merge branch 'main' into website 2026-06-12 13:22:52 +00:00
claude@clouddev1 82b9f7f9b9 docs: handoff 67 — manual-testing bug fixes + open issues
Captures this session's three committed fixes (flag-completion dash,
table-alias validity, `:` one-shot live feedback), the two
investigated-as-designed findings (comma-FROM, aggregate-without-GROUP
BY), and points the next session at the filed enhancement issues
(#26 seed-count hint, #27 bottom status line, #28 add-column
relationship prose) plus the standing roadmap.
2026-06-12 12:59:38 +00:00
claude@clouddev1 f7155ceafc fix(input): thread the : one-shot escape into live SQL feedback
The `:` one-shot escape (ADR-0003) is stripped at submission, but the
*live* feedback kept the leading `:` in the buffer it handed the
walker — so Tab completion, the validity verdict, and the highlight
overlays all bailed at the `:` and treated the SQL as an unknown
command. Effect: in `:`-mode, Tab completed nothing and a valid query
could flash an error, while the identical line in full `mode advanced`
worked. (The ambient hint already stripped it, which is why the hint
showed the right column name while Tab did nothing.)

Add `App::feedback_view()` — the `:`-stripped SQL view, the cursor
mapped into it, and the stripped byte offset — and route all four live
paths through it:

- completion (Tab): complete against the view, then shift the returned
  `replaced_range` back by the offset so the edit lands in the buffer;
- validity verdict: verdict the SQL, not the sigil;
- highlight/overlays: new `render_input_runs_feedback` highlights and
  diagnoses the view (shifted by the offset) while the `:` renders as
  plain text;
- ambient hint: consolidated onto `feedback_view`, replacing the
  duplicate local `strip_one_shot_prefix`.
2026-06-12 12:43:00 +00:00
claude@clouddev1 4cacb8261c fix(completion): don't flag a table alias used before its FROM clause
In a SELECT, the projection can reference a table alias whose defining
FROM binding sits textually *after* the cursor — e.g.
`select sum(ol.count*p.price) … from … OrderLines ol …`. The candidate
engine already recovers that scope via the §10.6 full-input lookahead
(ADR-0032), but the typing-time validity indicator
(`invalid_ident_at_cursor`) walked only the text before the cursor,
found `ol` in no scope, and flagged it as an unknown column — a red
"ERR" overlay on an otherwise-valid query. (Other aliases escaped only
by coincidentally prefix-matching real columns.)

Give the validity check the same full-input lookahead: at a SQL
expression slot, recover the from-scope from the whole input and bail
when the partial prefix-matches a binding's alias or table name.
2026-06-12 12:19:55 +00:00
claude@clouddev1 c3e010332c fix(completion): flag-aware partial so a dash completes flags, not keywords
The partial-token walk stopped at `-`, so after typing `-` (or `--`)
the partial was empty and the replaced range was a zero-width point
*after* the dash. Two bugs followed at a flag position (e.g.
`add 1:n relationship … -`): the `on` keyword was offered (it
prefix-matched the empty partial), and accepting a candidate inserted
after the dash — `-on`, `---create-fk`, `----all-rows`.

Detect a dash-prefixed token at a word boundary as a flag-in-progress
and fold the whole dash-run into the partial, gated on a flag actually
being expected there (so `where x = -5` stays a signed number, not a
flag). The flag matcher now strips leading dashes and matches the body
uniformly (empty / `-` / `--` → all flags; `--cr` → create-fk).

Keywords like `on` no longer appear after a dash, and accept replaces
the dash(es) so `-` → `--create-fk` and `--all` → `--all-rows`. Two
partial-flag snapshots updated (they had captured the old behaviour).
2026-06-12 10:59:49 +00:00
claude@clouddev1 30b2677bf3 docs: ADR-0048 Phase 2 implemented + handoff 66
- ADR-0048: status → Phase 1 + Phase 2 implemented; D2 amendment
  (quoted dates, no date-literal token) and the override × UNIQUE
  capacity-guard decision; phasing/Status blocks marked done.
- README index: 0048 entry updated (Phase 2 shipped, 2400 tests).
- requirements.md: SD2 → [x] (the override-hooks core + column-fill).
- handoff 66: this session's Phase 2 build + the two /runda passes.
2026-06-12 09:44:36 +00:00
claude@clouddev1 a12facc784 feat(seed): set override clause + column-fill (ADR-0048 Phase 2)
Build the two SD2 surfaces Phase 1 deferred:

- `set` override clause (D2): comma-separated per-column pins —
  `= 'v'` (fixed), `in ('a','b')` (pick-list), `as <generator>`
  (named), `between x and y` (range; numeric and quoted dates).
  Type-aware via the typed `current_column_value` slot; an override
  drops its column from the generic-fill advisory (D13). Folded from
  the flat matched path (build_seed_overrides) and applied to the
  per-column plan (apply_seed_overrides).
- `<table>.<column>` column-fill (D1 form 2): an UPDATE over existing
  rows. Refuses PK/autogen targets, empty-table no-op, FK-samples the
  parent, collision-free for UNIQUE/identifier targets, one undo step;
  `set` may only adjust the filled column.

Supporting work: KNOWN_GENERATORS vocabulary + generator_for_name
(src/seed/vocabulary.rs, D9); a range Generator + range_bounds_reason;
IdentSource::Generators and HighlightClass::Function; completion of the
generator vocabulary after `as` and the set/.col column slots; the
typing-time validity indicator for an unknown generator; help,
parse-error pedagogy rows, and the D13 advisory's Phase-2/3 wording.

A bounded override (fixed value / too-short pick-list) on a
single-column-UNIQUE target is a friendly error rather than a silent
uniqueness cap (post-implementation /runda finding, user-chosen).

Dates in the range form are quoted (no date-literal token exists);
ADR-0048 D2 amended accordingly. Both modes (D5); reproducible (D4).
2026-06-12 09:44:30 +00:00
claude@clouddev1 78c38e8b33 docs: ADR-0048 Phase 1 accepted/implemented + handoff 65
- ADR-0048 status -> Accepted; Phase 1 implemented (commits
  202e25a..fbd219b), with the pre-build and post-implementation /runda
  passes and the 2358-test green state recorded; index entry updated.
- requirements.md: SD1 [x] (whole-row seed + FK/junction, both modes,
  --seed reproducibility with no exceptions), SD2 [/] (core generators /
  determinism done; the set override clause + column-fill are Phase 2),
  A1 14/15 (only hint/H2 remains unregistered).
- Handoff 65: the full seed Phase-1 build, the two /runda passes, where
  the code lives, and Phase-2 / next steps.
2026-06-11 21:49:06 +00:00
claude@clouddev1 fbd219b631 feat(seed): --seed flag, ambient wiring, and /runda hardening (ADR-0048 P1.4 + DA)
P1.4 — user-visible surface:
- Grammar: `seed <table> [count] [--seed <n>]` (the first DSL flag with a
  value); build_seed disambiguates the seed value from the positional count.
- Verified the auto-wired surface: table-name completion, --seed offered as
  a candidate, validity consistent with `show data`, an ADR-0042 near-miss
  row for bare `seed`, and render tests for the seed outcome.

/runda hardening — eight DA findings, all resolved:
- FK sampling now uses ORDER BY so --seed reproducibility no longer relies
  on SQLite's unspecified DISTINCT order (D4).
- shortid columns now generate from seed's seeded RNG (new
  shortid::generate_with_rng) — D4 now holds with no exceptions.
- Added the missing coverage the DA flagged: undo-one-step (D15), replay
  re-runs a seed line (D16), advanced-mode (D5), atomic rollback on a
  constraint failure, seed 0 no-op, complex-CHECK advisory (D17), and
  FK + shortid reproducibility.

2358 pass / 0 fail / 0 skip, clippy all-targets clean.
2026-06-11 21:45:34 +00:00
claude@clouddev1 e6ff63daa2 perf(seed): single-transaction multi-row insert path (ADR-0048 P1.3d)
do_seed inserted row-by-row through do_insert, re-writing the whole
table CSV each time — O(N^2). Extract do_insert's row core into a new
insert_one_row (bind + serial/shortid autofill + FK-enriched execute,
no tx/persist), shared by:
- do_insert: one row in its own transaction (behaviour unchanged).
- do_seed: all rows in ONE transaction, with a single
  finalize_persistence before the single commit — O(N), preserving
  ADR-0015 §6 commit-db-last. A mid-batch failure now rolls the whole
  seed back atomically; the capped preview is read back by rowid.

A near-max 10000-row seed drops from ~tens of seconds to well under
one. do_insert behaviour unchanged (whole suite green: 2346 pass /
0 fail / 0 skip, clippy clean); seed's existing tests exercise the
batch path.
2026-06-11 20:44:34 +00:00
claude@clouddev1 069f9277d1 fix(website): landing card links + keep inline code from breaking mid-token
- Add a teal 'more' link pinned to each landing feature card's
  bottom-right, pointing at the relevant doc page (modes, the SQL echo,
  undo & history, query plans, the assistive editor).
- Stop short inline code (flags like --all-rows) from breaking after a
  hyphen: white-space:nowrap on inline code only; block code in <pre>
  is unaffected and still wraps/scrolls.
2026-06-11 19:24:21 +00:00
claude@clouddev1 0b3ab3cc13 feat(seed): SeedResult outcome, capped preview, advisory, count cap (ADR-0048 P1.3c)
A dedicated SeedResult replaces the borrowed insert outcome (X5):
- CommandOutcome::Seed + DslSeedSucceeded event + handle_dsl_seed_success
  render: the echo, "N row(s) seeded into T", a capped preview table
  (D18, first 20 rows; full count always reported), and a Hint-styled
  advisory naming enum-ish / un-derivable-CHECK columns filled with
  generic text (D12/D13, Phase-1 wording).
- SeedResult carries requested vs produced, so a junction cap is now
  reported to the user, not only logged.
- Count cap (D6): a seed over 10000 rows is refused with a friendly error.
- Catalog keys ok.rows_seeded / seed.capped / seed.advisory_generic.

4 new tests (advisory flag, IN-check not flagged, preview cap, excess
count). 2346 pass / 0 fail / 0 skip, clippy clean.
2026-06-11 19:11:18 +00:00
claude@clouddev1 09b64cbfb7 feat(website): Open Graph social card
Add a 1200x630 social card (dark bg, monospace, teal database-table
motif, the relplay/RDBMS reveal) shown when pages are shared. Source
SVG in src/assets/og-card.svg, rasterised to public/og-card.png with
sharp. Wire site-wide og:image + twitter summary_large_image tags via
Starlight head, with the absolute relplay.org URL.
2026-06-11 18:59:02 +00:00
claude@clouddev1 abd3739168 feat(website): brand layer — teal palette, table logo, wordmark, footer
Anchor the site to the product's identity (Phase B branding):
- Accent palette mapped to the app's in-TUI teal (--sl-color-accent-*,
  light + dark); trim the splash hero's oversized desktop bottom padding.
- Header logo: a database-table glyph with a teal primary-key cell
  (light/dark variants); favicon redrawn to match.
- Landing wordmark 'RELational PLAYground': teal picks out REL+PLAY
  ('relplay', the domain) and R/D/B/M/S (spelling out RDBMS). Sizes
  locked in em off one master scale so the lockup zooms as a rigid unit.
- Footer override: default footer + an understated company (Lazy
  Evaluation Ltd) and source/issues line.

No engine names or 'DSL' in user-facing copy.
2026-06-11 18:50:07 +00:00
claude@clouddev1 9c135010ba feat(seed): uniqueness, junction distinct-combos, IN-CHECK (ADR-0048 P1.3b)
do_seed now enforces value uniqueness and derives enum values:
- Uniqueness groups (D10): the user-fillable PK, compound UNIQUE
  constraints, and single-column UNIQUE / identifier columns stay
  distinct across the batch and against existing rows (retry per row).
  Junction distinct-combos fall out of PK-tuple uniqueness and cap at
  the available parent combinations (logged when capped; the
  user-facing note arrives with the advisory in P1.3c).
- Identifier-int columns get a monotonic sequence past MAX(col) (D10),
  so they never collide.
- IN-CHECK derivation (D17): a simple `col IN ('a','b')` CHECK becomes
  the value source via the new, unit-tested seed::parse_in_check_values,
  so the enum-as-CHECK pattern just works.

8 parser unit tests + 4 integration tests (unique column, identifier
sequencing, junction cap, IN-check enum). 2343 pass / 0 fail / 0 skip,
clippy all-targets clean.

Deferred to P1.3c: dedicated SeedResult + capped preview (D18) + the
enum/CHECK advisory incl. the cap note (D12/D13); P1.3d: multi-row path.
2026-06-11 18:50:05 +00:00
claude@clouddev1 73493fa68b feat(seed): FK sampling, empty-parent error, block guard (ADR-0048 P1.3a)
do_seed fills foreign-key columns by sampling existing parent rows
(D14): sample_parent_key_tuples reads distinct parent keys, and a
compound FK reads all its child columns from one sampled parent row per
child row. An empty parent is refused with a friendly "seed the parent
first" error. The block guard (D1) refuses a NOT NULL blob column (seed
can't generate one); a nullable blob is omitted (-> NULL).

4 integration tests (valid FK references, empty-parent refusal, NOT NULL
blob refusal, nullable-blob omission). 2331 pass / 0 fail / 0 skip,
clippy all-targets clean.

Deferred to P1.3b: identifier/constraint uniqueness incl. junction
distinct-combos (D10), IN-CHECK derivation (D17), dedicated SeedResult +
capped preview (D18) + advisory (D12/D13), and the multi-row path.
2026-06-11 17:22:04 +00:00
claude@clouddev1 f1e9484af3 feat(seed): command plumbing + walking skeleton (ADR-0048 P1.2)
End-to-end `seed <table> [count]` path, both modes:
- Command::Seed AST + grammar node (show-data table slot + optional
  positional count) + REGISTRY registration + build_seed.
- Runtime dispatch -> Database::seed -> Request::Seed worker arm ->
  do_seed.
- do_seed (Phase-1 skeleton): generates whole rows for non-FK,
  non-autogen columns via the seed library and inserts them one at a
  time through do_insert (reusing validation / autogen autofill /
  FK-error / persistence). One undo step (snapshot_then wraps it) and
  one history.log line (only the first row carries the source);
  default count 20.
- help (`help seed`) + parse-usage catalog entries.
- Reuses CommandOutcome::Insert for the auto-show; a dedicated
  SeedResult (capped preview + advisory) replaces it in P1.3.

5 Tier-3 integration tests (parse, populate+persist, default-20,
reproducible --seed, one history line). 2327 pass / 0 fail / 0 skip,
clippy all-targets clean.

Deferred to P1.3: FK sampling, identifier/constraint uniqueness, CHECK
derivation, block guard, capped preview, advisory, multi-row path.
Deferred to P1.4: completion/highlight/hint/validity wiring + --seed flag.
2026-06-11 16:57:43 +00:00
claude@clouddev1 a72d53de51 docs(website-adr): hosting target Vercel -> Cloudflare via Gitea Actions
Record the deployment decision (2026-06-11): static build deploys to
Cloudflare (Workers static assets or Pages; no Astro adapter needed),
driven by a planned Gitea Actions pipeline. Update the ADR-website-001
index entry to match.
2026-06-11 15:37:11 +00:00
claude@clouddev1 6777216e37 feat(website): set production site URL (relplay.org); record Phase B decisions
Set Starlight `site` to https://relplay.org (apex) — enables the
sitemap, canonical URLs, and Open Graph URL resolution; clears the
sitemap build warning. Record the resolved STYLE.md decisions:
single-version launch, fixed-dark cast theme (casts bake RGB colours,
so light/dark would need dual-theme recordings), and the site origin.
2026-06-11 15:36:29 +00:00
claude@clouddev1 202e25a94f feat(seed): fake-data generation library + fake dependency (ADR-0048 P1.1)
The pure generation half of `seed` — no command wiring yet:
- src/seed/: ColumnSpec + Generator model and a seeded StdRng; the
  type-gated name-heuristic catalogue (D7) with documented
  false-positive guards; table-context name disambiguation (D11);
  identifier (D10) and enum-ish (D12) detection; per-type + bounded-date
  generators (D8); the hand-rolled product generator (D9); and PickFrom
  for IN-CHECK / enum lists.
- Adds the `fake` crate (v5, default features). Verified: single rand
  0.10.1 (no duplication), determinism via one seeded StdRng driving
  both fake and the hand-rolled generators, security-clean across
  osv/grype/trivy.
- ADR-0048 D3 updated to record the dependency verification.

32 Tier-1 tests (exact-value via fixed --seed); 1673 lib tests pass,
clippy all-targets clean.
2026-06-11 15:35:17 +00:00
claude@clouddev1 13c9c1bcd9 feat(website): add payoff captions to joins/relationship-diagram/sql-echo
Use the ADR-0047 Ctrl+]-delimited demo caption to narrate the payoff
moment of three casts with a neutral one-liner (no key names): the join
result, the relationship diagram, and the m:n junction expansion. Add a
`caption` step kind to the cast generator. Captions show at the climax
during playback and clear as the cast quits.
2026-06-11 13:54:42 +00:00
claude@clouddev1 946dd88db6 feat(website): pace modes/undo-redo/joins casts (split submits, surface state)
Split the short pivotal commands from their submit so they read before
the screen changes (`mode advanced` in modes/joins; `undo`/`redo` before
their confirm modals), and surface the source tables in joins with
`show data` before the join, since the schema sidebar is hidden at 90 cols.
2026-06-11 13:49:40 +00:00
claude@clouddev1 0af7f56821 docs: ADR-0048 — seed fake-data generation command (SD1/SD2, A1)
Dedicated `seed` command: realistic, name-aware fake data via the
`fake` crate + a type-gated heuristic catalogue, table-context name
disambiguation, a hand-rolled product generator, bounded dates, an
identifier-uniqueness rule, a quoted `set` override clause (value /
list / generator / range), `--seed` reproducibility, FK sampling
(empty-parent error, junction distinct combinations), CHECK
derive-or-friendly-fail, undo as one batch step, replay as a
data-write, capped auto-show, and an enum/CHECK advisory.

Design settled across an extended user fork dialogue, then hardened
by a /runda DA pass that found six blockers (undo, replay, set
quoting, CHECK handling, advisory phasing, auto-show flood) — all
folded in, genuine forks re-escalated and user-resolved.

Takes up SD2 ([~]->[ ]); SD1 implementation in progress.
2026-06-11 13:48:19 +00:00
claude@clouddev1 ad43cce945 fix(website): connect box-art in plaintext output blocks
Tighten line-height (1.75 -> 1.2) on plaintext code blocks only, so the
box-drawing in rendered output (tables, query results, plan trees)
connects vertically as it does in the app. Command blocks keep the
looser spacing.
2026-06-11 13:35:29 +00:00
claude@clouddev1 7099bd3cde docs(website): expand the SQL-echo section; prune over-promised notes
Rewrite "Seeing the SQL behind a command" with the learning framing,
a grounded ALTER TABLE example, and the sql-echo cast. Drop the
"multiple result tabs" promise (won't-do on main) and the planned
`hint`-command note (superseded by the hint panel).
2026-06-11 13:28:37 +00:00
claude@clouddev1 5908891d6b feat(website): sql-echo cast — the DSL→SQL teaching echo demo
Advanced-mode cast running simple commands (create table, add column),
culminating in `create m:n relationship` expanding to a full junction
table, each tagged `Executing SQL:`. Recorded at height 34 so the long
m:n echo + junction structure stay fully on screen. Verified against
real app output.
2026-06-11 13:28:37 +00:00
claude@clouddev1 4d0ae776cc docs: withdraw multi-tab output from scope (S3/V2 → satisfied)
The trailing "multiple tabs" clause of S3 and V2 is dropped from
tracked scope by user decision. The output pane is settling on the
single scrollable V4 journal model rather than switchable result
tabs, so both items are now fully satisfied (the table view and
single-element visualisation were already built). V4 noted as the
sole tracked direction for evolving the output pane. A future
return to tabbed output would be a fresh requirement.

No ADR touched: multi-tab output never had a deciding ADR.
2026-06-11 12:26:33 +00:00
claude@clouddev1 6778c338d4 docs(website): document m:n, --demo, schema sidebar, responsive input
Document the features the main merge shipped: `create m:n relationship`
(relationships ref + build-the-library note), the `--demo` teaching
flag (command-line-options), the Ctrl-O schema sidebar (output-pane,
now .mdx to embed the new cast), and horizontal/two-row input
(assistive-editor).
2026-06-11 12:26:31 +00:00
claude@clouddev1 823b413ca3 feat(website): schema-sidebar cast + Ctrl-O/Esc cast keys
Add a `schema-sidebar` cast that reveals the ADR-0046 sidebar with
Ctrl-O (the only way to show it at 90 cols) and steps through the
Tables and Relationships panels. Teach the generator the CtrlO/Esc
control codes; quote control codes so `^[`/`^]` stay valid YAML.
2026-06-11 12:26:25 +00:00
claude@clouddev1 5d9ef6b21f docs: finalize handoff 64 — issues closed, tree clean
Bring handoff-64 current: it was written just before #22/#24 were closed
and the docs commit landed. §1 now reflects HEAD f0afec3 with both
issues closed on Gitea; §6 removes the completed finalization steps and
points the next session at the open requirements backlog (§7).
2026-06-11 12:08:12 +00:00
claude@clouddev1 a0dd202f67 feat(website): pace the projects cast + show table state; record cast guidelines
Projects cast review fixes:
- Pace the confirms: `save as` name and `new` now type, pause, then Enter as
  separate steps, so the viewer can read them before they execute.
- Insert `show tables` at each phase (before save / after `new` / after load),
  since the schema sidebar is hidden at 90 cols (ADR-0046) — the sequence now
  reads "books -> no tables -> books" so the round-trip is followable.

STYLE.md: new "Cast pacing & clarity" guidelines (beat-before-submit; surface
state where the sidebar would). Handoff item 2: chase these up across the
existing casts.
2026-06-11 10:56:46 +00:00
claude@clouddev1 595386e370 docs: note caption-banner review for existing casts in the handoff
Expand next-work item 2: review whether neutral step-caption banners (the demo
overlay) would improve the existing casts — narrating phases or calling out the
relationship diagram / teaching echo — cast-by-cast, with the no-naming-keys
constraint.
2026-06-11 10:43:38 +00:00
claude@clouddev1 51a29e5069 docs: website-branch session handoff (website-2)
Captures everything since website-1: the ADR-namespace move, all Reference +
Guides + the new SQL queries page, the cast pipeline + 7 casts (incl. the new
projects cast via #24 vi-nav), --demo on all casts (#22), and the main merge
(m:n/ADR-0045, UI sidebar+responsive input/ADR-0046, demo overlays/ADR-0047,
logging, FK fixes).

Flags the next-session work: document the merge's new features (m:n command,
--demo flag, ADR-0046 UI) which are not yet in the docs; the no-advertising
constraint (vi keys / Ctrl+] secret); cast tooling limits (no arrow keys);
the capture-harness recipe; Phase B; and open STYLE decisions.
2026-06-11 10:19:22 +00:00
claude@clouddev1 e782a280cc feat(website): projects cast (vi-nav load picker) + --demo on all casts
- New projects cast: create → save as library → new (fresh) → load → navigate
  the picker to the saved project (j, now possible via #24 vi-nav) → Enter
  loads it, the table is restored. Runs under an isolated --data-dir so the
  picker lists only this cast's projects.
- Turn on the demonstration overlay (--demo, #22 / ADR-0047) for ALL casts,
  for a consistent viewer experience: special keys show a badge — e.g.
  [ENTER], and [TAB] at the assistive-editor's completion moment, finally
  making that keystroke visible. Plain j/k navigation stays unbadged, so the
  picker navigation is not surfaced.
- Generator: per-cast `dataDir` (isolated data root) + default-on `--demo`
  (opt out with demo:false). All 7 casts regenerated.

Convert projects.md → .mdx and embed. Build clean (26 pages). Visual playback
of all casts pending a tunnel check.
2026-06-11 10:17:04 +00:00