Skip to content

perf(cmux-next): gate find highlight repaints by transcript changes - #21384

Merged
teamleaderleo merged 5 commits into
feat-cmux-nextfrom
perf/find-highlight-deps
Oct 18, 2026
Merged

teamleaderleo merged 5 commits into
feat-cmux-nextfrom
perf/find-highlight-deps

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

VirtualTranscript repainted every mounted text node for Find in Chat on every commit, including scroll and layout commits that did not change query, transcript rows, or mounted DOM.

Change

  • derive a primitive mounted-range signature from the virtualization windows
  • rerun highlighting when the query/active target, immutable row snapshot, or mounted range changes
  • preserve streaming/reveal updates and clear behavior when Find closes

This avoids redundant DOM tree walks while keeping highlights correct as rows stream or virtualized rows enter the viewport.

Validation

  • git diff --check
  • Fleet CI: web checks, React Doctor, compiler/typecheck, focused chat-find tests, and gallery/render guards

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Gates Find in Chat highlight repaints on transcript changes so scrolling and layout commits no longer walk every mounted text node.

Highlighting reruns only when the query, active target, immutable row snapshot, or mounted range changes. Streamed text, fold reveals, and clear-on-close behavior are preserved; the effect keeps revealed as a dependency so opening a fold repaints the match. Effect dependencies use primitive signatures (row id, occurrence, mounted-range key) so spurious state changes don't invalidate the highlight pass.

Validation:

  • git diff --check
  • Fleet CI: web checks, React Doctor, compiler/typecheck, focused chat-find tests, and gallery/render guards, including the apps empty-state selector carried through this change.

Written for commit 3f21ea0. Summary will update on new commits.

View guided diff Turn on auto-fix

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: aa9361b7-34cb-4642-809b-3238dedc64b3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-l0csy created for this PR by the cmux coordinator.

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

all web/size checks green

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Passes: CI passes on 3f21ea0afe.

CI passes on 3f21ea0afe (run 39093237708 attempt 1).

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

CI fast guards passes on 3f21ea0afe (https://github.com/manaflow-ai/cmux/actions/runs/39093237708). This covers only the fast guards, not CI: CI's result is the ci-status check, and the CI failure attribution comment names any failing test.

@teamleaderleo
teamleaderleo force-pushed the perf/find-highlight-deps branch from 8e886ad to 746dc8e Compare October 17, 2026 23:19
@teamleaderleo
teamleaderleo force-pushed the perf/find-highlight-deps branch from 746dc8e to 2dfeb6e Compare October 17, 2026 23:21
@blacksmith-sh

blacksmith-sh Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Found 2 test failures on Blacksmith runners:

Failures

Test View Logs
test/apps-flow.test.ts/apps-flow.test View Logs
test/apps-flow.test.ts/apps-flow.test View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo
teamleaderleo force-pushed the perf/find-highlight-deps branch from 6e041c0 to 7225d5c Compare October 18, 2026 00:11
@cursor

cursor Bot commented Oct 18, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@manaflow-ai manaflow-ai deleted a comment from github-actions Bot Oct 18, 2026
@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Visual review: HQ feed · workflow run

@teamleaderleo
teamleaderleo merged commit afec4de into feat-cmux-next Oct 18, 2026
99 checks passed
@teamleaderleo
teamleaderleo deleted the perf/find-highlight-deps branch October 18, 2026 03:52
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/39095141726 at afec4de failed: cmux-next Release compile (Xcode 26).
Those jobs last passed at fde94c5. This pull request is one of 3 merged since: #21383, #21446, #21384.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/39095228117 at 9e14d7a failed: cmux-next Release compile (Xcode 26).
Those jobs last passed at fde94c5. This pull request is one of 3 merged since: #21383, #21446, #21384.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/39096093835 at b246059 failed: cmux app scheme compile (Debug), cmux-next Release compile (Xcode 26).
Those jobs last passed at fde94c5. This pull request is one of 5 merged since: #21383, #21446, #21384, #21450, #21442.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

teamleaderleo added a commit that referenced this pull request Oct 18, 2026
- Always high, at any size: release and signing, migrations, schemas/defaults,
  the protocol spec, pins, the merge gates and the workflows that route
  checks (cmux-next.yml, ci.yml, ci-guards.yml, ...).
- Runtime paths (daemon, acpmux, backend, Remote, Terminal, ...) are high
  only when the change is over 40 lines outside tests and generated files;
  a smaller one is medium, which a reviewer can read whole.
- Other workflows and actions are medium.
- New: a pull request that takes back another pull request's change from
  the last 7 days (deletes what it added, restores what it replaced) is
  high and names it. On #21194's squash this names exactly the five PRs it
  undid (#21199, #21234, #21369, #21384, #21446); moves and generated files
  don't count. The workflow fetches the base's last 9 days blobless for it.

On the 10-04..10-18 history by path: 225 low, 1207 medium, 617 high (30%),
down from 856 high (42%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 18, 2026
…quash (#21690)

* test(cmux-next): older history is asked for once per page

Fails on feat-cmux-next: a streaming commit near the top asks for the same
older page again, because 50a0c60 (#21194) restored the effect #21369
had keyed on the first row.

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

* perf(cmux-next): avoid duplicate older-history loads (#21369)

(cherry picked from commit 8f6f9cb)

* perf(cmux-next): gate find highlight repaints by transcript changes (#21384)

* perf(cmux-next): gate find highlight repaints by transcript changes

* fix(cmux-next): preserve find repaint triggers after fold reveals

* style(acpmux): format find highlight effect

* test(next): carry apps empty-state selector through PR 21384

* test(next): carry apps empty-state selector through find highlight PR

(cherry picked from commit afec4de)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 18, 2026
* cmux NEXT: a folded long thought reads "Thought for 12s"

A long thought folded once done (#20948, Debug toggle
agentPane.debug.foldLongThoughts) now reads how long the agent thought,
from its first chunk to its latest, clamped at zero for out-of-order
events. An undated thought, or one under a second, reads "Thought".

#20948's "Thought" plus first line stays as the Debug choice
agentPane.debug.thoughtHeader = preview, which the app sets on <html> as
data-thought-header. New string tools.thoughtFor in all 21 pane locales
(split from #20963).

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

* cmux NEXT perf-hitch2: an evicted terminal shows its last frame at once when shown again (GhosttyNextKit a19c884fa, cx-8w027.19.1)

A terminal the warm set evicted showed an empty pane until its new session
attached and drew. Ghostty emptied every released drawable
(kIOSurfacePurgeableEmpty in IOSurface.deinit), and a hidden surface releases
its swap chain, so even the layer's presented frame was blank (ghostty-next
PR 42: a plain release; the last owner frees the pages).

- A paused surface marks its presented frame volatile and makes it
  non-volatile before it shows again; a purged one leaves the layer empty
  until Ghostty's next frame, as before.
- Eviction keeps the presented IOSurface (no copy, volatile), at most the warm
  set terminal capacity, oldest first; a frame dropped by the bound leaves a
  480 px hover picture; memory pressure drops them with no renders.
- The new session shows it over its first surface (TerminalFrameHold
  begin(lastFrame:)) until its first content is parsed and drawn, at most 3 s;
  a purged frame or a hidden mount shows nothing. Hover cards picture it on
  demand.
- debug.surfaces: last_frames outcomes, per pane last_frame_holds, frame_held.
  Proof: scripts/cmux-next/evicted-terminal-frame-live.py.

Pins GhosttyNextKit release xcframework-a19c884fa8d132378ae838dcba95654b177b6723-apple-v6
(checksum 94ff3178... from SHA256SUMS, matching the downloaded zip) and moves the
ghostty-next gitlink, package-notices.json and vt-link-graph.json to it (only
pkg/macos/iosurface/iosurface.zig changed since e6a27a1fb).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(cmux-next): a terminal mounted hidden after an eviction shows its last frame at its reveal (cx-8w027.19.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(cmux-next): hover pictures reclaim a paused surface's volatile frame for the read; a frame in flight at the pause is not reclaimed; no last frame at capacity 0 (cx-8w027.19.1, review)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(cmux-next): last-frame logic lives in CmuxNextTerminal (TerminalLastFrames evict/show/report); the frame shows at the reveal; CmuxNextApp does not grow (cx-8w027.19.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* release-notes(next): fit browser highlights to the What's New limits (#21716)

* release-notes(next): fit browser highlights to the What's New limits

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

* release-notes(next): live links, dev-build wording for remote tabs

Replaces cmux.com/whats-new (404) with real try-it actions, says the
remote browser tab entries are development-build features (their action
is DEV/Nightly only), and drops 'instant' from the tab-switch entry.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* release-notes(next): fit app highlights to the What's New limits (#21717)

* release-notes(next): fit app highlights to the What's New limits

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

* release-notes(next): live links and exact profile-menu wording

Replaces two 404 links (cmux.com/whats-new, docs/agent-integrations) with
real actions or docs pages, and says what the profile button opens.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(next): workspace name source and revision, like tab names (hq#1957) (#21648)

* feat(next): workspace name source and revision, like tab names (hq#1957)

Workspaces now record whether their name came from a person or from
auto-naming, the way tab names do (NameSource { User, Auto } and a
name_revision), and the daemon decides whether an automatic rename lands.

- RegistryWorkspace and the mux Workspace carry name_source and
  name_revision, stored in two additive workspaces columns (legacy rows
  read user/0). Both commit paths re-check the stored row's name, source
  and revision inside the transaction.
- rename-workspace and workspace.rename accept source, expected_generation,
  expected_name_revision and release. An automatic rename never replaces a
  person's name (operation.failed, reason_code name_pinned), never empties
  one (name_empty), and loses to any rename after the revision it read
  (revision.conflict). source auto with release hands a pinned name back.
- Workspace projections (raw tree, list-workspaces, resource extra) expose
  name_source and name_revision; the daemon advertises
  workspace-name-source-v1.
- CLI: cmux workspace rename --source auto --expected-generation G
  --expected-name-revision N, and --release-to-auto.
- Spec, regenerated SDK bindings, cmux-app.d.ts and resource descriptor
  hashes follow; optchat-chief's RenameWorkspaceRequest literal gains the
  new fields.
- The app's DaemonCapabilities moves workspace-name-source-v1 from
  unservedByBundledDaemon to optional, since the bundled daemon now serves
  it.

Carved from #20710 onto current feat-cmux-next.

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

* fix(next): project workspace name provenance like the journal states it (hq#1957)

feat-cmux-next tests that landed after #20710's base failed on this slice:

- batch_close and resource_effects: the journal decorates every stored
  workspace with extra.name_source/name_revision, but the projected
  workspace values had no extra, so the public fold never matched and every
  commit restated every workspace. Every workspace value builder (deltas,
  full and scoped projection, normalized registry deltas, resource
  snapshots) now carries the same extra.
- key_close_cannot_rebind_a_live_durable_workspace_identity: creating a
  workspace at a key bound to another live workspace hit the name fence
  (revision.conflict) before the identity check. The name fence now
  applies only to the same workspace (numeric id), and the resource store
  checks identity before the name.

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

* refactor(next): workspace_resource_upsert lives with workspace renames (hq#1957)

Its name provenance parameter pushed mux.rs past the 1000-line god-file
budget (check-no-godfiles.sh); the helper moves to mux/workspace_rename.rs
unchanged.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-next): restore #21369 and #21384, undone by the Chief Dock squash (#21690)

* test(cmux-next): older history is asked for once per page

Fails on feat-cmux-next: a streaming commit near the top asks for the same
older page again, because 50a0c60 (#21194) restored the effect #21369
had keyed on the first row.

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

* perf(cmux-next): avoid duplicate older-history loads (#21369)

(cherry picked from commit 8f6f9cb)

* perf(cmux-next): gate find highlight repaints by transcript changes (#21384)

* perf(cmux-next): gate find highlight repaints by transcript changes

* fix(cmux-next): preserve find repaint triggers after fold reveals

* style(acpmux): format find highlight effect

* test(next): carry apps empty-state selector through PR 21384

* test(next): carry apps empty-state selector through find highlight PR

(cherry picked from commit afec4de)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* acpmux: no-ask start modes by inherit or an approved preset (#21666)

* feat(acpmux): start a no-ask mode from a session in it or an approved preset

A `session/new` that asks for a mode that doesn't ask, without the
person, now has two ways through:

- Inherit: a caller that is itself an acpmux session in that exact mode on
  the same harness family. Each harness gets ACPMUX_SESSION_TOKEN, an HMAC
  of its session id under a per-run in-memory secret, and
  ACPMUX_SESSION_TOKEN_SOCKET. The token is read only from a unix socket
  connection's first `initialize`. The caller's mode is read at request
  time.
- Approved preset: `_acpmux/presets {name, approveMode: true}` from the
  person records the sha256 of the preset's contents. The approval counts
  only while the resolve and the spawn both used those exact contents, for
  the preset's own mode, with no request overrides other than a folder.

A start mode never applies to an adopt without the person, and a proven
caller session that asks never gets the full-access default for its
chats. The refusal names where to approve (cmux NEXT on this host, or the
preset to approve there once), with {reason, host, mode, preset} in
error.data. Web and peer clients never get the host name.

person_auto_start.rs runs in the hermetic test environment, and its
person-key pipe is close-on-exec so parallel tests' daemons never hold
each other's key pipe open.

Carved from #20653.

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

* test(acpmux): an approved preset with a route, and env that names the caller token

Red on 116ab01:
- an approved preset plus a request `route` passes the start gate and
  reaches the handler ("no route"), where it should need the person;
- a harness profile env that sets ACPMUX_SESSION_TOKEN reaches the agent
  in place of acpmux's caller token.

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

* fix(acpmux): a route counts as an override, env never sets the caller token

Review fixes for the start gate:
- A request `route` on an approved preset now needs the person, like its
  own model, effort, policy or env: a route swaps the provider base URL
  and keys.
- A profile's, preset's or request's env no longer replaces
  ACPMUX_SESSION_TOKEN or ACPMUX_SESSION_TOKEN_SOCKET. That env is
  layered after `caller_env`, so the spawn drops both keys from it.
- The CLI's daemon readiness pipe is close-on-exec from creation
  (`std::io::pipe`, pipe2(O_CLOEXEC) where the OS has it) instead of a
  `pipe` then `fcntl`, which raced with a fork on another thread.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next: the static status look everywhere; indicators name their state (cx-sya4n) (#21664)

* test(cmux-next): the static look reaches tabs, the attention ring, the agent pane and every label (cx-sya4n)

Red: tabs keep their icon set's marks and colored dots, the attention
ring blinks, the agent pane's theme has no statusIndicators look and
indicators have no tooltip or VoiceOver label (compile failure).

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

* cmux-next: the static status look everywhere, and every indicator names its state (cx-sya4n)

Tabs draw the static look's still marks (the badge too, never a dot
told apart by color alone); the pane attention ring is the steady ring
under Static; the agent pane's theme sends statusIndicators (static
under Static or Reduce Motion). Every StatusIndicatorView's tooltip and
VoiceOver label is the state's short name (StatusIndicatorState
.shortLabel, nine strings in every catalog locale), and a tab's
needs-input VoiceOver text names the blocked kind. Carved from #20511.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 18, 2026
* cmux-next: keep the Mac awake while agents work (sessions.keepAwake)

New Settings > Agents > Agent Sessions row, "Keep Mac Awake While Agents
Work": Off, While Plugged In (default) or Always. While a local agent runs a
turn (an acpmux session, or a tab's agent hooks or OSC 7501 working record),
idle system sleep stays off. The display can still sleep and closing the lid
still sleeps the Mac.

- schemas/settings/source/sessions.json is the row's source; the Swift
  descriptor, parser constants and choice enum are generated.
- KeepAwakeService holds one ProcessInfo activity for every reason, so the
  Keep Mac Awake action and the setting never end each other's hold. The
  action now goes through it and still holds on battery.
- PowerSourceMonitor follows IOKit's power-source notification on the main
  run loop (no polling); unplugging releases a While Plugged In hold.
- Agents may not set the key (userOnly).
- Strings in all 21 locales of the settings catalog.

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

* cmux NEXT perf-hitch2: an evicted terminal shows its last frame at once when shown again (GhosttyNextKit a19c884fa, cx-8w027.19.1)

A terminal the warm set evicted showed an empty pane until its new session
attached and drew. Ghostty emptied every released drawable
(kIOSurfacePurgeableEmpty in IOSurface.deinit), and a hidden surface releases
its swap chain, so even the layer's presented frame was blank (ghostty-next
PR 42: a plain release; the last owner frees the pages).

- A paused surface marks its presented frame volatile and makes it
  non-volatile before it shows again; a purged one leaves the layer empty
  until Ghostty's next frame, as before.
- Eviction keeps the presented IOSurface (no copy, volatile), at most the warm
  set terminal capacity, oldest first; a frame dropped by the bound leaves a
  480 px hover picture; memory pressure drops them with no renders.
- The new session shows it over its first surface (TerminalFrameHold
  begin(lastFrame:)) until its first content is parsed and drawn, at most 3 s;
  a purged frame or a hidden mount shows nothing. Hover cards picture it on
  demand.
- debug.surfaces: last_frames outcomes, per pane last_frame_holds, frame_held.
  Proof: scripts/cmux-next/evicted-terminal-frame-live.py.

Pins GhosttyNextKit release xcframework-a19c884fa8d132378ae838dcba95654b177b6723-apple-v6
(checksum 94ff3178... from SHA256SUMS, matching the downloaded zip) and moves the
ghostty-next gitlink, package-notices.json and vt-link-graph.json to it (only
pkg/macos/iosurface/iosurface.zig changed since e6a27a1fb).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* cmux-next: regenerate settings exports and defaults for sessions.keepAwake

Exports from the fleet export step at 4beacc0 (run-swift-testing-suites.sh,
export-settings); defaults snapshot from defaults_guard.py snapshot.

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

* perf(cmux-next): a terminal mounted hidden after an eviction shows its last frame at its reveal (cx-8w027.19.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(cmux-next): hover pictures reclaim a paused surface's volatile frame for the read; a frame in flight at the pause is not reclaimed; no last frame at capacity 0 (cx-8w027.19.1, review)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* cmux-next: regenerate settings exports after merging feat-cmux-next

Exports from the fleet export step at 011a67c.

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

* restore-trace.py: trace a relaunch restore per pane with the snapshot sources that moved (cx-8w027.23)

* restore-trace.py: every pane in short, 50 ms reads (cx-8w027.23)

* perf(cmux-next): last-frame logic lives in CmuxNextTerminal (TerminalLastFrames evict/show/report); the frame shows at the reveal; CmuxNextApp does not grow (cx-8w027.19.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* cmux NEXT perf-restore: no pane re-run on connect, room badge from the strip's window, one topology per turn for every pane that changed (cx-8w027.23)

- PaneController.Snapshot.connected is gone: apply never read it, and the
  read re-ran every pane's snapshot when the daemon connected (16 per
  16-pane restore). A reconnect with a new daemon still re-maps through
  generation and surfaces.
- BrowserProfileService.roomDefault takes the room of the window the
  strip or sidebar avatar draws in (WindowState.profileID, observed), so a
  room's profile badge follows that window; the lookup of WindowManager
  state (not observed) stays only for one-time choices (a new tab's profile).
- A pane whose part of the focus topology changed marks the workspace
  (setNeedsTopology); FocusCoordinator builds and sends one topology per
  owner for the whole main-actor turn, at its end or before any state read
  or event (I4), instead of one per pane.

* cmux NEXT: no focus ring on the daemon recovery status label (#21679)

#20765 made the not-connected screen's status label selectable without
focusRingType = .none, so check:text-focus fails every feat-cmux-next PR.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* FocusCoordinator: state is a pure read; key routing and events reduce the pending topology; the turn-end reduction runs detached; what the settled observer queues runs (review of cx-8w027.23 slice 1)

* release-notes(next): fit browser highlights to the What's New limits (#21716)

* release-notes(next): fit browser highlights to the What's New limits

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

* release-notes(next): live links, dev-build wording for remote tabs

Replaces cmux.com/whats-new (404) with real try-it actions, says the
remote browser tab entries are development-build features (their action
is DEV/Nightly only), and drops 'instant' from the tab-switch entry.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* release-notes(next): fit app highlights to the What's New limits (#21717)

* release-notes(next): fit app highlights to the What's New limits

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

* release-notes(next): live links and exact profile-menu wording

Replaces two 404 links (cmux.com/whats-new, docs/agent-integrations) with
real actions or docs pages, and says what the profile button opens.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(next): workspace name source and revision, like tab names (hq#1957) (#21648)

* feat(next): workspace name source and revision, like tab names (hq#1957)

Workspaces now record whether their name came from a person or from
auto-naming, the way tab names do (NameSource { User, Auto } and a
name_revision), and the daemon decides whether an automatic rename lands.

- RegistryWorkspace and the mux Workspace carry name_source and
  name_revision, stored in two additive workspaces columns (legacy rows
  read user/0). Both commit paths re-check the stored row's name, source
  and revision inside the transaction.
- rename-workspace and workspace.rename accept source, expected_generation,
  expected_name_revision and release. An automatic rename never replaces a
  person's name (operation.failed, reason_code name_pinned), never empties
  one (name_empty), and loses to any rename after the revision it read
  (revision.conflict). source auto with release hands a pinned name back.
- Workspace projections (raw tree, list-workspaces, resource extra) expose
  name_source and name_revision; the daemon advertises
  workspace-name-source-v1.
- CLI: cmux workspace rename --source auto --expected-generation G
  --expected-name-revision N, and --release-to-auto.
- Spec, regenerated SDK bindings, cmux-app.d.ts and resource descriptor
  hashes follow; optchat-chief's RenameWorkspaceRequest literal gains the
  new fields.
- The app's DaemonCapabilities moves workspace-name-source-v1 from
  unservedByBundledDaemon to optional, since the bundled daemon now serves
  it.

Carved from #20710 onto current feat-cmux-next.

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

* fix(next): project workspace name provenance like the journal states it (hq#1957)

feat-cmux-next tests that landed after #20710's base failed on this slice:

- batch_close and resource_effects: the journal decorates every stored
  workspace with extra.name_source/name_revision, but the projected
  workspace values had no extra, so the public fold never matched and every
  commit restated every workspace. Every workspace value builder (deltas,
  full and scoped projection, normalized registry deltas, resource
  snapshots) now carries the same extra.
- key_close_cannot_rebind_a_live_durable_workspace_identity: creating a
  workspace at a key bound to another live workspace hit the name fence
  (revision.conflict) before the identity check. The name fence now
  applies only to the same workspace (numeric id), and the resource store
  checks identity before the name.

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

* refactor(next): workspace_resource_upsert lives with workspace renames (hq#1957)

Its name provenance parameter pushed mux.rs past the 1000-line god-file
budget (check-no-godfiles.sh); the helper moves to mux/workspace_rename.rs
unchanged.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-next): restore #21369 and #21384, undone by the Chief Dock squash (#21690)

* test(cmux-next): older history is asked for once per page

Fails on feat-cmux-next: a streaming commit near the top asks for the same
older page again, because 50a0c60 (#21194) restored the effect #21369
had keyed on the first row.

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

* perf(cmux-next): avoid duplicate older-history loads (#21369)

(cherry picked from commit 8f6f9cb)

* perf(cmux-next): gate find highlight repaints by transcript changes (#21384)

* perf(cmux-next): gate find highlight repaints by transcript changes

* fix(cmux-next): preserve find repaint triggers after fold reveals

* style(acpmux): format find highlight effect

* test(next): carry apps empty-state selector through PR 21384

* test(next): carry apps empty-state selector through find highlight PR

(cherry picked from commit afec4de)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* acpmux: no-ask start modes by inherit or an approved preset (#21666)

* feat(acpmux): start a no-ask mode from a session in it or an approved preset

A `session/new` that asks for a mode that doesn't ask, without the
person, now has two ways through:

- Inherit: a caller that is itself an acpmux session in that exact mode on
  the same harness family. Each harness gets ACPMUX_SESSION_TOKEN, an HMAC
  of its session id under a per-run in-memory secret, and
  ACPMUX_SESSION_TOKEN_SOCKET. The token is read only from a unix socket
  connection's first `initialize`. The caller's mode is read at request
  time.
- Approved preset: `_acpmux/presets {name, approveMode: true}` from the
  person records the sha256 of the preset's contents. The approval counts
  only while the resolve and the spawn both used those exact contents, for
  the preset's own mode, with no request overrides other than a folder.

A start mode never applies to an adopt without the person, and a proven
caller session that asks never gets the full-access default for its
chats. The refusal names where to approve (cmux NEXT on this host, or the
preset to approve there once), with {reason, host, mode, preset} in
error.data. Web and peer clients never get the host name.

person_auto_start.rs runs in the hermetic test environment, and its
person-key pipe is close-on-exec so parallel tests' daemons never hold
each other's key pipe open.

Carved from #20653.

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

* test(acpmux): an approved preset with a route, and env that names the caller token

Red on 116ab01:
- an approved preset plus a request `route` passes the start gate and
  reaches the handler ("no route"), where it should need the person;
- a harness profile env that sets ACPMUX_SESSION_TOKEN reaches the agent
  in place of acpmux's caller token.

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

* fix(acpmux): a route counts as an override, env never sets the caller token

Review fixes for the start gate:
- A request `route` on an approved preset now needs the person, like its
  own model, effort, policy or env: a route swaps the provider base URL
  and keys.
- A profile's, preset's or request's env no longer replaces
  ACPMUX_SESSION_TOKEN or ACPMUX_SESSION_TOKEN_SOCKET. That env is
  layered after `caller_env`, so the spawn drops both keys from it.
- The CLI's daemon readiness pipe is close-on-exec from creation
  (`std::io::pipe`, pipe2(O_CLOEXEC) where the OS has it) instead of a
  `pipe` then `fcntl`, which raced with a fork on another thread.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next: the static status look everywhere; indicators name their state (cx-sya4n) (#21664)

* test(cmux-next): the static look reaches tabs, the attention ring, the agent pane and every label (cx-sya4n)

Red: tabs keep their icon set's marks and colored dots, the attention
ring blinks, the agent pane's theme has no statusIndicators look and
indicators have no tooltip or VoiceOver label (compile failure).

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

* cmux-next: the static status look everywhere, and every indicator names its state (cx-sya4n)

Tabs draw the static look's still marks (the badge too, never a dot
told apart by color alone); the pane attention ring is the steady ring
under Static; the agent pane's theme sends statusIndicators (static
under Static or Reduce Motion). Every StatusIndicatorView's tooltip and
VoiceOver label is the state's short name (StatusIndicatorState
.shortLabel, nine strings in every catalog locale), and a tab's
needs-input VoiceOver text names the blocked kind. Carved from #20511.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-next): restore the URL chip hover card styles lost in the Chief Dock squash (#21699)

* test(cmux-next): every URL chip hover card class has a rule

Fails on feat-cmux-next: 50a0c60 (#21194) dropped the .cv-link-preview
rules #21199 added, while LinkChips.tsx still renders those classes.

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

* fix(cmux-next): restore the URL chip hover card styles (#21199)

50a0c60 (#21194, a stale-base squash) removed the nine .cv-link-preview
rules while LinkChips.tsx still renders them, so the card drew unstyled.
Restored byte for byte from 5106cc9.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* acpmux: a saved model or effort pick reaches open New Tab pages (#21677)

* test(acpmux): a saved model or effort pick is announced to watchers

A New Tab prewarmed before a pick draws the old start effort and the chat
then starts on the pick. Fails: note_pick saves the new start default but
sends no _acpmux/harnesses_changed.

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

* fix(acpmux): announce a saved model or effort pick to watchers

note_pick makes the pick the harness's start in _acpmux/harnesses, but
told nobody, so a New Tab prewarmed before the pick kept drawing the old
start effort until the chat started on the pick. It now sends
_acpmux/harnesses_changed, as a saved mode pick already announces
start_mode_changed; pages re-read the catalog on it.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next: keep awake lives in its own target (CmuxNextKeepAwake)

Review of #21730: CmuxNextApp only shrinks (check-app-size.sh), so
KeepAwakePolicy, PowerSourceMonitor and KeepAwakeService move to a new
CmuxNextKeepAwake target with their tests. The App keeps a one-line start
and the Keep Mac Awake binding; its source is 10 lines under the base.

The power-source callback now hops to the main actor with a Task instead of
MainActor.assumeIsolated (a banned crash class).

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

* cmux-next: route test knows the keep-awake tests; one policy write per change

Review of #21730: a CmuxNextSidebar change now also selects
CmuxNextKeepAwakeTests (CmuxNextKeepAwake depends on CmuxNextBridge), so
test_a_shared_module_selects_its_dependents lists it. KeepAwakeService sets
the setting and the agents-working fact in one policy write, so the hold
cannot drop between the two.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: safe-push <safe-push@cmux.local>
teamleaderleo added a commit that referenced this pull request Oct 19, 2026
…sk evidence check (#21718)

* ci(cmux-next): path-based risk tiers with an evidence check

Label each feat-cmux-next pull request risk:low, risk:medium or risk:high
from the paths it changes, and keep a 'risk evidence' check red until the
description has that tier's evidence: a screenshot for medium, plus a
reviewed SHA and an executed runtime test for high. The policy is in
docs/ci/risk-tiers.md and CLAUDE.md.

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

* ci(cmux-next): close the risk evidence bypasses review found

- Grade on every pull_request_target event with job-level concurrency, and
  move the unit tests to risk-tier-tests.yml, so no skipped 'risk evidence'
  run can become the newest check and read as a pass.
- Check out the classifier at github.workflow_sha.
- Grade merge gates, CODEOWNERS, publish/deploy workflows, schemas/, and the
  BrowserImport, BrowserAutomation and Cloud targets high; stop treating
  every .txt and src/ fixture as low.
- Proof needs media, not any URL; field values must be on the same line;
  a runtime SHA must be a commit on the pull request.
- risk:waived counts only when an admin or maintainer added it.

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

* ci(cmux-next): read risk:waived only when evidence is missing

A failed permission lookup no longer turns a check with full evidence red,
and reads as no waiver.

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

* ci(cmux-next): grade workflows high and keep file names out of workflow commands

From coord-2's review of #21691: every .github/workflows and .github/actions
file runs with secrets or a write token and decides what other pull requests
skip, so it is high tier. File names in the report have control characters
and backticks replaced, so a newline in a name can't start a :: command.

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

* ci(cmux-next): sharper risk designations

- Always high, at any size: release and signing, migrations, schemas/defaults,
  the protocol spec, pins, the merge gates and the workflows that route
  checks (cmux-next.yml, ci.yml, ci-guards.yml, ...).
- Runtime paths (daemon, acpmux, backend, Remote, Terminal, ...) are high
  only when the change is over 40 lines outside tests and generated files;
  a smaller one is medium, which a reviewer can read whole.
- Other workflows and actions are medium.
- New: a pull request that takes back another pull request's change from
  the last 7 days (deletes what it added, restores what it replaced) is
  high and names it. On #21194's squash this names exactly the five PRs it
  undid (#21199, #21234, #21369, #21384, #21446); moves and generated files
  don't count. The workflow fetches the base's last 9 days blobless for it.

On the 10-04..10-18 history by path: 225 low, 1207 medium, 617 high (30%),
down from 856 high (42%).

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

* ci(cmux-next): printable() also replaces C1 controls and line separators

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

* ci(cmux-next): a line moved to another file isn't taken back

#21242 moved #20398's mouseDownCanMoveWindow override from
SidebarContainerView into SidebarResizeHandle; the revert check read the
move as a revert.

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

* ci(cmux-next): full-blob base fetch, visible blame gaps, advisory until 10-21

From coord-2's re-review:
- Fetch the base's 9 days with blobs. Blobless, blame fetched blobs one by
  one and passed its 30 s timeout on busy files, so #21724's takeback of
  #21320 and #21536 went unflagged; with blobs it is flagged in seconds.
- A file the revert check couldn't read is listed in the report for a
  manual check, never skipped silently.
- Generated settings exports (*.sha256, settings-export/, the settings
  schema) don't count toward the 40-line runtime threshold.
- The evidence check is advisory (a warning, check passes) until
  2026-10-21T00:00Z, so pull requests already in flight can add evidence.

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

* test: register tests/test_risk_tier.py in the execution registry

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

* ci(cmux-next): base history in a fresh repo, a time budget, and the merge base

From review of fa3750e:
- actions/checkout turns a sparse checkout into a blobless partial clone,
  and a later fetch into it stays blobless, so blame still fetched blobs one
  at a time. Fetch the base's 9 days into a fresh repository instead (about
  60 s, not a partial clone; blame then takes about 2 s on #21724).
- The revert check stops after 120 s and lists what it didn't reach as
  'check by hand', so the job always ends inside its 5-minute timeout (a
  timed-out risk evidence check is red and can't be waived).
- Blame at the merge base the patches are relative to, not the base tip.
- Docs: re-run risk evidence on open PRs at the advisory cutover.

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

* ci(cmux-next): cap the base history fetch at 150 s

From review of 8a61191: an uncapped fetch could still run the job past its
5-minute timeout, and a timed-out risk evidence check is red. A slow fetch
now skips the revert check with a warning.

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

* test(risk tiers): cover the audit misgrades and advisory-era verdicts

The designation audit found paths graded too high (Rust *_tests.rs, spec
prose), too low (nested deploy and signing scripts, merge-gate helpers,
OptChat backend, pins), and that a risk evidence check that passed while
advisory stays green after the cutover. These tests fail until the fix.

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

* ci(risk tiers): apply the designation audit and refuse advisory-era verdicts

Agents audited the designations against 40 merged and 30 open PRs.
- Rust *_tests.rs, tests.rs and tests_v2/ grade as tests, and spec Markdown
  as docs. The cmux-tui/spec JSON stays a contract.
- Nested deploy, signing, nightly, promote and rollback scripts and workflows,
  scripts/ci/lib, the gh-merge-green helpers, merge-main.sh and the god-file
  check now grade high. The merge-gate rule moves first, so
  select_package_tests.py can never match the test rule.
- The OptChat agent backend counts as runtime (its inspector stays UI).
  ghostty.h, homebrew-cmux and .xcode-version count as pins.
- A Demo, Video or Recording heading holds proof.
- ENFORCE_FROM moves to 2026-10-24 00:00 UTC. After that, gh-merge-green
  reads ENFORCE_FROM from the base's risk-tier.yml and refuses a
  risk evidence verdict that finished before the cutover, or no verdict at all.
- The module docstring now matches the rules.

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

* test(risk tiers): judge a verdict by its start and refuse an unreadable cutover

Review nits on 83f662d: a job that started before the cutover can grade
as advisory and still finish after it, and a risk-tier.yml whose ENFORCE_FROM
no longer parses silently skipped the gate. Also test_*.py scripts and
fixtures should grade as tests. These fail until the fix.

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

* ci(risk tiers): judge a verdict by its job start; refuse an unreadable cutover

gh-merge-green now compares the risk evidence job start time with
ENFORCE_FROM, since the job decides advisory-or-not while it runs, and
refuses when risk-tier.yml is readable but has no ENFORCE_FROM in the
expected form instead of skipping the gate. test_*.py scripts and fixtures
under scripts/ grade as tests.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 19, 2026
…ine internal

The 49-nightly gallery range showed export-backdrop-art, "#N", "#21369 and #21384" and two
Chief Dock squash repairs under Improved and Fixed. readableChange and release-notes.py now read
a three-part hyphenated tool name (not up-to-date or drag-and-drop), a bare PR number and
squash as internal, so the page folds them, the pipeline leaves them out of summary lines, and
the pre-publish check fails a build whose notes still carry one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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