From 3b8e426f90b77cda25623099f2d69b7584a97dd2 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Sun, 9 Aug 2026 21:28:30 +0200 Subject: [PATCH] test(window): pin the cross-frontend exception, and fix two ledger counts panel_commit_dedication_refusal matches on `fid` as well as on the profile: a nested commit for a DIFFERENT frontend may dedicate that frontend's own side slot, because resolve_placement consults only the requesting frontend's panel_capable and its own one side window, so nothing done to B can change where A's side request lands. That promise was documented and unpinned. Both revision 9 nesting tests drive a single frontend, so the comparison is trivially true throughout them: deleting it, and making any outer "panel" contract globally restrictive, passed the whole file. a_nested_commit_for_another_frontend_may_dedicate_its_own_slot runs two frontends. While an outer "panel" commit for A is in force, a nested commit for B dedicates B's slot and is ALLOWED --- and B's slot is asserted really dedicated afterwards, not merely unrefused. The far side runs in the same test: A's slot stays undedicated and A's result still lands in A's panel, so the row cannot pass by having weakened the restriction generally. This is the suite's only POSITIVE row; every other asserts a refusal, which is the shape it was thinnest on. An exception only the doc comment knows about is one review round from being simplified out. Mutation-checked: deleting `&& contract.destination.frontend == fid` fails ONLY this test. Both single-frontend nesting tests pass under it, which is the evidence they are independent of the frontend match rather than merely looking so. journey_acceptance (47), dired_acceptance (31) and cargo test --lib (1920) stay green. Two ledger corrections, both section-local: * "Eight writes exist; five are reachable" then listed four. The fifth is quit_window's QuitAction::Restore --- the site proved unreachable and guarded anyway. It now appears in the list that justifies it, and the bullet counts what actually matters: all five are guarded. * The revision 9 mutation paragraph had the preservation counts REVERSED (journey 31 / dired 47). It is journey 47 / dired 31, matching the bullet further up and measured per target. The same reversal is in 394fa43's commit message; that is left as written rather than rewriting a pushed commit, and the ledger now says so where the numbers are, so a reader following the SHA takes the corrected pair. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 77 +++++++++++----- docs/destination-capture-framing.md | 15 ++++ tests/destination_capture_acceptance.rs | 115 ++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 23 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index c81de48..2d8194f 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -335,10 +335,15 @@ form: `register_frontend_view` has callers only in `daemon.rs` and core unit tests. - **Eight writes to `dedicated` exist** (`rg 'params\.dedicated\s*=' - src/`); **five are reachable**: `apply_placement`'s `Side` created / - replacing / non-replacing arms, and `set_params`. Two `Ordinary` arms - are harmless (their target is never a side window; one only ever - clears the flag) and one is a unit test. + src/`); **four are reachable and a fifth is guarded defensively** — + `apply_placement`'s `Side` created / replacing / non-replacing arms + and `set_params` are the reachable four, and `quit_window`'s + `QuitAction::Restore` is the fifth, proved unreachable below and + guarded anyway. **All five are guarded**, which is the count that + matters; listing four under the word "five" is what an earlier version + of this bullet did. Two `Ordinary` arms are harmless (their target is + never a side window; one only ever clears the flag) and one is a unit + test. - **The guards are sited where the property converges, not per caller.** All three `Side` arms are reached through `apply_placement`, which has **exactly one caller** — so one guard in `display_buffer` covers every @@ -383,10 +388,11 @@ authoritative tip** — the ref, not a SHA. Recover with (`pmacs.window.capture_destination()`, the `ViewDestination` rename, the profile argument); `d5a6170` is `tests/destination_capture_acceptance.rs`; `469d5c8` is the - revision-8 panel-profile correction plus the invalid-UTF-8 hole; the - commit below is revision 9's contract stack. **14 pins**, and both - preservation suites pass **unchanged** (journey 47, dired 31) — §7's - stop signal not firing rather than being suppressed. + revision-8 panel-profile correction plus the invalid-UTF-8 hole; + `394fa43` is revision 9's contract stack and the commit below adds its + cross-frontend pin. **15 pins**, and both preservation suites pass + **unchanged** (journey 47, dired 31) — §7's stop signal not firing + rather than being suppressed. - **HOW THE PANEL PROFILE IS ENFORCED, in one sentence so no earlier revision gets reinstated by someone reading only that document:** the preflight stays exactly where it was, and the mutations that would @@ -413,10 +419,17 @@ authoritative tip** — the ref, not a SHA. Recover with so a nested scope rightly replaces them; a contract is a *restriction*, and replacing one suspends it. The guard stores a depth and truncates back to it, so an inner exit removes exactly the - contract it added and leaves every enclosing one in force. Matching - is per **frontend**: a nested commit for a different frontend may - dedicate *its* side slot, which cannot change where this frontend's - side request lands. + contract it added and leaves every enclosing one in force. + - **Matching is per FRONTEND as well as per profile, and that is a + deliberate exception with its own positive pin.** A nested commit for + a different frontend may dedicate *its* side slot: `resolve_placement` + consults only the requesting frontend's `panel_capable` and its own + one side window, so nothing done to B can change where A's side + request lands. Pinned by + `a_nested_commit_for_another_frontend_may_dedicate_its_own_slot`, + which is the file's only row asserting that something is **allowed** + — every other asserts a refusal, and an exception only the doc + comment knows about is one review round from being simplified out. - **Prohibiting nested `commit_to` was the other candidate and was rejected.** It closes the hole by forbidding a construction no rule objects to — `commit_to` is public Lua API for saying where a @@ -516,17 +529,35 @@ authoritative tip** — the ref, not a SHA. Recover with And reverting the byte comparison to `to_str()?` fails the `invalid utf-8` row with mlua's conversion error, on content. - **Revision 9's, run across all three suites and the lib:** restore - `panel_commit_dedication_refusal` to reading only the innermost - contract (`.last()`, which is exactly revision 8's swapped slot) → - **only** `a_nested_commit_cannot_mask_an_outer_panel_restriction` - fails. The other 13 pins, `journey_acceptance` (31), - `dired_acceptance` (47) and `cargo test --lib` (1920) all stay green, - which is what makes the new test the pin for this defect and not a - restatement of the depth-1 one. Note the ordinary-nesting pin - deliberately survives that mutation — it exists to fail the *other* - candidate fix (prohibit nesting), so the two are a pair rather than - one test written twice. + **Revision 9's two, each isolating a different half of the rule:** + 1. restore `panel_commit_dedication_refusal` to reading only the + innermost contract (`.last()`, which is exactly revision 8's + swapped slot) → **only** + `a_nested_commit_cannot_mask_an_outer_panel_restriction` fails. + Note the ordinary-nesting pin deliberately survives this — it + exists to fail the *other* candidate fix (prohibit nesting), so the + two are a pair rather than one test written twice. + 2. delete `&& contract.destination.frontend == fid` from the same + scan, making any outer `"panel"` contract **globally** restrictive + → **only** + `a_nested_commit_for_another_frontend_may_dedicate_its_own_slot` + fails. Both single-frontend nesting tests pass under it, which is + the evidence they are independent of the frontend match rather than + merely looking so; the cross-frontend exception had no pin at all + before this row, since every other test in the file drives one + frontend. + + Both were run across all three acceptance suites and the lib: in each + case `journey_acceptance` (47), `dired_acceptance` (31) and + `cargo test --lib` (1920) stay green, along with every other pin in + this file. + + **The counts above are journey 47 / dired 31**, matching the bullet + further up. The mutation paragraph committed at `394fa43` had them + **reversed** in both the ledger and that commit's message; the ledger + is corrected here and the message is left as written, since rewriting + a pushed commit is worse than a footnote. A reader following that SHA + should take these numbers, not those. - **The public API #227 adopts against (Q#DC-5), pinned so it is a contract rather than an intention:** `pmacs.window.commit_to(dest, body [, profile])`. Profile is an diff --git a/docs/destination-capture-framing.md b/docs/destination-capture-framing.md index 2e19165..d6f868f 100644 --- a/docs/destination-capture-framing.md +++ b/docs/destination-capture-framing.md @@ -719,6 +719,21 @@ incidental: no arguments is what keeps capture profile-blind. force after the nested commit returns** (popped, not cleared), and **outside every commit dedication is ordinary again**, so the fix leaked no permanent restriction onto the editor. +- **THE CROSS-FRONTEND EXCEPTION IS PINNED POSITIVELY**, over **two** + frontends: while an outer `"panel"` commit for A is in force, a nested + commit for **B** dedicates **B's** side slot and is **allowed** — and + B's slot is asserted really dedicated afterwards, not merely + unrefused. The far side runs in the same test: A's slot is still + undedicated and A's result still lands in A's panel, so this cannot + pass by having weakened the restriction generally. **This is the one + row asserting that something is permitted**; every other in the suite + asserts a refusal, and without it, deleting the `fid` comparison — + making any outer panel contract *globally* restrictive — passes the + whole file, because both nesting rows above drive a single frontend. + The exception is real and not a convenience: `resolve_placement` + consults only the requesting frontend's `panel_capable` and its own + one side window, so nothing done to B can change where A's side + request lands. - **A `"panel"` commit that really lands in the panel still skips checks 2–4** — otherwise the fix has quietly collapsed the two profiles into one and the parameterization buys nothing. diff --git a/tests/destination_capture_acceptance.rs b/tests/destination_capture_acceptance.rs index 54fdf99..0ae179f 100644 --- a/tests/destination_capture_acceptance.rs +++ b/tests/destination_capture_acceptance.rs @@ -1062,6 +1062,121 @@ fn an_ordinary_nested_commit_still_runs_and_restores_the_outer_restriction() { ); } +/// **P** — the restriction is scoped to its **frontend**: a nested commit +/// for a *different* frontend may still dedicate that frontend's own side +/// slot (revision 9). +/// +/// `panel_commit_dedication_refusal` scans every contract in force, but it +/// matches on `fid` as well as on the profile, and that comparison is a +/// deliberate exception rather than an oversight: frontend B's side slot +/// has no bearing on where **A's** side request lands. `resolve_placement` +/// consults only the requesting frontend's `panel_capable` and its own one +/// side window, so a contract for A cannot be invalidated by anything done +/// to B. +/// +/// **This is a POSITIVE pin, which is the shape this suite is thinnest +/// on** — every other row asserts a refusal. Without it, deleting the +/// `fid` comparison and making any outer `"panel"` contract *globally* +/// restrictive passes the whole file: the two nesting tests above use one +/// frontend, so the comparison is trivially true throughout them. An +/// exception that only the doc comment knows about is one review round +/// away from being "simplified" out. +/// +/// The far side is still asserted in the same run: A's slot stays +/// undedicated and A's commit still lands in A's panel, so this cannot +/// pass by having weakened the restriction generally. +/// +/// *Mutation:* delete `&& contract.destination.frontend == fid` from +/// `panel_commit_dedication_refusal` and only this test fails. +#[test] +fn a_nested_commit_for_another_frontend_may_dedicate_its_own_slot() { + let s = editor(); + + // Frontend B: its own layout, its own undedicated panel, and a + // destination captured while it is the acting frontend. + attach_frontend(&s, COMPETITOR); + s.core.borrow_mut().active_frontend = COMPETITOR; + exec( + &s, + "pmacs.window.display(pmacs.buffer.create('*b-panel*'), + { side = 'bottom', select = false }) + dest_b = pmacs.window.capture_destination()", + ); + let b_panel = s + .core + .borrow() + .side_window_for(COMPETITOR) + .expect("the competitor gets its own side slot"); + assert!( + !dedicated(&s, b_panel), + "B's slot must start undedicated, or the row would prove nothing" + ); + s.core.borrow_mut().active_frontend = FrontendId::LOCAL; + + // Frontend A: an undedicated panel, so its `"panel"` commit takes the + // relaxed preflight and the restriction is really in force. + exec(&s, PANEL_ARRANGED); + let a_panel = s + .core + .borrow() + .side_window_for(FrontendId::LOCAL) + .expect("the arrangement creates A's side slot"); + capture(&s); + let doc = local_window(&s); + exec( + &s, + "pmacs.window.switch_buffer(pmacs.buffer.create('*newer*'))", + ); + + commit_body( + &s, + Some("'panel'"), + &format!( + "b_ok, b_reason = pmacs.window.commit_to(dest_b, function() + pmacs.window.set_params(pmacs.window.panel(), {{ dedicated = true }}) + end) + {PANEL_BODY}" + ), + ); + + // 1. THE CROSS-FRONTEND DEDICATION IS ALLOWED. + assert_eq!( + raised(&s), + None, + "dedicating ANOTHER frontend's side slot must not be refused -- it cannot change \ + where this frontend's side request lands" + ); + assert!( + eval::(&s, "return b_ok == true"), + "the nested commit for B must be accepted: {}", + eval::(&s, "return tostring(b_reason)") + ); + assert!( + dedicated(&s, b_panel), + "B's slot must really be dedicated -- asserting only that nothing was refused \ + would pass on a call that was silently dropped" + ); + + // 2. AND A'S RESTRICTION IS UNWEAKENED: its slot is untouched and its + // commit still lands in its own panel rather than falling back. + assert!(ok(&s), "A's commit must be accepted: {}", reason(&s)); + assert!( + !dedicated(&s, a_panel), + "A's own slot must be untouched -- this row must not pass by having relaxed the \ + restriction for everyone" + ); + assert_eq!( + name_in(&s, a_panel), + "*result*", + "A's \"panel\" commit still belongs in A's panel" + ); + assert_eq!( + name_in(&s, doc), + "*newer*", + "and A's newer document buffer must survive" + ); +} + /// **P** — a `"panel"` commit that falls back with a **still-valid** /// destination lands in the document window, exactly as it does today. ///