Repository navigation
chore: cover the mouse encoder in the lifecycle model - #32
Merged
Merged
Conversation
PR #12 adds a second libghostty handle (mouse_encoder_) and encodeMouse, which reads caller values in two places where JS can run: the TypeScript normalizers after #assertUsable, and the native Get() reads. The old model had neither, and its assumption "no JS runs inside a native method" is false for encodeMouse. Model the encoder handle (create, the constructor's failure path, dispose, finalize), split encodeMouse at the JS windows, and add EncoderFreedOnce. Three new mutants: the code before the F2 fix (handles taken before the reads), no native null checks, and DisposeNative keeping mouse_encoder_. Record F2, move the sync commit to the PR #12 head, and update the view. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_ Change-Id: I2581fa76d309060eedd375edc79d0f9a2a3575a3
Change-Id: I78cc6ff2143014924571060acda28920218fceea Signed-off-by: Thomas Kosiewski <tk@coder.com>
7366b75, the covered code changed only in PositiveUint16 and NonNegativeSize (argument checks from #30, which the model does not describe) and in how test/mouse-safety.test.ts loads src/. run.sh still matches EXPECT in all 35 rows. Signed-off-by: Thomas Kosiewski <tk@coder.com> --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_ Change-Id: Id8a32feb7af0e8da355aa2ebeaaaa327fd7924be
ThomasK33
marked this pull request as ready for review
October 29, 2026 22:39
This was referenced Oct 29, 2026
ThomasK33
added a commit
that referenced
this pull request
Oct 30, 2026
Closes #37 ## Why Terminals ignored the DECSTR soft reset (`ESC[!p`), so a program that reset with it left the cursor hidden and the pen styled in every later snapshot. This moves the Ghostty pin to the `v1.4.0` release, which includes upstream DECSTR support. ## What changed - The build pins Ghostty `v1.4.0` and Zig 0.17.0 (`mise.toml`, `mise.lock`, the build script and its docs). - `native/terminal.cc` follows two C API changes. Terminal creation now sets scrollback with `ghostty_terminal_set`, and the UTF-8 mouse mode read uses `ghostty_terminal_get`. - The DECSTR test now asserts the reset, and the README drops the soft-reset limit. - `resize` does a narrower and taller resize in two steps, rows first. Ghostty v1.4.0 skips the scrollback pull when one call does both, which left the prompt up with blank rows below it. ## Scope - The lifecycle model's coverage record still names its sync commit's code. I will move its sync commit to this PR's squash commit in a follow-up, as #32 did after #12. ## Tradeoffs - `scrollbackLimit` maps to the byte limit, not the new line limit. The old Ghostty counted `max_scrollback` in bytes, and only the byte setter keeps 0 as "no history". The unit was never documented, so changing it would be a silent behavior change. - I pinned the `v1.4.0` release instead of `f473f31`, the first commit with DECSTR. It is a supported release, and it needs Zig 0.17.0 instead of 0.16.0. ## Blast Radius Every terminal now runs on Ghostty `v1.4.0` (2,472 upstream commits). An independent verifier diffed main against this branch through the packed package. The differences it traced to upstream fixes include reflow cursor placement, C1 and C0 control characters no longer printing as cells, Unicode 18 width tables, and `formatHtml` no longer adding a newline at each page. Building from source now needs Zig 0.17.0. ## Upstream changes consumers can see These come from Ghostty `v1.4.0`, not from this binding: - Reflow keeps the cursor at the last write position, and a pending wrap is repaired after a resize. - C0 (0x10 to 0x1F) and C1 (0x80 to 0x9F) control characters no longer print as cells. Unicode 18 width tables change the width of 1,021 newly assigned codepoints. - CHA, VPA, HPR and VPR are origin-relative, BS stops at the left margin, and TBC changed. - With OSC 133, ED2 at a prompt moves the screen into scrollback. A `scrollbackLimit` of 0 no longer keeps rows from a scroll region at the top. - In mouse mode 1005, buttons eight and nine now send bytes (`c2a0`, `c2a1`). - `formatHtml` no longer adds a newline at each page. ## Verification - The full local gate passes: libghostty build, native build, typecheck, 73 tests, smoke, `npm pack`, the UBSan build and tests, and the TLA+ lifecycle model. - Scrollback, old build against new build, for 20,000 lines: an unset limit and 0 keep no history on both. A limit of 1 to 100,000 keeps 969 lines on the old build and 903 on the new one. Both are Ghostty's page minimum. A new test fails when the code uses the line limit instead. - In the verifier's 400-scenario seeded fuzz, the resize fix brings 16 more scenarios back to main's exact state, and no scenario diverges earlier than before. - The Zig 0.17.0 checksums in `mise.lock` match ziglang.org's `index.json` for linux-x64, linux-arm64 and macos-arm64. --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This updates the
verify-native-lifecyclemodel to describe the code that #12 added. The sync commit is7366b7545170ad77f5151e445c60bbf5bb110d87, the squash commit of #12 on main.Why
#12 adds a second libghostty handle (
mouse_encoder_) andencodeMouse. The old model had neither. Its assumption "JS code cannot run inside a native method" is false forencodeMouse:Get()runs getters, includingObject.prototypegetters for keys thatsrc/index.tsleaves out. That window let a getter dispose the terminal whileEncodeMouseheld copies of the handles (finding F2, fixed in #12 before it merged).What changes
DisposeNative, and the finalizer.encodeMouseis split at its JS windows: the TypeScript normalizers after#assertUsable(EncodeTs), the nativeGet()reads (EncodeEnter), and the libghostty calls (EncodeCall).EncodeThrowscovers a getter that throws.EncoderFreedOnce.NoCallOnDeadHandlealso covers the encoder handle.mutant-handles-before-reads: the code before the F2 fix.mutant-no-native-guard: noRequireTerminalorRequireMouseEncodercheck.mutant-keeps-encoder-pointer:DisposeNativedoes not clearmouse_encoder_.NoCallOnDeadHandle, because a getter can dispose the terminal after#assertUsablepassed.statechart-view.mjslabels the new steps and the encoder handle.Result
run.shexits 0. All 35 rows match EXPECT, andcurrent.cfghas 8,661 distinct states (it had 2,121).The
mutant-handles-before-readscounterexample is the F2 bug: load the addon, create t1, callencodeMouse, copy the handles in native code, dispose t1 in a getter, then call libghostty on the freed handles.test/mouse-safety.test.tson #12 replays it against the real addon. That test fails on the code before the fix and passes after it.Not covered: the mouse argument checks, the encoded bytes and the mouse mode cache. #12's tests cover those.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:xhigh