Both conflicts were competing rewrites of the same anchor lines: #172 refreshed the canonical base and the handoff header while this branch did the same for #165. Resolved by taking main's list, which is the more accurate of the two (it names Lean 4 Stage 2 #161 properly), refreshing it to the current tip `ccf29e3`, and keeping this branch's note that lanes naming an older base have not been re-based. #172 also removed the inline-math lane, so the stale-header note drops from three back to two and now says who owes the remaining updates.
This commit is contained in:
commit
39233aa25f
13
COHERENCE.md
13
COHERENCE.md
|
|
@ -1272,9 +1272,16 @@ its asks are already practiced.**
|
|||
exclusive by construction; every other per-frontend-kind pair in the
|
||||
dispatcher remains two adjacent `if`s that a reader must notice are
|
||||
alternatives.
|
||||
- The GPU frontend exceeds the TUI (minimap, squiggles, typography)
|
||||
without the TUI losing the model — the "no privileged frontend" rule
|
||||
is holding under real divergence pressure.
|
||||
- The GPU frontend exceeds the TUI (minimap, squiggles, typography,
|
||||
and since #158 rendered inline math) without the TUI losing the
|
||||
model — the "no privileged frontend" rule is holding under real
|
||||
divergence pressure. Inline math is the sharpest case so far: the
|
||||
GPU shapes `$…$` spans through a bundled MATH-table font while the
|
||||
TUI shows the LaTeX source unchanged, and the TUI's distinct-face
|
||||
fallback is a **named deferral rather than an oversight**. What
|
||||
keeps it inside the rule is that the slice reserves no protocol
|
||||
version and adds no wire surface — the divergence is presentational
|
||||
only, and the semantic model both frontends read is identical.
|
||||
|
||||
Remaining, honestly small relative to the section's ambition: capability
|
||||
negotiation is per-bit rather than a first-class declared capability
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ landed on `main`. Read it after `docs/agent-handoff.md`. Remove completed
|
|||
entries when their PR merges; do not let this become a second permanent
|
||||
backlog.
|
||||
|
||||
**Three lane headers below are stale on purpose**, pending the docs
|
||||
updates their own lanes owe: the inline-math slice **#158 has merged**
|
||||
(its lane still says PR #158 OPEN), multi-root LSP affinity **#161 has
|
||||
merged** (the Lean 4 lane still says IN REVIEW; its continuation is PR
|
||||
#167), and GPU terminal input **#166 has merged** (its lane still says IN
|
||||
REVIEW; PR #168 records it). Trust the canonical-base line below over a
|
||||
lane header: if a PR number appears in `git log --first-parent
|
||||
githubsucks/main`, it has landed regardless of what its lane says.
|
||||
**Two lane headers below are stale on purpose**, pending the docs updates
|
||||
their own lanes owe: multi-root LSP affinity **#161 has merged** (the
|
||||
Lean 4 lane still says IN REVIEW; its continuation is PR #167) and GPU
|
||||
terminal input **#166 has merged** (its lane still says IN REVIEW; PR
|
||||
#168 records it). Trust the canonical-base line below over a lane header:
|
||||
if a PR number appears in `git log --first-parent githubsucks/main`, it
|
||||
has landed regardless of what its lane says. (The inline-math lane was
|
||||
here too until #172 removed it — that is the update those two owe.)
|
||||
|
||||
## Repository authority
|
||||
|
||||
|
|
@ -23,14 +23,13 @@ githubsucks/main`, it has landed regardless of what its lane says.
|
|||
machine-local: `origin` may name this canonical URL, a release mirror,
|
||||
or something else, and therefore has no authority by name alone.
|
||||
- Canonical base at this snapshot:
|
||||
`githubsucks/main` @ `d152120` (the bottom-panel docs #156 atop the
|
||||
inline-math slice #158, dired Stage 1 #165, GPU terminal input #166,
|
||||
multi-root LSP affinity #161, the dired framing #164,
|
||||
find-file #162, COHERENCE.md #163, Lean 4 Stage 1 #160, the minimap
|
||||
blank-slab fix #159, bottom-panel Stage 1 #155, the inline-math re-scout
|
||||
#154, the vterm PTY-flake fix #153, and the GPU initial-target doc
|
||||
refresh #152; protocol v20). **Lanes below that name an older base have
|
||||
not been re-based; derive their integration surface from
|
||||
`githubsucks/main` @ `ccf29e3` (the CRDT undo repro #157 atop the
|
||||
inline-math landed-doc refresh #172, the bottom-panel landed-doc
|
||||
refresh #156, the inline-math slice #158, dired Stage 1 #165, the GPU
|
||||
terminal input fix #166, Lean 4 Stage 2 #161, the dired framing #164,
|
||||
COHERENCE.md #163, find-file #162, Lean 4 Stage 1 #160, and the minimap
|
||||
blank-slab fix #159; protocol v20). **Lanes below that name an older
|
||||
base have not been re-based; derive their integration surface from
|
||||
`git diff <their base>..main`.**
|
||||
- On the transfer source, `origin/main` named a release mirror at
|
||||
`d3fa632` and lagged badly. On the current destination, `origin` names
|
||||
|
|
@ -65,137 +64,9 @@ git worktree list
|
|||
git status --short --branch
|
||||
```
|
||||
|
||||
The `git log` command must expose `8c86d34` or a newer intentional main.
|
||||
The `git log` command must expose `d152120` or a newer intentional main.
|
||||
If it does not, stop and repair the remote/fetch configuration.
|
||||
|
||||
## Inline-math slice lane — PR #158 OPEN, main integrated
|
||||
|
||||
- Portable branch: `githubsucks/inline-math-slice`; worktree
|
||||
`../pmacs-math-slice`. **PR #158**, base `main`.
|
||||
- **Canonical `main` merged into the lane three times on 2026-07-25**,
|
||||
every time merged rather than rebased, per the #135/#137 precedent: the
|
||||
PR is awaiting review rounds and a rebase would break every review
|
||||
anchor.
|
||||
- First at `8c86d34` (28 commits behind). The conflict was
|
||||
**pre-existing**, not introduced by the dired (#164) or Lean 4
|
||||
ledger commits; it already conflicted against `main` @ `e745068`.
|
||||
- Then at `46a1b8f`, after Lean 4 Stage 2 (#161) landed while this
|
||||
branch's CI was still running. Same single conflict, same shape,
|
||||
same resolution.
|
||||
- Then at `b889873`, after the GPU terminal input fix (#166) landed.
|
||||
**No conflict at all this time** — and that is exactly why it still
|
||||
needed a real integration, see below.
|
||||
- **The first two conflicts were this ledger and nothing else** — both
|
||||
sides' lanes kept verbatim each time. That is the standing cost of a
|
||||
long-lived PR here: every merge to `main` edits this file, so a branch
|
||||
awaiting review re-conflicts on it and only on it. It is a docs
|
||||
collision, never a code one, and it says nothing about integration
|
||||
risk — do not read a `CONFLICTING` badge on this PR as a code signal
|
||||
without checking which file `git merge-tree` names.
|
||||
- **The inverse trap matters more, and #166 is the case in point: a
|
||||
CLEAN `git merge-tree` is not a reason to skip integrating.** #166
|
||||
landed 41 lines in `pmacs-gpu/src/main.rs`, the same heavily-rewritten
|
||||
file as the first integration, and git merged it without a murmur
|
||||
because the two edits sit in different regions (#166 is entirely in the
|
||||
headless probe — `PMACS_GPU_PROBE_OBSERVE_MS`, `PROBE_INPUT_CHAR`,
|
||||
`input_echo_observed` — while this lane rewrites the render path).
|
||||
Merging the PR on the strength of that clean auto-merge would have
|
||||
shipped a combination no gate had ever run. **Decide whether to
|
||||
integrate from the shared-FILE set, not from whether git complained.**
|
||||
- **First integration's surface** (derived from `git diff
|
||||
<merge-base>..main`, not from another PR's file list):
|
||||
`pmacs-gpu/src/main.rs` gained 72 lines on main from `e547a90` — the
|
||||
minimap all-blank-slab divide-by-zero fix — and this lane rewrites
|
||||
large parts of the same file. Git auto-merged it **textually**; a
|
||||
clean auto-merge is not evidence the tree compiles (the folding-arc
|
||||
lesson), so the full gate suite below is what actually discharges it.
|
||||
- **Second integration's surface is code-disjoint.** #161 touched
|
||||
`COHERENCE.md`, `builtin/runtime/lsp.lua`, `src/lua_bindings/mod.rs`,
|
||||
and a new `tests/lsp_multi_root_acceptance.rs`; intersecting that
|
||||
against this lane's own changed-file set leaves exactly one entry,
|
||||
`docs/active-work.md`. No source file is touched by both sides, so
|
||||
this one carries none of the first integration's semantic risk.
|
||||
- **CI ran on this branch for the first time on 2026-07-25 and passed
|
||||
all twelve** (Format, both Lints, GPU Render headless, all four Test
|
||||
matrix jobs, M1/M4/M5/M6 gates) at `8b457de` — the first-integration
|
||||
tip. Before that there were zero workflow runs since the PR opened on
|
||||
2026-07-24, while every other open PR had a full run; not a fork and
|
||||
not a trigger-config issue (the workflow fires on all `pull_request`
|
||||
events), cause never identified. So the green run **validates the
|
||||
first integration, including the `pmacs-gpu/src/main.rs` auto-merge,
|
||||
on macOS and Linux both** — the platforms local gating could not
|
||||
cover. The second and third integrations get their own CI run on the
|
||||
push that carries them.
|
||||
- Framing: `docs/inline-math-slice-framing.md` rev 3, approved after two
|
||||
review rounds; parent arc framing merged as #154.
|
||||
- State: parser, font bundle (GUST licence), MATH-table layout with the
|
||||
measured height budget, currency-guarded detection, and the
|
||||
`ChunkSource::MathBox` spacer substrate are implemented and
|
||||
round-3-reviewed (review fixes at `cbf7782`: the exclusive-`end`
|
||||
mapping bug its own test had pinned, script-marker whitespace, fallible
|
||||
layout via `UncoverableGlyph`, real fraction gap-min constants —
|
||||
flagship scale 0.867, fallback depth 5).
|
||||
- Caret-driven suppression (the Q#MS5 gate over the effective caret and
|
||||
Q#MS11 selection endpoints, chunk substitution before tab expansion,
|
||||
the line-reuse predicate's third input, and the CursorByte /
|
||||
optimistic-edit / Decorations refresh triggers), the draw pass
|
||||
(per-glyph mini-buffers positioned by each shaped line's real
|
||||
baseline, fraction-rule quads over the washes, the F8b family pin),
|
||||
the Q#MS11 whole-rectangle wash widening, and the pixel acceptance
|
||||
battery (criteria 5–11, 14–16; 17 discharged by the differential
|
||||
`cargo tree -e features` check — byte-identical with and without the
|
||||
dependency line) are implemented on the branch tip.
|
||||
- Clippy is CLEAN on the whole workspace at `-D warnings` — the draw
|
||||
pass consumed every formerly-dead item.
|
||||
- Verification **pre-integration** (at `14c1c01`, against the old base):
|
||||
199 `pmacs-gpu` tests under `PMACS_REQUIRE_GPU=1`; 1,815 default +
|
||||
1,992 CRDT library tests; M4 121; full workspace sweep green (isolated
|
||||
`XDG_CONFIG_HOME`). Superseded by the post-integration run below —
|
||||
those numbers describe a tree 28 commits behind.
|
||||
- Verification after the **first** integration: `cargo fmt --check`
|
||||
clean; strict workspace Clippy clean; 1,826 default + 2,003 CRDT
|
||||
library tests; **202 `pmacs-gpu` tests under `PMACS_REQUIRE_GPU=1`**;
|
||||
M4 121; isolated-`XDG_CONFIG_HOME` `--no-fail-fast` workspace sweep
|
||||
3,208 across 91 suites, zero failures; `git diff --check` clean.
|
||||
- Verification after the **third** integration (this is the set that
|
||||
describes what the PR now proposes): fmt clean; `git diff --check`
|
||||
clean; strict workspace Clippy clean; **1,829 default + 2,006 CRDT**
|
||||
library tests; **202 `pmacs-gpu`** under `PMACS_REQUIRE_GPU=1`; M4 121;
|
||||
**isolated-`XDG_CONFIG_HOME` `--no-fail-fast` sweep 3,224 across 92
|
||||
suites, zero failures**.
|
||||
- **Test-count reconciliation is the integration proof, not the pass.**
|
||||
Run it against what the other side actually added, per merge:
|
||||
- First: GPU 199 → **202**, and `e547a90` added exactly **3**
|
||||
`pmacs-gpu` tests — the whole delta on main since the merge base.
|
||||
Structurally spot-checked too: main's fix survives as
|
||||
`(count > 0).then(|| MinimapLineShape {` (the deferred closure,
|
||||
**not** the eager `then_some`) with its regression test.
|
||||
- Third: #166 adds **3** library tests, **2** to
|
||||
`vterm_stage3_acceptance`, and **0** to `pmacs-gpu`. Predicted lib
|
||||
1,826 → 1,829, CRDT 2,003 → 2,006, GPU unchanged at 202 — and that
|
||||
is exactly what ran. Suite count 91 → **92** is #161's new
|
||||
`tests/lsp_multi_root_acceptance.rs` binary. All three sides'
|
||||
markers confirmed live in `pmacs-gpu/src/main.rs`: #166's probe
|
||||
symbols, this lane's `math_plan_for_line` / `math_gates_match` /
|
||||
`cached_math_subs_for_slice` / `widen_over_math_chunks` / 21
|
||||
`MathBox` references, and the first integration's minimap fix.
|
||||
- **Ops trap, cost hours: `m4_5_basedpyright_initializes_and_negotiates_
|
||||
encoding` does not time out — it hangs forever.** A `--workspace`
|
||||
sweep parks on `m4_acceptance` with a live
|
||||
`basedpyright/langserver.index.js` child and never advances (observed
|
||||
stuck at 38 of 92 suites for 2h26m). The per-suite M4 gate already
|
||||
carries `-- --skip basedpyright`; **the workspace sweep needs the same
|
||||
flag** — `cargo test --workspace --no-fail-fast -- --skip
|
||||
basedpyright` (libtest filters apply to every binary; verify it bit by
|
||||
checking the run reports exactly 1 filtered out). Do not read a
|
||||
long-running sweep as "slow": check whether the suite count is
|
||||
advancing.
|
||||
- Remaining: the user's review pass.
|
||||
Named v0 approximations: the peer-caret half of acceptance 14 is
|
||||
pinned at the mapping level (unit tests), not pixels; a soft-wrapped
|
||||
spacer draws its box whole at the first run's origin; the fit budget
|
||||
reads the bundled code face even under a custom `set_font` family
|
||||
(the draw anchors to the real shaped baseline either way).
|
||||
## Lean 4 lane (Arc 8) — Stage 1 MERGED; Stage 2 IN REVIEW (PR #161)
|
||||
|
||||
- Stage 1 **merged as #160** (`main` @ `0827dd1`, 2026-07-25, one review
|
||||
|
|
@ -496,6 +367,47 @@ git worktree add --track \
|
|||
undifferentiated `ReplyKind::FsUnit` and so must be keyed on
|
||||
`JobKind::FsRename`.
|
||||
|
||||
|
||||
- **Inline-math slice — MERGED as #158** (`main` @ `5aa9044`,
|
||||
2026-07-25). Detect → parse → layout → draw for `$…$`, entirely inside
|
||||
`pmacs-gpu`, no protocol change. Verified by the user's manual pass on
|
||||
a real paper after the landing. What is worth carrying forward:
|
||||
- **The v0 subset is 34 Greek symbols, sub/superscript, and `\frac`.**
|
||||
An unsupported command fails the **whole span** back to source, so on
|
||||
a real document most inline spans still show LaTeX. Widening the
|
||||
symbol map is the highest-value next increment — ahead of display
|
||||
math, which is also deferred.
|
||||
- **A stale frontend binary is invisible from the source tree.** The
|
||||
slice lives only in `pmacs-gpu`, so after it merged the feature was
|
||||
absent until `cargo build --release -p pmacs-gpu` and a client
|
||||
restart; the daemon needs neither. Diagnose with `strings` on the
|
||||
binary (`Latin Modern Math`, `MathBox`) rather than by re-reading the
|
||||
checkout, which was already current.
|
||||
- **Main was integrated three times in one day** (`8c86d34`,
|
||||
`46a1b8f`, `b889873`), merged not rebased to preserve review anchors.
|
||||
Two conflicts, both this ledger and nothing else. **The dangerous
|
||||
case was the one that did NOT conflict**: #166 auto-merged into
|
||||
`pmacs-gpu/src/main.rs`, the file this lane rewrites, because the two
|
||||
edits sat in different regions of it. Decide whether to integrate
|
||||
from the shared-**file** set, never from whether git complained.
|
||||
- **Integration was proved by test-count reconciliation**, not by a
|
||||
green run: predict what the other side adds, then check the deltas.
|
||||
GPU 199→202 matched `e547a90`'s 3; later lib 1,826→1,829 and CRDT
|
||||
2,003→2,006 matched #166's 3, with GPU unchanged because #166 adds
|
||||
none. Suites 91→92 was #161's new binary.
|
||||
- **Why the branch had no CI for a day**: a conflicting PR builds no
|
||||
merge ref, so no `pull_request` run is created. The ledger previously
|
||||
recorded this cause as unidentified; it is not. Check `mergeable` and
|
||||
confirm a run exists for the current head SHA.
|
||||
- **`m4_5_basedpyright` has no timeout and hangs forever**, parking a
|
||||
`--workspace` sweep (observed 2h26m at 38 of 92 suites). It is
|
||||
**intermittent**, so an earlier clean sweep proves nothing. Sweep with
|
||||
`cargo test --workspace --no-fail-fast -- --skip basedpyright` and
|
||||
judge progress by whether the suite count advances.
|
||||
- Named v0 approximations: the peer-caret half of acceptance 14 is
|
||||
pinned at the mapping level, not pixels; a soft-wrapped spacer draws
|
||||
its box whole at the first run's origin; the fit budget reads the
|
||||
bundled code face even under a custom `set_font` family.
|
||||
- **Bottom panel Stage 1 — MERGED as #155** (`main` @ `e745068`,
|
||||
2026-07-24, after two review rounds). Window placement, window
|
||||
parameters, TUI side windows, the divider, and the adopter `display`
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
# Agent handoff — cross-machine continuity
|
||||
|
||||
**Last updated: 2026-07-25, after dired Stage 1 (#165) landed — the
|
||||
directory view — following GPU terminal input (#166), multi-root LSP
|
||||
affinity (#161), the dired framing (#164), find-file (#162) — the dired
|
||||
arc's Stage 0 — COHERENCE.md (#163), Lean 4 Stage 1 (#160), the
|
||||
**Last updated: 2026-07-25, after the CRDT undo repro (#157) and the
|
||||
inline-math landed-doc refresh (#172) — following the bottom-panel
|
||||
landed-doc refresh (#156), the inline-math slice (#158), dired Stage 1
|
||||
(#165) — the directory view — the GPU terminal input fix (#166), Lean 4
|
||||
Stage 2 (#161), the dired framing (#164), find-file (#162), the dired
|
||||
arc's Stage 0, and COHERENCE.md (#163), Lean 4 Stage 1 (#160), the
|
||||
minimap blank-slab fix (#159), bottom-panel Stage 1 (#155), the
|
||||
inline-math re-scout (#154), the vterm PTY-flake fix (#153), and the
|
||||
GPU initial-target doc refresh (#152); and before that GPU
|
||||
|
|
@ -28,11 +30,12 @@ commands, read `docs/active-work.md` immediately after this file.
|
|||
|
||||
## 1. Where the project stands (2026-07-25)
|
||||
|
||||
- `main` @ `c8ec8f3` (dired Stage 1 #165 atop GPU terminal input #166,
|
||||
multi-root LSP affinity #161, the dired framing #164, find-file #162,
|
||||
COHERENCE.md #163, Lean 4 Stage 1 #160, minimap blank-slab #159,
|
||||
bottom-panel Stage 1 #155, inline-math re-scout #154, vterm PTY-flake
|
||||
#153, and doc refresh #152). Protocol unchanged at **v20**. The bullets
|
||||
- `main` @ `ccf29e3` (the CRDT undo repro #157 atop the inline-math
|
||||
landed-doc refresh #172, the bottom-panel landed-doc refresh #156, the
|
||||
inline-math slice #158, dired Stage 1 #165, the GPU terminal input fix
|
||||
#166, Lean 4 Stage 2 #161, the dired framing #164, COHERENCE.md #163,
|
||||
find-file #162, Lean 4 Stage 1 #160, minimap blank-slab #159,
|
||||
bottom-panel Stage 1 #155). Protocol unchanged at **v20**. The bullets
|
||||
below describe the arcs in their own terms; this line is the
|
||||
head-of-`main` anchor.
|
||||
- **`COHERENCE.md` is now required reading and a required framing input
|
||||
|
|
@ -43,6 +46,32 @@ commands, read `docs/active-work.md` immediately after this file.
|
|||
interaction islands added, config-registry adoption, background-work
|
||||
attribution. Its §2 grades the golden journey **broken at step 3**
|
||||
(`pmacs .` exits 1).
|
||||
- **Inline math LANDED — #158** (`docs/inline-math-slice-framing.md` rev 3;
|
||||
merge `5aa9044`). pmacs renders `$…$` as typeset mathematics in the GPU
|
||||
frontend. **No protocol change (still v20); the whole slice lives in
|
||||
`pmacs-gpu`**, because `pmacs-gpu` depends only on `pmacs-protocol` and
|
||||
never on `pmacs` — a core-crate parser would have been unreachable from
|
||||
where rendering happens.
|
||||
- `math_parse.rs` → `math_layout.rs` → a `ChunkSource::MathBox` spacer
|
||||
chunk → per-glyph mini-buffers drawn at the shaped line's real
|
||||
baseline, with fraction rules as quads. Font is bundled Latin Modern
|
||||
Math (~717 KiB) under the **GUST Font License** — not OFL.
|
||||
- **The v0 subset is narrow and deliberately so**: Greek (34 entries),
|
||||
sub/superscript, and `\frac`. Everything else — including relations
|
||||
like `\geq`, fences, big operators, and all display math (`$$…$$`,
|
||||
`\[…\]`) — is a named deferral, and an unsupported command degrades
|
||||
the **whole span** back to source rather than rendering partially.
|
||||
In a real paper most inline spans still show source; that is the
|
||||
designed behaviour, not a defect.
|
||||
- **Math is suppressed while the caret is inside its span**, so editing
|
||||
always sees source. That gate reads the effective caret plus
|
||||
selection endpoints and is fed by three separate refresh triggers;
|
||||
it is the most delicate part of the slice.
|
||||
- Selection and search washes cover the whole box rectangle, not
|
||||
sub-ranges (sub-range washes are deferred).
|
||||
- TUI shows the LaTeX source unchanged. That divergence is recorded
|
||||
against `COHERENCE.md` §16, which audits the "no privileged
|
||||
frontend" rule.
|
||||
- **find-file LANDED — #162** (`docs/dired-framing.md` §10, Q#DR11; merge
|
||||
`2af1ab3`; one review round). `C-x C-f` is the dired arc's **Stage 0**:
|
||||
pmacs previously had no discoverable way to open a file by path — no
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ candidates, ranked:
|
|||
|
||||
| Font | Table quality | License | Notes |
|
||||
|------|--------------|---------|-------|
|
||||
| **Latin Modern Math** | Full | OFL (GUST) | Reference, ships with TeX Live, most widely tested |
|
||||
| **Latin Modern Math** | Full | **GUST Font License** (not OFL) | Reference, ships with TeX Live, most widely tested; ~717 KiB. Bundled by #158 as `pmacs-gpu/fonts/latinmodern-math.otf` |
|
||||
| **STIX Two Math** | Full | OFL | Broader Unicode coverage |
|
||||
| **Cambria Math** | Full | Proprietary | Ships with Office; unavailable on Linux |
|
||||
| **Libertinus Math** | Full | OFL | Derivative of Latin Modern, wider |
|
||||
|
|
|
|||
|
|
@ -2790,6 +2790,88 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// Deterministic reduction of a `rope_matches_crdt_projection_
|
||||
/// after_arbitrary_edits` failure found by raising the case
|
||||
/// count (`PROPTEST_CASES=2000`) on `main` @ `e745068`.
|
||||
///
|
||||
/// **What happens.** Replacing a byte range with *identical*
|
||||
/// bytes is a textual no-op but a real CRDT operation (a delete
|
||||
/// plus an insert). Undoing it therefore advances the CRDT
|
||||
/// version while leaving the materialized text unchanged, so
|
||||
/// `undo_crdt_mode` derives an EMPTY replacement edit — and
|
||||
/// still attaches the `crdt_op` that `crdt.undo()` produced.
|
||||
/// That trips the proptest's `crdt_op` shape invariant, "a
|
||||
/// no-op edit must have `crdt_op = None`".
|
||||
///
|
||||
/// **What was verified about the consequences**, so the next
|
||||
/// reader does not have to redo it:
|
||||
///
|
||||
/// * content stays correct — rope and CRDT projection agree
|
||||
/// before and after (asserted below);
|
||||
/// * replicas stay converged — both `crdt_op` consumers
|
||||
/// (`EditorCore::queue_daemon_origin_crdt_op` and the remote-op
|
||||
/// path) read `edit.crdt_op` unconditionally and do **not**
|
||||
/// short-circuit on an empty range, so the op is broadcast;
|
||||
/// * the cursor does not jump — `EditorCore::undo` only clamps
|
||||
/// to buffer length and never seeks `edit.range.start`.
|
||||
///
|
||||
/// **The open question** is therefore whether the *invariant* is
|
||||
/// simply mis-scoped rather than the behavior being wrong. It
|
||||
/// was written for the FORWARD `apply_edit` short-circuit, which
|
||||
/// returns before ever producing an op; CRDT-mode undo/redo
|
||||
/// never reach that path. One artifact is genuinely arbitrary
|
||||
/// either way: `derive_replacement_edit` reports the empty range
|
||||
/// at the buffer END rather than at the edit site.
|
||||
///
|
||||
/// Ignored, not deleted: it documents a real, reproducible
|
||||
/// asymmetry that nothing else on `main` records, and un-ignoring
|
||||
/// it is the first step of whichever resolution wins.
|
||||
#[test]
|
||||
#[ignore = "known pre-existing main behavior; see the doc comment \
|
||||
for the verified consequences and the open question"]
|
||||
fn crdt_undo_of_an_identity_replace_reports_a_no_op_edit_carrying_an_op() {
|
||||
let mut buffer =
|
||||
Buffer::new_with_crdt(BufferId::next(), "*identity-undo*", 1).expect("crdt");
|
||||
buffer
|
||||
.apply_edit(EditOp::Insert {
|
||||
pos: 0,
|
||||
bytes: b"hello",
|
||||
})
|
||||
.expect("seed insert");
|
||||
|
||||
// Replace one byte with the SAME byte.
|
||||
let forward = buffer
|
||||
.apply_edit(EditOp::Replace {
|
||||
range: Range::new(1, 2),
|
||||
bytes: b"e",
|
||||
})
|
||||
.expect("identity replace");
|
||||
assert_eq!(forward.range, Range::new(1, 2));
|
||||
assert_eq!(forward.inserted_len, 1);
|
||||
|
||||
let undone = buffer.undo().expect("undo");
|
||||
assert!(
|
||||
undone.range.is_empty() && undone.inserted_len == 0,
|
||||
"the undo produced no textual change: {:?}/{}",
|
||||
undone.range,
|
||||
undone.inserted_len
|
||||
);
|
||||
assert!(
|
||||
undone.crdt_op.is_some(),
|
||||
"…yet it carries a version-advancing CRDT op — the invariant \
|
||||
the proptest trips on"
|
||||
);
|
||||
|
||||
// Content is unharmed in both projections.
|
||||
let mut bytes = vec![0u8; buffer.len() as usize];
|
||||
buffer.snapshot_rope().slice(0, buffer.len(), &mut bytes);
|
||||
assert_eq!(String::from_utf8(bytes).expect("utf8"), "hello");
|
||||
assert_eq!(
|
||||
buffer.crdt_state().expect("crdt").materialize_string(),
|
||||
"hello"
|
||||
);
|
||||
}
|
||||
|
||||
proptest! {
|
||||
// Smaller proptest case count than the default (64) to keep
|
||||
// CI overhead modest; the per-op invariant check is the
|
||||
|
|
|
|||
Loading…
Reference in New Issue