From 72b0d091196e502c0cb0ec055ee56e4644d62510 Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Sun, 20 Sep 2026 11:14:28 -0700 Subject: [PATCH] docs: finish the reduce_full deletion in the prose that outlived it Self-review caught three references the deletion commit missed, which is gotcha 48's rule arriving on schedule: when a fact is stated in more than one place, changing it is a grep, not an edit. - context/code/command.md still had a `### reduce_full / reduce_key` section calling it "the signature the three hosts share" -- the exact claim the ticket was filed against, two hundred lines below the paragraph that corrects it. - ADR 001 stated in the present tense that apply_command/reduce_full do not check, and recorded improvise-ondj giving both a Checked signature without saying that one of them has since gone. The ADR now says why deleting beat typing: having no caller was the condition that let the defect hide, and a Checked on a function nobody calls fixes the type and not that. - The test-evidence entry's "no longer compiles" is now "no longer exists". Also records the AddItem/AddItemInGroup success gating and the four effects that reset unconditionally because they cannot report a miss. Co-Authored-By: Claude Opus 5 (1M context) --- context/adr/001-concurrent-edits.md | 7 +++++-- context/code/command.md | 24 +++++++++++++++++------- context/test-evidence/command.md | 3 ++- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/context/adr/001-concurrent-edits.md b/context/adr/001-concurrent-edits.md index 52df697e..44971586 100644 --- a/context/adr/001-concurrent-edits.md +++ b/context/adr/001-concurrent-edits.md @@ -272,7 +272,8 @@ the workbook refuses a view it does not have, and every mirror takes what was *accepted* (gotcha 36) — but it is a hole in "a batch carries its basis" and should be decided rather than left as an accident. -**`apply_command`/`reduce_full` do not check at all**, and the *principle* is +**`apply_command` does not check at all** (nor did `reduce_full`, which +improvise-s17o has since deleted for having no caller), and the *principle* is correct: the check is a property of the **session door**, not of the mutation path, because a host holding the `App` is the truth and not a claimant. That is also why `ui::reduce::caught_up(&App, cmd)` is not a bypass — it takes `&App`, @@ -283,6 +284,8 @@ a wire `Command` whose `Command::Model { cmd, .. }` arm discarded the basis with `..`, while `ui/reduce.rs`'s module doc pointed every future host at them by name. **Closed by improvise-ondj** as layer-1 cleanup: both now take a `Checked<'_>`, whose only constructor runs the check against the authoritative -`App` and returns a `Rejection`. The exemption stands — a host's own +`App` and returns a `Rejection`. `reduce_full` was deleted outright shortly after +(improvise-s17o): having no caller was the condition that let the defect hide, +and a `Checked` signature on a function nobody calls fixes the type and not that. The exemption stands — a host's own `ModelCommand` still carries no basis — but it is no longer reachable as a door, and the unchecked path is unconstructible rather than merely discouraged. diff --git a/context/code/command.md b/context/code/command.md index eab6dc2d..e0d79d82 100644 --- a/context/code/command.md +++ b/context/code/command.md @@ -423,14 +423,16 @@ push it through the same door a client's would take, and the tests whose subject is not staleness. The tests whose subject *is* staleness build the `Basis` by hand, so neither kind can pass by accident through the other's convenience. -### `reduce_full` / `reduce_key` +### `reduce_key` -`reduce_full` is the signature the three hosts share. The returned commands are -the document-scoped projections; per-client grid updates need a session's -viewport and come from `Sessions::project_all`, driven by the `Dirty` that -`apply_command` returns. `reduce_key` is the same for a keypress: resolve it -through the keymap, run the commands, apply the effects, report what to send -onward. +Resolve a keypress through the keymap, run the commands, apply the effects, and +report what to send onward. The returned commands are the document-scoped +projections; per-client grid updates need a session's viewport and come from +`Sessions::project_all`, driven by the `Dirty` that `apply_command` returns. + +It used to have a wire-command twin, `reduce_full`, described right here as "the +signature the three hosts share". None of them shared it; the module section +above says why it is gone (improvise-s17o). --- @@ -601,6 +603,14 @@ vacuously. The per-effect arguments: block: adding a third `Product` inserts a row into the `North` block and pushes the whole `South` block down. `RemoveItem` is a `shift_remove` and moves positions on any level. +- `AddItem` and `AddItemInGroup` reset **only on success**. A refused add + reshapes nothing and the epoch is document-wide, so the first version of this + change — which reset after the error branch — sent every client a + `ResetCursor` for a typo'd category name. `RemoveItem`, `SetAxis`, `HideItem`, + `ShowItem` and `ToggleGroup` reset unconditionally because none of them can + report a miss; a no-op call costs one spurious `ResetCursor`, which is the + direction `Dirty::of` is deliberately sloppy in, and none is reachable from + the UI with an argument that misses. What does **not** reset, and why: diff --git a/context/test-evidence/command.md b/context/test-evidence/command.md index 423733d4..80383e8d 100644 --- a/context/test-evidence/command.md +++ b/context/test-evidence/command.md @@ -210,7 +210,8 @@ basis with no compile error. **The regression guard is the signature, not this test.** Both now take a `Checked`, whose only constructor runs `stale_basis`, so the version of this test that reproduced the bug — `reduce_full(&mut app, &wire)` with a stale `wire` — no -longer compiles. What is left to assert is that the constructor refuses, and that +longer compiles, and `reduce_full` itself no longer exists (improvise-s17o: having +no caller was the condition that let the defect hide in the first place). What is left to assert is that the constructor refuses, and that refusing leaves the document alone: there is no half-applied batch, because the type is obtained before anything is applied.