Skip to content

ghostty-next: pin 12ec155e1 (fork PRs #77, #79): an off-main present commits only a frame it shows - #36036

Merged
cmux-bot[bot] merged 2 commits into
feat-cmux-nextfrom
fix/ghosttykit-pin-off-main-commit
Nov 5, 2026
Merged

cmux-bot[bot] merged 2 commits into
feat-cmux-nextfrom
fix/ghosttykit-pin-off-main-commit

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

FRAME OWNER REFACTOR S4 (cmux-ad m6), the next step before the default flip of motion.frameOwner.terminals. GhosttyNextKit and the ghostty-next gitlink move together from 6cc749a8a to 12ec155e1 on release/cmux-9ce9b7d0-e2:

With the switch off (the default), nothing a person sees changes: the only off-path change is that a frame a newer frame superseded no longer commits an empty transaction.

The release: xcframework-12ec155e1e67f8f33a1cee5fd2e129f59277465c-apple-v6 (run 41955494921), zip sha256 5defd8f8b83a4fc8a7f74d805be380d5c566702cf35a19c2b92c0adda1730aa7. It agrees with the release's SHA256SUMS, the GitHub asset digest and the manifest's commit. The changed fork files (src/renderer/metal/IOSurfaceLayer.zig, src/renderer/Metal.zig) are not in the libghostty-vt link graph, so vt-link-graph.json changes only its commit. package-notices.json names the new paths (no license file or dependency change). check_ghostty_vt_notices.py --check-link-graph and package_notices.py check-data pass at this head.

Coordination: the same two commits are merged on the sync line as manaflow-ai/ghostty-next#80 (706c6963a). cmux #35478 must pin 706c6963a or later.

Testing

  • Fork: red at 694f7ffb7 (run 41953548703: only the new test fails, IOSurfaceLayer.zig:862, expected 0 commits, found 1); green at 7f2dcbf36 (run 41953551466: 111/111, lib-vt 97/97).
  • The gate A/B for the flip (pixel-perfect's 8-row rule), old pin 6cc749a8a against this pin, both from feat 4c35e528520 with the same bench file (scratch branches scratch/frame-owner-s4-gate-{old,new}-nomerge), on cmux24-perf, interleaved, 6 rounds, switch OFF and ON in each launch, background CPU per round (a round over 1 s is dropped and named): single presses b18904f4 (new) / 6d9dd1c4 (old); held keys 9acc4c56 (new) / efdb32f3 (old); profile at this pin f34e6860. Results replace this line.

Observed / Not run

  • Observed: the fork runs above; the two notice checks; prepush-gate.py passes.
  • Observed also: the 42 terminal suites at a1cf441095c (step 50f6ed920256d3914d8f0d46): all 42 suites ran, 224 tests pass, 0 fail. Independent review: SHIP at a1cf441095c (comment 6648707100). Its one finding (the fork doc's conflict note named the old order) is fixed in 0ba3948e9e4, a docs-only commit.
  • Observed also: the display suites at a1cf441095c (step 8a1efc6f628c9a44e6e2d4bc): TerminalKeyResizeFrameTests, TerminalFrameOwnerMainThreadTests and TerminalSurfaceCommitSizeTests pass. Gate A/B: single presses at this pin (b18904f4) pass 4 of 4 rows; the old pin's single run (6d9dd1c4, same day) failed keys and keys-stress. Held keys at this pin (9acc4c56): keys, light and STRESS drag pass; keys-stress still fails (OFF 20 / ON 42 over 4 valid pairs), so the flip stays off. The old pin's held run (efdb32f3) failed keys, STRESS drag and keys-stress. Profile at this pin: f34e6860.
  • Films (pixel-perfect, STATUS 13709; cmux22, the same kit, m14 judge f249741): this head 0ba3948e9e45 against its base 4c35e528520 (old pin): single-3k, rk-3t and lowprompt-reverse equal within 1 frame in every film, so no new red. held-2 at this head (requeued alone as ab-fixah2, after the first try did not record): terminal frame fails 2/2/0/0 against the base's 2/2/0/0, page frame fails 127/130/79/80 against 124/128/84/81. No new red in any film (STATUS 13726).
  • Not run: the flip. It needs the remaining held keys-stress cost gone (STATUS 13630, 13658). The flip PR turns the switch on only if the gate A/B shows no layout worse with ON.

Frames: terminal: with the switch off (the default), what the person sees in each frame does not change from the old pin 6cc749a8a. With the switch on (not shipped), the frames shown are the same; a frame that goes through main no longer costs an empty transaction on the GPU completion thread.

No capture: the change is behind a Debug switch that is off by default, and with it off no frame changes.

Changelog

none

…commits a Core Animation transaction only for a frame it shows

FRAME OWNER REFACTOR S4 (cmux-ad m6). Profile 4b41c42c (held keys-stress, motion.frameOwner.terminals on): the
largest single cost was 405 ms of CA::Context::commit_transaction on the GPU completion thread per round. The fork's
setSurfaceOffMain began and committed a transaction before its checks, so each new-size frame that went through
main committed an empty one. Fork #79 (independent review SHIP at 7f2dcbf36; red run 41953548703, green 41953551466)
makes the checks first and begins a transaction only for a frame it shows. #77 adds a test and one shared drop rule.

GhosttyNextKit xcframework-12ec155e1e67f8f33a1cee5fd2e129f59277465c-apple-v6 (run 41955494921), zip sha256
5defd8f8...30aa7 (SHA256SUMS, the GitHub asset digest and the manifest's commit agree). The switch stays off by
default; with it off nothing a person sees changes (a superseded off-main frame no longer commits).
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 0ba3948: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr36036 -f ref=fix/ghosttykit-pin-off-main-commit -f platform=macos -f backend_mode=local

Shipped in:

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (independent subagent): SHIP at a1cf441

I read the code and data myself. I did not build or run Swift or Rust.

1. Pin and gitlink

  • Packages/Shared/CmuxGhosttyKit/Package.swift:150-151: the url names xcframework-12ec155e1e67f8f33a1cee5fd2e129f59277465c-apple-v6. The checksum 5defd8f8...30aa7 is the same in 3 places: the release's SHA256SUMS, the GitHub asset digest and manifest.json archive.sha256. The digests of manifest.json and SHA256SUMS agree with the assets.
  • The manifest commit is 12ec155e1e67, and the gitlink is 12ec155e1e67. The flags, flavor, toolchain and slice library names are the same as in the old 6cc749a8a manifest. Release run 41955494921 is a push run on 12ec155e1, with conclusion success.
  • The release/cmux-9ce9b7d0-e2 tip is 12ec155e1. The guardrails ghostty-pin check passes because both values are the same commit.

2. Fork diff from 6cc749a8a to 12ec155e1 (5 commits: dc95e1538, merge ae7c1f741 (#77), 694f7ffb7, 7f2dcbf36, merge 12ec155e1 (#79))

  • Only 2 files change: src/renderer/Metal.zig (+26, a test only) and src/renderer/metal/IOSurfaceLayer.zig. Nothing changes in include/, build.zig(.zon), src/terminal, src/input or pkg/, and no @import line changes.
  • The libghostty-vt graph does not include these files. lib_vt.zig reaches renderer/size.zig only, which imports terminal/size.zig, and vt-link-graph.json names no src/renderer path. So the graph needs a new commit value only, not a full regeneration.
  • No C API or ghostty.h change. In cmux (excluding the submodule), setSurfaceOffMain, embedderDrops, offMainDecisionLocked and embedderShowsFrameLocked occur only in comments. The cmux side is not affected.
  • Logic: in setSurfaceOffMain, the read-only checks now run under [CATransaction lock] before begin. A failed check unlocks and returns: through_main returns false and superseded returns true, the same return values as before, with no transaction. A shown frame does lock, checks, begin, set contents, unlock, then commit. A commit never happens under the lock, so the Fix zsh git branch refresh race after cwd change #71 invariant holds. Bump version to 0.47.0 #77 only moves the main-path drop rule into embedderDrops. The behavior does not change.

3. Notices and docs

  • check_ghostty_vt_notices.py --check-link-graph and package_notices.py check-data pass at this head.
  • The new license_tree clause in package-notices.json (ae7c1f741 through 12ec155e1 only src/renderer/metal/IOSurfaceLayer.zig and src/renderer/Metal.zig) agrees with the diff. It uses the same style as the earlier db8627d95 through 6cc749a8a clause.
  • The order 6cc749a8a (Release v0.46.0 #75), then ae7c1f741 (Bump version to 0.47.0 #77), then 12ec155e1 (Fix FileDropOverlay recursion crash on mouse events #79) in docs/ghostty-fork.md:17-20 agrees with the merge commits and merge times.

4. Fleet steps at this head

  • 50f6ed920256d3914d8f0d46 (42 terminal suites, aws-m4pro-9): PASSED, exit 0, "All 42 suites passed". 224 tests passed and 0 failed, and each suite ran at least 1 test. The submodule was checked out at 12ec155e1. The stack before the table is the runner's own exit trace, not a failure.
  • 8a1efc6f628c9a44e6e2d4bc (display suites TerminalKeyResizeFrameTests, TerminalFrameOwnerMainThreadTests, TerminalSurfaceCommitSizeTests, cmux12): STILL RUNNING when I posted this review. It was still compiling about 22 minutes after the start. I have no result for it. These suites drive the switch-on path, and that path is off by default.

5. PR body

  • Summary, the Frames: line and the release data agree with the code.
  • The switch-off statement is incomplete but its conclusion is correct. cmux sets every terminal host-sized (TerminalSurfaceView.swift:206), so setSurfaceOffMain runs for each async present with the switch off too. There, a first frame and a new-size frame while the layer still shows the old size also no longer commit an empty transaction, not only a superseded frame. No pixel changes, so "nothing a person sees changes" is still true.

6. CI on the head

  • No failing check: 94 pass, 81 skipping, 3 pending (cmux-next swift test, cmux-next fast tier, portable job placement).
  • cmux-next app compile (build fleet), cmux-next fleet Release compile, cmux-next/compile, risk evidence and merge freeze pass. Nothing to classify.

Non-blocking

  • docs/ghostty-fork.md:45 and :50 still give the order begin, lock, checks, unlock, commit. After Fix FileDropOverlay recursion crash on mouse events #79 the order is lock, checks, then begin and contents for a shown frame only, unlock, commit. The :50 conflict note will lead the next fork merge to the wrong order. Correct both lines in this PR or in a follow-up.

This SHIP is for the pin only. It does not depend on the gate A/B. The A/B decides whether motion.frameOwner.terminals turns on, in the flip PR.

Review (independent subagent): SHIP at a1cf441

…eview of #36036 at a1cf441)

The conflict note still said begin, lock, checks, unlock, commit. Since #79 it is lock, checks, then begin, set
contents, unlock, commit only for a frame it shows; following the old note at the next fork merge would put the
empty commits back.
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (independent subagent): SHIP at 0ba3948

This review replaces my receipt at a1cf441095c (#36036 (comment)). All findings in that receipt still apply.

The new commit (0ba3948e9e4, parent a1cf441095c)

  • git diff a1cf441095c1662d9123050319e9eb2690860d84 0ba3948e9e45c8acaf750b2ac30fe12df4523e58 changes only docs/ghostty-fork.md (+7 -3). The pin, the gitlink, the notices and the code are the same as at a1cf441095c.
  • The text agrees with setSurfaceOffMain in src/renderer/metal/IOSurfaceLayer.zig at 12ec155e1:
    • It takes the lock and then runs the checks (offMainDecisionLocked).
    • For through_main and superseded, it unlocks and returns with no transaction.
    • For show only, it does begin, sets the contents, unlocks, then commits. A commit never happens under the lock.
    • The gate check (main_pending) stays after the shown-size and sequence checks.
    • The test name host present: an off-main present that does not show its frame commits no transaction is the exact name at line 850.
  • This fixes my non-blocking finding at docs/ghostty-fork.md:45 and :50.

Fleet steps (both were run at a1cf441095c; the code tree is the same at this head)

  • 50f6ed920256d3914d8f0d46 (42 terminal suites): PASSED. All 42 suites passed: 224 tests passed and 0 failed.
  • 8a1efc6f628c9a44e6e2d4bc (display suites TerminalKeyResizeFrameTests, TerminalFrameOwnerMainThreadTests, TerminalSurfaceCommitSizeTests, cmux12): STILL RUNNING at 03:19 UTC. It was still in the compile phase, so I have no result. These suites test the switch-on path, and the switch is off by default.

CI at this head: no check has failed. 64 pass and 22 are pending, including the compile checks. risk evidence and merge freeze pass. At a1cf441095c, which has the same code tree, cmux-next app compile (build fleet), cmux-next fleet Release compile and cmux-next/compile passed.

This SHIP is for the pin only. It does not depend on the gate A/B. The A/B decides whether motion.frameOwner.terminals turns on, in the flip PR.

Review (independent subagent): SHIP at 0ba3948

@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 5, 2026
@cmux-bot
cmux-bot Bot merged commit b8c0440 into feat-cmux-next Nov 5, 2026
260 of 266 checks passed
@cmux-bot
cmux-bot Bot deleted the fix/ghosttykit-pin-off-main-commit branch November 5, 2026 04:54
austinywang added a commit that referenced this pull request Nov 5, 2026
This branch still carried the older 6cc749a8a5 gitlink, while Package.swift downloads the
xcframework built at 12ec155e1e; the prepush ghostty-pin guardrail refused the push.
The branch now matches origin/feat-cmux-next for both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

3 inactive deployments
artifacts — 0ba3948e Deployed Nov 5, 2026 by lawrencecchen via publish tree-addressed cmux-tui #114021
sentry-dsyms — 0ba3948e Deployed Nov 5, 2026 by lawrencecchen via upload cmux-tui dSYMs to Sentry #114021
ci-routing-agent — 0ba3948e Deployed Nov 5, 2026 by lawrencecchen via cmux-tui tree preflight #114021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant