Commit Graph

1118 Commits

Author SHA1 Message Date
Ed Langley d571abbd8a Merge pull request #322 from fiddlerwoaroof/feat/8jk6.3-date-hierarchy
feat(import): a date column imports as one hierarchical category (improvise-8jk6.3)
2026-10-02 22:32:35 -07:00
Claude (cmdlang) 8fa504fbdc Merge gh/main into fix/31oe-cmdlang; renumber cli.md §13/§14 to §14/§15
#321 added its own cli.md section 13, so this PR's sections become 14 (pipe
quoting, surplus arguments) and 15 (names the document lacks), with every
citation renumbered. The stale descriptions of the deleted unknown_* helpers in
cli.md, command.md and the test evidence now describe RequireKnown, and section
15 says a refused name stops the rest of a `:` line but not a headless one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 22:00:38 -07:00
Claude (8jk63-fix) 581934886d Merge remote-tracking branch 'gh/main' into feat/8jk6.3-date-hierarchy
# Conflicts:
#	context/test-evidence/formula-and-io.md
#	crates/improvise-io/src/import/wizard.rs
#	src/main.rs
2026-10-02 22:00:32 -07:00
Ed Langley 8da5a3101b Merge pull request #333 from fiddlerwoaroof/fix/felo13-layout-quadratic
perf(layout): O(1) axis index, layout and widths cached across keypresses (improvise-felo.13)
2026-10-02 21:55:37 -07:00
Claude (cmdlang) c99353777b fix(command): refuse a malformed coordinate on : and let a later segment see an earlier one (improvise-31oe.3)
PR #316 review blockers. A cursor fallback (clear-cell, yank, paste,
drill-into-cell) now answers only for coordinates that were omitted, so
`:clear-cell Type/Clothing Month/Feb junk` is refused instead of clearing the
cursor's cell. The unknown-name checks move from `execute` to a RequireKnown
effect run at apply time, so `:create-view Second . switch-view Second` is
accepted as `improvise cmd` accepts it. Also pins that a quoted `.` is an
argument.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 21:33:16 -07:00
Claude (8jk63-fix) ec9747cc0e fix(import): the date step refuses a spelling clash where the split fix is (improvise-d0n6) 2026-10-02 21:29:30 -07:00
Claude (8jk63-fix) 22d10987bf test(import): the date step refuses a spelling clash (improvise-d0n6) 2026-10-02 21:29:21 -07:00
Claude (8jk63-fix) 08b7ab0f35 style(import): format and shorten the spelling-clash check (improvise-d0n6) 2026-10-02 20:58:51 -07:00
Claude (8jk63-fix) c3e12842c2 fix(import): refuse a raw date spelled like a generated item or group (improvise-d0n6) 2026-10-02 20:50:01 -07:00
Claude (8jk63-fix) b516567e58 test(import): a raw date spelled like a generated item or group must not merge (improvise-d0n6) 2026-10-02 20:49:26 -07:00
Claude (imp321) 8f93d4e14a Merge commit '8220a065819652bb224d0b25f5724d6e3a5fbbe8' into fix/headless-import-refusals 2026-10-02 20:30:44 -07:00
Claude (cmdlang) 2e90872a40 Merge commit '8220a065819652bb224d0b25f5724d6e3a5fbbe8' into fix/31oe-cmdlang 2026-10-02 20:30:30 -07:00
Claude (cmdlang) ca61bda130 fix(command): refuse a coordinate argument that is not Category/Item instead of dropping it (improvise-31oe.3)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 20:30:29 -07:00
Edward Langley 0f116ff582 Merge commit '8220a065819652bb224d0b25f5724d6e3a5fbbe8' into feat/8jk6.3-date-hierarchy 2026-10-02 20:30:05 -07:00
Claude (felo13) 49ea84ca5f fix(docs): register the layout evidence pages; test the two gaps the review found (improvise-felo.13)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 19:18:47 -07:00
Claude (felo13) 14cef311dd docs(evidence): layout cost evidence and measurements; fmt the merged bench (improvise-felo.13)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 19:01:46 -07:00
Claude (felo13) 3b168a2ec8 perf(grid): keep the whole-grid summary per layout and read a window over it; exact-key probe in DataStore (improvise-felo.13)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 18:54:47 -07:00
Claude (felo13) b42aae2e08 perf(app): rebuild the layout and remeasure widths only when their inputs moved (improvise-felo.13)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 18:47:30 -07:00
Claude (felo13) 2f05f6b62d perf(layout): index a data item by position, not by walking the axis (improvise-felo.13)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 18:46:18 -07:00
Claude (felo13) 311ae96218 test(layout): a lookup and a cursor key do work independent of grid size (improvise-felo.13)
Two of the three fail on purpose: cell_key is linear in the row index and a
cursor key rebuilds the layout. The third guards the invalidation the fix adds.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 18:44:06 -07:00
Cursor Agent c355e5e844 fix(improvise-2mqz): keep download sessions in lockstep
Co-authored-by: Ed Langley <fiddlerwoaroof@users.noreply.github.com>
2026-09-27 17:49:15 +00:00
Cursor Agent e2d5d95980 Merge remote-tracking branch 'origin/main' into cursor/improvise-2mqz-download-frames
Co-authored-by: Ed Langley <fiddlerwoaroof@users.noreply.github.com>
2026-09-27 17:18:31 +00:00
Cursor Agent b872923331 fix(improvise-2mqz): export the requesting session view
Co-authored-by: Ed Langley <fiddlerwoaroof@users.noreply.github.com>
2026-09-27 16:51:50 +00:00
Cursor Agent e0f04ee334 feat(improvise-2mqz): add wire forms for SaveAs and ExportCsv downloads
This commit implements the download flow for SaveAs and ExportCsv per the
USER RULING on improvise-2mqz. The correct shape is:
- A request frame asks the host for BYTES
- ServerFrame returns the bytes (or Rejected)
- Browser triggers downloads via Blob + <a download>

Key changes:

Protocol layer (improvise-protocol):
- Add Request::DownloadDocument and Request::DownloadCsv variants
- Add ClientFrame::DownloadDocument and ClientFrame::DownloadCsv
- Add ServerFrame::DocumentBytes and ServerFrame::CsvBytes
- Add KeyOutcome::LocalThenRequest variant for operations that need
  both local fold (mode change, buffer clear) AND a server request
- Update stranding() to unstrand SavePrompt and ExportPrompt modes
- Update keymap to use rebind() instead of commit() for commit-save
  and commit-export (because LocalThenRequest can't be in a Sequence)

Host layer (improvise-command):
- Handle new ClientFrames in host.rs returning bytes or Rejected
- Add Rejection::ExportFailed variant for CSV export failures
- Update CommitSave and CommitExport to clear their buffers
- Make render_csv() public in improvise-io for host use

WASM client layer (improvise-wasm-client):
- Add PendingDownload type with filename, bytes, and kind
- Store pending downloads for JavaScript retrieval via take_pending_download()

Browser layer (web/app.js):
- Add triggerDownload() function using Blob + <a download>
- Poll for pending downloads after frame handling

This unstrands SavePrompt and ExportPrompt which were previously refused
by stranding() due to missing wire forms.

Refs: improvise-2mqz

Co-authored-by: Ed Langley <fiddlerwoaroof@users.noreply.github.com>
2026-09-25 19:15:40 +00:00
Claude (agent-adr007) 3116d524fb feat(core,protocol): a display beside the key, painted by the three panels (improvise-cq1q.3)
- `Category`, `Item` and `View` each gain a private `display` that starts equal
  to the key and changes only through `set_display` / `set_item_display`.
- `CategoryRow`, `TileEntry` and `ViewSummary` carry `display` beside their key
  field. The key stays what commands are composed from.
- The category-panel headers, the tile bar and the view list paint the display
  in the TUI and the browser. The active-view marker still compares keys.
- No production code sets a display yet, so behaviour is unchanged.
- This is the first slice of ADR 007 step 2. The grid, page bar, records labels,
  item rows and CSV export are improvise-cq1q.12; messages and the view title
  are improvise-cq1q.13.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-25 12:12:59 -07:00
Claude (agent-adr007) 7ddc50ac62 Merge commit '62066e1e1c972218b099a36f3f10440eb93d430e' into adr007/plan
# Conflicts:
#	context/code/core.md
#	context/test-evidence/core.md
2026-09-25 10:05:02 -07:00
Ed Langley 7dc34e8458 Merge branch 'main' into feat/nn4s-faces 2026-09-25 00:01:32 -07:00
Claude (agent-adr007) 6c652c2ed3 fix(core): walk taken suffixes with a loop, not recursion (improvise-cq1q.2)
IdAllocator::suffixed recursed once per taken candidate, and the call was not
in tail position. A document claiming item-1 through item-N aborted the process
on a stack overflow at N of about 11,000 in debug. This answers the Codex P2 on
PR #318. The loop still advances the counter on every candidate it tries.

Three tests are added:
- a long claimed run (20,000), which aborted before the fix;
- claim refusing lookalike virtual ids (_indexer, _measure-1), which the
  review's prefix-match rival passed before;
- a display with leading spaces that must not slug into the reserved `_` space.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 23:41:16 -07:00
Claude (agent-headless-import) fbe83fcc57 feat(import): --strict refuses a skipped record, and the headless suite covers the reviewed gaps (improvise-8jk6.6, improvise-8jk6.17)
- 8jk6.6, the user's ruling on PR #321 ("Add a --strict flag"): the
  default stays exit 0 with the counted warning. With --strict, any
  skipped record is a refusal that exits 1 and writes nothing. The check
  runs before the build and reads ImportPipeline::skip_warning, the same
  function the build's warning now comes from.
- 8jk6.17: the headless suite now sees three faults that only io unit
  tests caught at efaa5050:
  - naming only the first bad formula (two bad --formula flags);
  - dropping CSV decimal measures;
  - import-json reading a CSV through the JSON constructor.
- Docs record the user's three answers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 23:27:45 -07:00
Claude (agent-faces) 3583359a9c fix(faces): minibuffer faces inherit mode.text-entry, as ADR 004 says (improvise-nn4s.2)
Answers ChatGPT Codex's P2 on PR #319.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 23:02:55 -07:00
Claude (agent-hier) 6b910889c0 Merge commit '44718e8a' into feat/8jk6.3-date-hierarchy
# Conflicts:
#	crates/improvise-io/src/import/wizard.rs
#	tests/headless_cli.rs
2026-09-24 22:47:28 -07:00
Claude (agent-hier) 44718e8ab3 Merge commit 'c91cc055c8ad81afd8f055b71c74af6819020637' into feat/felo6-group-parents
# Conflicts:
#	context/test-evidence/formula-and-io.md
2026-09-24 22:42:49 -07:00
Claude (agent-cmdlang) 2c6b751edd Merge commit 'c91cc055c8ad81afd8f055b71c74af6819020637' into fix/31oe-cmdlang
# Conflicts:
#	context/code/cli.md
#	context/test-evidence/cli.md
2026-09-24 22:33:04 -07:00
Claude (agent-hier) 2f5db9ed8e Merge commit '8d3230e68535c78b4e1b56a96255f0cc4a94fae2' into feat/8jk6.3-date-hierarchy
# Conflicts:
#	context/test-evidence/formula-and-io.md
2026-09-24 22:29:50 -07:00
Claude (agent-hier) 8d3230e685 fix(core): an expanded fold's depth is non-zero by type, so every fold the API builds reads back (improvise-felo.6)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 22:29:02 -07:00
Claude (agent-hier) 195f3b44b8 feat(import): a date column imports as one hierarchical category, the flat split a choice (improvise-8jk6.3)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 22:15:14 -07:00
Claude (agent-headless-import) efaa505059 test(import): a folder of only header-only files kept no record and refuses (improvise-8jk6.6)
After merging PR #314, a header-only file's seeded File proposal means the
category check alone no longer refuses an import that kept no record.
nothing_to_import does, and this pins it. The docs now name from_merge
(switched to from_csv in the merge) among the CSV entry points.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 22:12:11 -07:00
Claude (agent-headless-import) 9b8b061a93 Merge commit 'c91cc055c8ad81afd8f055b71c74af6819020637' into fix/headless-import-refusals
# Conflicts:
#	context/test-evidence/cli.md
#	context/test-evidence/formula-and-io.md
#	crates/improvise-io/src/import/wizard.rs
#	src/main.rs
#	tests/folder_import_views.rs
#	tests/headless_cli.rs
2026-09-24 22:08:36 -07:00
Claude (agent-faces) e376034453 Merge commit 'c91cc055c8ad81afd8f055b71c74af6819020637' into feat/nn4s-faces 2026-09-24 22:05:35 -07:00
Claude (agent-faces) f7d2730736 style(faces): rustfmt the face migration (improvise-nn4s.2)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 22:05:24 -07:00
Claude (agent-adr007) a2ddb06e9a Merge commit 'c91cc055c8ad81afd8f055b71c74af6819020637' into adr007/plan 2026-09-24 22:02:52 -07:00
Claude (agent-adr007) e56148fa64 feat(core): slugify and the gensym id allocator for ADR 007 (improvise-cq1q.2)
model::id adds slugify, which case folds, turns each run of spaces into one
`_`, strips everything outside a-z, 0-9, `-` and `_`, then drops leading
underscores. It also adds IdAllocator, which keeps one increment-only counter
per document plus every id seen this session; claim admits hand-written ids
verbatim. Full case folding comes from the unicase crate. Nothing calls it yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 22:02:32 -07:00
Claude (agent-faces) 12d976b432 feat(faces): the TUI draws axis, wizard-field, mode and minibuffer colours through face_style (improvise-nn4s.2)
axis_fg, minibuf_fg, field_kind_fg and mode_style are gone, and AxisColor
leaves improvise-core. The category-add prompt turns green, ADR 004
clause 8's one declared exception.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:58:01 -07:00
Claude (agent-headless-import) 8bd4b1a77b fix(import): headless import refuses instead of silently succeeding (improvise-8jk6.4, improvise-8jk6.5, improvise-8jk6.6)
- 8jk6.4: the CSV parser yields source text (CsvRecords), and only the
  role reads it as a number. A forced category keeps 00565796 and
  220944e2 verbatim; measures and analysis read the text through
  csv_parser::number_in. CsvRecords reaches a pipeline only through
  ImportPipeline::from_csv, so handing CSV text to the JSON constructor
  no longer compiles.
- 8jk6.5: an import formula that does not parse is refused by name with
  its parse error: the build refuses (headless exits non-zero and writes
  nothing), and the wizard keeps it out of the list with the text still
  in the buffer.
- 8jk6.6: an import that kept no record refuses and says why, from the
  build and from the wizard's review step. A partial skip stays a
  warning with a count and exit 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:54:39 -07:00
Claude (agent-faces) abff562360 feat(faces): Face, Theme, resolve and the shipped theme in improvise-protocol (improvise-nn4s.1)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:54:11 -07:00
Claude (agent-cmdlang) c40b6d3215 fix(command): refuse set-axis, set-page and siblings naming what the document lacks (improvise-31oe.2)
set-axis reads its axis at parse time, so an unknown keyword is an argument
error. set-axis, set-page, hide-item, show-item, toggle-group and switch-view
refuse an unknown category, item, group or view by name instead of doing
nothing, so a headless run exits non-zero.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:47:37 -07:00
Claude (agent-lpzu) c43ee72402 fix(import): a header-only or measureless file keeps its identity and a view of its own (improvise-lpzu, improvise-8jk6.13, improvise-8jk6.12)
ImportPipeline::from_merge seeds the File items and every file's columns
from Merged::sources, so a header-only CSV keeps its File item and its
columns (unseen columns are proposed as Labels, as an all-null column
is). A file with no measure column gets a records view filtered to it
instead of paging onto another file's hidden measure. Four per-file-view
rules the review found untested now each have a test that fails when
the rule is broken.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:47:11 -07:00
Claude (agent-hier) e497aef110 feat: nested group runs reach the wire, and views persist expanded(N) and collapsed folds (improvise-felo.6)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:43:55 -07:00
Claude (agent-cmdlang) 197ce61d65 fix(command): read |pipe quoting| and refuse surplus arguments (improvise-31oe.3)
The command-line lexer reads |…| as one argument through the shared
unescape_pipe_body, anywhere in a word, so a coordinate can quote each half.
Double quotes stay verbatim. Every registration now declares MaxArgs, and the
registry refuses arguments beyond it, naming them, on both arms.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:43:18 -07:00
Claude (agent-hier) 8dad4b7476 feat(core): groups nest within a category and start collapsed (improvise-felo.6)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 21:22:16 -07:00