Skip to content

docs: correct the I/O and cleanup claims in ARCHITECTURE.md - #547

Merged
ThomasK33 merged 1 commit into
mainfrom
docs/architecture-io-claims
Nov 12, 2026
Merged

ThomasK33 merged 1 commit into
mainfrom
docs/architecture-io-claims

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Why

The Performance & Security list of ARCHITECTURE.md says "Async I/O: Non-blocking vim.loop operations". That is too broad. Sockets and timers use libuv callbacks, but file I/O is synchronous. Two sibling bullets have the same problem: "Memory Efficient: Minimal footprint, no caching" and "Resource Cleanup: Automatic on vim exit". The advisor on #543 also asked for two small additions in the same file.

What changed

Five lines of ARCHITECTURE.md.

Statement Old New Evidence
Async I/O "Non-blocking vim.loop operations" "Async and Blocking I/O": sockets and timers use libuv callbacks, file I/O is synchronous The TCP server uses listen, read_start and a ping timer with callbacks (tcp.lua:120, :207, :534) and tcp_handle:write (client.lua:84, :90). Timers: selection.lua:506, init.lua:137. File I/O: lockfile.lua calls fs_open, fs_write and fs_close with no callback (:157, :172, :184) and uses os.rename and os.remove (:195, :221). diff.lua uses io.open (read_file :492, create_temp_file :553). Every fs_* call under lua/ is in lockfile.lua and has no callback (fs_open, fs_write, fs_close, fs_unlink, fs_chmod).
Memory "Minimal footprint, no caching" "In-memory State": the plugin keeps, among other things, the latest selection, the proposed text of each open diff, an input buffer for each client and the @-mentions that wait to go out, and reads CLAUDE_CONFIG_DIR once at load selection.lua:315 (latest_selection), diff.lua:1774 and :1026 (new_file_contents, active_diffs), client.lua:54 (buffer), init.lua:51 (mention_queue), lockfile.lua:20 (M.lock_dir = get_lock_dir()). The text had no number to support "minimal footprint", so the new bullet states what is kept.
Resource Cleanup "Automatic on vim exit" A VimLeavePre autocmd runs stop when the server runs, stop stops the server and tries to remove the lock file, and a SIGKILL skips it and leaves the lock file init.lua:514-522 and :635-648. Probe below.
Lock directory bullet (#543 advisor) no citation adds [lua/claudecode/lockfile.lua:M.create] lockfile.lua:94, :104
Reject list (#543 advisor) closing the last window or deleting the buffer adds switching that window to another buffer (:edit, :enew), which rejects through BufHidden on the next loop turn and only if the diff is still the same one and the proposal is still hidden diff.lua:1189-1226 (_register_reject_when_hidden). Probe below.

Scope

Only the Performance & Security list, and the two bullets from the #543 advisor.

  • Other bullets of the list. "Debounced Updates" holds (debounce_ms = 100, selection.lua:318). "Localhost Only" holds (both binds use 127.0.0.1, tcp.lua:86 and :114).
  • Thread Safety (Key Implementation Patterns, not changed). It says all Neovim API calls from async contexts use vim.schedule(). I read every callback in server/: it touches Neovim only through vim.schedule or the logger. The selection and mention timers wrap their work in vim.schedule. I found no counterexample.
  • Not audited. The rest of the file, including the Overview ("zero external dependencies") and the WebSocket "Key implementation details".

Blast Radius

One documentation file. Nothing loads it. A wrong sentence here misleads a contributor and breaks no behavior.

Verification

I ran the real modules in headless Neovim 0.12.3 with an isolated home.

  • Exit cleanup. A real server started by setup with auto_start, then :qa!: the lock file exists before and 0 lock files remain after. Nothing but the VimLeavePre autocmd of setup stops the server there.
  • SIGKILL. scripts/repro_issue_70_probe.lua, then kill -KILL of the nvim that the case started: the lock file stays (1 left). A normal stop leaves 0.
  • Switch reject. In the proposal window, :edit <other file> and :enew each make open_diff_blocking reply DIFF_REJECTED. This holds in the vertical and the unified layout. The reply does not exist right after the command and arrives on the next loop turn, as the vim.schedule in the BufHidden handler says.

Checks:

  • Citation check over the seven READMEs and ARCHITECTURE.md: 806 citations, 1 flagged. The flagged one is [plugin/claudecode.lua:pcall(require, "claudecode")], an expression that main already cites. A negative control with two wrong symbols flagged both (bad 3, then 1 after the restore).
  • mise run format-check: exit 0 (358 files, 0 changed).
  • I did not run mise run all. The change is documentation only, and nothing in tests, scripts, .github or mise.toml reads ARCHITECTURE.md. CI runs the full suite on the pushed head.
  • git merge-tree --write-tree of the head and origin/main is clean.

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

The Performance and Security list said 'Async I/O: Non-blocking vim.loop
operations', 'Memory Efficient: Minimal footprint, no caching' and 'Resource
Cleanup: Automatic on vim exit'. Sockets and timers use libuv callbacks, but
all file I/O is synchronous (lockfile.lua fs_open, fs_write and fs_close have
no callback, and it uses os.rename and os.remove. diff.lua uses io.open). The
plugin keeps the latest selection, the proposed text of each open diff, an
input buffer for each client and a mention queue, and it reads
CLAUDE_CONFIG_DIR once at load. The exit cleanup is a VimLeavePre autocmd that
runs stop. A SIGKILL skips it and leaves the lock file.

Two items from the review of #543: the lock directory bullet cites
lockfile.lua M.create, and the reject list names switching the last proposal
window to another buffer (:edit, :enew), which rejects through BufHidden in
_register_reject_when_hidden.
@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-12T05:23:45.410528Z ea1bcd1 Manual request
🔒 Security Review ✅ Completed 2026-11-12T05:24:10.291733Z ea1bcd1 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. 🚀

Reviewed commit: ea1bcd1b5a

ℹ️ 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: ea1bcd1b5a

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.

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 12, 2026
Merged via the queue into main with commit 86f425c Nov 12, 2026
6 checks passed
@ThomasK33
ThomasK33 deleted the docs/architecture-io-claims branch November 12, 2026 05:53
ThomasK33 added a commit that referenced this pull request Nov 12, 2026
Pick up #547 and #538. Neither adds a 'proposed buffer' to the READMEs.
ThomasK33 added a commit that referenced this pull request Nov 12, 2026
… the write path

The #547 advisor named two items in ARCHITECTURE.md:
- The Resource Cleanup sketch called M.stop() with no condition. The real
  VimLeavePre callback runs stop only when M.state.server is set, and clears
  the @-mention queue otherwise (init.lua:514-525). The sketch now shows the
  if and the else, and its lead-in no longer says 'Automatic cleanup'.
- The I/O bullet said the TCP server writes with libuv's asynchronous write
  without a citation. It now cites client.lua write, which calls
  tcp_handle:write.
hareki pushed a commit to hareki/claudecode.nvim that referenced this pull request Nov 13, 2026
… I/O citations (coder#549)

## Why

The READMEs name the buffer that holds Claude's proposed text in two
ways. `README.md:1144` and `:1148`, `ARCHITECTURE.md` and 8 of the 16
uses in `lua/claudecode/README.md` say "proposal buffer".
`lua/claudecode/README.md` and the new paragraph in `README.md:254`
(from coder#546) also say "proposed buffer". The advisor of coder#546 asked for
one name for one thing.

The advisor of coder#547 named two small items in `ARCHITECTURE.md`. This PR
takes them too, after coder#546 and coder#547 landed.

- The Resource Cleanup sketch calls `M.stop()` with no condition. The
real `VimLeavePre` callback runs `stop` only when `M.state.server` is
set, and otherwise clears the @-mention queue
(`lua/claudecode/init.lua:514-525`).
- The I/O bullet says the TCP server "writes with libuv's asynchronous
`write`" and cites nothing for it.

## What changed

**1. The rename.** Nine words in two files. Each "proposed buffer"
becomes "proposal buffer", and nothing else changes (a word-level diff
shows 9 changes of "proposed" to "proposal" and no other change).

| File | Lines | Count |
|---|---|---|
| `README.md` | 254 | 1 |
| `lua/claudecode/README.md` | 181, 182, 183 (twice), 184, 187 (twice),
208 | 8 |

I read each changed sentence in its new form. All nine read correctly,
for example "A write of the proposal buffer (`:w`, `:wq`, `:x`, `ZZ`
...)" and "Both layouts keep the proposal buffer's `'bufhidden'` at
`hide`". The other phrases in these two files already use "proposal"
(`proposal window`, `proposal lines`, `proposal buffers`). `proposed
changes` in `README.md` is a different thing and stays.

**2. Resource Cleanup sketch** (`ARCHITECTURE.md`). The sketch now shows
the `if M.state.server then M.stop() else clear_mention_queue() end` of
the real callback, with its `ClaudeCodeShutdown` group. Every code line
comes from `init.lua:514-525`, except two: the label `-- init.lua,
M.setup (shortened)` and the trailing comment on `M.stop()`, which the
old sketch had and which describes `M.stop` correctly. The other comment
line is the real comment at `init.lua:520`. The lead-in "Automatic
cleanup on shutdown:" had the same unconditional wording, so it now says
that the autocmd that `setup` creates runs `stop` only when the server
runs, and otherwise only clears the queue, with citations. This agrees
with the Performance bullet ("runs `stop` when the server runs").

**3. I/O citation** (`ARCHITECTURE.md`). The write clause now cites
`[lua/claudecode/server/client.lua:write]`. `write` is `local function
write(client, data, callback)` at `client.lua:81`, and it calls
`client.tcp_handle:write` at `:84` and `:90`.

## Scope

The two README files above and the two `ARCHITECTURE.md` items. Left
unchanged on purpose:

- **Other bullets and sketches of `ARCHITECTURE.md`.** Not audited again
here.
- **Code comments and strings under `lua/`** (9 uses of "proposed
buffer" in lowercase, plus `Proposed buffer ID` at `diff.lua:1187`).
They sit in `diff.lua` (8) and `init.lua` (1). Both files are recorded
in `covered.lock`, so a comment edit needs a new record, which is too
much for a wording fix.
- **`fixtures/issue-218/README.md` (2) and
`fixtures/issue-238/README.md` (7).** They describe repro scripts. The
sample output in `fixtures/issue-238/README.md` (`proposed buffer
bufhidden = "hide"`) is what `scripts/repro_issue_238.lua` prints
(`:260` and `:279`). A rename of the prose alone leaves two names in one
README, and a rename of the output changes a script string. They stay as
they are, because the fixture READMEs record what those scripts print.

## Blast Radius

Three Markdown files. Nothing loads them. A wrong sentence here misleads
a reader and breaks no behavior.

## Verification

- Word-level diff of the two READMEs against `main`: exactly 9 changes
of "proposed" to "proposal", no other change.
- `grep` for "proposed buffer" in `README.md`,
`lua/claudecode/README.md` and `ARCHITECTURE.md` finds 0 after the
change.
- The merge of `main` (coder#547 and coder#538) was clean and added no "proposed
buffer" to a README.
- `mise run format-check`: exit 0 (358 files, 0 changed).
- Citation check over the seven READMEs and `ARCHITECTURE.md`: 809
entries (733 citations, 26 relative links and 50 test paths), 1 flagged.
The flagged one is `[plugin/claudecode.lua:pcall(require,
"claudecode")]`, an expression that `main` already cites. A negative
control with three wrong symbols in the new citations flagged all three
(bad 4, then 1 after the restore). The validator matches a plain name
such as `write` only as a whole word anywhere in the file, so I also
confirmed the definitions of `write` (`client.lua:81`) and
`clear_mention_queue` (`init.lua:150`) with `grep`.
- I did not run `mise run all`. The change is documentation only, and no
test, script or CI file reads these files. CI runs the full suite on the
pushed 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`_
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