Skip to content

cmux NEXT Home: search finds message text and lists matching messages, as in Messages - #28532

Open
austinywang wants to merge 8 commits into
feat-cmux-nextfrom
feat-cmux-next-27950-chief-search
Open

austinywang wants to merge 8 commits into
feat-cmux-nextfrom
feat-cmux-next-27950-chief-search

Conversation

@austinywang

@austinywang austinywang commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #27950

Changelog

Changed: searching the Home (Chief) list now also finds messages whose text matches, under a Messages section with the conversation, the matching text and its time, as in Messages. Choosing one opens the conversation at that message.

What was wrong

Change

  • Vendored list (MessagesLabSidebar): takes any number of host search sections, each under its own title. The single extraStart/extraTitle became SidebarSectionMarks, which owns the row geometry: row top and its inverse, title rects, hit testing, separators, and the search queue's prerender. A request can answer twice: the quick sections first, then the slow ones replace that answer. Cancelling the request (the next keystroke, or an emptied field) cancels the slow task, and an older query's answer is dropped.
  • CmuxSidebarView: searchSections (sync, shown at once) plus laterSearchSections (async). A result can carry an avatar and a date. VoiceOver reads that date.
  • HomeSidebarView: Teammates show at once. Messages arrive from searchMessages; a hit is shown only for a conversation the list shows, and gets that conversation's name and avatar. Choosing one calls onOpenMessage.
  • TopHomePageView: searchMessages is homeStore.search(query, limit: 20), local owner only (the router's cloud has no home.search yet, so Cloud conversations get no message hits). onOpenMessage uses the permalink path show(HomeDockSelection(conversation:message:)), which reveals the message.
  • DEBUG only: debug.home.sidebar_fixture takes messages [{row, text}] and query for screenshots. There's a new tour, home-search. One new string, home.list.searchMessages ("Messages"), translated in all 21 catalog locales.

Tests

SearchSectionsTests (MessagesLabSidebar) drives a real CmuxSidebarView in a window:

  • everySectionShowsUnderItsOwnTitleAfterTheConversations: Teammates shows before the held message search answers. Then the Messages section joins: each title sits on its first row, no row overlaps a title, every row's middle hits that row, a title hits nothing, and a message row carries its text and time and reports its host id when chosen.
  • anOlderQuerysLateAnswerIsNeverShown: holds the "lun" answer past its cancellation and releases it after "lunch" has shown. The list keeps "lunch"'s sections only.

Fleet runs:

  • Step 8c084307974df7d15d2508e3 at be6ae7c (package-test-lane.sh suite Packages/Shared/CmuxMessagesLab SearchSectionsTests,PinnedUnreadDotLayoutTests,PinDragMotionTests): all 3 suites pass.
  • Step d4e7a686571b10f06004be3f at b71cb36, the first version: all 3 pass.
  • Commits after be6ae7c change only the tour JSON.

These tests are new, so there is no red run on the base: the multi-section API they call does not exist there.

Dev build and captures

Tag 27950-chief-search-messages: fleet build 6e44e1550aa9a465b9d298c1 at a693f53 (this head). The captures below come from build 30dcd0c39f9875137d3069b6 at 2781def; the only later commit is the French heading text, which no capture shows.

Viewed after image: yes
Visual verdict: Yes: the Messages section reads like iMessage's search results, in the list's own row style, and the header stays on one centre line.

"lunch" (three messages, no name match), "Aziz" (the name match, then a message mentioning him), and Home at rest:

Capture steps-38032e9241 at 2781def26c96 (fleet build, capture mini, text checked for private data)

Light Dark
light dark

Capture steps-e95fe29296 at 2781def26c96 (fleet build, capture mini, text checked for private data)

Light Dark
light dark

Capture tour-home at 2781def26c96 (fleet build, capture mini, text checked for private data)

Light Dark
light dark

Review

A correctness review subagent at edc6172 found nothing blocking. Its should-fix items are fixed in be6ae7c:

  • Teammates waited on the message search.
  • An emptied field didn't cancel the slow task.
  • The late-answer test didn't really hold the answer.
  • VoiceOver skipped the result's time.
  • The fixture copied the production wiring.

Not changed: one owner search per keystroke. Each search is local and cancelled by the next keystroke, and the repo rules say not to debounce visible work.

Observed / Not run

  • Observed:
    • Fleet suites above.
    • Real-app captures on the tagged build at this head: the "lunch" and "Aziz" searches, and tour:home for the header at rest.
    • The base tour:home at 3e65269, the header before.
  • Not run:
    • A real daemon conversation-search round trip in the app. The captures use the DEBUG fixture's hits; the daemon command has its own Rust tests (conversation_tests.rs), unchanged here.
    • Clicking a message result in the app (the test selects the row under the point).
    • Real keyboard typing (no focus-free route).
    • The full CmuxNext suite.

🤖 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

Home list search now matches message text, not just conversation names and latest previews. Matching messages appear in a new Messages section under Teammates — each row shows the conversation's name, the matched text, and the message's time — and choosing one opens the conversation at that message, as in Messages.

  • Teammates show immediately; message results arrive asynchronously from the conversation owner's search.
  • The vendored list now supports multiple search sections, each with its own title; a newer keystroke or an emptied field cancels an older query's answer.
  • Message hits appear only for conversations the list already shows; Cloud conversations get none because the cloud router lacks home.search yet.

Tests

  • SearchSectionsTests drives a real CmuxSidebarView: every section shows under its own title after the conversations, no row overlaps a title, and choosing a message row reports its host id.
  • A late answer for an older query is never shown once a newer query has run.

Written for commit 2781def. Summary will update on new commits.

View guided diff Turn on auto-fix

austinywang and others added 4 commits October 30, 2026 13:48
…s in Messages

The Home list's search matched only conversation names and each one's latest preview.
It now also asks the conversation owner's message search (conversation-search) and
shows a Messages section under Teammates: the conversation's name and avatar, the
matching text and its time. Choosing one opens the conversation at that message.

The vendored list takes any number of host search sections, each under its own
title, answered asynchronously; a newer keystroke cancels an older answer.

Refs #27950

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s; tour home-search

debug.home.sidebar_fixture takes messages [{row, text}] (the list's message search answers
from them; messages: [] gives it back to the owner) and query (types into the search field).
The home-search tour captures "lunch" and "Aziz" in light and dark.

Refs #27950

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

Review follow-ups: the quick sections no longer wait on the owner's message search; a
request's cancel (the next keystroke or an emptied field) cancels its slow task; VoiceOver
reads a message result's time; the fixture gives back the page's own message search; the
late-answer test holds the older answer past its cancellation instead of yielding.

Refs #27950

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@austinywang austinywang added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@austinywang

Copy link
Copy Markdown
Contributor Author

Correctness review (subagent) and resolution

Reviewed head before fixes: b71cb36. Fixes in be6ae7c; final head 2781def.

No blocking findings. Should-fix items and what happened:

  1. Teammates waited on the message search. Fixed: searchSections (sync) completes the request at once; laterSearchSections (async) completes it again with the messages appended. Test everySectionShowsUnderItsOwnTitleAfterTheConversations checks Teammates shows before the held message answer.
  2. Emptying the field didn't cancel the slow owner search. Fixed: SidebarSearchRequest.onCancel cancels the task; cancel() runs the handlers.
  3. The late-answer test didn't really hold the answer. Fixed: anOlderQuerysLateAnswerIsNeverShown holds the "lun" answer on a continuation past "lunch" showing, releases it, drains the main queue, and checks the stale section never appears.
  4. VoiceOver skipped the result's time. Fixed: the accessibility label of a dated search row includes its time.
  5. The DEBUG fixture copied the production wiring. Fixed: the fixture sets debugMessageHits, which replaces only the owner search; filtering, row building and selection run the production path.

Not changed: debouncing per-keystroke owner searches. They are local (conversation-search on the daemon), the next keystroke cancels the previous one, and the repo rules avoid delaying visible work.

Tests: SearchSectionsTests, PinnedUnreadDotLayoutTests, PinDragMotionTests passed on the fleet at be6ae7c (step 8c084307974df7d15d2508e3). Head 2781def only changed the media tour.

@austinywang

Copy link
Copy Markdown
Contributor Author

Visual review (subagent) at 2781def

Images: the three real-app captures in the PR body (fleet build 30dcd0c39f9875137d3069b6).

Reviewer verdict: FIX, with one fix finding. Resolution below.

  1. FIX: message previews wrap to two lines. Not a defect. The one-line criterion was my mistake in the brief. Every row in this list, conversations included, goes through the same renderer, which wraps the preview to at most two lines (SidebarDrawing.swift:362, lines: 2), like iMessage. The message rows match the existing rows. No change.
  2. Taste (advisory): the "Aziz Ali" name-match row has an empty second line. Every conversation row at rest has the same empty line, so it comes from before this PR. Left for taste.
  3. Note: the "Messages" title sits right above its first row, with no overlap, in light and dark.

Passes:

  • Header: the magnifier, the text and the filter button share a centre line in all six images.
  • Order: name matches come before Messages.
  • Light and dark: both are legible.
  • At rest: the list has no stray section titles.

My verdict after resolution: PASS.

…on ratchet)

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

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

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

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

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

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr28532 -f ref=feat-cmux-next-27950-chief-search -f platform=macos -f backend_mode=local

Default changes

This pull request changes 3 defaults at e0175fcef847 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextApp/Home/DebugHomeSidebarFixture.swift:handle: "75a328afec2c59eae3e0639d57d17dbe3c271ea7b6e2719202aae0fb8afecbe2" -> "4b80e24f84d5133845234c4caea1d56605f681ef2130d37eebf9c3a250a4d4bf"
  • tunable-source.CmuxNextHome/Sidebar/HomeSidebarFixtureRows.swift:messageHits: (none) -> "abc42b0905ba2b8a99718aa8b0479cfb54e998f4bfcb487770145f5b26163b3e"
  • tunable-source.CmuxNextHome/Sidebar/HomeSidebarFixtureRows.swift:team: (none) -> "b9f3f5898ae2cfe25aba5fb644ae10f06b9f52a735587a7513c2f5917474d41b"

Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at e0175fcef8470e7b1982d369517941d6ef285943, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @teamleaderleo (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

@austinywang

Copy link
Copy Markdown
Contributor Author

Review (subagent, correctness first): SHIP at a693f53

A fresh correctness review of the full diff at this head found nothing blocking.

The head adds one commit: the French value of home.list.searchMessages is now "Messages trouvés". The localization ratchet refuses a translation identical to English; the Home catalog goes back to 2 identical strings, the base's count.

Defaults guard: it flagged DebugHomeSidebarFixture.swift (handle, fixtureMessages). The whole file and its only call site (AppControl+Input.swift) sit behind #if DEBUG || CMUX_BENCH_HOOKS. It is fixture plumbing for the captures; no shipped default or tunable changes.

Advisory, not changed: messageHits keeps the last answer after the search ends. Only ids currently shown can be chosen, so the old hits can never be acted on.

@austinywang austinywang added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 30, 2026
# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Home/DebugHomeSidebarFixture.swift
#	Packages/macOS/CmuxNext/Sources/CmuxNextHome/Sidebar/HomeSidebarView.swift
…SidebarFixtureRows.messageHits), next to the fixture rows feat moved there

The merge of feat-cmux-next brought 2fb439d (fixture rows live in
CmuxNextHome) and the arch-ratchet app_lines row. The message fixture
moves with the rows: the App only reads the request's {row, text} pairs.
Same hits as before (ids by entry index, an hour apart, [] gives the
search back to the owner).
… app_lines)

The team fixture and the debug Me move to HomeSidebarFixtureRows with
the message fixture; the App's search wiring and fixture calls take one
line each (searchMessages' own doc says what the wiring does). The App
now adds no lines over feat-cmux-next.
@lawrencecchen lawrencecchen removed the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 31, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

For awareness: this PR has a SHIP review at its head, but GitHub reports it as conflicting with feat-cmux-next, so the lander's update-branch can't merge it and it can't land as is. Files that conflict in a test merge against the current base: Packages/Shared/CmuxMessagesLab/Sources/MessagesLabSidebar/Cmux/CmuxSidebarView.swift. Once feat-cmux-next is merged into the branch and the conflicts resolved, it needs only a quick review of the resolution before it can land. (From the conflict sweep; no push was made to this PR.)

This branch was previously deployed

1 inactive deployment
ci-routing-agent — e0175fce Deployed Oct 31, 2026 by lawrencecchen via wait for same-key tree publisher #87712
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants