Repository navigation
feat(cmux-tui): set-layout-sizes commits a divider batch as one change or none (layout-sizes-batch-v1; daemon only, no app caller yet) - #34928
Conversation
…e or not at all (R-DAEMON-STATE 2.10.1 red) Mux::set_layout_sizes_in_transaction_checked_as takes a batch of divider values (split ratios, column widths) under one resize transaction. This red commit applies them as today's app does, one commit per value, so a refused second value leaves the first applied and a batch is two layout changes: expected red in a_refused_second_value_leaves_the_first_unapplied and a_batch_is_one_layout_change_and_one_undo_step. The drag plus release undo step and the count refusal pass on both (guards).
…ut revision, one undo step, or nothing (R-DAEMON-STATE 2.10.1) set_layout_sizes_in_transaction_checked_as builds one resource plan (screen.layout_sizes.set): every value is applied, in order, to one layout snapshot of the screen with the checks of its single command (unknown split, row split, the ratio's implied column width from the batch's own earlier widths, width range, pane not resizable, one screen), then one commit: one durable screen, one layout revision, one undo entry keyed by the resize transaction (a drag's earlier values under it stay in the same step), one layout-changed event with the transaction echo. A refused value refuses the plan before anything is staged, with the single command's typed error and its index; a batch that changes nothing commits nothing.
…the count limit is not re-exported)
…ues as one change (layout-sizes-batch-v1)
The wire command for the batch (R-DAEMON-STATE DESIGN 2.10.1): values are {split, ratio} or {pane, width}, 1 to
64 on one screen, with the gesture's resize transaction. One commit and one undo step, or nothing: a refused value
answers with its single command's error_code and a message naming its index. Spec (commands.md), SDK schema and
inventory updated; bindings regenerated (bindings/codegen/generate.py --write).
Test: server::tests::layout_receipts_shutdown::set_layout_sizes_applies_a_trade_whole_or_refuses_it_whole.
…write, step 079bc5529a51008685712c92)
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: Shipped in:
|
|
Review (claude-reviewer-rds-batch): SHIP at ca012e6 No defect must be fixed before merge. I read the full non-generated diff against the singles ( Verified
Non-blocking findings
Observed / Not run
|
|
Base finding, not this PR's own red:
|
…34928 review B, on the path it named) a_non_finite_ratio_is_refused_and_changes_nothing used a column split, where the implied width already refuses a NaN, so it passed before the fix. A tree split takes the ratio as it is: this is the path the review named.
…e pair and refuses a non-finite ratio; tests and docs (#34928 review follow-ups) (#35261) * test(cmux-tui-core): set-layout-sizes refuses a value with both pairs and a non-finite ratio; covers the ratio arm, two screens, a no-op batch, one layout event and the capability (#34928 review follow-ups, red) Red: a value with both a ratio and a width decodes as a ratio and drops the width (review A); a NaN or infinite ratio is committed in-process (review B). The rest pins behavior that is right already (review C): a_ratio_value_uses_the_widths_the_batch_set_before_it, values_on_two_screens_are_refused_whole, a_batch_of_the_current_sizes_commits_nothing, a_batch_sends_one_layout_changed_event, identify_advertises_the_layout_sizes_batch. * fix(cmux-tui-core): set-layout-sizes refuses a value that is not exactly one pair and a non-finite ratio; its wire type moves to cmd_panes (#34928 review follow-ups) - Review A: LayoutSizeWire's variants are newtypes over two structs with deny_unknown_fields, so a value with both {split, ratio} and {pane, width} (or any other field) is refused, not decoded as a ratio with the width dropped. - Review B: a NaN or infinite ratio is refused in-process (LayoutSizesError::NonFiniteRatio, invalid-argument), as the single command refuses it; the clamp keeps a NaN. - Review D: events.md lists set-layout-sizes among the commands whose transaction layout-changed echoes; commands.md states the strict value shape. (DESIGN 2.10.1 already names layout-sizes-other-screen.) - Review E: LayoutSizeWire and its From impl move from server.rs to server/cmd_panes.rs (server.rs 3022 -> 3006 lines; still over its warn-only ceiling of 2978). The Command field keeps the name, so check-sdk-schema.py maps it as before; generate.py --check and check-sdk-schema.py pass. Tests (red at efe6dbf): set_layout_sizes_applies_a_trade_whole_or_refuses_it_whole (the both-pairs case), a_non_finite_ratio_is_refused_and_changes_nothing. * test(cmux-tui-core): a non-finite ratio on a tree split is refused (#34928 review B, on the path it named) a_non_finite_ratio_is_refused_and_changes_nothing used a column split, where the implied width already refuses a NaN, so it passed before the fix. A tree split takes the ratio as it is: this is the path the review named. * test(cmux-tui-core): set-layout-sizes refuses an array value and clamps an infinite ratio as set-split-ratio does; the event echoes its transaction (#35261 review, red) Red at c7b0434: the newtype-over-struct LayoutSizeWire accepts [split, ratio] (serde gives a plain struct a sequence form; untagged struct variants have none), and NonFiniteRatio refuses an infinite ratio that set-split-ratio clamps to 0.95 (JSON 1e39 reads as f32 infinity). Also: a ratio value on the wire, the bad-request shape of a refused value, the layout-changed event's transaction echo. * fix(cmux-tui-core): set-layout-sizes values are untagged struct variants with deny_unknown_fields; only a NaN ratio is refused (#35261 review) - Review 1: back to struct variants, with #[serde(untagged, deny_unknown_fields)] on the enum: a value with both pairs or another field is still refused, and an array value is refused again (serde gives untagged struct variants no sequence form; the newtype structs had one). - Review 2: an infinite ratio clamps to 0.95 as set-split-ratio clamps it ('same clamping and ranges' in commands.md). Only a NaN is refused (LayoutSizesError::NanRatio, invalid-argument): in-process callers only, the clamp keeps a NaN and the store cannot persist one (before, the batch answered layout-sizes-not-persisted). - The tests match the variant (NanRatio) where they only matched an index. Tests (red at 20f0fa4): set_layout_sizes_applies_a_trade_whole_or_refuses_it_whole (the array case), a_nan_ratio_on_a_tree_split_is_refused_and_an_infinite_one_clamps.
Summary
No change a person can see; the P0 resize rule does not apply. This PR adds a daemon command that no app path sends yet:
git grep -i -E 'set-layout-sizes|set_layout_sizes|layout-sizes-batch|setLayoutSizes'on feat-cmux-next d422b94 finds 0 hits inPackages,webviews,iosandweb.set-split-ratio,set-viewport-pane-width) are unchanged: the PR removes 0 lines in the daemon source files (mux.rs,mux/resource_topology.rs,mux/resource_topology/layout_ops.rs,server.rs,server/capabilities.rs,server/cmd_panes.rs,server/command_dispatch.rs,server/responses.rs). Its other files are new files, the spec, and generated bindings.layout-sizes-batch-v1. The app reads that list only throughcapabilities.contains(<name>)checks, and no app code names this capability.The app change that sends
set-layout-sizes(KEYS owner) changes what a person sees. That PR carries the display evidence of the P0 rule (the resize-keyboard journey or a divider-drag display run on a gui-session-v1 worker, at its head).A key resize or a drag release that ends with 2 or more divider values (a keyboard column trade's two widths, an Option or Command drag's widths and ratios:
EndedValues, #34123) went to the daemon as oneset-split-ratioorset-viewport-pane-widthper value under one transaction. Each was its own commit, so a value the daemon refused after it applied another left that one applied; the app kept all-or-nothing only on its own side (EndedValues.swift: "Two commands are still two daemon commits"). CLAUDE.md: batch requests apply as one transaction. (R-DAEMON-STATE DESIGN 2.10.1, lead item 2026-11-04.)New command
set-layout-sizes {values: [{split, ratio} | {pane, width}, ...], transaction}, capabilitylayout-sizes-batch-v1:screen.layout_sizes.set) applies every value, in order, to one layout snapshot of the screen, with the checks of its single command (unknown split, row split, the ratio's implied column width computed from the batch's own earlier widths, width range, pane not resizable), then commits once: one durable screen, one layout revision, one undo entry keyed by the resize transaction (the values a drag sent while it moved, under the same transaction, stay in the same undo step), onelayout-changedevent with the transaction echo.error_code, and its message names the value's index (value 1: ...). Values on two screens, no value or more than 64 values are refused too. A batch that changes nothing commits nothing.bindings/codegen/generate.py --write).The app side is next (KEYS owner, frame-owner-keys):
EndedValues.sendsends oneset-layout-sizeswhen the daemon advertiseslayout-sizes-batch-v1, else the per-value commands as today.Testing
Red first, focused command
./scripts/verify-cmux-tui-hosted.sh --filter layout_sizes(Linuxtest (linux)):test/rds-batch-red-never-merge: the same method, applying one commit per value as the app does today), hosted run https://github.com/manaflow-ai/cmux/actions/runs/41778535469:a_refused_second_value_leaves_the_first_unappliedanda_batch_is_one_layout_change_and_one_undo_stepFAILED ("a refused second value left the first applied"); the drag-plus-release undo step and the count refusal passed (guards).mux::tests::layout_sizes4 of 4.server::tests::layout_receipts_shutdown::set_layout_sizes_applies_a_trade_whole_or_refuses_it_whole(a refused trade answersviewport-width-out-of-rangewithvalue 1:and changes nothing; a malformed value is refused; a valid trade applies both widths). Hosted run https://github.com/manaflow-ai/cmux/actions/runs/41782294289 at ca012e6:test (linux)5 of 5 (the fourmux::tests::layout_sizestests and the wire test).python3 cmux-tui/scripts/check-sdk-schema.py: ok (290 commands).generate.py --check: ok.Compile: fleet compile check job 4b6311261f683aade3e7f6db at ca012e6: CmuxNext (386 s), app (102 s) and cmux-tui (75 s) passed.
lint (linux)at the head: no clippy error; the panic ratchet rows are base rows (cmux-tui-core arithmetic 1007 > 875, as on feat).Observed / Not run
Changelog
none
Proof
No capture: daemon command only; the app does not send it yet.
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Introduces
set-layout-sizes(layout-sizes-batch-v1), a daemon command that commits a resize gesture's final divider values as one change or not at all.set-split-ratioorset-viewport-pane-widthper value under one transaction, each its own commit, so a value the daemon refuses after applying another still leaves that one applied.layout-changedevent. A refused value refuses the whole batch before anything is staged, returning the single command's error code and the failing value's index; values across two screens, empty batches, batches over 64 values, and no-op batches are refused or commit nothing.Written for commit ca012e6. Summary will update on new commits.