Repository navigation
NEXUS-4029: Preserve semantic chips in the core composer - #2303
Conversation
d0d88cb to
a10d7e1
Compare
a10d7e1 to
32f3960
Compare
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord automated source review via Wes's account, with independent Rocket, Mantis and Groot coverage.
P2 — Remove internal coordination links from the public PR description. The opening ELIE overview link points to an internal service, and the closing issue reference exposes an internal tracker/workspace identifier. This repository is public, so those URLs are published to readers who do not have access to the underlying material. Remove those links or replace them with a public summary/reference. The source code does not need to change for this finding.
No actionable implementation defect established in the reviewed diff and callers. Reviewed head 32f39609612ab66ceb84532d033fbffca9f1257c against base 662ccc546ee01d00e55ac9ef7317deb3494e880b; no attached images were present in the description.
Source-only: no tests, builds, app launches, native editing, accessibility or performance workflows executed. Downstream task consumers and human acceptance remain unverified. The hosted snapshot for this head reports CI required failing, including Chromium 2/9 and WebKit 3/14 browser jobs; their cause was not established by this review. This COMMENT review is not an approval or a runtime-readiness verdict.
32f3960 to
a801533
Compare
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord automated source follow-up via Wes’s account.
No new actionable findings. The previously reviewed 13-file composer-token feature patch is byte-identical; the only old-to-new endpoint change is an inherited CommunityAddress.test.tsx retry assertion, also identical to the merge-base delta. This uses the small-follow-up exception to the prior Rocket, Mantis, Groot and Star Lord review; no new team review is claimed.
The public-description links identified in the previous review remain present, so that requested cleanup is still unresolved. No duplicate inline findings added.
Reviewed head a80153355a3b63008f08d9bba429051a5836fcbf against base 9c941525cd37ba1ead6d30547524f577484c00a1 (merge base 27c60c28fc7d0fb5771d640bb22ec90b2877b916). Public description and sole feature commit inspected; no attached images.
Source-only: no tests, builds or app execution; native editing, clipboard/focus/accessibility behavior, downstream consumers and human acceptance remain unverified. Hosted snapshot reports CI required and WebKit 14/14 failing; cause not established. This COMMENT is not approval or a runtime-readiness verdict.
…a channel (#2512) ## TL;DR Adds `conversation.ui.Conversation`, a public host-owned scope that lets a plugin's own `ui.Message` rows and `ui.Composer` for one channel get native Edit, confirmed Delete with recovery and retry, and host media review. Mounting it never marks anything read, follows a thread or enters the channel visit. Cross-channel overview cards need this; today a bare `ui.Message` row has neither Edit nor Delete, and `ui.Thread` always visits. Fixes NEXUS-4193 ## How it works `ui.Conversation({ session, scope, channelId, channelName?, threadId?, children(interactions) })` renders the existing `ConversationChannel` in its host-dialog, non-visiting mode (`host` plus `active={false}`). Inbox Drafts already uses this mode internally. Inside it: - `MessageManagement` supplies the row menu's Edit/Delete under the existing permission checks, the delete confirmation and the failed/unconfirmed recovery notice. - `MessageEditScope` makes Edit target the `ui.Composer` in the same scope. A scope without a composer offers no Edit, as in other previews. - `ConversationHost` owns media review and panel overlays, focus return, and the existing stale-session guard (nothing opens once the relay snapshot is no longer this ready session). `children` receives the host's `onOpenLink`, `canOpenLink` and `onOpenMediaReview` to pass to the rows. `EmbeddedThread` and the new scope now share one `HostedChannel` wrapper, so `ui.Thread` behavior is unchanged. No changes to `MessageManagement`, `ConversationHost`, `MessageComposer` or `contracts.ts`. ## Evidence `src/features/conversation/EmbeddedConversation.test.tsx` mounts two fictional channel cards (real relay session, real `ui.Message` rows and `ui.Composer` from `ConversationService`; only `MediaReviewViewer` is reduced, since it has its own suites). It covers: - the same rows without the scope have no Edit/Delete; inside it, each card offers both - mount, background presentation, re-present and unmount never call `enterChannel`, `leaveChannel`, `follow`, `markMessageRead`, `markChannelRead` or the roster's `profiles.reserve`, and publish nothing - Edit fills only that card's composer and publishes a kind-40003 edit tagged with that card's channel. The other card's message is untouched. - Delete: cancel publishes nothing; confirm publishes kind 5; a relay rejection shows the recovery notice in that card only; Retry resends the same event id and the row goes away - media review opens with the card's channel and message, and stops opening after the session stops being ready Fail-then-pass: with `active={false}` removed from the scope, all 4 tests fail (`enterChannel` and `profiles.reserve` are called). The scope restored, all pass. The packed `@buzz/author` consumer fixture (`tests/fixtures/conversation-consumer`) now renders its rows and composer inside `ui.Conversation` and passes `interactions.onOpenLink` to its rows. So the generated declarations must export the new component and its `children(interactions)` type, and the existing `conversation.spec.mjs` journey mounts it in the real app. The fixture type-checks against freshly built declarations. As a negative control, a misspelled interactions field fails `tsc`. Run on a Linux Blox box on base `a34ba4f` (the local host-build guard refused under load): - `vitest run src/features/conversation src/features/messages/MessageManagement.test.tsx src/bundled/inbox/DraftsView.test.tsx`: 19 files, 221 tests passed - `tsc --noEmit` and `biome check --error-on-warnings` on the touched files: clean - `pnpm author:build`, packed and installed into a copy of the consumer fixture, then `pnpm build` (`tsc`): clean No browser journeys were added or removed. The existing consumer journey now mounts the scope; it runs only in hosted CI, not locally. Focus, overlay and native-edit geometry are unchanged existing `ConversationHost`/composer behavior that existing suites already cover. ## Limits and coordination - Not exercised in the native desktop app or a browser journey. Hosted CI runs the full suites. - Two `ui.Conversation`s for the same channel each show that channel's recovery notice, because recovery is per channel. The docs say to render one per channel or card. - No overlap in hunks or behavior with #2483 (Solo list arrangement/row action in `service.tsx`), #1889, #2306 or #2303 (`contracts.ts`), #2083 (`MessageManagement.tsx`) or #2167 (`ConversationHost.tsx`). This PR does not edit `contracts.ts`, `MessageManagement.tsx` or `ConversationHost.tsx`. - This PR doesn't adopt the scope in any plugin. That is separate work. ## Initiative context [Buzz Threads status](https://g2.sqprod.co/apps/kylez-buzz-threads-status) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Kyle Zemek <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
a801533 to
7bc1a52
Compare
7bc1a52 to
fc50baa
Compare
fc50baa to
2c3e8c1
Compare
2c3e8c1 to
eff434b
Compare
eff434b to
070ad3b
Compare
070ad3b to
51f981b
Compare
51f981b to
d6af1fb
Compare
d6af1fb to
771af41
Compare
Add the core chip editor infrastructure that the folder and skill layers build on. A semantic chip is a token node with a bounded `ComposerToken`: a `folder` or a `skill`, plus extra JSON fields that round-trip without interpretation. The editor inserts one over an open completion query as one undo step, names it for assistive technology, keeps it through saved drafts, copies it as its label text, and never lets a decoration or link adopt it. Only a provider that a bundled plugin registered can produce a chip. The plugin runtime marks the owner object it creates for a host-shipped module, and contribution registries mark the entries such an owner registers. completionResult keeps a token edit only for a marked entry. An id, revision, title or flag that a provider or a ctx.extend scope claims is not provenance. The token edit lives in host-internal types in completion.ts. The plugin completion contract, MentionDraft and the generated public declarations are unchanged. Chips stay unsent in this layer. Every composer keeps a draft with chips unchanged and refuses to send it. Saved chip data that does not restore as a chip restores no chip, whatever rejected the snapshot: an unreadable token, a label that is not its source, a recipient, link or pending-mention conflict, or any other invalid part of the document. Co-authored-by: Codex <[email protected]> Co-authored-by: Claude <[email protected]> Signed-off-by: Gil Birman <[email protected]>
A folder chip now writes the folder's path, and a skill chip writes `$name`. Both still show only their label. The folder chip uses the shared inline-chip classes. Co-authored-by: Claude <[email protected]> Signed-off-by: Gil Birman <[email protected]>
dc29a8a to
76a511c
Compare
…y-untagged-reactions * origin/main: (324 commits) fix(github): show private-repo body images from signed links (#3252) NEXUS-4029: Preserve semantic chips in the core composer (#2303) Make plugin signature enforcement opt-in (#2212) NEXUS-4156: Add workspace Leads and choose a chat's workspace (#2788) feat(plugins): report conclusively retired update providers (#3263) feat(messages): let attachment renderers open files from the host file card (#2239) feat(charts): bundle a Charts code-block renderer (#3226) Expose native reply grouping through Conversation.ui (#3245) NEXUS-4163: Keep plugin-owned chat deletion in Solo (#2787) NEXUS-4156: Expose Solo Workspaces to plugin regions (#2786) NEXUS-4022: Start region chats in the New Chat editor (#2784) feat(link-previews): unfurl web links below messages by default (#3225) fix(messages): keep names in literal Markdown as written when editing (#2834) feat(plugins): fetch a packaged managed plugin policy from a URL (#2504) fix(goose): enable deferred tool loading for goose agents (#3227) fix(unread): preserve manual intent in captured explicit reads (#3228) NEXUS-4337: Expose retained plugin update reviews (#3075) feat(conversation): add a link preview slot below messages (#3219) feat(plugins): let link previews read a public page's preview fields (#3217) Let sidebar row plugins decorate ordinary Solo chats (#3222) ...
* origin/main: (121 commits) Expose Solo region state before a component mounts (#3296) fix(builderlab): say a 401 was refused, not expired, and show each sign-in failure once (#3241) feat(agents): file new Solo chats in explicit personal workspaces (#2857) perf(css): limit broad style invalidation (#3267) Delay and fade in the Bestie badge celebration (#3292) fix(github): show private-repo body images from signed links (#3252) NEXUS-4029: Preserve semantic chips in the core composer (#2303) Make plugin signature enforcement opt-in (#2212) NEXUS-4156: Add workspace Leads and choose a chat's workspace (#2788) feat(plugins): report conclusively retired update providers (#3263) feat(messages): let attachment renderers open files from the host file card (#2239) feat(charts): bundle a Charts code-block renderer (#3226) Expose native reply grouping through Conversation.ui (#3245) NEXUS-4163: Keep plugin-owned chat deletion in Solo (#2787) NEXUS-4156: Expose Solo Workspaces to plugin regions (#2786) NEXUS-4022: Start region chats in the New Chat editor (#2784) feat(link-previews): unfurl web links below messages by default (#3225) fix(messages): keep names in literal Markdown as written when editing (#2834) feat(plugins): fetch a packaged managed plugin policy from a URL (#2504) fix(goose): enable deferred tool loading for goose agents (#3227) ... Signed-off-by: Tyler Longwell <[email protected]> Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
* origin/main: NEXUS-4029: Offer folder chips in the composer (block#2789) perf(css): narrow effort button invalidation (block#3297) NEXUS-4433: Expose saved plugin installation source kind (block#3242) fix(identity): keep an unbacked key safe on Replace and unblock a corrupt saved key (block#3233) Expose Solo region state before a component mounts (block#3296) fix(builderlab): say a 401 was refused, not expired, and show each sign-in failure once (block#3241) feat(agents): file new Solo chats in explicit personal workspaces (block#2857) perf(css): limit broad style invalidation (block#3267) Delay and fade in the Bestie badge celebration (block#3292) fix(github): show private-repo body images from signed links (block#3252) NEXUS-4029: Preserve semantic chips in the core composer (block#2303) Make plugin signature enforcement opt-in (block#2212) NEXUS-4156: Add workspace Leads and choose a chat's workspace (block#2788) feat(plugins): report conclusively retired update providers (block#3263) feat(messages): let attachment renderers open files from the host file card (block#2239) feat(charts): bundle a Charts code-block renderer (block#3226) Expose native reply grouping through Conversation.ui (block#3245) Signed-off-by: Joah Gerstenberg <[email protected]> # Conflicts: # src/features/conversation/ComposerCompletions.test.tsx # src/features/conversation/ComposerCompletions.tsx # src/features/messages/MessageComposer.tsx
Summary
Adds host-internal semantic chips to the composer (
070ad3b96). The folder (#2789) and skill (#2790) layers build on them.ComposerToken, afolderor askill. Extra JSON fields round-trip without interpretation.completionResultkeeps a token edit only for a marked entry. An id, revision, title or flag that a provider claims is not provenance.MentionDraftand the generated public declarations are unchanged.Testing
Local runs on macOS, on the stack rebased onto main
9596cd3db:adbdf424echain only intests/browser/solo-rename.spec.mjs.02f9c0277makes the new plugin-owned lifecycle test wait for the chat's row before filing it, after the hosted flake check caught it racing the roster load. With that fix, the fullsolo-rename.spec.mjspassed 180/180 at02f9c0277(10 repeats, Chromium and WebKit) and 120/120 atc99d0ce51(5 repeats).eff434bd0:pnpm check(Biome, TypeScript and the design checks) and the icon check passed. Vitest for the files the flake check selects for this PR: 632 passed.adbdf424e: full Vitest, 20556 passed and 23 skipped (includesbrowser-host/channel-kit.test.mjs).tests/browser/solo-rename.spec.mjs, repeated 5 times, passed 120/120. The 34 other specs that the flake check relates to the stack, run once in each engine: 343 passed, 3 skipped by their own conditions. The full browser suite was not run locally.049a9b57e(now1fbd49c49), which includes this PR: 53 passed.Native testing: Gil ran the native desktop app on this stack at
adbdf424e, with the matching Nexus plugin build. Gil confirmed that these native-only paths passed:!folder listing through the Taurirepositories_folder_listcommand (NEXUS-4029: Offer folder chips in the composer #2789);/SKILL.md listing throughlocal_skills_list(NEXUS-4033: Offer session skills in the core task composer #2790);--add-dirfolder grant (NEXUS-4029: Offer folder chips in the composer #2789);Agent testing did not reach these paths: the agent ran no native app, no real relay and no real agent.
Known gaps
Hosted or local failures that this stack does not cause:
tests/browser/typing.spec.mjs:290("a growing channel/thread composer lifts history with it at the bottom") intermittently fails with React error Add complete reaction toggles to the message menu #185 on main too. Locally it failed 12 of 12 runs at9596cd3dband 9 of 12 at a later main commit.cargo test -p Buzzcrashes the library test binary (SIGSEGV), and somehost_commanddeadline tests fail. Both happen the same way at base9596cd3db, before this stack. Hosted Linux CI is the reference for these.Test changes
Titles are compared only in the test files each range changes. Tests that moved or were renamed are matched by title.
Removed by this PR's diff (0)
Added by this PR's diff (10)
src/features/conversation/ComposerCompletions.test.tsx: hands a chip edit to the composer only from a bundled provider (bundled: %s)src/features/conversation/ComposerCompletions.test.tsx: opens no query at a trigger inside a resolved chipsrc/features/conversation/completion.test.ts: keeps chip edits only from a provider a bundled plugin registered, for that registration's lifetimesrc/features/messages/MessageComposer.test.tsx: inserts a bundled provider's chip as one atom and keeps it unsent until chips shipsrc/features/messages/composer-token.test.tsx: bounds token JSON by UTF-8 bytes, including multibyte identitiessrc/features/messages/composer-token.test.tsx: copies a bounded, frozen token of a known kind and nothing elsesrc/features/messages/composer-token.test.tsx: copies a chip as its label text, never as a link its label resemblessrc/features/messages/composer-token.test.tsx: refuses an unknown kind, a stale or literal range, and edits beyond the chip or length boundssrc/features/messages/composer-token.test.tsx: replaces an open query with one chip: named, separate from recipients, one undo step, and restored from a saved draftsrc/features/messages/composer-token.test.tsx: restores a chip only from chip data its snapshot keepsIn the previous version of this PR, not carried over (3)
src/features/messages/MessageComposer.test.tsx: inserts a bundled provider's chip as one atom and keeps it unsent until task references ship (task chat: %s)src/features/messages/composer-token.test.tsx: refuses a workspace, a stale or literal range, and edits beyond the chip or length boundssrc/features/messages/composer-token.test.tsx: restores a chip, and marks chip data any snapshot rejection would drop as another build's databuzz-review-completed