Skip to content

docs: verify every README claim against the code and correct the ones it contradicts - #533

Merged
ThomasK33 merged 19 commits into
mainfrom
docs/readme-verified-claims
Nov 12, 2026
Merged

ThomasK33 merged 19 commits into
mainfrom
docs/readme-verified-claims

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Why

The goal is that every claim in the README contracts of this repository is true for the code at main, and that each correction names its evidence. A contract is the README of one folder. It states what the code does and cites the function that does it. The branch docs-gtz7 corrected many claims at an old commit of main. main has moved since (peer PRs #445 to #522 rewrote several passages and changed the code). This PR merges main into that work, re-checks every line that it changes against the current code, and fixes the lines that the peers made stale or that the merge joined into false text.

What changed

Docs only, in seven README files. The branch has four parts.

  1. The commits of docs-gtz7 (three content commits and a merge of main): a refresh of the contracts against the code, a pass that fixed the drift that the refresh left, and a pass that corrected claims which runtime probes disproved.

  2. Five merge commits of main (the second for test: start the runner's spec Neovims with tests/minimal_init.lua #522, the third for fix(selection): keep the release of a visual selection after a plugin edits another line or writes the file #524 and fix(terminal): name the provider that setup keeps for an invalid provider value #530, the fourth for fix(skills): check the state dir once, not each run.env, and resolve TMPDIR once #506, the fifth for fix(scripts): read the Unreleased draft with commonmark.js and refuse what it does not read #531 and test(terminal): test the snacks guards that no test reached, and drop four dead window option assignments #526). Where a peer PR and docs-gtz7 both changed a passage, main's text won. A docs-gtz7 correction stayed only where it is still true.

  3. Nine correction commits. Six verifier agents, one per file or half file, checked every line that this diff changes against the code. They ran headless Neovim 0.12.3 probes (one on 0.10.4) where reading did not decide the claim. I applied their corrections in commits that group the files: server, root and plugin, tools, lua, terminal, scripts, the main-text fixes, and one for the exit sentences and the last seven findings. A second verifier then found one false sentence (the exit sentence below) and seven wording findings, which that last commit fixes.

  4. One commit for two P2 findings of the Codex code review on 42ef1bd1. First, stop and the token mismatch in start try to remove the lock file and only log a warning when that fails (lua/claudecode/init.lua:642-647, :605-608), so three sentences in README.md now say "tries to". Second, the headless auto-setup check in plugin/README.md used --cmd "set rtp^=$PWD", which Ex splits at a space in the checkout path. I ran it in /…/with space/repo on Neovim 0.12.3: it fails with E518 and prints 0. The lua vim.opt.rtp:prepend(vim.fn.getcwd()) form prints 2, and 0 without the auto-setup line, as the README says.

Per file, with the number of claims checked and the result:

File Claims checked True False Incomplete Unverified Edits
README.md (Repository Blueprint) 41 39 0 2 0 2
plugin/README.md 40 39 0 1 0 1
lua/claudecode/README.md 198 173 11 14 0 23
lua/claudecode/server/README.md 88 75 3 9 1 13
lua/claudecode/terminal/README.md 106 100 2 4 0 5
lua/claudecode/tools/README.md 68 54 4 10 0 14
scripts/README.md 7 0 2 4 0 13

A false claim was true at the old base or never true. An incomplete claim leaves out a condition that the code has. The row for scripts/README.md lists the seven items of the #462 verifiers (one more was misleading). The 541 claims of the first six rows split into 480 true, 20 false, 40 incomplete and 1 unverified.

Re-sync items after the peer PRs

Corrections per file

README.md
  • The list of what rejects a pending openDiff now includes Claude's close_tab and closeAllDiffTabs calls, which reject it through close_diff_by_tab_name (lua/claudecode/diff.lua:2040-2044, :2105-2107, lua/claudecode/tools/close_tab.lua:53, lua/claudecode/tools/close_all_diff_tabs.lua:30).
  • At exit, Neovim fires BufUnload for each loaded buffer before VimLeavePre, and the proposal buffer's BufUnload autocmd rejects its pending diff (lua/claudecode/diff.lua:1279-1285). So with one pending diff the rejection runs before the VimLeavePre cleanup. With two or more pending native diffs there is one exception: the reject of a new-file diff in the current tab with diff_opts.on_new_file_reject = "keep_empty" (the default) deletes its proposal buffer (diff.lua:1171-1175, :1523-1524), Neovim's exit loop then stops firing BufUnload, and the cleanup removes the other diffs with no answer. Probes on Neovim 0.8.0, 0.9.5, 0.10.4, 0.11.5 and 0.12.3 show both cases, and the unified layout answers every diff. The sentence states both. A fix PR (F13) follows, see "Defects in the code".
  • start removes the lock file on a token mismatch (see above).
  • The Processes bullet adds :checkhealth claudecode (<cli> --version, lua/claudecode/health.lua:43-66) and the git rev-parse of terminal.git_repo_cwd (lua/claudecode/cwd.lua:28-42).
  • CLAUDE_CONFIG_DIR set but empty uses ~/.claude/ide (lua/claudecode/lockfile.lua:11-18). Three lines say so now.
  • The Side Effects bullet lists the autocmd groups of lua/ and plugin/ (ClaudeCodeShutdown, ClaudeCodeSelection, ClaudeCodeMCPDiff, ClaudeCodeDiffCleanup, ClaudeCodeNativeAdopted, ClaudeCodeOpenFileNewFiles, and one snacks_win_<id> per Snacks terminal whose split the plugin re-creates, lua/claudecode/terminal/snacks.lua:259), the nvim_buf_attach listeners (lua/claudecode/selection.lua:175-191) and the "unified" highlight groups (lua/claudecode/diff_inline.lua:33-36).
plugin/README.md
  • Commands from auto-setup exist after a startup script that waits (:sleep or vim.wait()) lets the deferred setup run. They do not exist when the -c commands and VimEnter run. Headless probes on Neovim 0.12.3 (plugin/claudecode.lua:13-17).
  • The other 39 changed claims held: the load guard order, the second source doing nothing, the version error on Neovim older than 0.8, the failed module load shown once, the auto-setup global read twice, and the error from the deferred setup.
lua/claudecode/README.md: 23 corrections with evidence
  • Only :ClaudeCodeSend uses the local add_paths_to_claude. :ClaudeCodeTreeAdd and :ClaudeCodeAdd call M.send_at_mention in their own code. Evidence: lua/claudecode/init.lua:703, init.lua:830, init.lua:904, init.lua:914, init.lua:974-975, init.lua:1021-1022, init.lua:1126.
  • expand_tilde expands only ~ and ~/.... A path such as ~user/x stays as it is. Evidence: lua/claudecode/init.lua:1113-1117, lua/claudecode/utils.lua:167-181.
  • The fallback split runs create_split, whose leave_preview_window moves from the preview window to a tiled Claude terminal window in the same tab before it splits. Evidence: lua/claudecode/diff.lua:803-810, diff.lua:263-276, diff.lua:279-281.
  • Since fix(diff): leave no leftovers after :wq, a second :w, :qa or :edit #483 and fix(diff): reject a unified diff when the user closes it with :q #469, diff_inline.lua no longer calls _resolve_diff_as_saved (it calls _write_proposal) and it also calls _register_reject_when_hidden and _close_proposal_window. Evidence: lua/claudecode/diff_inline.lua:471, diff_inline.lua:485, diff_inline.lua:616, lua/claudecode/diff.lua:1228-1234, commits 6eef218 (fix(diff): leave no leftovers after :wq, a second :w, :qa or :edit #483) and 36f4a0e (fix(diff): reject a unified diff when the user closes it with :q #469).
  • lockfile.update no longer exists: PR fix(lockfile): report failed removals and clean up on token mismatch #459 (0e63cc7) removed it. Evidence: lua/claudecode/lockfile.lua:74, lockfile.lua:84, lockfile.lua:208, lockfile.lua:239, lockfile.lua:292 (the only M functions), commit 0e63cc7 (fix(lockfile): report failed removals and clean up on token mismatch #459).
  • terminal.setup also calls get_provider, whose fallback warnings go through logger.warn, as the bullet above says. Evidence: lua/claudecode/terminal.lua:584, terminal.lua:124-130, terminal.lua:145, terminal.lua:163-166, terminal.lua:178.
  • A connected send that the debounce queues still fires ClaudeCodeSendComplete. Only the disconnected branch fires none. Evidence: lua/claudecode/init.lua:383-398, lua/claudecode/init.lua:1395-1400, lua/claudecode/init.lua:401-416.
  • The terminal call and the event happen only when _broadcast_at_mention succeeds. Evidence: lua/claudecode/init.lua:383-400.
  • No handshake polling exists since fix(mention): deliver queued @mentions once, in order, or report an error #454/fix(mention): give each queued mention a deadline, keep a due flush on another client's handshake, and report refused writes #480. The 50 ms, 25 ms and connection_wait_delay facts repeat main's queue bullet. A send with debouncing off still queues behind a non-empty queue. Evidence: lua/claudecode/init.lua:283-289, lua/claudecode/init.lua:110-111, lua/claudecode/init.lua:1381-1396.
  • PR fix(selection): end a held selection when its text or the cursor changes #452 added TextChangedI and TextChangedP. Evidence: lua/claudecode/selection.lua:387.
  • Since fix(selection): end a held selection when its text or the cursor changes #452 reconcile_held_selection reports the cursor at CursorMoved, not after visual_demotion_delay_ms. A text change and another buffer also end the hold. Evidence: lua/claudecode/selection.lua:237-265, lua/claudecode/selection.lua:118-159, lua/claudecode/selection.lua:576-584, tests/selection_test.lua:2341.
  • find_main_editor_window skips only a fixed filetype list, not every explorer or outline sidebar. Evidence: lua/claudecode/diff.lua:157-190.
  • find_main_editor_window can return a window of another tab (current tab first), as the bullet above says. Evidence: lua/claudecode/diff.lua:125-142, lua/claudecode/diff_inline.lua:382-409.
  • Probe: proposal "a\n\n" is accepted as "a\n" (split_lines drops one trailing empty line, and the newline fix adds none back). Evidence: lua/claudecode/diff_inline.lua:44-52, lua/claudecode/diff_inline.lua:526-540, lua/claudecode/diff_inline.lua:303, probe_unified_accept.out.
  • An invalid diff percentage falls back to split_width_percentage, not straight to 0.30. Evidence: lua/claudecode/diff.lua:50-69.
  • PR fix(diff): reject a unified diff when the user closes it with :q #469 set the unified proposal buffer to bufhidden=hide (main's bullet above says so), WinClosed/BufHidden reject it. Evidence: lua/claudecode/diff_inline.lua:299, lua/claudecode/diff_inline.lua:475-485, lua/claudecode/diff.lua:1189-1222.
  • The close_tab tool also passes a client_id. Evidence: lua/claudecode/tools/close_tab.lua:53, lua/claudecode/diff.lua:2105-2148.
  • At qa! the BufUnload autocmd (diff.lua:1283) calls _resolve_diff_as_rejected before the VimLeavePre cleanup runs, for one pending diff. With two or more native diffs, a keep_empty reject of a new-file diff deletes its buffer and stops the exit loop, so the later diffs stay pending until the cleanup (the Augroups bullet states this). Evidence: lua/claudecode/diff.lua:1171-1175, lua/claudecode/diff.lua:1279-1285, lua/claudecode/diff.lua:1523-1524, probes on 0.8.0 to 0.12.3.
  • PR fix(diff): drop the new-tab terminal's BufEnter handler when its window closes #478 added the WinClosed autocmd that deletes the handler. Evidence: lua/claudecode/diff.lua:455-463, tests/unit/diff_new_tab_terminal_handler_spec.lua:127.
  • require('claudecode').setup validates log_level (assert) before logger.setup runs. Evidence: lua/claudecode/init.lua:462-465, lua/claudecode/config.lua:15, lua/claudecode/config.lua:98-106, lua/claudecode/logger.lua:26-40.
  • Neovim 0.10 has no 'messagesopt' and always stops. The parenthetical read as if only 0.11+ stops. Evidence: probe_echospace.out (0.10.4: NO SUCH OPTION, 0.11.5: hit-enter,history:500).
  • With laststatus=1 and two windows v:echospace is 68, not 51. Evidence: probe_echospace.out.
  • PR fix(scripts): fail the integration runner when a spec hangs and run command_args_spec again #445 removed the skip. The loop runs every file. Evidence: scripts/run_integration_tests_individually.sh:86-88.
lua/claudecode/server/README.md: 13 corrections with evidence
  • The pending check/idle pair of a tick runs judge_silence and judge_stall, not only a stall confirmation Evidence: lua/claudecode/server/tcp.lua:601-611, tcp.lua:424-435, tcp.lua:490.
  • The state stays closing after on_close. On_close only removes the client (README line on client states says it never becomes closed) Evidence: lua/claudecode/server/client.lua:363-371, tcp.lua:227-228, tcp.lua:275-283.
  • start_close_timer also sets closed when a keepalive window passes with no write progress Evidence: lua/claudecode/server/client.lua:459-466, client.lua:140-144.
  • Completes the state list: _disconnect_client does not touch client.state (probe: on_disconnect saw state connected after EOF) Evidence: lua/claudecode/server/tcp.lua:209-217, tcp.lua:255-294, probe-server/events.log client_8, client_9.
  • PR fix(mention): give each queued mention a deadline, keep a due flush on another client's handshake, and report refused writes #480 added connected_at to get_client_info Evidence: lua/claudecode/server/client.lua:522-531, client.lua:292.
  • PR fix(mention): deliver queued @mentions once, in order, or report an error #454 moved process_mention_queue from on_connect to on_open Evidence: lua/claudecode/server/init.lua:57-73, client.lua:294-296.
  • After the merged sentences, It reads as process_data or the Close frame. Process_data does check the whole message Evidence: lua/claudecode/server/frame.lua:156-168, client.lua:184-188.
  • parse_frame rejects a 1-byte Close payload with 1002 (same bullet group says so), so only an empty payload reaches the 1000 default Evidence: lua/claudecode/server/frame.lua:157-160, client.lua:352-361, probe S5, S6.
  • Since PR fix(server): drop dead clients promptly and never time out a live Claude #455/fix(server): judge a silent Claude only after reading its socket #488 last_pong plays no part in the keepalive Evidence: lua/claudecode/server/client.lua:381-383, client.lua:529, tcp.lua:220-222, tcp.lua:474-475.
  • PR fix(tools): answer malformed tools/call and close_tab with -32602 #497/fix(tools): check a tools/call once and answer a malformed one with -32602 #500: tools/call answers -32602 for a non-string name before handle_invoke. Contradicts the JSON-RPC errors bullet Evidence: lua/claudecode/server/init.lua:353-368.
  • Two callbacks share the name: process_data's on_error carries client errors (other bullets say so), server.on_error only server failures Evidence: lua/claudecode/server/tcp.lua:121,190,196,524, tcp.lua:229-231, client.lua:202,275.
  • The 101/error write callback calls on_error when err or not success Evidence: lua/claudecode/server/client.lua:271-279, probe events client_1..3.
  • The message carries the tool name Evidence: lua/claudecode/tools/init.lua:90-96.
lua/claudecode/terminal/README.md: 5 corrections with evidence
  • FALSE since fix(terminal): find the running Claude after a plugin reload #464: native close and the first get_active_bufnr of a module copy adopt a marked live terminal. The sentence also contradicts the same bullet's second sentence. Evidence: lua/claudecode/terminal/native.lua:292, lua/claudecode/terminal/native.lua:574-577, probe probe-terminal/probe_native_reload.out.
  • INCOMPLETE: on Neovim 0.12.3 termopen also returns 0 under :silent! for a modified buffer, which is not an invalid argument. Evidence: probe probe-terminal/probe_termopen.out (cases D, E, F, G, H, I), lua/claudecode/terminal/native.lua:237-242.
  • INCOMPLETE: through the dispatcher a missing Snacks never reaches the ERROR notification, because get_provider falls back to native. Evidence: lua/claudecode/terminal.lua:133-146, lua/claudecode/terminal.lua:192-196, lua/claudecode/terminal/snacks.lua:691-693.
  • INCOMPLETE: an unset snacks_win_opts.position falls back to split_side (left or right), so cc_show re-creates a split itself. Evidence: lua/claudecode/terminal/snacks.lua:374-377.
  • INCOMPLETE: for an adopted terminal each entry with a config replaces term._cc.config, so it is not the config captured at open. Evidence: lua/claudecode/terminal/snacks.lua:463-474, lua/claudecode/terminal/snacks.lua:646-647, lua/claudecode/terminal/snacks.lua:747.
lua/claudecode/tools/README.md: 14 corrections with evidence
  • FALSE after PR fix(tools): check a tools/call once and answer a malformed one with -32602 #500: handle_invoke uses params.arguments or {}, so no Lua error and no -32000 (probe p1: openFile/saveDocument -32602, getDiagnostics []). Also contradicted line 17. Evidence: lua/claudecode/tools/init.lua:88, lua/claudecode/server/init.lua:357, probes/p1_static.out.
  • FALSE: the script loops over every tests/integration/*_spec.lua with no skip. PR fix(scripts): fail the integration runner when a spec hangs and run command_args_spec again #445 (a4d3238) made it run command_args_spec again. Evidence: scripts/run_integration_tests_individually.sh:86.
  • Misleading: bufnr() finds 'file.txt', 'b/file', './dir/../dir/file.txt' and '' (current buffer). Probes p1 and p5. Evidence: lua/claudecode/tools/save_document.lua:31, lua/claudecode/tools/check_document_dirty.lua:27, probes/p1_static.out, probes/p5_bufnr.out.
  • INCOMPLETE after PR fix(selection): answer getCurrentSelection from the editor when no selection is tracked #457: with no stored selection it reads the editor (the bullet above says so), so it does not always return the stored selection. Evidence: lua/claudecode/tools/get_current_selection.lua:37-39, :83-95.
  • INCOMPLETE: the -32603 table is returned, not raised, so build_response sends it as { result = ... }. Also joins the hard-wrapped bullet like the rest of the file. Evidence: lua/claudecode/tools/close_tab.lua:26-33, lua/claudecode/tools/init.lua:180-182, lua/claudecode/server/init.lua:387.
  • Format: the merge wrapped a quoted error message across two lines inside a code span, so a search for the message misses it. Every other bullet is one line. Evidence: lua/claudecode/tools/open_diff.lua:56.
  • Coherence: the inserted sentence split 'finds it' from 'Without one', so 'one' no longer names the loaded buffer. The moved claim is TRUE (probe p1). Evidence: lua/claudecode/tools/open_file.lua:133-140, probes/p1_static.out.
  • INCOMPLETE: expand_tilde leaves ~user/... unchanged. Evidence: lua/claudecode/utils.lua:167-181, lua/claudecode/tools/open_file.lua:547.
  • INCOMPLETE: with makeFrontmost=false the answer is the JSON object, and in the middle of a command openFile appends a suffix. Evidence: lua/claudecode/tools/open_file.lua:735, :741, :746-760, probes/p4_openfile_save.out.
  • INCOMPLETE: source and code are nil (absent from the JSON) when the diagnostic has none. Evidence: lua/claudecode/tools/get_diagnostics.lua:82-83.
  • INCOMPLETE: nvim_get_current_tabpage() returns a handle. Probe p1: tabpagenr() 2, handle 3, groupIndex/viewColumn 2/3. Evidence: lua/claudecode/tools/get_open_editors.lua:19, :65-66, probes/p1_static.out.
  • INCOMPLETE: reload_file_buffers skips a modified buffer, and a diff kept for another client does not close. Evidence: lua/claudecode/diff.lua:2015-2018, :2025-2027, :1104.
  • INCOMPLETE: no API tells which loaded buffers were opened before their file existed. The loop marks every loaded, named, normal buffer whose file is not readable. Evidence: lua/claudecode/tools/open_file.lua:170-179.
  • INCOMPLETE (minor): with diff_opts.layout = "unified" diff.lua hands the result to diff_inline, which builds it. Evidence: lua/claudecode/diff.lua:1050-1053, lua/claudecode/diff_inline.lua:526-537.
scripts/README.md: 7 items of the #462 verifiers, each checked against the scripts
  • The CI paragraph named no job for "the same job". It now names the three jobs of .github/workflows/test.yml (unit-tests, integration-tests, covered-lock), says that integration-tests runs the runner twice (the second time with a TMPDIR that holds a space and a %), and says that Required needs only unit-tests and integration-tests (test.yml lines 52-80, 98-167, 215-234).
  • tla/check-lib.sh exit precedence: 2 wins over 1, and 1 wins over 3. A stale lock plus a broken rule exits 1. --hash-only exits 0 or 3, and --record exits 0. A script that sources the lib and ends without tla_main turns an exit 0 into exit 2. Probed with a fake curl and a fake TLC: default with a broken rule and a stale lock gave rc=1, default with a pass and a stale lock rc=3, a broken TypeOK rc=2, --record on a stale lock rc=0 (scripts/tla/check-lib.sh:81-84, :226-246, :313-333, :406-419).
  • tla_init comes right after SKILL and MODEL, before covered_block (.agents/skills/verify-diff-lifecycle/check.sh:15-29, scripts/tla/check-lib.sh:461).
  • run-release-please.sh prints nothing itself, and exits 1 with no message when release-please is missing. The runner's stdout and file outputs are listed: release-please's own log lines go to stdout (info and debug) and stderr (warnings and errors), the key=value lines go to GITHUB_OUTPUT or to stdout when it is unset, and --dry-run prints JSON after the log lines and still runs Communique. Probed without a token and without network: wrapper rc=1 with no output, and Error: GITHUB_TOKEN must be set (scripts/release-please-runner.js:487-492, :555, :590, :614).
  • --record and --hash-only exit before the TLC jar is fetched, so they never download it and need no java. A plain run and --mutants do. Probe with an empty cache and a fake curl: --hash-only and --record made 0 curl calls, a plain run and --mutants made 1 and exited 2 (scripts/tla/check-lib.sh:452-453, :147-151).
  • The Lua repros: under nvim -l an uncaught error prints E5113 and exits 1, cquit N and os.exit(N) exit N, and a bare file name run from scripts/ fails with module 'claudecode.diff' not found. In the :luafile form of CI an uncaught error falls through to cquit 2 (probes on Neovim 0.12.3, and -l exit 1 on 0.9.5, 0.10.4 and 0.11.5).
  • repro_issue_70.sh and repro_issue_277.sh side effects that the file did not list: work dir names, the att-home folder, the empty /tmp/agent-tty/<8 hex> socket folder and the homes.json entry that agent-tty leaves, the inherited environment, the three background probes of 70 and their PORT.lock files (a SIGKILL leaves the lock), the unpinned diffview.nvim clone of 277, the state and cache files of NVIM_APPNAME=issue-277, the perl timeouts, and the nested copy under an existing issue277-artifacts-latest. A full run of 277 with private dirs took 32 s. A SIGKILL run left the lock file and 3 processes until agent-tty destroy.
  • manual_test_helper.lua calls the handler itself, so no response sender is stored for its coroutine. Any resolution after the handler yields (accept, reject, or qa!) logs No global response sender found for coroutine. It is expected and harmless (all four CI-form runs exited 0).

Scope

  • No code changes. covered.lock does not change.
  • Lines of scripts/README.md about repro_issue_218.sh stay as they are on main. PR fix(scripts): stop repro_issue_218.sh from rewriting a tracked file and leaking its temp dir #458 owns them, and its merge will change them.
  • I checked every line that this diff changes. Lines that the diff does not touch were not re-verified, except where a verifier found one false while reading its neighbors. Those fixes are in the last correction commit: server/mock.lua is required by tests/unit/server/mock_spec.lua, the augroup and utils.lua lists, the empty CLAUDE_CONFIG_DIR, and the Processes bullet.
  • Probes ran on Linux with Neovim 0.12.3. One probe ran on 0.10.4. The old Neovim claims that earlier lanes proved on 0.8 were not run again.
  • One claim stays unverified: the sentence in lua/claudecode/server/README.md that a client whose EOF the server read in the same read as its request is handled as the code says. Six probe tries did not produce that case. The sentence is a softening, so I kept it.
  • The terminal README says that the wait before a close does not prevent a hang at exit. A probe saw the hang with and without a close, so the probe does not prove that the buffer delete causes it. I did not open Terminal buffer deletion hangs with a pending write neovim/neovim#42508 (the host has no network).

Defects in the code that the verifiers found

These need a code fix and a test, so they are not in this docs PR.

  1. Accepting a unified diff drops one trailing empty line of the proposal: "a\n\n" is accepted as "a\n" (lua/claudecode/diff_inline.lua:44-52 and :531). The native layout is not affected. A probe shows it. The README says the accepted text is the proposal lines that setup computed.
  2. lua/claudecode/server/tcp.lua:19 says the PRNG is seeded once per process. It is seeded once per load of the module.
  3. lua/claudecode/server/init.lua:59-60 logs "Authenticated WebSocket client connected" from on_connect, before the authentication check runs.
  4. lua/claudecode/cwd.lua:36-42 runs the same git rev-parse twice.
  5. At exit, a pending native diff can stay unanswered. Two native diffs are pending, and the first one (the lower proposal buffer number) is a new file in the current tab with diff_opts.on_new_file_reject = "keep_empty" (the default). On :qa! its reject deletes its proposal buffer (lua/claudecode/diff.lua:1171-1175, :1523-1524), Neovim's exit loop stops firing BufUnload (src/nvim/main.c, the bufref_valid check), and the VimLeavePre cleanup removes the second diff with no answer. Reproduced on Neovim 0.8.0, 0.9.5, 0.10.4, 0.11.5 and 0.12.3, with and without the server. A separate PR (F13) will make exit answer every pending diff. It will change the exit sentences of this PR: the openDiff bullet in README.md (Global Invariants, the sentence that starts "When Neovim exits") and the Augroups bullet in lua/claudecode/README.md (the sentences about BufUnload and the exception).

Blast Radius

Seven README files. Nothing loads them at runtime. A wrong correction here misleads a reader but breaks no behavior.

Verification

  • Six Opus verifiers, one per file (two for the 198 claims of lua/claudecode/README.md). Each checked every claim that the diff adds or changes against the code, and every [file:symbol] citation, with file and line evidence. Their findings, edits and probe scripts are in the evidence folder of the run.
  • A second, independent verifier checked the head bcacd14c (134 sentences and all seven scripts items, with probes on Neovim 0.8.0 to 0.12.3). It found one false sentence (the exit sentence, now fixed with its exception) and seven wording findings (fixed). It found no other false claim.
  • Citation check on the final head: 760 citations, links and test paths over the seven files, 1 flagged. The flagged one is [plugin/claudecode.lua:pcall(require, "claudecode")], an expression that main already cites in that README.
  • mise run all: exit 0 on the final head e3e48af1 (1682 successes, 0 failures, 0 errors, 24 pending, luacheck 0 warnings and 0 errors in 178 files). mise run format-check: exit 0 on the final head (355 files, 0 changed). 1676 successes, 0 failures, 0 errors, 24 pending. luacheck reports 0 warnings and 0 errors in 178 files. The format step changes 0 files.
  • git merge-tree --write-tree of the head and origin/main (3a0bb769) is clean.
  • The merges of fix(selection): keep the release of a visual selection after a plugin edits another line or writes the file #524 and fix(terminal): name the provider that setup keeps for an invalid provider value #530 changed one sentence of lua/claudecode/README.md and merged two conflict hunks. I checked that sentence and the merged bullets against lua/claudecode/terminal.lua and lua/claudecode/selection.lua at a41254a4. I did not run a verifier agent over the merge delta.

Generated with xum • Model: anthropic:claude-sonnet-5-5 • Thinking: xhigh

Re-ran egm-bootstrap over lua/, plugin/ and scripts/, then an EGM drift
pass, and fixed every claim the code contradicted or left uncovered.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
Ran each claim that the drift pass could not check from source in real
Neovim 0.8 to 0.12, against the live server, Snacks at the pinned commit,
and the scripts, then corrected the claims the runs did not support.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
The WebSocket shell clients are being removed in their own PR, which carries the refreshed scripts README.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
Resolve the server and terminal README conflicts with #451 and #455, and
update the at-mention, queued-mention and saveDocument lines for #460 and
#453.
Take main's newer text where a peer PR rewrote a passage (#445 to #504).
Keep a docs-gtz7 correction where both sides left it compatible. Drop the
docs-gtz7 lockfile.update bullet and the "leaves that lock file on disk"
claim, because #459 changed them. The corrections are verified against the
code in the commits that follow.
Checked each line that the branch changes against lua/claudecode/server/*.lua
at origin/main. on_connect only logs since #454, a tools/call without a name
answers -32602 since #497, get_client_info has connected_at since #480, and
last_pong no longer feeds the keepalive since #455.
Add what rejects a pending openDiff (Claude's close tools too) and say that
nothing answers it when Neovim exits. Say that the commands of auto-setup
exist after a startup script that waits lets the deferred setup run.
Checked each line that the branch changes against lua/claudecode/tools/*.lua
at origin/main. A call without arguments runs the tool with {} since #500, the
integration runner no longer skips command_args_spec.lua since #445, and the
getCurrentSelection bullet needs the #457 condition. The openFile recovery
read does not end Visual mode, which a probe confirmed.
At exit Neovim fires BufUnload for each loaded buffer before VimLeavePre.
The BufUnload autocmd of the proposal buffer rejects its pending diff
(diff.lua:1279), so the VimLeavePre cleanup finds none. A probe that fired
VimLeavePre alone had hidden this.
Checked each line that the branch changes against lua/claudecode/*.lua at
origin/main. Drop lockfile.update (removed by #459), the old mention-queue
polling (removed by #454), the unified bufhidden=wipe claim (#469), the
BufEnter pile-up claim (#478) and the integration runner skip (#445). Add
TextChangedI and TextChangedP (#452).
Native close and get_active_bufnr adopt a reloaded terminal since #464, so
drop the sentence that said they never adopt. Add the conditions that probes
found for termopen under :silent!, the Snacks window position fallback and
the config of an adopted terminal.
…erifier notes

Name the CI job of each command and the jobs that Required needs. State the
exit-code precedence of check-lib.sh and which modes download the TLC jar
(only a plain run and --mutants). Say how a Lua repro exits under nvim -l and
which scripts need the repo on runtimepath. List the release runner's stdout
and file outputs. List the side effects of the 70 and 277 repros that the
file did not name, and why the helper logs No global response sender.
…lete

mock.lua is required by tests/unit/server/mock_spec.lua. The augroup and utils
lists miss ClaudeCodeNativeAdopted, ClaudeCodeOpenFileNewFiles and
map_terminal_suspend. An empty CLAUDE_CONFIG_DIR uses ~/.claude/ide. The
Processes bullet misses the checkhealth --version call and the git rev-parse
call. The selection bullet moves below the mention bullets.
#522 changed the integration runner, its README bullets and two comments in
test.yml. The merge is clean. The README lines of this branch that name the
runner are re-checked in the next commit.
…d fix seven wording findings

A new-file diff in the current tab with on_new_file_reject = "keep_empty"
deletes its proposal buffer when it is rejected. In Neovim's exit loop that
stops BufUnload for the later buffers, so a second native diff reaches the
VimLeavePre cleanup unanswered (Neovim 0.8.0 to 0.12.3, diff.lua:1171-1175).
One pending diff and the unified layout are not affected.

Also: set -e exits with the status of the failed command, the patched snacks
toggle hides a visible terminal and focuses nothing, error_data counts when
truthy, getCurrentSelection can adopt a Claude terminal after a plugin reload,
the snacks_win_<id> augroup joins the lists, _accumulate joins the seam only
when acc is not empty, and the when_windows_allowed citation names its file.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-12T02:21:15.347063Z e3e48af Manual request
🔒 Security Review ✅ Completed 2026-11-12T02:20:55.580201Z e3e48af Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 1a4cb31bc9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 1a4cb31bc9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Resolve the README conflicts with #524 and #530. Main's listener and flush
wording for visual selections stays. The root Editor state bullet keeps the
verified augroup list and takes main's listener wording. The terminal.setup
sentence in lua/claudecode/README.md now names the provider that the warning
keeps (#530), which replaces the claim that the warning is wrong.
Pick up #506, which changes only .agents/skills/verify-claudecode-nvim. No README line of this branch cites a file that it changed.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 8f7d0c912f

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 8f7d0c912f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Resolve the scripts/README.md conflict with #531. The run-release-please.sh
bullet keeps the verified text and adds main's clause that commonmark must be
on the module path too (release-please-runner.js requires it at load). #526
changes only comments and dead window option assignments in terminal/snacks.lua,
and no README line of this branch depends on them.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 42ef1bd122

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42ef1bd122

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread README.md Resolved
Comment thread plugin/README.md Resolved
…in a path with a space

Codex P2 findings on 42ef1bd:
- stop tries to remove the lock file and only logs a warning when it cannot
  (init.lua M.stop). A token mismatch in start does the same.
- The headless auto-setup check used --cmd "set rtp^=$PWD", which Ex splits at a
  space in the checkout path (E518). The lua form takes the path as a string.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: e3e48af115

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: e3e48af115

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 12, 2026
Merged via the queue into main with commit 45bc293 Nov 12, 2026
9 checks passed
@ThomasK33
ThomasK33 deleted the docs/readme-verified-claims branch November 12, 2026 02:55
hareki pushed a commit to hareki/claudecode.nvim that referenced this pull request Nov 13, 2026
)

## Why

The advisor on coder#533 found that three sentences in `scripts/README.md`
say the plugin removes the lock file with no condition. The removal can
fail. `lockfile.remove` returns an error when `os.remove` fails (for
example in a read-only lock directory) and when `vim.fn.filereadable`
reports the file as missing (the file is gone, or it exists but is
unreadable; follow-up F19 fixes the unreadable case)
(`lua/claudecode/lockfile.lua:208-232`). `stop` and the token mismatch
path of `start` only log a warning then, so a lock file that the removal
failed to delete stays (`lua/claudecode/init.lua:642-647`, `:605-608`).
`README.md` and `lua/claudecode/README.md` already carry the condition.

`ARCHITECTURE.md` has the same wording: a comment says `M.stop()` will
"remove lock file", and the Lock File System section shows an
unconditional `fs_unlink` in a `VimLeavePre` callback.

The lock directory sentence for `repro_issue_277.sh` said "else
`~/.claude/ide`". The default applies when `CLAUDE_CONFIG_DIR` is unset
or empty (`lua/claudecode/lockfile.lua:11-18`), and `README.md` already
says so.

## What changed

Three bullets in `scripts/README.md`, one sentence each, and two lines
in `ARCHITECTURE.md`:

- `repro_issue_70_probe.lua` (older text on `main`). Other Claude CLIs
see the lock file until `claudecode.stop()` removes it. New: when the
removal fails, `stop` only logs a warning, so a lock file that the
removal failed to delete stays.
- `repro_issue_70.sh`. A probe stopped by SIGTERM "still tries to
remove" its `PORT.lock`. When that fails, `stop` only logs a warning, so
a lock file that the removal failed to delete stays. A SIGKILL leaves
the file behind, as before.
- `repro_issue_277.sh`. The plugin "removes the lock, or only logs a
warning when it cannot". The lock directory is `$CLAUDE_CONFIG_DIR/ide`,
or `~/.claude/ide` when that variable is unset or empty.

I added the citation `[lua/claudecode/init.lua:M.stop]` to the first
bullet.

- `ARCHITECTURE.md`, Resource Cleanup. The comment now reads `-- Stop
server, try to remove lock file (only logs a warning when it cannot)`.
The file has no `[file:symbol]` citations, so I added none.
- `ARCHITECTURE.md`, Lock File System. One sentence after the code
block: the real cleanup runs from `init.lua`, whose `VimLeavePre`
autocmd calls `stop` when the server runs, `stop` calls
`lockfile.remove`, and `stop` only logs a warning when the removal
fails, so a lock file that the removal failed to delete stays.

## Scope

I grepped every tracked Markdown file for lock-file removal wording
(remove, delete, unlink, clean up, stale, leaves). The other READMEs
already carry the condition: `README.md:1126` and `:1154-1155`, and
`lua/claudecode/README.md:109-111` and `:196`.

The `ARCHITECTURE.md` sketch (line 55) reads as how the plugin works
today and not as an illustration. It sits under the heading
`lockfile.lua` and no text calls it an example. It is also wrong:
`lockfile.lua` has no `VimLeavePre` autocmd and removes the file with
`os.remove` in `lockfile.remove` (`lua/claudecode/lockfile.lua:221`),
and the exit cleanup is in `init.lua`
(`lua/claudecode/init.lua:514-518`). So I left the code block as it is
and added the one sentence. I did not fix the other lines of the sketch
(`write_file` and `fs_rename` are not in `lockfile.lua` either). That is
a wider rewrite of the section.

Not changed:

- `.agents/skills/verify-claudecode-nvim/features/server.md:9` and `:12`
describe the checked working case ("deletes `<port>.lock`"). They are
test expectations.
- `scripts/repro_issue_70_probe.lua:84` has the code comment `-- removes
the lock file`. It is code and not a README.

## Blast Radius

Two documentation files: three lines of `scripts/README.md`, and two
lines of `ARCHITECTURE.md` (one changed, one added). Nothing loads them.
A wrong sentence here misleads a reader and breaks no behavior.

## Verification

I probed `scripts/repro_issue_70_probe.lua` on Neovim 0.12.3 in an
isolated home (`env -i`, private `HOME`, `XDG_*` and
`CLAUDE_CONFIG_DIR`, the stub `claude` first on `PATH`, provider
`none`). Each case signalled only the `nvim` that it started.

| Case | Result |
|---|---|
| Stop file | exit 2, 0 lock files left (`stop` removed it) |
| SIGTERM | exit 1, 0 lock files left, `Claude Code integration stopped`
logged |
| Read-only lock directory, then stop file | exit 2, 1 lock file left
(the removal failed, the file stays) |
| SIGKILL | 1 lock file left |

In the read-only case the probe prints no warning. `logger.warn` runs
through `vim.schedule` (`lua/claudecode/logger.lua:109-120`), and the
probe calls `os.exit` right after `stop()`. So the README says what
`stop` does (it logs a warning) and does not say that the probe shows
it.

- Citation check over the seven READMEs: 762 citations, 1 flagged. The
flagged one is `[plugin/claudecode.lua:pcall(require, "claudecode")]`,
an expression that `main` already cites.
- `mise run format-check`: exit 0 (355 files, 0 changed).
- `mise run all`: exit 0 (1682 successes, 0 failures, 0 errors, 24
pending, `luacheck` 0 warnings and 0 errors in 178 files).
- The Codex code review of round 2 raised one P3: `lockfile.remove` also
fails when the file is already gone (or unreadable; see F19)
(`lua/claudecode/lockfile.lua:215-216`), so a failed removal does not
always leave a file. The three sentences that said "the file stays" now
say that a lock file that the removal failed to delete stays.
- The commits after the first are docs only. No test, script or CI file
reads `ARCHITECTURE.md` (grep over `tests`, `scripts` and `.github`).
For them I ran `mise run format-check` (exit 0, 355 files, 0 changed)
and the citation check (762 citations, same 1 flagged). I did not run
`mise run all` again. CI runs the full test suite on the final head.
- `git merge-tree --write-tree` of the head and `origin/main` is clean.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model:
`anthropic:claude-sonnet-5-5` • Thinking: `xhigh`_
hareki pushed a commit to hareki/claudecode.nvim that referenced this pull request Nov 13, 2026
… per lookup (coder#539)

## Why

The plugin's code text and debug log must say what the code does. Three
small places did not. A client with a wrong token was logged as
authenticated. One git lookup started two git processes. A comment gave
the wrong scope for the PRNG seed.

## What changed

1. **Authenticated log (`lua/claudecode/server/init.lua`).**
`on_connect` runs at the TCP accept, before the handshake and the token
check. With an auth token it logged `Authenticated WebSocket client
connected` there, so a client with a wrong token got that line before
the server rejected it. `on_connect` now logs `WebSocket client
connected, awaiting authentication`. `on_open` runs after the handshake
passed the check and now logs `Authenticated WebSocket client
connected`. The line without a token (`WebSocket client connected (no
auth)`) is the same.
2. **One git process per lookup (`lua/claudecode/cwd.lua`).** `git_root`
called `vim.fn.systemlist` inside a `pcall` only to see whether it takes
a list, then called it again for the result. It now keeps the result of
the first call. The shell-string fallback for a `systemlist` that
refuses a list is the same.
3. **PRNG comment (`lua/claudecode/server/tcp.lua`).** The comment said
the PRNG is seeded once per process. `rng_seeded` is a module local, so
it is seeded once per load of the module. I fixed the comment and left
the seeding alone. A second seed in one process is harmless, because it
mixes in the time and a sub-second source. Neovim loads the module once,
so a fresh Neovim still seeds once, which is all that coder#283 needs. A real
once-per-process guard would need global state that nothing else uses.

READMEs: `lua/claudecode/server/README.md` describes `on_open`,
`on_connect` and the seeding scope. `lua/claudecode/README.md` says git
runs at most once for each lookup (a missing folder or a nil start
folder runs no git). The seeding line has the same text as the line on
the `docs-gtz7` branch, so the two merge without a conflict.

## Scope

No behavior changes except the two log lines and the number of git
processes. The handshake, the token check and the shell fallback in
`git_root` are untouched. I added no test for the comment, because it
has no behavior to test. A real Neovim probe confirms its new claim (see
Verification).

## Blast Radius

- Debug log only: with an auth token, the line `Authenticated WebSocket
client connected: <id>` moves from the TCP accept to after the
handshake. Nobody parses it in this repo (I grepped code, tests,
scripts, fixtures and docs).
- `git_root`: one process fewer for each lookup. The result and the
`shell_error` it checks come from the call that remains.
- `covered.lock`: the diff touches three covered files (`cwd.lua`,
`server/init.lua`, `server/tcp.lua`) and none of their covered blocks.
`check.sh` printed STALE for the three file hashes only. It printed no
changed block and no changed call site. The change cannot reach diff
state, an openDiff answer, a disconnect or a diff command.
`on_disconnect`, `M.stop` and the request handlers are unchanged.
`on_connect` and `on_open` only gain or move a `logger.debug` call.
`tcp.lua` changes a comment. `cwd.lua` is the terminal's git root
lookup. The model passed (`main`: 89205 distinct states,
`live-DisconnectedCallsAnswered`: 5269). `check.sh --record` wrote the
new lock and `check.sh --hash-only` reports that it matches.

## Verification

Red before the fix, green after (same specs, only the three `lua/` files
swapped):

| Spec | origin/main | with the fix |
| --- | --- | --- |
| `tests/unit/server/connect_log_spec.lua` (4 new cases: log order and
no `Authenticated` for a TCP-only client or a wrong token) | 1 success,
3 failures | 4 successes |
| `tests/unit/cwd_spec.lua` (5 new cases: git invocations per lookup) |
2 successes, 3 failures (2 runs, expected 1) | 5 successes |

Real Neovim probes (loopback server with a raw TCP client, and a real
git repository), before and after:

- Wrong token: `server: Authenticated WebSocket client connected:
client_1` was logged first, then `Rejected client_1: Invalid
authentication token`. After the fix the wrong-token client has no
`Authenticated` line. The right-token client gets it after `Client
authenticated successfully`. Lines with `Authenticated` for the two
clients: 2 before, 1 after.
- `git_root` on a real repository: 2 git invocations before, 1 after.
- `tcp.lua` seeding: 1 seed for one load and two port searches. 2 seeds
after a reload of the module and one more search.

Gates on the final commit, which merges `origin/main` (036427a) into
the branch (private XDG folders):

- `mise run all`: native exit 0. luacheck: 0 warnings / 0 errors in 180
files. busted: 1691 successes / 0 failures / 0 errors / 24 pending.
treefmt: 0 files changed.
- `mise run format-check`: native exit 0 (357 files, 0 changed).
- Sibling specs (every spec under `tests/unit/server/`, `server_spec`,
`server_tool_call_log_spec`, `cwd_spec`, `terminal_spec` and
`tests/unit/terminal/`): 556 successes, 0 failures.
- `scripts/run_integration_tests_individually.sh`: 331 successes, 0
failed, 0 errors.
- `.agents/skills/verify-diff-lifecycle/check.sh --hash-only`:
covered.lock matches the code.

The merge with `origin/main` conflicted in `lua/claudecode/README.md`
and `lua/claudecode/server/README.md`, where the README refresh (coder#533)
rewrote the lines this PR edits. I kept main's text and reapplied this
PR's two changes (the `at most once` wording and the `on_open` log). Two
independent verifiers (Opus and GPT) checked the head before the merge
with `origin/main`. Both found no introduced defect. They reran the red
and green specs, reverted each code change alone to see the new specs
fail, and ran real loopback clients against the server. Their wording
findings are in the branch (the README line says "at most once", and the
`on_open` comment says "with a token").

---
_Generated with [`xum`](https://github.com/coder/xum) • Model:
`anthropic:claude-sonnet-5-5` • Thinking: `xhigh`_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant