docs(adr): ADR 009 records the user's galloping top-left search and revises the predecessor lean (improvise-felo.4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
885e8eb469
commit
3698c68025
@@ -1444,6 +1444,44 @@ analysis.*
|
||||
The bottom-right corner is symmetric. An axis with **no** occupied position
|
||||
answers "empty axis" under both, and the window is empty.
|
||||
|
||||
**The user's simpler procedure** (chat, relayed on 2026-10-05; on no PR), quoted
|
||||
exactly as sent: "The simplest might be some kind of binary search for a new top left
|
||||
corner: increasing jumps of the top left until you get a hit and then move down/right
|
||||
until
|
||||
You only have one new row column." *The author's reading:* the procedure belongs to the
|
||||
client and uses forward requests only. The client moves its requested top-left up (or
|
||||
left) in growing jumps until a request returns an occupied row before its old
|
||||
top-left, then narrows back down (or right) until exactly one new row (or column) is
|
||||
gained. A pruned top-left is no longer an edge case at all: the response simply starts
|
||||
at a later position than the one asked for. *The rest is the author's analysis.*
|
||||
- **What it requires of the response:** the **actual** absolute position of every
|
||||
row and column returned, the first one included. The client compares those
|
||||
positions with its old top-left, so this is T1 again, and it already holds under
|
||||
clause 12. Nothing else is needed: no error, no snap rule, no direction in the
|
||||
request, and no predecessor query.
|
||||
- **Cost.** With doubling jumps, the gallop takes about log₂(gap) requests. A plain
|
||||
binary search over the last interval takes about log₂(gap) more. At density 10^-4
|
||||
the expected gap is about 10^4 rows, so that is 14 + 14 ≈ 28 forward requests,
|
||||
against one predecessor request. The refinement is often much cheaper. A forward
|
||||
response holds k occupied rows with their positions, so if the hit request's k rows
|
||||
reach the old top-left, the client reads the last row before it directly, and the
|
||||
search ends after the gallop, about 14 requests. Refinement is needed only when
|
||||
more than k occupied rows lie between the hit and the old top-left. These figures
|
||||
are arithmetic, not measured.
|
||||
- **Statelessness and network transparency.** The host keeps nothing for the search.
|
||||
Every request is an ordinary `project` from an absolute top-left, so the in-process
|
||||
and remote consumers do exactly the same thing (T6). The cost is round trips: about
|
||||
14 for a remote client and about 14 function calls for the TUI. For the TUI that is
|
||||
nothing. Over a socket it is about 14 latencies for one scroll step into a sparse
|
||||
stretch.
|
||||
- **The author's lean, revised.** Take the user's procedure as the **baseline**. It
|
||||
makes (a), (b) and (c) unnecessary, because a pruned top-left just returns a later
|
||||
first position. Keep a model-side predecessor query only as an **optional
|
||||
optimisation** for a remote client. It costs no state (see above) and collapses
|
||||
the gallop into one request. Offer it once a measured round-trip cost shows it is
|
||||
worth a second query direction. *As first written*, this item leaned to offering it
|
||||
outright; that lean is withdrawn.
|
||||
|
||||
Cost at density 10^-4: finding the nearest occupied neighbour is one seek in the
|
||||
ordered index, O(log n), in either direction, so (a) with named neighbours and (b)
|
||||
cost the same on the host. (a) adds a round trip, and (b) adds none. The expected gap
|
||||
@@ -2046,7 +2084,11 @@ revision, and none is renumbered.
|
||||
predecessor search, which every option serves as cheaply as a successor search). It
|
||||
also raises the edge case of a top-left that lands on a pruned row: fail and retry,
|
||||
snap forward (which the user objects to: "the viewport getting stuck"), or snap toward
|
||||
the scroll direction (clause 12). That edge case is
|
||||
the scroll direction (clause 12). The user has since suggested a simpler client procedure:
|
||||
gallop the top-left with forward requests until one hits, then narrow. A pruned
|
||||
top-left then needs no special answer, provided responses report actual positions.
|
||||
The author now takes that as the baseline, and keeps a predecessor query only as an
|
||||
optional optimisation. That edge case is
|
||||
part (d) of this question.
|
||||
*Recommendation (the author's):* (a) yes, with (ii). (b) yes, once the user confirms
|
||||
that pruning is the client's. (c) restate both in those terms, in ADR 008, since they
|
||||
|
||||
Reference in New Issue
Block a user