A view-scoped ModelCommand names its view (improvise-lltt)
Nine ModelCommand variants configure a view and named it implicitly: the effect read App::view_mut(), the HOST's slice. Since improvise-jytm made ViewState::active_view authoritative per client, a client on another view moved the host's view instead of its own -- its grid did not change and every other client's did. Each of the nine now carries `view: String`; model_effects maps it to effect::ViewTarget::Named, and the nine effects carry a ViewTarget rather than reading an ambient one. There is no operandless form left: App::view_mut() is deleted and replaced by view_mut_of(&ViewTarget), so a future geometry effect has to say which view it writes. The host's key path passes ViewTarget::Active, which is right -- the TUI is the host and has no session to ask. A Named view the document has not got is a no-op rather than resolve_view's fallback onto the default. Second half, which the ticket did not predict: naming the view made a reframe of a view the host is NOT on reachable, and adopt_cursor_epoch could not see one -- cursor_epoch is bumped only by the host's own reset_cursor, so those clients were reset by nobody and told nothing (gotcha 24's strictly-worse-than-nothing state). App::last_reframed_elsewhere is the second trigger; its opening frames are taken lazily inside view_mut_of, the one door such a write goes through, so the held-key path still hashes one view and improvise-mcq4's declined cost is not paid. Evidence and the three injected faults: context/test-evidence/command.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
@@ -8,7 +8,7 @@ use improvise::model::cell::{CellKey, CellValue};
|
||||
use improvise::view::Axis;
|
||||
use improvise::workbook::Workbook;
|
||||
use improvise_command::ui::app::App;
|
||||
use improvise_command::ui::effect::{CycleAxis, Effect, SetCell};
|
||||
use improvise_command::ui::effect::{CycleAxis, Effect, SetCell, ViewTarget};
|
||||
|
||||
/// The fixture `grid_projection` uses, so the two numbers are comparable.
|
||||
fn dense_app(regions: usize, products: usize, measures: usize) -> App {
|
||||
@@ -108,7 +108,10 @@ fn geometry_at(
|
||||
let (rows, cols) = (app.layout.row_count(), app.layout.col_count());
|
||||
let mut best = Duration::MAX;
|
||||
for i in 0..iters.max(3) {
|
||||
let effects: Vec<Box<dyn Effect>> = vec![Box::new(CycleAxis("Product".to_string()))];
|
||||
let effects: Vec<Box<dyn Effect>> = vec![Box::new(CycleAxis(
|
||||
ViewTarget::Active,
|
||||
"Product".to_string(),
|
||||
))];
|
||||
let start = Instant::now();
|
||||
std::hint::black_box(app.apply_effects(effects));
|
||||
best = best.min(start.elapsed());
|
||||
|
||||
Reference in New Issue
Block a user