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) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-09-20 11:14:28 -07:00
parent 93f795291e
commit 72b0d09119
3 changed files with 24 additions and 10 deletions
+5 -2
View File
@@ -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.
+17 -7
View File
@@ -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:
+2 -1
View File
@@ -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.