Commit Graph

147 Commits

Author SHA1 Message Date
Claude (agent-faces) 92f8ac2113 docs(faces): where faces live and what the first two steps settled (improvise-nn4s)
context/code/protocol.md gains section 10 and tui.md's colour section now
describes face_style; the pointers to axis_fg, minibuf_fg and AxisColor
elsewhere follow. Evidence for the new tests.

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
Edward Langley 7d1f90dbf9 feat(core): raise MAX_CATEGORIES from 12 to 24, with one home (improvise-felo.1)
The wizard's private copy of the limit is gone; it reads the model's
now-public constant. Tests that fill to the cap derive it. Why 12 was
chosen and what 24 costs: context/code/core.md section 9.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 19:19:39 -07:00
Edward Langley ffc7d0aecc Merge gh/main 08ad7b81 into fix/wpxr-empty-record-view
Every write the merged PRs added now names a view, chosen deliberately:

- The keyboard commit names OpenedCell::view, captured when the editor
  opened, as EditTarget does for the mouse (context/code/clients.md).
- RenameRecordCoordinate names no view. Its record must hold cells, so it
  resolves in the store alone: NamedRecord::Stored, as does the rename
  destination records_at_stake adds. named_records replaces cells_named as
  the exhaustive list records_named is read off.
- #252/#265's non_item_refusal moves into Grids::unwritable. The strict view
  lookup (a missing view is RecordGone) and the Grids memo are kept.
- Test fixtures name a view their document has: Default for host() and
  host_on_a_fold(), the records view for the rename pair, and the viewing
  client's own view in browser_round_trip.

Evidence files: both sides kept, every heading of both parents verified
present. Test names: the merge holds every test of both parents.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:53:03 -07:00
Edward Langley 8dd39fd5ba Merge commit '37ff61f9de10b8df679b80ee4002061f117e2021' into wave/integration-editor-2026-09-24 2026-09-24 12:17:55 -07:00
Edward Langley 32c555767a Merge #274 (bce496b7, improvise-8xq0 editor commits the opened record) into the editor integration branch
Resolutions:
- resolve.rs: dropped #295's record_at_cursor in favour of 8xq0's
  captured-cell path (commit_value / opened_at_cursor); nothing references
  it any more. declined_at keeps #292's NonItem arm. #274's two new
  exhaustive matches (opened_at_cursor, uncaptured) gain a NonItem arm that
  answers None; refused_here already declines a commit over a NonItem cell
  when nothing is captured, so uncaptured never reaches it.
- client.rs: kept main's status_seen/status_owner beside #274's
  Opened/OpenedCell/OpenedTarget.
- lockstep.rs: #274 made the same sent -> sent_to_host rename #295 did;
  kept this branch's sent_or_upstream (main already owns sent_to_host).
- context/test-evidence/clients.md: kept both sides. Because #274 and #295
  both carry the 7mro commits, the three 7mro entries
  (keys_sent_before_a_scroll_is_answered_agree_with_the_tui,
  a_held_cell_is_read_at_its_position_and_not_its_cache_index,
  resolve::tests::a_cursor_on_an_empty_grid_waits_for_nothing) arrived
  twice. The first two copies were byte-identical; #274's copy of the third
  also carries its "Amending the entry ... for #274's capture" paragraph,
  so #274's copies are kept and #295's are removed. Heading union against
  both parents: nothing missing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:17:49 -07:00
Edward Langley a7ec482552 Merge #251 (3f5f90a5, improvise-20ek/milr rename races) into the editor integration branch
Resolutions:
- client.rs imports: EditorSession (main) and ModelCommand (#251).
- client.rs refused(): #251 keeps the popped frame to learn which record it
  renamed; main (#279/3kfc) calls settle_sent() after the pop. Both kept, in
  the order pop, settle_sent, replay, then #251's Opened::Retry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:14:44 -07:00
Edward Langley 5e8e838f23 Merge #221 (c7b5b825, improvise-fdk1 coordinate rename) into the editor integration branch
Resolutions:
- CellId: #221 gives Coordinate fields { record, category }; main (#292)
  adds NonItem { category, item }. Every exhaustive match now names both
  (render.rs, core.rs x2, project.rs, resolve.rs x3, wasm-client lib.rs and
  render.rs); project.rs's basis arm keeps #221's Coordinate-carries-a-record.
- resolve.rs edit_or_drill: #221 drops the "renaming a coordinate" decline
  (Coordinate opens an editor); main's NonItem decline arm is kept.
  coordinate_at_cursor's None arm gains NonItem. reopened_at keeps #295's
  declined_at shape; declined_at's editable arm names Coordinate { .. }.
- client.rs: kept main's status_seen/status_owner and #221's opened +
  OpenedCoordinate; every settle site calls both settle_opened and
  settle_status. Main's new rebase() also gets settle_opened, since it
  rebuilds the view exactly as apply() does.
- view/mod.rs: re-export both GridEval (main) and record_row (#221).
- context/code/command.md and context/test-evidence/clients.md: both sides
  appended independent sections; kept both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:13:42 -07:00
Edward Langley 2fbb43b9ee Merge #295 (65d6a3e1, improvise-7mro projected reads) into the editor integration branch
Resolutions against gh/main 8d870c15:
- client.rs: kept main's settle_status (1x9h) and #295's
  settle_declined_editor (5m9z) side by side.
- resolve.rs reopened_at: took #295's declined_at shape and moved #292's
  CellId::NonItem arm into declined_at, which reopened_at consults before
  any seed choice, so a NonItem landing still re-opens nothing.
- lockstep.rs: both sides appended at EOF; kept main's tail then #295's.
  Both defined sent_to_host with different semantics (main's panics on a
  non-local key, #295's lets an upstream key reach a silent host), so
  #295's copy is renamed sent_or_upstream with its three callers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 12:10:53 -07:00
Edward Langley 46896a7512 Merge PR #250 (3e417729) into the 2026-09-24 integration wave
Conflicts with #294 in render.rs and project.rs resolved as tested:
#250's side of every hunk (levelled GroupEnd { level }, groups()/group_of,
axis_frame's carried headers, the try_from level check), then #294's shape
(Item { tuple, .. }, FrameEntry::item(..), the DataItem { tuple, collapsed }
arm, and GroupEnd { .. } in folds). Evidence EOF appends keep both sides.
2026-09-24 02:49:32 -07:00
Edward Langley f39a95709e Merge PR #279 (044e8d2d) into the 2026-09-24 integration wave
# Conflicts:
#	context/test-evidence/clients.md
2026-09-24 02:47:40 -07:00
Edward Langley 783f92cdce Merge PR #266 (d0e36142) into the 2026-09-24 integration wave
# Conflicts:
#	crates/improvise-wasm-client/tests/lockstep.rs
2026-09-24 02:47:20 -07:00
Edward Langley 52946bd3e3 Merge PR #246 (37dbf02e) into the 2026-09-24 integration wave
# Conflicts:
#	context/test-evidence/clients.md
#	context/test-evidence/command.md
2026-09-24 02:46:58 -07:00
Edward Langley 1efb774f9f Merge PR #294 (088d469f) into the 2026-09-24 integration wave
# Conflicts:
#	crates/improvise-wasm-client/tests/lockstep.rs
2026-09-24 02:45:54 -07:00
Edward Langley 5b73e67caf Merge PR #223 (e1453797) into the 2026-09-24 integration wave 2026-09-24 02:44:11 -07:00
Ed Langley 088d469fbb Merge branch 'main' into fix/oyaa-host-list-complete 2026-09-24 01:57:22 -07:00
Edward Langley e44b1491ca Merge gh/main (cc95cfbf) into fix/e265-levelled-groups
# Conflicts:
#	context/test-evidence/command.md
#	context/test-evidence/core.md
2026-09-23 23:26:55 -07:00
Edward Langley 0b645a8f0e Merge fix/xd3q-reset-clobbers-pipelined-placement (75ce4230) into fix/1x9h-browser-refusal-stands 2026-09-23 23:15:08 -07:00
Edward Langley ef30dcd941 Merge gh/main (666de199) into fix/7mro-projected-reads
Conflicts:
- context/test-evidence/clients.md: both sides' entries kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 23:12:35 -07:00
Edward Langley 75ce42309a Merge fix/hv0r-jpba-relays (361ba50e) into fix/xd3q-reset-clobbers-pipelined-placement
# Conflicts:
#	context/test-evidence/clients.md
#	context/test-evidence/command.md
2026-09-23 23:11:00 -07:00
Edward Langley 361ba50e6c Merge gh/main (666de199) into fix/hv0r-jpba-relays
# Conflicts:
#	context/test-evidence/clients.md
#	context/test-evidence/command.md
2026-09-23 23:07:10 -07:00
Edward Langley f892e8014f Merge #274's head (a468f2b2, gh/main 666de199) into fix/joed-waiting-commit-keeps-text
No conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 23:02:02 -07:00
Edward Langley cc5e2635d5 Merge gh/main (666de199) into wave/tej1-browser-delete-formula
context/test-evidence/command.md: both sides inserted a block at the
same point, before the "improvise-i3o5: four declines" subsection. Both
kept: this branch's remove_formula_of_a_missing_formula_is_a_refusal,
then gh/main's totals-strip section (improvise-wm20).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 23:00:13 -07:00
Edward Langley a468f2b28f Merge #251's head (7eeba18e, gh/main 666de199) into fix/8xq0-editor-commits-opened-record
Conflicts:
- resolve.rs reopened_at: this branch's `declined_at` form kept. It
  already names `CellId::Coordinate { .. }` and reads the frame's own
  origin; main's form (read through `cell_at`) is what 8xq0 replaced.
- context/test-evidence/clients.md: both sides' entries kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 22:58:29 -07:00
Edward Langley 7eeba18eb9 Merge #221's head (516ad66a, gh/main 666de199) into fix/20ek-milr-rename-races
Conflicts:
- context/test-evidence/clients.md: both sides' entries kept, this
  branch's first (its amendment reads "above").

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 22:54:31 -07:00
Edward Langley c7f93515ba Merge gh/main (666de199) into fix/oplp-followups
context/test-evidence/command.md: both sides appended at EOF; both kept
(this branch's two drill tile-select entries, then gh/main's
Host::mutating_frame abort-arm section).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 22:49:52 -07:00
Edward Langley 516ad66af2 Merge gh/main (666de199) into fix/fdk1-coordinate-rename
Conflicts:
- cmd/core.rs committable_cell_key: take main's `uneditable` door; its
  pattern names fdk1's struct `CellId::Coordinate { .. }`.
- resolve.rs reopened_at (main, clean text): same pattern fix, a
  compile-only semantic conflict.
- context/test-evidence/{clients,command}.md: both sides' entries kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 22:47:10 -07:00
Ed Langley eb9ec7e98b Merge pull request #277 from fiddlerwoaroof/fix/enz6-advance-onto-fold
No editor re-opens on a cell i declines: a fold or a formula's result (improvise-enz6)
2026-09-23 22:41:16 -07:00
Edward Langley fc4a41cb87 Merge #274's head (3dad3b09, improvise-3h9w) into fix/joed-waiting-commit-keeps-text
refused_here now skips the commit keys for a captured editor. The test
file was rebuilt as #278's tests plus #274's new block, because git's
hunks split a function.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 20:14:23 -07:00
Edward Langley 3dad3b0954 improvise-3h9w: a captured commit is not refused for the cursor's cell
refused_here (from #286) ran before commit() consulted the capture and,
for the commit keys, judged the cell under the cursor. After a reframe
left the cursor on an aggregate, a captured editor's Enter was declined
on every retry. The commit-key guard now applies only to an editor that
captured nothing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 20:10:36 -07:00
Edward Langley 2cb88203d1 Merge #274's head (8c28360f, now carrying #286) into fix/joed-waiting-commit-keeps-text
step() keeps #286's refused_here (declined, so it keeps the text too)
ahead of joed's committed(); both functions are kept. Evidence appended
on both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 19:47:30 -07:00
Edward Langley 8c28360f47 Merge #286 (fix/7mro-projected-reads, 6b604a9e) into fix/8xq0-editor-commits-opened-record
#274's capture read the cell through the cursor's offsets and stuck, so a
scrolling Enter captured the old window's cell even with every reply
delivered (improvise-7mro's horizontal wrap: Jan/Revenue for Feb/Revenue).
#286's cell_at_cursor reads through projected_at, so the capture waits
until the host projects the cell. Taken by merge, not by port: the matrix
test's held cases need #282/#277's waits too.

Resolutions: committable_cell_key takes #286's uneditable(); the two unit
CellId::Coordinate patterns become struct patterns; evidence is appended
on both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 19:40:25 -07:00
Edward Langley 6b604a9e3b improvise-7mro: evidence and the clients.md account
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 19:29:55 -07:00
Edward Langley 7025ec2471 Merge #266 (fix/xd3q) into #279: one notify, and a rebase settles the status (improvise-0dbk)
Both PRs added ClientState::notify, so the merge failed with E0592. #266's
is kept: it queues the sentence through fold_outgoing, which runs
settle_status, so the owner is still recorded. #279's direct-write notify
is deleted.

#266's rebase() rebuilt the view without settle_status, so a relay that
moved the view off the editor left the message owned, and an equal
editor reopened afterwards took it back. rebase() now settles it, pinned
by a_rebase_off_the_editor_ends_the_message_standing (red before).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:57:06 -07:00
Edward Langley 5c69381b69 Walk every mode a browser can reach; an empty status is not a decline
From PR #280's review.

improvise-s2gb: every_silent_binding_is_on_the_list walked Normal and
search mode only, so a black hole bound in FormulaPanel (the reviewer's
Z -> commit-export) passed the whole suite. The modes are now derived:
reachable_modes starts from both halves of Normal (the grid, not a key,
picks RecordsNormal, e5pf) and closes over the modes a pressed binding
lands in. Doors `declined` shuts (the three stranding prompts, the
import wizard, records editing, search now that `/` declines) fall out
with no list to maintain. A floor assertion names seven modes the walk
must reach, so it cannot pass by shrinking. furnished_to_type seeds the
mode's own minibuffer as well as the search query.

`heard` counts a SetStatus as a decline only when it says something: a
resolver answering SetStatus("") left the user seeing nothing and passed
this guard, caught only incidentally by the Ctrl-Q tests.

Merges #275's new head (improvise-4k1j) and fixes the fmt gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:52:49 -07:00
Edward Langley dffbf99ff7 improvise-y5eb/ik6l: evidence and the clients.md account
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:40:09 -07:00
Edward Langley bb2f889732 A retry whose cell is Gone keeps the typed text (improvise-joed on #251's decline)
renamed_away() is a Step::Declined, like still_waiting(), so the Enter
binding's welded clear-buffer no longer empties the editor the user must
Esc away from. Shared by the value and rename paths. Red first:
a_retry_whose_cell_is_gone_keeps_the_typed_text failed with Some("").

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:36:24 -07:00
Edward Langley 6609a743a4 Merge branch 'fix/fo0w-black-holes' into fix/oyaa-host-list-complete 2026-09-23 18:35:47 -07:00
Edward Langley 1e49bc0df7 H refuses on every fold the host refuses on; carry the fold flag
improvise-4k1j, from PR #275's review. hidden_row_item refused on a fold
only when the NEAREST group header was collapsed. Under two row
categories that header can be the inner one's: with Region's Coast
collapsed and Product's Kit expanded, the client composed
HideItem{Region, "Coast"} and a twin host wrote a group name into the
document, where the host refuses.

The frame cannot answer this on gh/main: FrameGroup names no level and
an inner GroupEnd reads as an outer one. So FrameEntry::Item now carries
the layout's own DataItem::collapsed flag (a fold, or under one, at any
level) and AxisFrame::folds reads it, the same bit
GridLayout::row_folds_a_group reads. FrameEntry::item builds an
unfolded one, as AxisEntry::item does.

hiding_agrees_with_the_host_on_every_row_of_nested_groups presses H on
all 25 rows of four nested grouped grids, in two windows each. It was
red on the nearest-header check at rows 4 and 5, as the review found.

Also fixes the fmt gate the review found red: fmt-workspaces.sh is a
check, not a formatter, and its diff output was misread as success.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:35:38 -07:00
Edward Langley 1572258e03 Merge #274's head (8d9de94e) into fix/joed-waiting-commit-keeps-text
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:31:51 -07:00
Edward Langley 8d9de94e08 A value retry writes only the cell it named; Enter follows the capture (improvise-8phw)
8phw: when A's Enter crossed B's HideItem, the LayoutMoved refusal replayed
the editor over South and settle_opened recaptured South/Cost, so the
retry wrote there. #251's Opened::Retry/Gone now covers values:
written_to() recognises SetCell/ClearCell as well as a rename, and Retry
and Gone carry the whole OpenedTarget, which the recapture must match.
A Gone value editor declines with RECORD_RENAMED_AWAY. seen stays
rename-only.

Codex P2 on #274: commit picked value/rename/create from the cell under
the cursor before it consulted the capture, so a reframe that left no
cell there sent a captured editor's Enter upstream. commit now
dispatches on opened.target(); only an uncaptured editor is dispatched by
the cursor. A records grid's measure cell is not captured as a value,
since the browser still declines it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:29:33 -07:00
Edward Langley 57b713cf15 A refusal's sentence queues at the tail, so a rebase cannot erase it (improvise-n0pb)
`fold_frame` wrote the rejection sentence straight into `view.status_msg`,
so it was in neither `settled` nor `in_flight`, and the xd3q rebase erased
it whenever a relay queued behind a frame still in flight: an in-flight
frame's own `SetStatus` was replayed over it.

`ClientState::notify` queues the sentence as a view-only entry at the tail
of `in_flight`, where `fold_outgoing` puts a frame the host never answers.
Frames sent before it replay first, relays queue ahead of it, frames sent
after it may replace it, and it settles when everything ahead is answered.
Writing it into `settled` too was tried as a rival and fails the same way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:20:12 -07:00
Edward Langley cc7e49ac67 Merge #251 (fix/20ek-milr-rename-races, ff8ea239) into fix/8xq0-editor-commits-opened-record
OpenedCoordinate becomes #274's OpenedCell, now carrying #251's seen
(filled for a rename only) inside Opened::Target. Retry/Gone keep #251's
rename-only semantics in this commit; the value-cell retry (improvise-8phw)
follows. #221's superseded "a retry after a refusal is a force" paragraph
is dropped in favour of #251's rule.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:17:20 -07:00
Edward Langley 689c8c6eb5 improvise-5m9z: an editor opened past the window settles on the host's answer
reopened_at opens provisionally where the landing cell is not projected
yet; ClientState::settle_declined_editor closes an untouched editor once
the host projects that cell as one i declines. Both ask one
resolve::declined_at. A touched editor is kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:11:33 -07:00
Edward Langley 88e53aed73 Hold NEEDS_THE_HOST complete from the keymaps, not the help rows
improvise-oyaa. every_silent_binding_is_on_the_list presses every
binding the Normal and search-mode keymaps reach (parents unshadowed,
prefixes expanded) on the furnished fixture, and requires each silent
one to be on NEEDS_THE_HOST. The two earlier guards could not see an
unlisted binding that no help row names: dropping force-quit (Ctrl-Q)
from the list failed nothing. Now it fails this test.

every_binding_reaches_parents_and_prefixes checks the walk itself
against a hand-built keymap, because no silent binding in today's maps
sits in a parent or behind a prefix, so a walk that skipped either
passed the first test unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:09:54 -07:00
Edward Langley 9eb83538fe A message beside its open editor stands in the browser too (improvise-1x9h)
The toast hid every status after six seconds, so a refusal the user was
still fixing vanished with its prompt open: su4u's bug on a timer. The
browser now asks the TUI's question. EditorSession moves into
improvise-protocol, ClientState records which editor a status was
written in, and RenderModel::status_stands tells the toast to hold it
until that editor closes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:08:26 -07:00
Edward Langley d79a8bd5b0 improvise-wpxr: argue the named view in context/, and record the evidence
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:03:42 -07:00
Edward Langley c704ea1263 A commit that waits for the host keeps the typed text (improvise-joed)
Enter in Editing/RecordsEditing is [commit-cell-edit, clear-buffer edit].
The "still waiting" answer came back from composed() as an ordinary
Local step, so the sequence ran the welded clear after it and emptied
the editor it had left open, on the value path and on #221's rename
path alike.

The two cell commits are now answered by committed(), ahead of
composed(), and still_waiting() is a Step::Declined: the existing
channel by which a step stops a sequence. Under #227 (no weld; the
commit clears at its head) the binding is one command and the waiting
return precedes that clear, so the fix fits both.

Stacked on #274.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:03:39 -07:00
Edward Langley cdefeeb9b8 Resolve Enter and H in the browser; decline / and n out loud
improvise-fo0w. Three black-hole keys closed over vocabulary that
already exists, each mirroring its Cmd line for line with a lockstep case:

- enter-advance (Normal Enter) resolves as cursor arithmetic over
  GridExtent; the host's bottom-right AbortChain is Ignored here, which
  loses nothing because Enter is never bound inside a Sequence.
- hide-selected-row-item (H) resolves to ModelCommand::HideItem over the
  outer row category and the selected tuple's first label, and refuses
  on a fold with the host's own FOLD_REFUSAL, now in improvise-protocol.
- search (/) and search-navigate (n) decline out loud as a pair: n needs
  the whole model, and / alone would open a box that finds nothing.

NEEDS_THE_HOST drops to exit-search-mode, force-quit and
toggle-group-under-cursor. Tests that used Enter or "Start search" as
their upstream example move to Ctrl-Q and "Exit search mode", including
shell.spec.js's not-sent case.

Also improvise-0629: the help render test now asserts every ex row is
drawn dim, not just that its description is marked.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 18:01:08 -07:00
Edward Langley aab62a362a improvise-enz6: pin the commit door directly, and write up the evidence
The advance no longer reaches the commit door on a fold or a formula's
cell, so the two older advance tests stopped seeing it (measured: the
cell_key rival passes them). Two tests seat the editor there directly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:56:41 -07:00
Edward Langley 7bf8debd12 The keyboard editor commits to the cell it opened on (improvise-8xq0, improvise-xz2z)
resolve.rs::written read its operands at Enter: the record and measure
from the cell under the cursor, and the basis from claim(), i.e. the
version current at commit. So a HideItem from another client that
renumbered the rows under an open editor sent the write to whichever
cell the cursor then named (8xq0), and a write by another client to the
record while the editor was open was silently overwritten instead of
refused RecordMoved (xz2z, 0j0f's rule on the keyboard door).

The fix reuses #221's capture rather than adding a second one.
ClientState::opened becomes OpenedCell { record, target, version,
document_generation }, where OpenedTarget is Value { measure } or
Coordinate { category }. settle_opened captures a Record cell as a
Value target, and written builds the RecordCell and the claim_as_read
basis from it. With no capture while the host has yet to answer this
client's own last write, the commit declines with the rename's "still
waiting" status.

Red first: both round-trip probes failed on gh/main 202e7eac and on
#221's head 39821d5f. Unit-test fixtures that set Editing by assignment
now open the editor through the fold, which is where the capture is
taken.

Stacked on #221 (fix/fdk1-coordinate-rename).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-23 17:49:43 -07:00