Repository navigation
history: closed chat rows carry their agent session and harness (C6 step 1, daemon) - #31871
Conversation
…for search Ports ClosedAgentIdentityTests (daemonClosedSearchFiltersAfterEnrichmentAndBeforeLimit, closedContainersRetainTheirOwnKind) to history_ops/sources.rs. Red on the base: the merged history drops the closed chat's agent identity, so the daemon search cannot find a chat by its session id or harness; the app enriches it afterwards.
The merged history (history.entries.list) now sets session_id and provider on a closed tab row whose tab is an agent chat, and the search text of a closed row includes them, as the Swift HistoryEntry.searchText does. A screen, workspace or window keeps its container kind and carries no agent identity (Swift HistoryService.closedAgentSession). This is the rule the app applied after the read (HistoryService.enrichClosedEntries); the app half that deletes that copy follows in its own PR.
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green Shipped in:
|
|
Found 12 test failures on Blacksmith runners: Failures
...and 2 more test failures. View all on Blacksmith
|
Clippy job a49bac0aea6ac71436590cc5 (hq run 41395440128) refused two qualified paths that the module imports already (sources.rs:152, :174).
…ion/history-merge
…ion/history-merge
|
Review (rm-history-merge-review): SHIP at 69cc27d I reviewed only this PR's own change ( Correctness
Readers
TestsEach new test has an assertion that fails on the base, and the red job 4c0e5906edb44b1489265384 confirms this.
Layer ownershipThis change moves a search rule from Swift into the Rust owner, as L1 and L7 of Non-blocking notes
|
…itle Ports the AgentPaneModel.tabTitle case of the deleted Swift test daemonClosedSearchFiltersAfterEnrichmentAndBeforeLimit (review of #31871, finding 3). Red on 8318ac2: the row title is empty, so a search for "agent" finds nothing; before this PR the app's enrichment gave the row its localized title and searched it.
The row leaves an untitled closed chat's title empty and the client shows its localized default (Swift AgentPaneModel.tabTitle). cmux-history search_text now adds that default's English text for a closed conversation_tab row with no title, so a search for "agent" finds it, as the app's enrichment did before this PR. Also corrects the docs of HistoryEntry.session_id and provider: closed agent chat tabs carry them too (review of #31871, finding 1).
…sed rows
history.entries.list takes untitled_titles {chat, terminal}: the titles the
client shows, in the person's language, for a closed row the daemon leaves
untitled. A closed agent chat (session_id or provider set) shows the chat
title, every other untitled closed row the terminal title (Swift
DaemonHistoryEntry.historyEntry and closedAgentSession). The search matches
that title; without the field no default title matches, as before, so the CLI
and older apps see no change. No word is built into Rust.
Capability history-untitled-titles-v1 (identify) says the daemon takes the
field and lists a closed chat's session id and harness: an app sends the field
only to such a daemon (cmux-tui-contract.md: wire changes behind a capability).
Catalog: the untitled_titles field and the HistoryUntitledTitles type; the
descriptions of HistoryEntry.session_id and provider now name closed chat tabs
(review of #31871, finding 1). Generated: the seven .cmux-resource-api.json
descriptors (sync-resource-api.py) and cmux-app.d.ts (gen-cmux-global.ts);
both --check clean, check-resource-api-boundary.py and check-spec-inventory.py
pass.
…te the Swift closed-row enrichment (#36900) * test(history): a daemon closed chat row carries its agent identity (red: the app reads it only from its own closed records) * history: closed chat rows take their agent identity from the daemon; delete the Swift enrichment and the 5,000-row closed re-read The daemon's history.entries.list closed rows carry session_id and provider since #31871, and the daemon search matches them. The app now maps them in DaemonHistoryEntry.historyEntry and lists closed rows in the same daemon read as the other kinds. HistoryService.filteredClosedDaemonEntries and enrichClosedEntries (Swift copies of the daemon's closed-row rule) are gone. Changed for a person: a search for the localized untitled chat name ("New Chat") no longer finds untitled closed chats; their session id and harness still find them.
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Rust migration C6, step 1 (daemon only, no FFI input). The merged history (
history.entries.list) now carries a closed chat's agent identity, so the daemon's search finds a closed chat by its session id or harness. Until now, the app read closed rows in a separate 5000-row request and searched them again in Swift after it added that identity from its own closed records (HistoryService.filteredClosedDaemonEntries,enrichClosedEntries).What changes
history_ops/sources.rsclosed_entry: a closed tab whose tab has anagent_sessionsetssession_idandprovider(the harness) on its row. A screen, workspace or window carries no agent identity, even when the first tab it would reopen is a chat. This is the rule of SwiftHistoryService.closedAgentSession.cmux-historysearch_text: a closed row also matches itssession_idandprovider, as SwiftHistoryEntry.searchTextdoes for.closed.session_idandproviderare already optional fields ofHistoryEntryin resource-operations-v2.json. The React History page shows Copy Session ID only for agent rows, so closed chat rows get no new UI from this PR. The field docs ofsession_idandprovider(cmux-historyentry.rsand the catalog) still say "Agent only"; history: search untitled closed rows by the localized titles the app shows; delete the app's closed enrichment (C6 step 2) #31941 fixesentry.rs, and the catalog description goes with the next catalog PR in this lane.The app half, which deletes the Swift enrichment copy, is the stacked PR on
rust-migration/history-merge-app.Tests (ported from the Swift suite
ClosedAgentIdentityTests)closed_chat_search_matches_session_and_harness_before_limit: port ofdaemonClosedSearchFiltersAfterEnrichmentAndBeforeLimit. 59 newer unrelated closes andlimit: 1; a search for the session id or the harness finds the chat, an unknown text finds nothing.closed_containers_carry_no_agent_identity: port ofclosedContainersRetainTheirOwnKind.closed_tab_without_session_carries_no_session_id: a plain browser close, and a chat with no session yet (harness only).Command (fleet):
scripts/ci/cmux-tui-rust-check.sh test closed_, submitted withproof-step.py.closed_chat_search_matches_session_and_harness_before_limit(sources.rs:171,same-sessionfound nothing),closed_containers_carry_no_agent_identity(:188),closed_tab_without_session_carries_no_session_id(:210).closed_759ae78ca9fb29d6d105089a, testquery(cmux-history) 244575eea054bbc4d79c12bd, clippy 8c90f7df7abdf81d18b0cfc7 (hq run 41396859904), fmt 2f87851d212046cba17cf615 (hq run 41396792242).--no-ffmerge of origin/feat-cmux-next for the clippy base fix base red: agent_chat_notices clippy (obfuscated if/else, a missing ;, a redundant clone) from #31770 #31907; this PR's own diff did not change): clippy 45784b550246ca7bf50cb552 PASSED; testclosed_90c87e9136d3c5a123acdb26 PENDING.Review receipt: #31871 (comment) (SHIP at 69cc27d).
The app half is #31941 (stacked on this PR).
Follow-up (not in this PR): the daemon trail keeps the forward entries after a Back
Found while mapping the Swift trail rules against
history_ops/trail.rs. It is a behavior gap, so it gets its own fix, not a part of this move.LocationTrail.recordremoves the entries after the cursor before it adds a new step (Chrome does the same: a new navigation drops the forward entries). The daemon has no cursor:TrailDocument::recordalways compares the step with the newest entry and adds it after that entry, so the forward branch stays in the daemon trail.HistoryTrailSync.adopt), and the dropped entries come back.trail.rs): record A, B, C; record a Back to A (the step the app reports for the cursor move, which needs a field onhistory.trail.record, for exampleback_to: <entry id>or a cursor index); then record D. Expect the entries A, D. The test fails on the base, which keeps A, B, C, D. A second case: withsteps: workspaces, a step in A's sidebar item after the Back refreshes A (the Swift rule compares with the cursor entry, not the newest one).history.trail.record(a catalog change), so the app can tell the daemon where its cursor is.Changelog
none
Observed / Not run
Observed: the red failed on the three new assertions and the greens above passed (job ids and hq runs above). The pre-push gate passed.
Not run: no Swift build or test (this PR changes no Swift). No live daemon check of
history.entries.list; the tests call the row mapping andHistoryQuery::applydirectly.