Part of the Vim-compatibility push. This is the first issue in a chain of 9 — it must land before the rest, because every later issue's acceptance criterion is expressed as "delete labels from this issue's known-deviation list".
Background
tests/nvim_conformance.rs is the only oracle-backed test in the repo: it runs the same keystrokes through nvim --headless and through Engine, then asserts buffer + cursor match. Neovim is the oracle, so no expectations are hand-authored. It has 31 cases.
Every other Vim test in tests/ (~1,297 tests) asserts against hand-written expectations — i.e. it encodes the author's belief about what Vim does. A shared misconception passes such a test forever. tests/operator_motions.rs:1047 test_dj_at_last_line_noop_or_delete_last is a live example: its comment states the wrong Vim behaviour, and its assertion (b.contains("aaa")) is too weak to catch either answer.
An analysis grew the harness to 1,432 cases. Result: 808 pass, 624 fail (43.6%). The failures are ordinary daily-use behaviour, not exotica.
The input artifact
The extended harness is committed on the pushed branch artifact-vim-oracle-harness (origin), commit 1159730 (tests/nvim_conformance.rs, 1,695 lines). Start from that file rather than rewriting it.
Harness fidelity fixes it contains — do not drop these
Each one was silencing real failures. Three were found only because probes produced impossible results:
| Change |
Why |
Cost if omitted |
vim.o.undolevels = -1 around the fixture write, restored to 1000 |
nvim_buf_set_lines is itself an undo step, so u undid the fixture and the buffer became "" |
41 spurious undo failures |
feedkeys(..., "ntx") not "nx" |
Without t, keys count as mapping-sourced: q records nothing (every @a was a silent no-op in nvim) and undo is not synced between commands |
every macro probe and most undo probes invalid |
capture nvim_win_get_height(0), mirror via engine.set_viewport_lines(rows) |
H/M/L/<C-d>/zt are meaningless with mismatched window heights |
screen-relative motions incomparable |
engine.ensure_cursor_visible() after placing the start cursor |
nvim_win_set_cursor scrolls the window; a raw engine cursor write does not |
12 spurious scroll failures |
pump macro_playback_queue after every key |
the UI normally pumps it; the harness must too |
@a never executes on the vimcode side |
per-case setup Lua field (cs(...) constructor) |
pins a Vim-vs-Neovim default (startofline, joinspaces, nrformats, smarttab) |
cannot distinguish "vimcode differs from Vim" from "Neovim differs from Vim" |
PROBE_FILTER=<label-substring> env var; BUF/CUR/BUF+CUR failure tags |
iteration speed and triage |
— |
What to do
-
Land the harness from 1159730, keeping Case backwards compatible via the c() / cs() const fn constructors.
-
Keep the per-area const arrays (CASES_OP, CASES_DOT, CASES_UNDO, CASES_REG, CASES_MAC, CASES_MARK, CASES_SEARCH, CASES_EX, CASES_INS, CASES_VIS, CASES_VB, CASES_NUM, CASES_SCROLL, CASES_WORD, CASES_TO, CASES_MISC) flattened by the runner — 1,432 cases in one literal is unworkable.
-
Add KNOWN_DEVIATIONS: &[&str], a list of currently-failing labels. The test must fail if:
- a label in the list starts passing (so a fix is forced to delete its entry), or
- a label not in the list fails (so regressions are caught).
This is what lets 1,432 cases land green today and shrink monotonically.
-
Print per-category pass/fail totals in the run output.
-
Document in CLAUDE.md's Testing section: a Vim-behaviour PR must add oracle cases; hand-written expectations are second-class.
Explicitly not in scope
Fixing any of the 624 deviations. This issue lands the instrument only. The subsequent 8 issues in the chain do the fixing.
Acceptance
Depends on
#795 (install nvim in CI). Without it this harness runs nowhere in CI and protects nothing — the two should land together.
Artifacts on origin/artifact-vim-oracle-harness
| Path |
What |
tests/nvim_conformance.rs @ 1159730 |
the 1,432-case harness — start here |
docs/VIM_ORACLE_ANALYSIS.md @ 33668a0 |
full analysis, incl. the 621-row deviation table whose labels every issue in this chain cites |
docs/vim-oracle-probe-run3.txt @ 33668a0 |
authoritative raw run (808 pass / 624 fail of 1,432) |
The two docs/ files are reference material, not necessarily a merge target — this issue decides what lands on develop. The branch is not a claim on this issue; it predates any implementation work.
Part of the Vim-compatibility push. This is the first issue in a chain of 9 — it must land before the rest, because every later issue's acceptance criterion is expressed as "delete labels from this issue's known-deviation list".
Background
tests/nvim_conformance.rsis the only oracle-backed test in the repo: it runs the same keystrokes throughnvim --headlessand throughEngine, then asserts buffer + cursor match. Neovim is the oracle, so no expectations are hand-authored. It has 31 cases.Every other Vim test in
tests/(~1,297 tests) asserts against hand-written expectations — i.e. it encodes the author's belief about what Vim does. A shared misconception passes such a test forever.tests/operator_motions.rs:1047 test_dj_at_last_line_noop_or_delete_lastis a live example: its comment states the wrong Vim behaviour, and its assertion (b.contains("aaa")) is too weak to catch either answer.An analysis grew the harness to 1,432 cases. Result: 808 pass, 624 fail (43.6%). The failures are ordinary daily-use behaviour, not exotica.
The input artifact
The extended harness is committed on the pushed branch
artifact-vim-oracle-harness(origin), commit1159730(tests/nvim_conformance.rs, 1,695 lines). Start from that file rather than rewriting it.Harness fidelity fixes it contains — do not drop these
Each one was silencing real failures. Three were found only because probes produced impossible results:
vim.o.undolevels = -1around the fixture write, restored to1000nvim_buf_set_linesis itself an undo step, souundid the fixture and the buffer became""feedkeys(..., "ntx")not"nx"t, keys count as mapping-sourced:qrecords nothing (every@awas a silent no-op in nvim) and undo is not synced between commandsnvim_win_get_height(0), mirror viaengine.set_viewport_lines(rows)H/M/L/<C-d>/ztare meaningless with mismatched window heightsengine.ensure_cursor_visible()after placing the start cursornvim_win_set_cursorscrolls the window; a raw engine cursor write does notmacro_playback_queueafter every key@anever executes on the vimcode sidesetupLua field (cs(...)constructor)startofline,joinspaces,nrformats,smarttab)PROBE_FILTER=<label-substring>env var;BUF/CUR/BUF+CURfailure tagsWhat to do
Land the harness from
1159730, keepingCasebackwards compatible via thec()/cs()const fnconstructors.Keep the per-area
constarrays (CASES_OP,CASES_DOT,CASES_UNDO,CASES_REG,CASES_MAC,CASES_MARK,CASES_SEARCH,CASES_EX,CASES_INS,CASES_VIS,CASES_VB,CASES_NUM,CASES_SCROLL,CASES_WORD,CASES_TO,CASES_MISC) flattened by the runner — 1,432 cases in one literal is unworkable.Add
KNOWN_DEVIATIONS: &[&str], a list of currently-failing labels. The test must fail if:This is what lets 1,432 cases land green today and shrink monotonically.
Print per-category pass/fail totals in the run output.
Document in
CLAUDE.md's Testing section: a Vim-behaviour PR must add oracle cases; hand-written expectations are second-class.Explicitly not in scope
Fixing any of the 624 deviations. This issue lands the instrument only. The subsequent 8 issues in the chain do the fixing.
Acceptance
cargo test --no-default-features --test nvim_conformanceruns all cases and prints per-category totals.CLAUDE.md, a test that cannot fail is not coverage (#448-F: GTK tab click (activate/close) dead when only ONE tab group exists #553).mac:qaxjq @a), undo (undo:xxx u) and scroll (scroll:H from 30) categories produce meaningful nvim-side results, proving the fidelity fixes survived.CLAUDE.mdTesting section updated.Depends on
#795 (install
nvimin CI). Without it this harness runs nowhere in CI and protects nothing — the two should land together.Artifacts on
origin/artifact-vim-oracle-harnesstests/nvim_conformance.rs@1159730docs/VIM_ORACLE_ANALYSIS.md@33668a0docs/vim-oracle-probe-run3.txt@33668a0The two
docs/files are reference material, not necessarily a merge target — this issue decides what lands ondevelop. The branch is not a claim on this issue; it predates any implementation work.