Skip to content

cmux-next: clear five base reds in cmux-next checks (ErrorJournal, browser popups) - #21981

Merged
teamleaderleo merged 1 commit into
feat-cmux-nextfrom
fix/next-base-reds-errorjournal-popups
Oct 19, 2026
Merged

teamleaderleo merged 1 commit into
feat-cmux-nextfrom
fix/next-base-reds-errorjournal-popups

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

feat-cmux-next has five red checks in "cmux-next checks", added by the ErrorJournal commit (1597dc9) and the browser popup commits (fa8b3fc). Because of them, every PR into feat-cmux-next fails that lane, gh-merge-green refuses every PR (it never waives the concurrency lint), and the web lane's check:text-focus failure skips "Test webviews". This PR only changes comments and baselines. Nothing behaves differently.

Check Cause on base Change
Main-thread concurrency ErrorJournalService.start() harvest loop and sleep; ErrorJournal.scheduleFlush() sleep Reviewed concurrency-allow and wakeup-allow comments. The loop runs in a Task.detached(priority: .utility) and the flush delay runs in the ErrorJournal actor's task, so neither runs on main. Both are cancellable cadence or one-shot deadlines.
No literal state roots home.appendingPathComponent(".acpmux/daemon.log") A keep row in state-roots-baseline.tsv. The app only reads the shared Release/NIGHTLY daemon log and never writes it.
Package conventions lint enum BrowserPopupWindowGeometry namespace type lint:allow with the reason (pure geometry over value inputs)
Type scale BrowserPopupPanel.swift is below its baseline Its baseline row is dropped (the ratchet goes down)
web check:text-focus PopupLocationBarView selectable field draws a focus ring field.focusRingType = .none, folded in from #21963

Not included: Motion tokens in SidebarCardTransition.swift, which stays with #21951 for its owner.

Testing

Run on huge-blue at base f143ac4 with this change. Every check below failed on base before the change:

  • scripts/cmux-next/check-concurrency.sh Packages/macOS/CmuxNext: ok
  • scripts/cmux-next/check-state-roots.sh: ok
  • scripts/lint-ios-package-conventions.sh: no unjustified violations
  • gen-type-scale.py --check and check-swift-type-scale.py: ok
  • check-text-focus-rings.py: no focus ring on a text field

@lawrencecchen FYI, these are your ErrorJournal and popup files. If you'd rather move the harvest to a DemandTimer, or resolve the app's acpmux home through AcpmuxEnvironment, those can replace the allow comments later.

🤖 Generated with Claude Code


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


Summary by cubic

Clears the five red checks in the "cmux-next checks" lane so PRs into feat-cmux-next stop failing it, getting refused by gh-merge-green, and skipping the web lane's "Test webviews". Only comments and baselines change; nothing behaves differently.

  • Concurrency lint: adds concurrency-allow and wakeup-allow comments on the ErrorJournal harvest loop and flush delay, which run in a detached utility task and the actor's task, never on main.
  • State roots: adds a keep row for ~/.acpmux/daemon.log, which the app only reads and never writes.
  • Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry over value inputs).
  • Type scale: drops BrowserPopupPanel.swift from the baseline since it no longer uses raw font sizes.
  • Text focus: sets focusRingType = .none on the popup location bar field.

Motion tokens in SidebarCardTransition.swift stay with #21951.

Written for commit 7a9c29e. Summary will update on new commits.

View guided diff Turn on auto-fix

The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left
five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks"
and its web lane skips its tests. Comments and baselines only, no behavior change:

- Main-thread concurrency: the harvest loop runs in a detached utility task and
  the flush delay in the ErrorJournal actor's task, so neither is on main;
  reviewed concurrency-allow and wakeup-allow comments.
- No literal state roots: the app's ~/.acpmux/daemon.log is only read; a
  keep row in the baseline.
- Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry).
- Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row.
- Text focus: the popup address field sets focusRingType = .none (was #21963).

Motion tokens (SidebarCardTransition) stays with #21951 for its owner.

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

coderabbitai Bot commented Oct 19, 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: f65be94b-6a97-4e2b-8990-9b2fdef467c0

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.

@github-actions

Copy link
Copy Markdown
Contributor

Receipt for 7a9c29e (this PR's head; a new push replaces it)

  • Visual review: HQ feed card · gallery before/after runs
  • Checks: this head
  • 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=pr21981 -f ref=fix/next-base-reds-errorjournal-popups -f platform=macos -f backend_mode=local

@github-actions

Copy link
Copy Markdown
Contributor

Not verified: macOS jobs did not run: compile and app tests were skipped on 7a9c29e0f7; ci-status is green without them.

CI passes on 7a9c29e0f7 (run 39207345698 attempt 1).
macOS jobs did not run: compile and app tests were skipped: Fast static checks skipped (the macos job needs both to succeed). Re-run CI once they pass, before merging.

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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Merging at 7a9c29e by coordinator priority. Review SHIP: the Swift changes are lint-allow annotations only (concurrency-allow and wakeup-allow on the ErrorJournal sleeps, a namespace-type allow on the popup geometry), plus the state-roots and type-scale baseline rows and the focusRingType line #21963 already landed (merge-tree is clean). The checks it fixes pass here: cmux-next checks (state roots, concurrency, type scale). Remaining reds: defaults-snapshot, which also fails on the feat-cmux-next tip, and cmux/reservation, an advisory reservation of ErrorJournalService.swift by feat-cmux-next-errjournal-wakeups until 06:54Z. This PR adds only comments to that file. Still pending: cmux-next fast tier (runner backlog) and build / release-compile (known base red).

@teamleaderleo
teamleaderleo merged commit 2265728 into feat-cmux-next Oct 19, 2026
@teamleaderleo
teamleaderleo deleted the fix/next-base-reds-errorjournal-popups branch October 19, 2026 06:36
teamleaderleo added a commit that referenced this pull request Oct 19, 2026
…t frame of a click (#21976)

* test(ui): a picker trigger is marked pressed from press to release (red)

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

* fix(agent pane): a composer picker keeps its pressed tone on the first frame of a click

Opening a picker moves focus into its popup before the held frame paints,
which clears :active. The trigger carries data-press-active from press to
release, and the composer's picker buttons draw the open-chip tone under it.

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

* guards: drop the pull_request_target publish case removed with publish-pr-tree

17bb49c deleted the dead publish-pr-tree job, so release-notary's
'pull_request_target refs/heads/feat-cmux-next publishes once' cases failed
5 times (run 39205353024).

* ci(cmux-next media): rebuild a warm tour's prebuilt modules after a binary pin change (#21971)

* test(ci): a warm tour must rebuild after a GhosttyNextKit pin change

The cmux-next tour keeps each tag's DerivedData warm, and Xcode reused the
explicit module it had precompiled from the old pin's ghostty.h: "ghostty.h
has been modified since the module file ... was built" (job 117892119256).
This regression runs the tour's build step twice with a stand-in reload.sh
that fails the same way; it fails until the fix lands.

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

* fix(ci): drop a warm tour's prebuilt modules when a binary pin changes

A Mac that last built a pull request's tag with GhosttyNextKit e6a27a1fb
failed the next tour, which pinned ced99dcde: Xcode copied the new ghostty.h
into Build/Products/Debug/include but kept the explicit module it had
precompiled from the old one (job 117892119256).

scripts/ci/media_module_cache_stamp.py keys a tag's build on every sha256 in
the tracked Package.swift files and every Package.resolved. Before reload.sh
it removes SwiftExplicitPrecompiledModules, ExplicitPrecompiledModules and
ModuleCache.noindex when that key differs from the stamp of the tag's last
good build; after the build it writes the stamp. The rest of DerivedData
stays warm.

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

---------

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

* gallery advisory: sample the states a PR adds first (#21850)

* gallery advisory: sample the states a PR adds first

A PR that touches a shared file (strings, App.tsx) touches every gallery
entry, so the first 16 states in order came from unrelated entries and the
receipt never showed what the PR added. The manifests now list every touched
state and the sample puts the new ones (no base case with that id) first.

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

* gallery advisory: the base keeps every sampled state before removed ones

The base filter cut at 16 in base order, so removed states early in that
order could push out sampled states that exist in base, which were then
compared as new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0283a51)

* gallery advisory: each stage renders its own manifest

Both stages rendered the joined case list, so the base reported the states a
PR adds as not ready (it has no such variant) and the capture stopped before
the head ran. Now that new states come first, every PR that adds a variant
hit this (#21851's first run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5b6d825)

---------

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

* docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback (#21958)

* docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback

The guarded fallback for when gh-merge-green couldn't read the coordinator's
WINDOW no longer applies: freezes are merge-freeze issues that every host
reads through the GitHub API (#21957).

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

* docs(merge-freeze): gh-merge-green enforces the freeze check

Same line as #21957 on main.

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

---------

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

* apps: preserve provider mutation context for owner handlers (#21406)

Replays #21406's change onto current feat-cmux-next as one commit.

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

* test(sidebar): a dragged group drops between every group

Regression test for scrawl-1792382497882-1673e-10: on the sidebar
document path a dragged group found a drop only on the thin bands of
each group header. Fails without the fix.

* fix(sidebar): fluid group drag, a drop at every gap between groups

- SidebarDragGeometry: a drop that cannot go into a group (a dragged
  group, groups do not nest) goes before or after the whole group, by
  the half of its block the probe is in, over its header or any member
  row. Before, every member row refused and the gap closed.
- A dragged group's header, not the tall card's centre, decides the drop.
- A refused place keeps the last open gap instead of springing it shut
  and dimming the card, so rows stop jumping during the drag.

* test(layout): a divider drag keeps one daemon command in flight

Adds GestureCommandCoalescer and its tests: 125 live values while one
command is in flight send the first and the newest only; the ended value
goes last; a failed live value with a newer one waiting is superseded.

* fix(layout): stop flooding the daemon during divider and column drags

NIGHTLY sent one set-viewport-pane-width per mouse move (~125/s); each
timed out at 2 s and every other command (pane and tab moves, saves,
attaches) timed out behind them. Divider and column gestures now go
through GestureCommandCoalescer: one command in flight per gesture, only
the newest value waits, the ended value always goes last. A failed live
value with a newer one waiting no longer rolls the divider back.

* scripts(cmux-next): drag-lag-live.py, column/tab/sidebar drag timing on a fleet app

* scripts(cmux-next): drag-lag-live probes the daemon during drags, bigger scene

* ci(nightly-next): one-command rollback of the cmux NEXT feed (#21887)

* ci(nightly-next): one-command rollback of the cmux NEXT feed

nightly-next-rollback.yml takes a bad build, and every newer one, off
appcast-arm64.xml so the feed serves the previous signed build again. It
runs in release-next on branch nightly-next, guards the appcast and R2 key
like publish-nightly, checks the fallback DMG exists, refuses to empty the
feed, and stops when the feed changed while it planned.

docs/ci/nightly-next-canary.md maps the nightly pipeline and its holds and
says what a pull can and cannot do: Sparkle never offers a lower build.

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

* ci(nightly): the delta lane never puts a pulled build back on the feed

republish-nightly-deltas skipped its rewrite only when the live NEXT feed
served a newer build. After nightly-next-rollback.yml pulls build N, the
feed serves N-1 and the lane's two-item appcast would restore N. It now
skips whenever the feed serves any other build. The regression cases in
test_nightly_republish_delta_guard.py fail on the old guard.

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

* ci(nightly-next): rollback runs-on keeps a fork branch

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

* ci(nightly-next): the rollback writes the feed only with If-Match

upload-r2-object.py --replace-sha256 HEX reads the object, requires the
bytes the caller planned from, and writes with If-Match on its ETag; a
changed object is not written (--conflict-exit-code). The rollback uses it
instead of a public re-read, so a publication that lands between the plan
and the write is never overwritten. Its summary no longer says "nothing
to pull" when the plan itself failed. (CodeRabbit on #21900.)

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

---------

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

* cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions (#21951)

* cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions

c5a1f90 built the update card's entrance, exit and crossfade from raw
CABasicAnimation, CASpringAnimation, CATransition and CAMediaTimingFunction, so
check-motion is red on feat-cmux-next (9 hits). Every duration and spring
already comes from the injected MotionPolicy's tokens; Motion.set would write
the model value and read the global policy instead. The 9 lines carry a
motion-allow and the type doc says why. Comments only.

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

* cmux-next: the sidebar card's motion-allow note names what stays literal

The curves and the spring's settle tolerance are literal, not tokens; say so,
so the allow does not overclaim (coord-2's review of #21951).

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

---------

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

* optchat-chief: auto-resume subagents that stop on a model or network error

A subagent run that ends on an API/harness error is classified
(auto_resume.rs): transient errors (overloaded, 429, 5xx, did not start)
are told to continue after a 30/60/120 s backoff, at most 3 times in a
row; network errors (connection lost, fetch failed, DNS) are not retried
blind: a thread waits until a TCP probe of the model endpoint (the
subrouter from ANTHROPIC_BASE_URL or ~/.claude/settings.json) answers,
then continues. The Chief's chat gets a quiet '[id] stopped: <reason>'
note; the subagent's chat shows each '[auto-resume N]' continue. A stop
auto-resume gives up on is reported as usual. OPTCHAT_AUTO_RESUME=off
turns it off.

* optchat-chief: auto-resume agent CLIs in cmux terminals; fix clone_on_copy

terminal_watch.rs: every 30 s the Chief host lists cmux terminals; a
Claude Code or Codex terminal that reports 'error', or sits idle at an
empty prompt with an API error as its last output, is classified as in
auto_resume.rs. Transient errors get '[auto-resume N] ... continue' typed
at the prompt after a backoff; network errors wait until the model
endpoint answers. Working, blocked (a question) or half-typed prompts are
never touched. Each event reaches the Chief chat as
'[term_...] stopped: <reason>' (a notice while a continue is planned, a
Chief note when it gives up). OPTCHAT_TERMINAL_RESUME=off turns it off.

Also: a short reply that only mentions an error is not a stop, and the
clippy clone_on_copy in workspaces.rs (a75b0c3) is fixed.

* optchat-chief: module order in lib.rs (rustfmt)

* fix(acpmux): clear stop timer on client close (#21615)

* Markdown: cmux:// workspace, pane, tab and chat links open in the app

A cmux:// link in rendered Markdown did nothing or left the app: the
Markdown file page classified every non-web scheme as unsafe, Home only
linked a Chief subagent's chat, and the agent pane drew only http(s).

- One opener, CmuxAppLinks (was ChiefSubagentLinks): a workspace, pane,
  tab or session link in the `cmux` scheme or this build's scheme, or this
  Chief's subagent link, runs link.open. Terminals and pages reach it via
  LinkRouter.appLink.
- Markdown file page: `cmux://...` is link kind "app" (hover: "Opens in
  cmux", 21 locales); cmux.markdown.openLink kind "app" opens it in the app
  or refuses, never the system.
- Home: URL.isCmuxAppLink draws and routes the same links to onAppLink.
- Agent chat: replies draw cmux app links; a click after a real gesture
  goes to the app opener, never NSWorkspace.
- javascript:, file:, data:, vbscript:, ssh: and malformed ids stay text.

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

* cmux-next palette: Go to Workspace (Cmd-P) searches groups, panes, tabs and agent sessions

Cmd-P now lists sidebar groups, panes and every tab (terminal, browser,
markdown, file, agent chat) next to the workspaces once you type, each row
with its kind and its parent workspace and group. Titles, cwd, URL, group
names and session ids are searchable; whole-title and prefix matches rank
first, then the recently used.

- Picking a group shows its first workspace, expanding the group when
  collapsed (WorkspaceGroupFocus, shared with Next/Previous Workspace Group).
- Picking a pane or tab shows its workspace and focuses it (pane.focus,
  revealTab as Search Tabs).
- Cmd-K in the palette shows the row's Actions menu; agent rows offer Copy
  Session ID: acp:<session id> for acpmux chats (what cmux agent message
  takes), the harness session UUID for Claude Code / Codex terminals.
  Handle format documented in skills/cmux-acpmux/SKILL.md.

* acpmux: require version evidence for already-current updates (#21398)

Replays #21398's change onto current feat-cmux-next as one commit.

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

* cx-dgsp follow-ups: scope-bound wire tickets, hold a refused feed token (#21725)

* test(api): the forwarded wire upgrade carries no credential

A native header upgrade with stray bearer.x and ticket.y subprotocols
reaches UserDO with no Authorization header and only cmux.wire.v1.
Green on the current strip; red when wireCredential keeps bearer. or
forwardHeaders keeps Authorization.

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

* test(api): a wire ticket opens only the scope it was minted for (red)

POST /v1/wire/ticket takes {scope}; a feed ticket must not open the user
socket, a refused try spends it, an unscoped ticket is a user ticket and
an unknown scope mints nothing. Fails now: the feed ticket opens
/v1/wire/user (101).

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

* test(cloud-client): openWire mints its ticket for the scope it opens (red)

Fails now: POST /v1/wire/ticket goes out with no body.

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

* fix(api): bind a wire ticket to the socket scope it was minted for

POST /v1/wire/ticket takes {scope} (user|team|feed|cloud|conv|mux; no
body or no scope means user, which the dashboard panel and any client
minted before this send). The ticket record keeps the scope; the router
entry still spends a ticket on any path, and wire() refuses one of
another scope with the usual 401. openWire and the dashboard's
wireCredential name their scope.

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

* test(cmux-next): a 401 on the feed wire holds the refused token (red)

CloudFeedSource takes an internal Connect seam and reconnect Backoff so
the loop runs against a fake; the socket session throws Unauthorized
when the upgrade's response is 401. The test fails now: the loop opens a
socket for every repeat of the refused token (a, a, a, b), not a then b.
Compile-only on this Linux host; it runs in CmuxNextAppTests on macOS.

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

* fix(cmux-next): stop reconnecting the feed wire with a token the server refused

A 401 on the upgrade fed the outer reconnect loop, which opened a socket
with the same token every 500 ms..30 s. The loop now remembers the
refused token, reports a disconnected reason once, and opens no socket
with it again: it asks the token provider on the Backoff schedule (no
request reaches the server) until it returns another token. start and
reset still restart the loop on a sign-in or account change.

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

* test(api): the expired-ticket test mints a feed ticket for the feed socket

With scope binding, an unscoped (user) ticket on /v1/wire/feed is refused
for its scope, so the test no longer reached the expiry check. Red when
WireTicketDO.spend ignores expires_at.

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

---------

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

* cmux-next: the Desktop Wallpaper tile shows the desktop, never a broken image

macOS can report a desktop picture that is gone (a deleted file in /tmp),
a folder it rotates through, or a .madesktop description. The Settings
thumbnail and the window backdrop loaded that URL as is, so the tile drew
the webview's broken-image mark and choosing it showed nothing.

DesktopPicture resolves the reported URL to a picture that decodes: the
file, a picture in the folder, the still a description names, or else a
picture of the desktop fill color. The picker swaps a thumbnail that fails
to load for an empty framed box.

* Home dock: pinned column kind (pinned-dock-v1)

Lawrence 2026-10-18: "I should not be able to close Home inside the Home
thing ... I should not be able to create more tabs in the Home thing
unless I explicitly enable it."

Daemon (cmux-tui): a dock column may be pinned. Its first tab stays (no
close, move out or reorder away from the first place) and it takes no
other tab unless its allow_tabs is on (column.update {allow_tabs}). The
column is never removed, undocked or unpinned. Enforced on every path
(resource ops, JSON-lines, layout undo, terminal tab creation before the
spawn) with reason_code dock-column-pinned. set-column-dock takes pinned;
column.update takes pinned and allow_tabs. Spec, docs, bindings updated.

App: Home pins its left chat dock on connect (page tab first). Home's tab
shows no close button, the strip no new-tab button while the column
takes no tabs, Cmd-W keeps Home's tab, new agent chats open beside a
pinned dock, and a refused close says "Home stays open in its column."

* cmux NEXT: compact attachment strip in the composer (#21739)

* test(acpmux): the attachment strip is compact

Leo 2026-10-18: pasted screenshots took ~100 px off the composer. One row of
64 px tiles 6 px apart, 8 px under the composer's top, the text 6 px under it.

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

* fix(acpmux): compact attachment strip, like the Claude desktop composer

64 px tiles (from 80), a 6 px gap, an 8 px top inset, and the prompt starts
6 px under the strip instead of 15. The strip adds about 78 px, not ~100.

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

* fix(acpmux): shell field follows the compact strip; tighten the gallery budget

Review: in shell mode under attachments the field and glyph kept the 15 px
inset, so typing ! moved the text 9 px. The attach-screenshot gallery budget
still allowed the old 96 px row.

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

* test(acpmux): wait for the thumbnails to load instead of decode()

CI: decode() rejected while a thumbnail's source was swapped for its copy.

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

---------

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

* cmux-next: the popup address field draws no focus ring (#21963)

fa8b3fc made the popup URL label selectable without focusRingType = .none, which turns check:text-focus red on every webviews job.

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

* composer: picking another provider's model keeps the typed prompt (#21937)

* test: a harness switch keeps the typed prompt (red)

* composer: picking another provider's model keeps the typed prompt through the harness switch

* composer: a chat's own saved draft wins over a carried prompt (review)

* fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ (#21870)

* test(acpmux): a running turn's empty prompt teaches Return and ⌘Return

Leo 2026-10-18: like Claude's "↵ to send, ⌘↵ to queue for later", the
empty prompt mid-turn says "↵ to queue, ⌘↵ to steer" (or interrupt, for an
agent that cannot steer). The Quick Composer keeps "Queue a follow-up".

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

* fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵

Mid-turn the empty prompt says "↵ to queue, ⌘↵ to steer" (or "to interrupt"
when the agent cannot take steering), as Claude's composer does. The Quick
Composer keeps "Queue a follow-up", since its ⌘↵ opens the window.

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

* test(acpmux): an attachment-only prompt mid-turn names only the queue key

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

* fix(acpmux): drop the ⌘↵ hint with only attachments, match the Steer button's verb

⌘Return needs typed text, so an attachment-only prompt mid-turn says only
"Queue a follow-up". The es, fr, it, ja, ko and uk hints now use the Steer
button's own verb.

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

* docs(acpmux): say when the queued placeholder still shows

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

---------

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

* acpmux: schema doc names peer masking and the lane error cut (#21924)

* docs(acpmux): the schema names peer masking and the lane error cut

The SessionSummary lane note still said every other field stays raw;
since #21871 a peer daemon reads them masked, and since #21799 the lane
error is cut to 3072 characters.

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

* docs(acpmux): raw for every client but a proven peer

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

---------

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

* cmux-next: every markdown viewer is read-write; Cmd-=/-/0 text size and a default size setting

Root cause: a markdown file opened by cmux open, an agent or a link (not the
user's own Open File...) was writable only inside a files.roots folder. The
roots setting is empty by default and never holds home, so viewers opened
from the Home workspace (and any workspace) came up read only with an
"outside the workspace" note.

- Markdown pages are writable for every document they show; only a real
  reason keeps one read only (not UTF-8, binary, not writable, or a chat
  transcript the host opens read only), and the page names the reason.
  The code editor keeps its root rule.
- The markdown page handles the zoomIn/zoomOut/zoomReset page commands the
  app already sent: one pixel per step (8-40) in rich and source mode,
  Cmd-0 back to markdown.font.size. Cmd-Shift-= is a Zoom In alias.
- Settings > Appearance > Markdown Viewer > Default Font Size
  (markdown.font.size, 16, 8-40), localized.

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

* fix(home): pasted pictures are small thumbnails in a row in the composer

The vendored MessagesLab compose strip copies macOS 27 Messages: every
attachment is a 177 x 118 pt tile stacked top to bottom above the text.
Two pasted screenshots made the field ~280 pt tall and pushed the text
line to the bottom. Images are now aspect-fit in 128 x 64 pt, files are
200 x 52 pt pills, and tiles flow left to right and wrap at the field's
right edge.

Tests: ComposeAttachmentLayoutTests (MessagesLabHome).

* test(home): qualify Attachment (Swift Testing has one too)

* cmux-next: page strings tables become build output (#21970)

* test(webviews): strings tables must not be tracked

Red on feat-cmux-next: every table gen-strings.mjs writes is committed, and
none is ignored (#21946).

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

* cmux-next: page strings tables become build output (#21946)

The generated strings tables (webviews/src/**/generated/strings.json, the diff
page's per-locale tables and loader, the home-channels pane table) are no longer
committed. bun install (postinstall, best effort), the webviews test preload
(only stale pages) and every bundle build (strict) write them from the
checkout's xcstrings catalogs and settings schema.

Committed copies conflicted in every pull request that changed a catalog or the
settings schema, and the PR autofix could rebuild one from a stale schema and
drop another branch's labels (#21746). A table made from the tree it sits in
can do neither.

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

* cmux-next: merge rules and atomic writes for every strings output (#21946)

The diff page's locale tables and loader and the home-channels pane table are
build output too: route them through cmux-generated-v1 and next_batch's
WEB_GENERATED, so a branch from before the change that edited one catches up
instead of stopping on a modify/delete conflict. gen-strings writes through a
temporary file (parallel test preloads), and --best-effort skips a page whose
catalog or schema is missing instead of failing bun install.

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

* chore(next): PR autofix at f2ef8f4

- regenerated schemas/settings-export/settings-schema.sources.sha256
- vp fmt webviews/scripts/pages/gen-strings.mjs
- vp fmt webviews/test/strings-build-output.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39205550635

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* cmux NEXT: a new terminal tab spawns at its pane's grid, so its first frame is final

The Mac's new-tab request sent no size. The daemon then spawned the PTY at
the grid of whichever terminal reported last, anywhere
(client_sizing_state.rs creation_size), the shell printed its first prompt
at that width, and the pane snapped when the view's first report resized it.

newTerminalTab now sends cols/rows (NewTerminalGrid): the fitted grid of the
terminal the pane shows (Ghostty's own fit of the same content host), else
the content host size, backing scale, a live terminal's cell size and the
configured padding through Ghostty's formula (TerminalGridEstimate; Cmd-T's
New Tab page, a page or agent tab). A zoomed terminal does not count. With
neither known the daemon's fallback applies as before.

docs/shared-terminal-sizing.md: a Creation size section (who sizes a new
terminal, and why a later attach never draws a wrong frame for others).

* cmux NEXT: NewTerminalGridTests builds its padding from the public default

* perf-10x daemon: request-latency bench (raw, 10 clients, CLI; 1 and 200 terminals)

* cmux-next: clear five base reds in the cmux-next checks lane (#21981)

The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left
five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks"
and its web lane skips its tests. Comments and baselines only, no behavior change:

- Main-thread concurrency: the harvest loop runs in a detached utility task and
  the flush delay in the ErrorJournal actor's task, so neither is on main;
  reviewed concurrency-allow and wakeup-allow comments.
- No literal state roots: the app's ~/.acpmux/daemon.log is only read; a
  keep row in the baseline.
- Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry).
- Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row.
- Text focus: the popup address field sets focusRingType = .none (was #21963).

Motion tokens (SidebarCardTransition) stays with #21951 for its owner.

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

* cx-ncc.104: Debug toggle for the agent pane's in-session status (agent.sessionStatus) (#20953)

Recut of #20953 onto the current feat-cmux-next as one commit: the
In-session status Debug toggle, its sessionStatus page event, and
useSessionStatus() for the plan and recap cards. The base merge kept
both sides of the tunables list, the view's observations and the page
host's events (the sidebar preview variant landed meanwhile).

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

* acpmux: route/list says which routes serve the session's family (#21852)

* test(acpmux): route/list names a session's family and which routes serve it

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

* feat(acpmux): route/list says which routes serve the session's family

With a sessionId, _acpmux/route/list now returns the session's family and a
serves flag on each route (Route::serves), so the composer's Account menu can
list only the routes that can run this chat without copying that logic.

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

---------

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

* cmux-next: tunable registries list one entry per line (#21972)

* cmux-next: tunable registries list one entry per line (#21946)

AgentPaneTunables.all and SidebarTunables.all were single lines, so every pull
request that added a tunable conflicted with every other one there (14 open
PRs on AgentPaneTunables, 4 on SidebarTunables). Each entry now has its own
line in alphabetical order, so two additions insert different lines and merge
cleanly; TunableCatalog.all lists one module per line. Debug Settings shows the
agent-pane and sidebar tunables alphabetically; nothing else depends on the
order.

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

* Keep the TunableCatalog list as it was: CmuxNextApp may not grow

The one-per-line TunableCatalog added 20 source lines to CmuxNextApp, which
check-app-size.sh refuses. The conflict hotspots are the AgentPaneTunables and
SidebarTunables lists, which live in their own targets and stay one per line.

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

---------

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

* test(next): cover dictation auto-send prompt routing (#21169)

* test(next): cover dictation auto-send prompt routing

* fix(next): satisfy dictation test formatting

* chore(next): PR autofix at 60f4a49

- regenerated Packages/macOS/CmuxNext/ci-target-graph.json
- vp fmt webviews/src/agent-session/acpmux/replyHref.ts
- vp fmt webviews/src/pages/markdown/README.md
- vp fmt webviews/src/pages/markdown/links.ts
- vp fmt webviews/test/markdown-cmux-app-links.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39212288176

* chore: drop the autofix bot's unrelated markdown-link and target-graph edits from this PR

They aren't part of this change; base carries its own version.

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

* fix(agent pane): a pressed pill keeps the pill's own open tone

The model, effort and access pills open at --acpmux-pill-hover; under the
press marker alone they drew the brighter --acpmux-pill-open.

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

* test(ui): window blur, Escape and a drag-out release clear the press marker (red)

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

* fix(ui): the press marker clears on window blur, Escape and unmount

A press whose pointerup never reaches the page (Cmd-Tab away, Escape)
left the pill tinted. The plain footer's resting and hover rules also
exclude the marker, so it can't flash there.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: Lucas Ribeiro <lucascamribeiro@gmail.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
teamleaderleo added a commit that referenced this pull request Oct 19, 2026
…and renamed lanes; route web like ci.yml

- The fast gate's poll reads baseRefName and refuses a base other than the
  one the gate was chosen for. Both gates re-read head, base and state right
  before gh pr merge (--match-head-commit pins only the head); this replaces
  the --override path's own head re-check.
- A cancelled, timed-out, startup-failed or stale fast lane refuses, even with
  --override: it has no verdict to waive.
- A check reported under a raw expression name (#21981's Debug compile) is the
  lane its quoted name names, so a queued one is waited for.
- gh-merge-green reads cmux-next.yml, ci.yml and ci-web.yml on the exact head;
  merge_fast_gate.py refuses when a lane it waits for (routing, fast tier,
  Swift canary, Debug compile, a lint job, web / react-apps-check) is no longer
  a job name there. An unreadable workflow refuses.
- react-apps-check is waited for when detect_ci_change_areas.py (this
  checkout's copy) routes a file to web, or the web caller job is running.

Green: test_merge_fast_gate (19), test_gh_merge_green (121).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 19, 2026
… the full wait (no bead) (#20566)

* test(gh-merge-green): feat-cmux-next merges on a fast gate; --full keeps the full wait

Failing tests first: the default feat-cmux-next merge waits only for routing,
the fast tier and the touched compiles on the exact head, refuses completed
reds in the fast lanes and gating families, gives up at --wait, and prints one
summary line; --full keeps the wait for every check.

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

* feat(gh-merge-green): fast gate by default for feat-cmux-next, --full for the old wait

Waiting for every check slowed feat-cmux-next iteration. Into feat-cmux-next
the helper now waits only for path routing, the fast tier and the touched
compiles on the exact head (scripts/ci/merge_fast_gate.py, one GraphQL read per
poll), refuses completed reds there and in the web, size, crash and lint
families, and keeps the conflict-marker and freeze checks. --full keeps the
full wait; main and every other base always get it. One summary line at exit.

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

* test(gh-merge-green): fast gate rerun order, web caller, one summary line, override and excuse

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

* fix(gh-merge-green): newest rerun by start time, stop waiting on a finished web caller, summary on early refusals

merge_fast_gate.py picks the CheckRun with the latest startedAt (then completedAt,
then list order) instead of trusting rollup order, and a webviews change stops
waiting for react-apps-check once the caller job "web" finished (a red caller is
a red). gh-merge-green sets its summary trap right after the PR reference is
parsed, so early refusals print one line with an unknown gate, and the trap
removes the fast gate's temp files on refusal or Ctrl-C.

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

* fix(gh-merge-green): pass - to paste in the fast gate's red summaries

BSD paste on macOS needs a file operand; without one the fast gate printed
an empty red list. tests.test_gh_merge_green's fast-gate override and
lint-refusal tests failed on macOS before this.

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

* test(gh-merge-green): the fast gate must wait for risk evidence and refuse a red one

Fails now: merge_fast_gate.py ignores risk evidence, so a pending or red
check passes the fast gate that main's full gate refuses (#21692).

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

* fix(gh-merge-green): the fast gate waits for risk evidence and refuses a red one

Main's full gate never waives a pending or red risk evidence check
(#21692); the fast gate ignored it. It now waits for it like a fast lane
and refuses a red one before any --override or base-red excuse.

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

* test(gh-merge-green): a red lint check the base shares must still refuse on the fast gate

Fails now: the fast gate hands lint reds to base_red_excuse.py, so a
god-file, l10n or concurrency red merges when the base is red too. The
full gate never waives them.

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

* fix(gh-merge-green): the fast gate never base-excuses a red lint check

Main's full gate refuses a red god-file, l10n or concurrency check with or
without --override, because lint fails only on the change itself. The fast
gate now refuses it the same way before trying the base-red excuse.

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

* test(gh-merge-green): the fast gate waits for lint, judges finished full-gate lanes, keeps the GraphQL files fallback

Red on this commit: test_merge_fast_gate fails 2 of 12 (pending lint is not
waited for, red lint and full-gate lane reds are not reported), and
test_gh_merge_green fails 3 new tests (5 subtests). test_main_keeps_the_full_wait_without_full
passes: main already keeps the full wait.

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

* fix(gh-merge-green): fast gate waits for lint, judges finished full-gate lanes, keeps the GraphQL files fallback

- merge_fast_gate.py waits for a pending god-file, l10n or concurrency check
  and refuses a red one outright, as main's full gate does (#21692); the bash
  side's duplicate lint refusal is gone.
- A completed red ci-status, Release compile or swift test is judged as the
  full gate judges it (base-red excuse or --override); a pending one does not
  block.
- The GitHub readers with GraphQL and Git fallbacks (#21529) move out of
  full_gate, so the fast gate's file listing, the conflict-marker read and the
  freeze check keep them.
- --help names --full and --wait.

Green: test_merge_fast_gate (12), test_gh_merge_green (117).

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

* test(gh-merge-green): base retarget, no-verdict lanes, renamed lanes and web routing on the fast gate

Red on this commit: test_gh_merge_green fails 4 new tests (6 subtests): a
base retargeted during the fast wait or before the merge (both gates), a
cancelled or timed-out fast lane waived by --override, and a renamed lint
job. test_merge_fast_gate errors in every test that calls run(), which
does not take base= yet, and in the new missing_job_names tests.

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

* fix(gh-merge-green): refuse a retargeted base, no-verdict fast lanes and renamed lanes; route web like ci.yml

- The fast gate's poll reads baseRefName and refuses a base other than the
  one the gate was chosen for. Both gates re-read head, base and state right
  before gh pr merge (--match-head-commit pins only the head); this replaces
  the --override path's own head re-check.
- A cancelled, timed-out, startup-failed or stale fast lane refuses, even with
  --override: it has no verdict to waive.
- A check reported under a raw expression name (#21981's Debug compile) is the
  lane its quoted name names, so a queued one is waited for.
- gh-merge-green reads cmux-next.yml, ci.yml and ci-web.yml on the exact head;
  merge_fast_gate.py refuses when a lane it waits for (routing, fast tier,
  Swift canary, Debug compile, a lint job, web / react-apps-check) is no longer
  a job name there. An unreadable workflow refuses.
- react-apps-check is waited for when detect_ci_change_areas.py (this
  checkout's copy) routes a file to web, or the web caller job is running.

Green: test_merge_fast_gate (19), test_gh_merge_green (121).

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

* test(gh-merge-green): the fast gate still refuses a frozen path; main without --full checks freezes

The fast gate shortens the wait for checks, never the merge-freeze check
from #21957. Verified by mutation: skipping merge_freeze.py on the fast
gate fails test_the_fast_gate_still_refuses_a_frozen_path.

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

* test(gh-merge-green): fast gate refuses untrusted forks and a skipped fast tier; routes web from the full file list

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

* fix(gh-merge-green): fast gate refuses untrusted forks and a skipped fast tier; routes web from the full file list

The fast path skipped merged_head_checks, which held the untrusted-fork
refusal, so a fork PR into feat-cmux-next merged on the fast lanes. A
skipped fast tier (push-head-preflight not current) counted as a pass.
Web routing read gh pr view --json files, which stops at 100 files.

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

* test(gh-merge-green): fast gate reads the paths filter from the base, refuses forks first, and runs merged-tree checks on gate paths

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

* fix(gh-merge-green): fast gate reads the paths filter from the base, refuses forks first, runs merged-tree checks on gate paths

- The routing wait follows the base's cmux-next.yml paths filter, so a PR
  can't drop its own files from the filter to skip the wait.
- The untrusted-fork refusal moves to the gate selection, before any read
  or wait.
- A PR touching a path in scripts/ci/merge-fast-gate-protected-paths.txt
  (read from the base; workflows, scripts/ci, gh-merge-green) gets the
  merged-tree checks back on the fast gate (leoli-f6, 2026-10-19).

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

* test(gh-merge-green): a web file past the first 100 changed files waits for react-apps-check, through the helper

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
* feat(agent-pane): accept new tab inline suggestions safely

* fix(agent-pane): complete visited URL suggestions

* test(new-tab): Tab without a highlighted row moves focus; history rows are not inline-accepted

Red: Tab is prevented whenever suggestions show, and Right/End inline-accepts
history rows.

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

* fix(new-tab): Tab steps only a keyboard-highlighted row; inline completion skips history rows

Tab is taken only after Down/Up/Tab moved the highlight, so keyboard users can
Tab to Send. Right/End inline-accept only top-row open results (typed address
or top site), matching the comment that history rows stay explicit picks.

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

* guards: drop the pull_request_target publish case removed with publish-pr-tree

17bb49c deleted the dead publish-pr-tree job, so release-notary's
'pull_request_target refs/heads/feat-cmux-next publishes once' cases failed
5 times (run 39205353024).

* ci(cmux-next media): rebuild a warm tour's prebuilt modules after a binary pin change (#21971)

* test(ci): a warm tour must rebuild after a GhosttyNextKit pin change

The cmux-next tour keeps each tag's DerivedData warm, and Xcode reused the
explicit module it had precompiled from the old pin's ghostty.h: "ghostty.h
has been modified since the module file ... was built" (job 117892119256).
This regression runs the tour's build step twice with a stand-in reload.sh
that fails the same way; it fails until the fix lands.

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

* fix(ci): drop a warm tour's prebuilt modules when a binary pin changes

A Mac that last built a pull request's tag with GhosttyNextKit e6a27a1fb
failed the next tour, which pinned ced99dcde: Xcode copied the new ghostty.h
into Build/Products/Debug/include but kept the explicit module it had
precompiled from the old one (job 117892119256).

scripts/ci/media_module_cache_stamp.py keys a tag's build on every sha256 in
the tracked Package.swift files and every Package.resolved. Before reload.sh
it removes SwiftExplicitPrecompiledModules, ExplicitPrecompiledModules and
ModuleCache.noindex when that key differs from the stamp of the tag's last
good build; after the build it writes the stamp. The rest of DerivedData
stays warm.

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

---------

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

* gallery advisory: sample the states a PR adds first (#21850)

* gallery advisory: sample the states a PR adds first

A PR that touches a shared file (strings, App.tsx) touches every gallery
entry, so the first 16 states in order came from unrelated entries and the
receipt never showed what the PR added. The manifests now list every touched
state and the sample puts the new ones (no base case with that id) first.

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

* gallery advisory: the base keeps every sampled state before removed ones

The base filter cut at 16 in base order, so removed states early in that
order could push out sampled states that exist in base, which were then
compared as new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0283a51)

* gallery advisory: each stage renders its own manifest

Both stages rendered the joined case list, so the base reported the states a
PR adds as not ready (it has no such variant) and the capture stopped before
the head ran. Now that new states come first, every PR that adds a variant
hit this (#21851's first run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5b6d825)

---------

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

* docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback (#21958)

* docs(CLAUDE.md): merge freezes are issues; drop the WINDOW fallback

The guarded fallback for when gh-merge-green couldn't read the coordinator's
WINDOW no longer applies: freezes are merge-freeze issues that every host
reads through the GitHub API (#21957).

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

* docs(merge-freeze): gh-merge-green enforces the freeze check

Same line as #21957 on main.

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

---------

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

* apps: preserve provider mutation context for owner handlers (#21406)

Replays #21406's change onto current feat-cmux-next as one commit.

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

* test(sidebar): a dragged group drops between every group

Regression test for scrawl-1792382497882-1673e-10: on the sidebar
document path a dragged group found a drop only on the thin bands of
each group header. Fails without the fix.

* fix(sidebar): fluid group drag, a drop at every gap between groups

- SidebarDragGeometry: a drop that cannot go into a group (a dragged
  group, groups do not nest) goes before or after the whole group, by
  the half of its block the probe is in, over its header or any member
  row. Before, every member row refused and the gap closed.
- A dragged group's header, not the tall card's centre, decides the drop.
- A refused place keeps the last open gap instead of springing it shut
  and dimming the card, so rows stop jumping during the drag.

* test(layout): a divider drag keeps one daemon command in flight

Adds GestureCommandCoalescer and its tests: 125 live values while one
command is in flight send the first and the newest only; the ended value
goes last; a failed live value with a newer one waiting is superseded.

* fix(layout): stop flooding the daemon during divider and column drags

NIGHTLY sent one set-viewport-pane-width per mouse move (~125/s); each
timed out at 2 s and every other command (pane and tab moves, saves,
attaches) timed out behind them. Divider and column gestures now go
through GestureCommandCoalescer: one command in flight per gesture, only
the newest value waits, the ended value always goes last. A failed live
value with a newer one waiting no longer rolls the divider back.

* scripts(cmux-next): drag-lag-live.py, column/tab/sidebar drag timing on a fleet app

* scripts(cmux-next): drag-lag-live probes the daemon during drags, bigger scene

* ci(nightly-next): one-command rollback of the cmux NEXT feed (#21887)

* ci(nightly-next): one-command rollback of the cmux NEXT feed

nightly-next-rollback.yml takes a bad build, and every newer one, off
appcast-arm64.xml so the feed serves the previous signed build again. It
runs in release-next on branch nightly-next, guards the appcast and R2 key
like publish-nightly, checks the fallback DMG exists, refuses to empty the
feed, and stops when the feed changed while it planned.

docs/ci/nightly-next-canary.md maps the nightly pipeline and its holds and
says what a pull can and cannot do: Sparkle never offers a lower build.

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

* ci(nightly): the delta lane never puts a pulled build back on the feed

republish-nightly-deltas skipped its rewrite only when the live NEXT feed
served a newer build. After nightly-next-rollback.yml pulls build N, the
feed serves N-1 and the lane's two-item appcast would restore N. It now
skips whenever the feed serves any other build. The regression cases in
test_nightly_republish_delta_guard.py fail on the old guard.

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

* ci(nightly-next): rollback runs-on keeps a fork branch

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

* ci(nightly-next): the rollback writes the feed only with If-Match

upload-r2-object.py --replace-sha256 HEX reads the object, requires the
bytes the caller planned from, and writes with If-Match on its ETag; a
changed object is not written (--conflict-exit-code). The rollback uses it
instead of a public re-read, so a publication that lands between the plan
and the write is never overwritten. Its summary no longer says "nothing
to pull" when the plan itself failed. (CodeRabbit on #21900.)

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

---------

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

* cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions (#21951)

* cmux-next: mark the sidebar card's Core Animation objects as reviewed motion exceptions

c5a1f90 built the update card's entrance, exit and crossfade from raw
CABasicAnimation, CASpringAnimation, CATransition and CAMediaTimingFunction, so
check-motion is red on feat-cmux-next (9 hits). Every duration and spring
already comes from the injected MotionPolicy's tokens; Motion.set would write
the model value and read the global policy instead. The 9 lines carry a
motion-allow and the type doc says why. Comments only.

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

* cmux-next: the sidebar card's motion-allow note names what stays literal

The curves and the spring's settle tolerance are literal, not tokens; say so,
so the allow does not overclaim (coord-2's review of #21951).

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

---------

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

* optchat-chief: auto-resume subagents that stop on a model or network error

A subagent run that ends on an API/harness error is classified
(auto_resume.rs): transient errors (overloaded, 429, 5xx, did not start)
are told to continue after a 30/60/120 s backoff, at most 3 times in a
row; network errors (connection lost, fetch failed, DNS) are not retried
blind: a thread waits until a TCP probe of the model endpoint (the
subrouter from ANTHROPIC_BASE_URL or ~/.claude/settings.json) answers,
then continues. The Chief's chat gets a quiet '[id] stopped: <reason>'
note; the subagent's chat shows each '[auto-resume N]' continue. A stop
auto-resume gives up on is reported as usual. OPTCHAT_AUTO_RESUME=off
turns it off.

* optchat-chief: auto-resume agent CLIs in cmux terminals; fix clone_on_copy

terminal_watch.rs: every 30 s the Chief host lists cmux terminals; a
Claude Code or Codex terminal that reports 'error', or sits idle at an
empty prompt with an API error as its last output, is classified as in
auto_resume.rs. Transient errors get '[auto-resume N] ... continue' typed
at the prompt after a backoff; network errors wait until the model
endpoint answers. Working, blocked (a question) or half-typed prompts are
never touched. Each event reaches the Chief chat as
'[term_...] stopped: <reason>' (a notice while a continue is planned, a
Chief note when it gives up). OPTCHAT_TERMINAL_RESUME=off turns it off.

Also: a short reply that only mentions an error is not a stop, and the
clippy clone_on_copy in workspaces.rs (a75b0c3) is fixed.

* optchat-chief: module order in lib.rs (rustfmt)

* test(new-tab): a visited page completes inline on Right and opens nothing (red)

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

* fix(new-tab): a visited page completes inline again

The Tab fix also dropped history rows from inline completion to match an
older comment, undoing 1d8f0db. Accepting a completion only fills the field
on an explicit Right or End, and Enter or Send still opens it, so a visited
page completes as in Chrome. The comment now says so.

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

* fix(acpmux): clear stop timer on client close (#21615)

* Markdown: cmux:// workspace, pane, tab and chat links open in the app

A cmux:// link in rendered Markdown did nothing or left the app: the
Markdown file page classified every non-web scheme as unsafe, Home only
linked a Chief subagent's chat, and the agent pane drew only http(s).

- One opener, CmuxAppLinks (was ChiefSubagentLinks): a workspace, pane,
  tab or session link in the `cmux` scheme or this build's scheme, or this
  Chief's subagent link, runs link.open. Terminals and pages reach it via
  LinkRouter.appLink.
- Markdown file page: `cmux://...` is link kind "app" (hover: "Opens in
  cmux", 21 locales); cmux.markdown.openLink kind "app" opens it in the app
  or refuses, never the system.
- Home: URL.isCmuxAppLink draws and routes the same links to onAppLink.
- Agent chat: replies draw cmux app links; a click after a real gesture
  goes to the app opener, never NSWorkspace.
- javascript:, file:, data:, vbscript:, ssh: and malformed ids stay text.

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

* cmux-next palette: Go to Workspace (Cmd-P) searches groups, panes, tabs and agent sessions

Cmd-P now lists sidebar groups, panes and every tab (terminal, browser,
markdown, file, agent chat) next to the workspaces once you type, each row
with its kind and its parent workspace and group. Titles, cwd, URL, group
names and session ids are searchable; whole-title and prefix matches rank
first, then the recently used.

- Picking a group shows its first workspace, expanding the group when
  collapsed (WorkspaceGroupFocus, shared with Next/Previous Workspace Group).
- Picking a pane or tab shows its workspace and focuses it (pane.focus,
  revealTab as Search Tabs).
- Cmd-K in the palette shows the row's Actions menu; agent rows offer Copy
  Session ID: acp:<session id> for acpmux chats (what cmux agent message
  takes), the harness session UUID for Claude Code / Codex terminals.
  Handle format documented in skills/cmux-acpmux/SKILL.md.

* acpmux: require version evidence for already-current updates (#21398)

Replays #21398's change onto current feat-cmux-next as one commit.

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

* cx-dgsp follow-ups: scope-bound wire tickets, hold a refused feed token (#21725)

* test(api): the forwarded wire upgrade carries no credential

A native header upgrade with stray bearer.x and ticket.y subprotocols
reaches UserDO with no Authorization header and only cmux.wire.v1.
Green on the current strip; red when wireCredential keeps bearer. or
forwardHeaders keeps Authorization.

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

* test(api): a wire ticket opens only the scope it was minted for (red)

POST /v1/wire/ticket takes {scope}; a feed ticket must not open the user
socket, a refused try spends it, an unscoped ticket is a user ticket and
an unknown scope mints nothing. Fails now: the feed ticket opens
/v1/wire/user (101).

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

* test(cloud-client): openWire mints its ticket for the scope it opens (red)

Fails now: POST /v1/wire/ticket goes out with no body.

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

* fix(api): bind a wire ticket to the socket scope it was minted for

POST /v1/wire/ticket takes {scope} (user|team|feed|cloud|conv|mux; no
body or no scope means user, which the dashboard panel and any client
minted before this send). The ticket record keeps the scope; the router
entry still spends a ticket on any path, and wire() refuses one of
another scope with the usual 401. openWire and the dashboard's
wireCredential name their scope.

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

* test(cmux-next): a 401 on the feed wire holds the refused token (red)

CloudFeedSource takes an internal Connect seam and reconnect Backoff so
the loop runs against a fake; the socket session throws Unauthorized
when the upgrade's response is 401. The test fails now: the loop opens a
socket for every repeat of the refused token (a, a, a, b), not a then b.
Compile-only on this Linux host; it runs in CmuxNextAppTests on macOS.

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

* fix(cmux-next): stop reconnecting the feed wire with a token the server refused

A 401 on the upgrade fed the outer reconnect loop, which opened a socket
with the same token every 500 ms..30 s. The loop now remembers the
refused token, reports a disconnected reason once, and opens no socket
with it again: it asks the token provider on the Backoff schedule (no
request reaches the server) until it returns another token. start and
reset still restart the loop on a sign-in or account change.

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

* test(api): the expired-ticket test mints a feed ticket for the feed socket

With scope binding, an unscoped (user) ticket on /v1/wire/feed is refused
for its scope, so the test no longer reached the expiry check. Red when
WireTicketDO.spend ignores expires_at.

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

---------

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

* cmux-next: the Desktop Wallpaper tile shows the desktop, never a broken image

macOS can report a desktop picture that is gone (a deleted file in /tmp),
a folder it rotates through, or a .madesktop description. The Settings
thumbnail and the window backdrop loaded that URL as is, so the tile drew
the webview's broken-image mark and choosing it showed nothing.

DesktopPicture resolves the reported URL to a picture that decodes: the
file, a picture in the folder, the still a description names, or else a
picture of the desktop fill color. The picker swaps a thumbnail that fails
to load for an empty framed box.

* Home dock: pinned column kind (pinned-dock-v1)

Lawrence 2026-10-18: "I should not be able to close Home inside the Home
thing ... I should not be able to create more tabs in the Home thing
unless I explicitly enable it."

Daemon (cmux-tui): a dock column may be pinned. Its first tab stays (no
close, move out or reorder away from the first place) and it takes no
other tab unless its allow_tabs is on (column.update {allow_tabs}). The
column is never removed, undocked or unpinned. Enforced on every path
(resource ops, JSON-lines, layout undo, terminal tab creation before the
spawn) with reason_code dock-column-pinned. set-column-dock takes pinned;
column.update takes pinned and allow_tabs. Spec, docs, bindings updated.

App: Home pins its left chat dock on connect (page tab first). Home's tab
shows no close button, the strip no new-tab button while the column
takes no tabs, Cmd-W keeps Home's tab, new agent chats open beside a
pinned dock, and a refused close says "Home stays open in its column."

* cmux NEXT: compact attachment strip in the composer (#21739)

* test(acpmux): the attachment strip is compact

Leo 2026-10-18: pasted screenshots took ~100 px off the composer. One row of
64 px tiles 6 px apart, 8 px under the composer's top, the text 6 px under it.

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

* fix(acpmux): compact attachment strip, like the Claude desktop composer

64 px tiles (from 80), a 6 px gap, an 8 px top inset, and the prompt starts
6 px under the strip instead of 15. The strip adds about 78 px, not ~100.

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

* fix(acpmux): shell field follows the compact strip; tighten the gallery budget

Review: in shell mode under attachments the field and glyph kept the 15 px
inset, so typing ! moved the text 9 px. The attach-screenshot gallery budget
still allowed the old 96 px row.

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

* test(acpmux): wait for the thumbnails to load instead of decode()

CI: decode() rejected while a thumbnail's source was swapped for its copy.

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

---------

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

* cmux-next: the popup address field draws no focus ring (#21963)

fa8b3fc made the popup URL label selectable without focusRingType = .none, which turns check:text-focus red on every webviews job.

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

* composer: picking another provider's model keeps the typed prompt (#21937)

* test: a harness switch keeps the typed prompt (red)

* composer: picking another provider's model keeps the typed prompt through the harness switch

* composer: a chat's own saved draft wins over a carried prompt (review)

* fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵ (#21870)

* test(acpmux): a running turn's empty prompt teaches Return and ⌘Return

Leo 2026-10-18: like Claude's "↵ to send, ⌘↵ to queue for later", the
empty prompt mid-turn says "↵ to queue, ⌘↵ to steer" (or interrupt, for an
agent that cannot steer). The Quick Composer keeps "Queue a follow-up".

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

* fix(acpmux): the empty prompt mid-turn teaches ↵ and ⌘↵

Mid-turn the empty prompt says "↵ to queue, ⌘↵ to steer" (or "to interrupt"
when the agent cannot take steering), as Claude's composer does. The Quick
Composer keeps "Queue a follow-up", since its ⌘↵ opens the window.

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

* test(acpmux): an attachment-only prompt mid-turn names only the queue key

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

* fix(acpmux): drop the ⌘↵ hint with only attachments, match the Steer button's verb

⌘Return needs typed text, so an attachment-only prompt mid-turn says only
"Queue a follow-up". The es, fr, it, ja, ko and uk hints now use the Steer
button's own verb.

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

* docs(acpmux): say when the queued placeholder still shows

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

---------

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

* acpmux: schema doc names peer masking and the lane error cut (#21924)

* docs(acpmux): the schema names peer masking and the lane error cut

The SessionSummary lane note still said every other field stays raw;
since #21871 a peer daemon reads them masked, and since #21799 the lane
error is cut to 3072 characters.

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

* docs(acpmux): raw for every client but a proven peer

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

---------

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

* cmux-next: every markdown viewer is read-write; Cmd-=/-/0 text size and a default size setting

Root cause: a markdown file opened by cmux open, an agent or a link (not the
user's own Open File...) was writable only inside a files.roots folder. The
roots setting is empty by default and never holds home, so viewers opened
from the Home workspace (and any workspace) came up read only with an
"outside the workspace" note.

- Markdown pages are writable for every document they show; only a real
  reason keeps one read only (not UTF-8, binary, not writable, or a chat
  transcript the host opens read only), and the page names the reason.
  The code editor keeps its root rule.
- The markdown page handles the zoomIn/zoomOut/zoomReset page commands the
  app already sent: one pixel per step (8-40) in rich and source mode,
  Cmd-0 back to markdown.font.size. Cmd-Shift-= is a Zoom In alias.
- Settings > Appearance > Markdown Viewer > Default Font Size
  (markdown.font.size, 16, 8-40), localized.

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

* fix(home): pasted pictures are small thumbnails in a row in the composer

The vendored MessagesLab compose strip copies macOS 27 Messages: every
attachment is a 177 x 118 pt tile stacked top to bottom above the text.
Two pasted screenshots made the field ~280 pt tall and pushed the text
line to the bottom. Images are now aspect-fit in 128 x 64 pt, files are
200 x 52 pt pills, and tiles flow left to right and wrap at the field's
right edge.

Tests: ComposeAttachmentLayoutTests (MessagesLabHome).

* test(home): qualify Attachment (Swift Testing has one too)

* cmux-next: page strings tables become build output (#21970)

* test(webviews): strings tables must not be tracked

Red on feat-cmux-next: every table gen-strings.mjs writes is committed, and
none is ignored (#21946).

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

* cmux-next: page strings tables become build output (#21946)

The generated strings tables (webviews/src/**/generated/strings.json, the diff
page's per-locale tables and loader, the home-channels pane table) are no longer
committed. bun install (postinstall, best effort), the webviews test preload
(only stale pages) and every bundle build (strict) write them from the
checkout's xcstrings catalogs and settings schema.

Committed copies conflicted in every pull request that changed a catalog or the
settings schema, and the PR autofix could rebuild one from a stale schema and
drop another branch's labels (#21746). A table made from the tree it sits in
can do neither.

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

* cmux-next: merge rules and atomic writes for every strings output (#21946)

The diff page's locale tables and loader and the home-channels pane table are
build output too: route them through cmux-generated-v1 and next_batch's
WEB_GENERATED, so a branch from before the change that edited one catches up
instead of stopping on a modify/delete conflict. gen-strings writes through a
temporary file (parallel test preloads), and --best-effort skips a page whose
catalog or schema is missing instead of failing bun install.

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

* chore(next): PR autofix at f2ef8f4

- regenerated schemas/settings-export/settings-schema.sources.sha256
- vp fmt webviews/scripts/pages/gen-strings.mjs
- vp fmt webviews/test/strings-build-output.test.ts

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39205550635

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>

* cmux NEXT: a new terminal tab spawns at its pane's grid, so its first frame is final

The Mac's new-tab request sent no size. The daemon then spawned the PTY at
the grid of whichever terminal reported last, anywhere
(client_sizing_state.rs creation_size), the shell printed its first prompt
at that width, and the pane snapped when the view's first report resized it.

newTerminalTab now sends cols/rows (NewTerminalGrid): the fitted grid of the
terminal the pane shows (Ghostty's own fit of the same content host), else
the content host size, backing scale, a live terminal's cell size and the
configured padding through Ghostty's formula (TerminalGridEstimate; Cmd-T's
New Tab page, a page or agent tab). A zoomed terminal does not count. With
neither known the daemon's fallback applies as before.

docs/shared-terminal-sizing.md: a Creation size section (who sizes a new
terminal, and why a later attach never draws a wrong frame for others).

* cmux NEXT: NewTerminalGridTests builds its padding from the public default

* perf-10x daemon: request-latency bench (raw, 10 clients, CLI; 1 and 200 terminals)

* cmux-next: clear five base reds in the cmux-next checks lane (#21981)

The ErrorJournal (1597dc9) and browser popup (fa8b3fc) commits left
five checks red on feat-cmux-next, so every PR into it fails "cmux-next checks"
and its web lane skips its tests. Comments and baselines only, no behavior change:

- Main-thread concurrency: the harvest loop runs in a detached utility task and
  the flush delay in the ErrorJournal actor's task, so neither is on main;
  reviewed concurrency-allow and wakeup-allow comments.
- No literal state roots: the app's ~/.acpmux/daemon.log is only read; a
  keep row in the baseline.
- Package conventions: lint:allow on BrowserPopupWindowGeometry (pure geometry).
- Type scale: BrowserPopupPanel.swift has no raw font sizes left; drop its row.
- Text focus: the popup address field sets focusRingType = .none (was #21963).

Motion tokens (SidebarCardTransition) stays with #21951 for its owner.

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

* cx-ncc.104: Debug toggle for the agent pane's in-session status (agent.sessionStatus) (#20953)

Recut of #20953 onto the current feat-cmux-next as one commit: the
In-session status Debug toggle, its sessionStatus page event, and
useSessionStatus() for the plan and recap cards. The base merge kept
both sides of the tunables list, the view's observations and the page
host's events (the sidebar preview variant landed meanwhile).

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

* acpmux: route/list says which routes serve the session's family (#21852)

* test(acpmux): route/list names a session's family and which routes serve it

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

* feat(acpmux): route/list says which routes serve the session's family

With a sessionId, _acpmux/route/list now returns the session's family and a
serves flag on each route (Route::serves), so the composer's Account menu can
list only the routes that can run this chat without copying that logic.

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

---------

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

* cmux-next: tunable registries list one entry per line (#21972)

* cmux-next: tunable registries list one entry per line (#21946)

AgentPaneTunables.all and SidebarTunables.all were single lines, so every pull
request that added a tunable conflicted with every other one there (14 open
PRs on AgentPaneTunables, 4 on SidebarTunables). Each entry now has its own
line in alphabetical order, so two additions insert different lines and merge
cleanly; TunableCatalog.all lists one module per line. Debug Settings shows the
agent-pane and sidebar tunables alphabetically; nothing else depends on the
order.

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

* Keep the TunableCatalog list as it was: CmuxNextApp may not grow

The one-per-line TunableCatalog added 20 source lines to CmuxNextApp, which
check-app-size.sh refuses. The conflict hotspots are the AgentPaneTunables and
SidebarTunables lists, which live in their own targets and stay one per line.

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

---------

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

* test(next): cover dictation auto-send prompt routing (#21169)

* test(next): cover dictation auto-send prompt routing

* fix(next): satisfy dictation test formatting

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: Lucas Ribeiro <lucascamribeiro@gmail.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
… a DemandTimer (drops #21981's allowlist entries) (#22021)

* test(cmux-next): the error journal's literal acpmux root and flush sleep leave the guard allowlists

Drops the state-roots baseline row and the concurrency/wakeup allow comments
that #21981 added for the error journal, so check-state-roots and
check-concurrency fail until the code asks the build's resolver and uses a
DemandTimer.

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

* fix(cmux-next): the error journal reads the build's acpmux home and flushes on a DemandTimer

The app's own acpmux log path now comes from BuildIdentity.acpmuxHome, the
home AcpmuxEnvironment starts the daemon in (NIGHTLY's ~/.acpmux, any other
build's ~/.acpmux/builds/<key>), instead of a literal ~/.acpmux that missed
dev builds. The batched write uses a DemandTimer deadline (not pushed back
by new records, cancelled by flush()) instead of a raw Task sleep, so both
guards pass without allowlist entries. Regenerates ci-target-graph.json for
the new CmuxNextWakeups dependency (it was also missing
CmuxNextTerminalGeometry on the base).

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

* fix(cmux-next): the error journal compiles its literal patterns without try!

check-crash-safety fails on the base for eight try! NSRegularExpression
sites in CmuxNextErrorJournal. They now use try? like FeedSecretScrubber:
the parser and normalizer skip a pattern that fails to compile, and the
redactor fails closed (returns <redacted>) if any of its rules is missing,
so a secret can never pass through unredacted. Also refreshes
ci-target-graph.json against the current base.

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

* chore(next): PR autofix at c7b2672

- Packages/macOS/CmuxNext/ci-target-graph.json
- schemas/defaults/cmux-next.json

Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/39357070458

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.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