Repository navigation
feat(composer): mention GitHub pull requests and issues - #1128
Conversation
Two new @-mention sections list the viewer's pull requests and issues from the GitHub repos of the composer's attached folders, ranked with the epic's own PRs first, then review-requested / assigned / authored. Typing filters the cached rows instantly while a debounced GitHub search merges in, deduplicated by GitHub identity so a cached row keeps its reference. A funnel popover filters by state, involvement and repository; refresh is a click, since the window's Reload owns Cmd-R. The wire gains mention.githubCatalog@1.0 and mention.githubSearch@1.0, both registered as additive degrade: unsupported methods, plus a github_pull_request context type beside the existing github_issue. Committing a row inserts a chip that serializes to org/repo#number and a URL, so the agent resolves the reference with its own tools rather than receiving inlined content that is stale by the time it is read. A paused limiter or a suppressed budget floor renders the cached rows with an info notice and a countdown rather than an error, and a missing or signed-out gh CLI raises a banner instead - waiting does not help there, so the copy has to carry it. Also fixes the Artifacts mention refresh, which re-set the step it was already on and therefore refetched nothing. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Summary by CodeRabbit
WalkthroughThe PR adds GitHub pull-request and issue mentions to the composer. It adds host contracts, catalog and search hooks, filtering, persistence, picker providers, serialization, previews, focus restoration, and step-specific menu controls. It also adds regression coverage. ChangesGitHub composer mentions
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Composer
participant Picker
participant Catalog
participant Search
participant Host
Composer->>Picker: Open GitHub mention step
Picker->>Catalog: Read cached catalog
Catalog->>Host: Call mention.githubCatalog
Picker->>Search: Search typed or reference query
Search->>Host: Call mention.githubSearch
Picker->>Composer: Publish rows and step chrome
Composer->>Picker: Apply filter or restore focus
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
clients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.ts (1)
74-91: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for
setStepChrome.This suite owns the picker store's guard behavior. The PR adds
setStepChromewith five new branches: closed store, non-mention kind, stalesessionId, stale step id, and the value-equal dedupe throughsameMentionStepChrome. None of those branches is exercised here.The stale-session and stale-step guards are the same class of defect this suite already tests for
setItems(lines 173 and 265 set up superseding sessions). Add the matching cases forsetStepChrome, plus one that assertsstepChromereturns tonullaftersetStep.Do you want me to generate these test cases?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.ts` around lines 74 - 91, Add test coverage in the composer picker store suite for setStepChrome: verify no update when the store is closed, the picker kind is non-mention, the sessionId is stale, or the step id is stale; verify sameMentionStepChrome value-equal updates are deduplicated; and verify setStep resets stepChrome to null. Reuse the existing setItems superseding-session setup and the open helper for consistent fixtures.clients/gui-app/src/components/chat/composer/menu/composer-menu.tsx (1)
339-355: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMove the chrome banner out of the
role="listbox"container.Line 342 sets
role="listbox"on the scroll container. Line 355 rendersMentionStepChromeBanneras a direct child of that container. The banner carriesrole="status". ARIA requires a listbox to own onlyoptionandgroupchildren. Astatuslive region inside a listbox is not a valid owned element, so assistive technology can drop the "GitHub CLI unavailable" announcement or map it to the wrong context.Render the banner as a sibling above the listbox. The banner is static chrome, not a row, so it does not need to scroll with the results.
♿ Proposed fix to move the banner outside the listbox
+ {chrome === null ? null : <MentionStepChromeBanner chrome={chrome} />} <div ref={listRef} id={menuId} role="listbox" // The first menu (mention categories, slash commands) stays compact: // tall enough for the full category roster without a scrollbar, // while typed-query results scroll behind the cap. A provider // submenu mirrors a bounded roster (terminals, git refs), so it // grows to the viewport cap instead of scrolling. className={cn( "overflow-y-auto py-1", kind === "mention" && step.kind === "provider" ? "max-h-[70vh]" : "max-h-[min(50vh,16rem)]", )} > - {chrome === null ? null : <MentionStepChromeBanner chrome={chrome} />} <ComposerMenuBody🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/gui-app/src/components/chat/composer/menu/composer-menu.tsx` around lines 339 - 355, Move MentionStepChromeBanner out of the div identified by listRef, menuId, and role="listbox", rendering it as a sibling immediately above the listbox. Keep the banner’s existing chrome-null conditional and ensure the listbox contains only its option/group result content while the banner remains visible outside the scrolling container.
🔇 Additional comments (71)
clients/gui-app/src/components/chat/composer/editor/extensions/attribute-helpers.ts (1)
55-62: LGTM!clients/gui-app/src/components/epic-canvas/pr/pr-source-notice.tsx (1)
6-9: LGTM!Also applies to: 21-33
clients/gui-app/src/components/epic-canvas/pr/__tests__/pr-source-notice.test.tsx (1)
6-6: LGTM!Also applies to: 15-27, 39-52, 72-76, 98-101, 136-140
protocol/src/common/__tests__/json-content-serializer-github-mentions.test.ts (1)
1-114: LGTM!clients/gui-app/src/lib/query-keys/index.ts (1)
53-53: LGTM!clients/gui-app/src/lib/persist/index.ts (1)
12-12: LGTM!clients/gui-app/src/lib/persist/keys.ts (1)
62-68: LGTM!Also applies to: 194-194, 263-267
clients/gui-app/src/stores/composer/github-mention-filter-store.ts (1)
1-143: LGTM!clients/gui-app/src/stores/composer/__tests__/github-mention-filter-store.test.ts (1)
1-262: LGTM!clients/gui-app/src/hooks/composer/__tests__/use-epic-mention-entries.test.tsx (1)
89-146: LGTM!clients/gui-app/src/lib/composer/segments.ts (1)
13-17: LGTM!protocol/src/common/json-content-serializer.ts (1)
8-8: LGTM!Also applies to: 249-249, 292-293, 409-418, 515-528
protocol/src/host/mention-schemas.ts (1)
1-157: LGTM!clients/gui-app/src/components/epic-canvas/pr/pr-detail-card.tsx (1)
26-26: LGTM!clients/gui-app/src/lib/pr/pr-source-notice-message.ts (1)
18-39: LGTM!Also applies to: 48-53
clients/gui-app/src/lib/query-keys/mention-query-keys.ts (1)
1-23: LGTM!clients/gui-app/src/hooks/composer/use-github-mention-catalog.ts (4)
1-65: LGTM!Also applies to: 100-139, 230-261
204-216: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winReport rejected manual refreshes.
A thrown host RPC error does not produce a
notice. This emptycatchtherefore gives no feedback when a manual refresh fails. AddtoastFromHostErrorin the mutationonErrorpath unless this hook exposes an inline error surface.As per coding guidelines, “Use
toastFromHostError,toastFromAuthError, ortoastFromRunnerErrorinonError, except for inline-error surfaces.”⛔ Skipped due to learnings
Learnt from: hdkshingala Repo: traycerai/traycer PR: 889 File: clients/gui-app/src/hooks/local-store/use-rebind-local-store-mutation.ts:0-0 Timestamp: 2026-08-11T12:49:03.942Z Learning: For `host.rebindLocalStore` in `clients/gui-app/src/hooks/local-store/use-rebind-local-store-mutation.ts`, a successful `rebound` response republishes the host durability store. Invalidate the complete `hostQueryKeys.scope(hostId)` rather than a hand-picked set of queries, because all reads that use that store can become stale. Capture `hostId` in `onMutate` and use the captured value in `onSuccess` to avoid invalidating a newly active host after a host swap.Learnt from: tanveergill Repo: traycerai/traycer PR: 951 File: clients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.ts:741-754 Timestamp: 2026-08-11T09:21:07.652Z Learning: In `clients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.ts`, `epic.listChatPublicationTargets` intentionally does not poll or invalidate on fork lifecycle changes. A fork can change the mapping once, and a temporary duplicate-looking cloud sidebar row is an accepted bounded freshness trade-off. The mapping refetches on mount, focus, and host/auth transitions. Do not report this as a data-integrity issue unless the lifecycle-observer design changes.Learnt from: hdkshingala Repo: traycerai/traycer PR: 1103 File: clients/gui-app/src/components/settings/panels/provider-pack-version-manager-presence.ts:0-0 Timestamp: 2026-08-12T00:53:09.461Z Learning: In `clients/gui-app/src/components/settings/panels/provider-pack-version-manager-presence.ts`, mutation outcome delivery must use a per-panel identity token, not global panel presence. Provider pack version mutation hooks must capture the initiating token in `onMutate` and show a fallback toast if `versionManagerPanelIsMounted(token)` is false when the outcome arrives. Panels must register only when `hostId !== null` and version-manager method support is `true`.Learnt from: tanveergill Repo: traycerai/traycer PR: 951 File: clients/gui-app/src/components/layout/__tests__/tab-strip-app-route.test.tsx:68-74 Timestamp: 2026-08-11T09:20:45.595Z Learning: In `clients/gui-app` focused component tests, a hook mock may return only the fields consumed by the rendered code path. The coding guideline to return the full `UseQueryResult` or `UseMutationResult` applies to production hooks, not to narrow test doubles. Do not require a disabled real TanStack Query solely to emulate unused status and error fields when the test does not validate query lifecycle behavior.Learnt from: tanveergill Repo: traycerai/traycer PR: 1102 File: protocol/src/host/usage-analytics/schemas.ts:219-223 Timestamp: 2026-08-11T05:31:30.952Z Learning: For `host.usage.summary`, the host implementation is intended to reject an unscoped `window: "epic"` request before data access. `host-usage-summary-resolver.ts` calls `assertValidEpicWindowRequest(request)` for the `"epic"` window and maps `InvalidUsageSummaryRequestError` to `InvalidArgumentError`; `usage-summary-local-reader.ts` performs the same validation. The expected error message is `window "epic" requires an epicId or chatId filter`.Learnt from: tanveergill Repo: traycerai/traycer PR: 1102 File: clients/gui-app/src/components/chat/__tests__/chat-usage-dialog.test.tsx:0-0 Timestamp: 2026-08-11T05:30:59.515Z Learning: In `clients/gui-app/src/components/chat/chat-usage-dialog.tsx`, `ChatUsageDialog` is mounted once for the whole session rather than once per tab. Its usage-summary query must remain gated by a non-null dialog target. Rendering no dialog does not prove that no `host.usage.summary` request occurs; tests should verify zero handler invocations with a null target and request activity only after the dialog target opens.Learnt from: tanveergill Repo: traycerai/traycer PR: 1102 File: clients/gui-app/src/components/epic-canvas/panels/epic-usage-entry-point.tsx:44-46 Timestamp: 2026-08-11T05:31:01.771Z Learning: In `clients/gui-app`, `EpicSessionProvider` binds Epic sessions to `useReactiveActiveHostId()` and re-acquires the session when the active host changes. `EpicShell` status-row components, including `clients/gui-app/src/components/epic-canvas/panels/epic-usage-entry-point.tsx`, are outside `TabHostProvider` scope and must use the app-wide host binding. Do not introduce a tab-bound host only in a status-row leaf component without redesigning the existing Epic session binding.Learnt from: tanveergill Repo: traycerai/traycer PR: 1102 File: protocol/src/host/usage-analytics/schemas.ts:176-176 Timestamp: 2026-08-10T22:02:30.958Z Learning: For the `host.usage.summary` RPC, the host validates request timezone values with `assertValidIanaTimeZone` and rejects invalid values with a typed error. In `clients/gui-app/src/lib/usage-analytics/day-window.ts`, `lastNCalendarDays` must tolerate an unknown response timezone by catching `Intl.DateTimeFormat` construction errors and falling back to UTC.Source: Coding guidelines
66-99: 📐 Maintainability & Code QualityInspect the hook implementations and call sites to determine whether they must expose complete TanStack Query and mutation results.
179-182: 🎯 Functional CorrectnessGuard against placeholder data before the automatic refresh.
If this query uses
placeholderData: keepPreviousData, return whencatalogQuery.isPlaceholderDatais true. Otherwise,data.stalecan describe the previous scope and trigger an"auto"request for the new scope.clients/gui-app/src/hooks/composer/use-github-mention-search.ts (2)
1-54: LGTM!Also applies to: 62-88, 101-130
89-90: 🎯 Functional CorrectnessCheck the
keepPreviousDatabehavior before merging. If prior-query rows remain visible for the current query, removeplaceholderData: keepPreviousData.clients/gui-app/src/stores/composer/github-mention-catalog-store.ts (1)
19-21: 📐 Maintainability & Code QualityConfirm catalog data ownership before changing the store.
Trace
useGithubMentionCataloganduseGithubMentionSearchto determine whetherGithubMentionRowandGithubMentionRepositoryare host response data. MoverepositoriesByScopeandrowsByKeyto TanStack Query only if its cache provides the required cross-observer lifetime; otherwise retain the Zustand state and tests.clients/gui-app/src/lib/composer/tiptap-json-content.ts (1)
8-9: LGTM!Also applies to: 172-192, 232-234, 748-795, 879-887
clients/gui-app/src/lib/composer/types.ts (1)
14-26: LGTM!Also applies to: 198-234, 263-282
protocol/src/host/mention-contracts.ts (1)
1-32: LGTM!protocol/src/host/registry.ts (1)
403-406: LGTM!Also applies to: 6132-6159
protocol/src/host/index.ts (1)
11-12: LGTM!protocol/src/host/__tests__/mention-contracts.test.ts (1)
1-396: LGTM!clients/gui-app/src/lib/pr/pr-review-decision-label.ts (1)
1-17: LGTM!clients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.ts (1)
756-764: LGTM!clients/gui-app/src/hooks/composer/use-epic-mention-entries.ts (1)
21-31: LGTM!Also applies to: 58-61
clients/gui-app/src/hooks/composer/__tests__/use-github-mention-search.test.tsx (1)
1-106: LGTM!clients/gui-app/src/lib/composer/mentions/github-mention-rows.ts (1)
18-196: LGTM!Also applies to: 198-322, 324-387, 389-475
clients/gui-app/src/lib/composer/mentions/github-mention-chrome.ts (1)
32-59: LGTM!Also applies to: 61-124
clients/gui-app/src/lib/composer/mentions/index.ts (1)
2-4: LGTM!Also applies to: 7-7
clients/gui-app/src/lib/composer/mentions/__tests__/github-mention-rows.test.ts (1)
16-62: LGTM!Also applies to: 64-175, 177-263, 265-319, 321-347, 468-554, 556-576
clients/gui-app/src/lib/composer/mentions/__tests__/github-mention-chrome.test.ts (1)
13-47: LGTM!Also applies to: 49-108, 110-146, 148-193
clients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.ts (1)
86-95: LGTM!Also applies to: 102-115, 117-130, 146-171, 187-212, 214-250, 257-292, 294-315, 317-349, 351-385
clients/gui-app/src/components/chat/composer/picker/use-mention-items.ts (2)
585-589: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
⚠️ Unverified finding
Sandbox verification was unavailable.Consider
useEffectEventin place of the ref-and-effect pair.The ref plus the sync effect reproduce what
useEffectEventprovides: a stable identity that always calls the latest closure. React 19.2 shipsuseEffectEvent. If the installed React version has it, this collapses to one line and removes the window in which the ref still holds the previous render'srefetch.♻️ Proposed refactor
- // `refetch` is rebuilt every render (it closes over the current query array), - // so publishing it directly would change the chrome's identity on every pass - // and republish forever. The ref holds ONE stable closure over the latest. - const artifactRefetchRef = useRef(artifactRefetch); - useEffect(() => { - artifactRefetchRef.current = artifactRefetch; - }, [artifactRefetch]); - const refreshArtifacts = useCallback(() => artifactRefetchRef.current(), []); + // `refetch` is rebuilt every render (it closes over the current query array), + // so publishing it directly would change the chrome's identity on every pass + // and republish forever. `useEffectEvent` keeps ONE stable identity over the + // latest closure. + const refreshArtifacts = useEffectEvent(() => artifactRefetch());Keep the current code if the project pins React below 19.2.
29-42: LGTM!Also applies to: 66-68, 232-256, 271-273, 287-295, 325-325, 394-403, 430-470, 521-521, 543-583, 591-611, 628-628, 660-660
clients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-catalog-write.test.tsx (1)
82-132: LGTM!Also applies to: 136-162, 164-213, 215-241, 243-282
clients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsx (1)
16-22: LGTM!clients/gui-app/src/components/chat/composer/menu/mention-preview-panel.tsx (1)
2-2: LGTM!Also applies to: 210-234
clients/gui-app/src/components/chat/composer/nodes/composer-mention-decorator.tsx (2)
68-83: 🎯 Functional Correctness | ⚡ Quick win
⚠️ Unverified finding
Sandbox verification was unavailable.Verify the two contextType literals against the protocol enum.
These branches compare against
"github_pull_request"and"github_issue". The neighbouring literals use kebab-case, such as"terminal-agent". If the protocol enum values are kebab-case, TypeScript narrowsmention.contextTypetoneverinside these branches, the code still compiles, and the decorator silently falls through to theGitBranchdefault icon.
1-8: LGTM!clients/gui-app/src/lib/composer/mentions/github-mention-display.tsx (1)
1-243: LGTM!clients/gui-app/src/lib/composer/mentions/step-chrome.ts (1)
1-235: LGTM!clients/gui-app/src/lib/composer/mentions/mention-dismissal.ts (1)
17-33: LGTM!Also applies to: 56-65, 83-83
clients/gui-app/src/lib/composer/mentions/providers.tsx (1)
16-37: LGTM!Also applies to: 74-75, 102-110, 227-254, 311-321, 831-840, 842-1007, 1102-1106, 1121-1122, 1148-1148, 1161-1161, 1177-1177
clients/gui-app/src/lib/composer/mentions/root-search-ranking.ts (1)
25-38: LGTM!clients/gui-app/src/lib/composer/mentions/__tests__/mention-dismissal.test.ts (1)
10-47: LGTM!Also applies to: 62-62, 117-149
clients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsx (1)
8-12: LGTM!Also applies to: 33-37, 135-144, 175-184, 196-196, 234-234
clients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.ts (1)
17-17: LGTM!clients/gui-app/src/lib/composer/mentions/__tests__/step-chrome.test.ts (1)
1-128: LGTM!clients/gui-app/src/components/chat/composer/picker/suggestion-render.ts (1)
5-5: LGTM!Also applies to: 75-85, 138-144, 154-157, 171-174
clients/gui-app/src/components/epic-canvas/pr/pr-detail-header.tsx (1)
126-126: LGTM!clients/gui-app/src/components/epic-canvas/pr/pr-panel-actions.tsx (1)
82-84: LGTM!clients/gui-app/src/components/chat/composer/picker/composer-picker-store.ts (1)
143-151: LGTM!Also applies to: 163-174, 221-221, 243-254, 298-301, 383-383, 404-407, 464-481
clients/gui-app/src/components/chat/composer/picker/__tests__/use-slash-items-session.test.tsx (1)
60-60: LGTM!clients/gui-app/src/components/chat/composer/menu/__tests__/github-mention-filter-popover.test.tsx (1)
31-38: LGTM!Also applies to: 47-99, 101-135, 137-158, 160-227, 229-283
clients/gui-app/src/components/chat/composer/menu/composer-menu.tsx (1)
29-39: LGTM!Also applies to: 79-79, 92-92, 104-104, 125-125, 146-146, 162-162, 177-177, 218-225, 271-273, 318-337, 364-364, 457-463, 475-475, 512-523, 577-586
clients/gui-app/src/components/chat/composer/menu/github-mention-filter-popover.tsx (1)
1-57: LGTM!Also applies to: 59-79, 80-172, 174-207, 209-278, 280-333
clients/gui-app/src/components/chat/composer/menu/mention-step-chrome-bar.tsx (2)
37-44: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
⚠️ Unverified finding
Sandbox verification was unavailable.Do not infer the notice subject from
chrome.filter.Line 41 derives the notice subject from
chrome.filter?.section.filterandnoticeare independently nullable onMentionStepChrome. If an Issues step publishes anoticewhilefilterisnull, the optional chain yieldsundefinedand the subject falls back to"pull-requests". The hint then describes the wrong entity on the Issues section.Carry the section explicitly on the chrome or on the notice, and read it directly instead of reading a sibling field.
Run the following script to check whether any step publishes
noticewithoutfilter:
1-36: LGTM!Also applies to: 45-57, 59-96, 98-140, 142-164, 166-180
clients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu-disabled-row.test.tsx (1)
68-68: LGTM!clients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu.test.tsx (1)
39-39: LGTM!clients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.ts (1)
33-33: LGTM!Also applies to: 88-88, 106-106, 128-128, 140-140, 173-173, 265-265, 444-444, 577-577
clients/gui-app/src/components/chat/composer/__tests__/chat-list-keymap-submit-source.test.tsx (1)
79-79: LGTM!Also applies to: 115-115, 165-165, 209-209, 237-237, 265-265, 328-328, 371-371
clients/gui-app/src/components/chat/composer/__tests__/composer-mention-dismissal-flow.test.tsx (1)
83-83: LGTM!clients/gui-app/src/components/chat/composer/__tests__/composer-mention-flow.test.tsx (1)
133-133: LGTM!Also applies to: 173-173, 206-206
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@clients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.ts`:
- Line 671: Add a test in the mention no-match dismissal suite using the
existing settledNoMatch fixture with referenceQuery set to true, and assert that
mentionNoMatchDismissVerdict returns false, covering the reference-shaped
zero-match case while preserving existing assertions.
In
`@clients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.ts`:
- Around line 179-185: Update the repositories effect in
useGithubMentionSections to depend on each catalog’s scopeResolved,
isPlaceholder, and repositories fields instead of whole catalog objects,
preserving the existing selection and setRepositories behavior. In
clients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-catalog-write.test.tsx
lines 39-65, have the mocked useGithubMentionCatalog return shallow copies of
catalogMocks.pullRequests and catalogMocks.issues to match production render
identity.
In `@clients/gui-app/src/hooks/composer/use-github-mention-catalog.ts`:
- Around line 140-160: Update the mention.githubCatalog refreshMutation
lifecycle to capture the current hostId and cache-only key in onMutate, then
return that scope as mutation context. Make onSuccess apply the response using
the captured cache key and ensure onError uses the same context, preventing
pending mutations from writing to a newer host’s cache.
In
`@clients/gui-app/src/lib/composer/mentions/__tests__/github-mention-rows.test.ts`:
- Around line 349-388: Add a “filter coercion” test suite alongside
filterGithubMentionRows covering asPullRequestMentionFilter with an issue-shaped
involvement and asIssueMentionFilter with a PR-shaped involvement, asserting
each returns its corresponding default filter. Also verify coercion preserves
the supplied repository object, using the existing GithubMentionFilter and
default-filter symbols.
---
Outside diff comments:
In
`@clients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.ts`:
- Around line 74-91: Add test coverage in the composer picker store suite for
setStepChrome: verify no update when the store is closed, the picker kind is
non-mention, the sessionId is stale, or the step id is stale; verify
sameMentionStepChrome value-equal updates are deduplicated; and verify setStep
resets stepChrome to null. Reuse the existing setItems superseding-session setup
and the open helper for consistent fixtures.
In `@clients/gui-app/src/components/chat/composer/menu/composer-menu.tsx`:
- Around line 339-355: Move MentionStepChromeBanner out of the div identified by
listRef, menuId, and role="listbox", rendering it as a sibling immediately above
the listbox. Keep the banner’s existing chrome-null conditional and ensure the
listbox contains only its option/group result content while the banner remains
visible outside the scrolling container.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 723a71d1-0ba4-4bb6-b407-c478cfffcf4f
📒 Files selected for processing (66)
clients/gui-app/src/components/chat/composer/__tests__/chat-list-keymap-submit-source.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-dismissal-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.tsclients/gui-app/src/components/chat/composer/editor/extensions/attribute-helpers.tsclients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu-disabled-row.test.tsxclients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu.test.tsxclients/gui-app/src/components/chat/composer/menu/__tests__/github-mention-filter-popover.test.tsxclients/gui-app/src/components/chat/composer/menu/composer-menu.tsxclients/gui-app/src/components/chat/composer/menu/github-mention-filter-popover.tsxclients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsxclients/gui-app/src/components/chat/composer/menu/mention-preview-panel.tsxclients/gui-app/src/components/chat/composer/menu/mention-step-chrome-bar.tsxclients/gui-app/src/components/chat/composer/nodes/composer-mention-decorator.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-catalog-write.test.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.tsclients/gui-app/src/components/chat/composer/picker/__tests__/use-slash-items-session.test.tsxclients/gui-app/src/components/chat/composer/picker/composer-picker-store.tsclients/gui-app/src/components/chat/composer/picker/suggestion-render.tsclients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.tsclients/gui-app/src/components/chat/composer/picker/use-mention-items.tsclients/gui-app/src/components/epic-canvas/pr/__tests__/pr-source-notice.test.tsxclients/gui-app/src/components/epic-canvas/pr/pr-detail-card.tsxclients/gui-app/src/components/epic-canvas/pr/pr-detail-header.tsxclients/gui-app/src/components/epic-canvas/pr/pr-panel-actions.tsxclients/gui-app/src/components/epic-canvas/pr/pr-source-notice.tsxclients/gui-app/src/hooks/composer/__tests__/use-epic-mention-entries.test.tsxclients/gui-app/src/hooks/composer/__tests__/use-github-mention-search.test.tsxclients/gui-app/src/hooks/composer/use-epic-mention-entries.tsclients/gui-app/src/hooks/composer/use-github-mention-catalog.tsclients/gui-app/src/hooks/composer/use-github-mention-search.tsclients/gui-app/src/lib/composer/mentions/__tests__/github-mention-chrome.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/github-mention-rows.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/mention-dismissal.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsxclients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/step-chrome.test.tsclients/gui-app/src/lib/composer/mentions/github-mention-chrome.tsclients/gui-app/src/lib/composer/mentions/github-mention-display.tsxclients/gui-app/src/lib/composer/mentions/github-mention-rows.tsclients/gui-app/src/lib/composer/mentions/index.tsclients/gui-app/src/lib/composer/mentions/mention-dismissal.tsclients/gui-app/src/lib/composer/mentions/providers.tsxclients/gui-app/src/lib/composer/mentions/root-search-ranking.tsclients/gui-app/src/lib/composer/mentions/step-chrome.tsclients/gui-app/src/lib/composer/segments.tsclients/gui-app/src/lib/composer/tiptap-json-content.tsclients/gui-app/src/lib/composer/types.tsclients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.tsclients/gui-app/src/lib/persist/index.tsclients/gui-app/src/lib/persist/keys.tsclients/gui-app/src/lib/pr/pr-review-decision-label.tsclients/gui-app/src/lib/pr/pr-source-notice-message.tsclients/gui-app/src/lib/query-keys/index.tsclients/gui-app/src/lib/query-keys/mention-query-keys.tsclients/gui-app/src/stores/composer/__tests__/github-mention-catalog-store.test.tsclients/gui-app/src/stores/composer/__tests__/github-mention-filter-store.test.tsclients/gui-app/src/stores/composer/github-mention-catalog-store.tsclients/gui-app/src/stores/composer/github-mention-filter-store.tsprotocol/src/common/__tests__/json-content-serializer-github-mentions.test.tsprotocol/src/common/json-content-serializer.tsprotocol/src/host/__tests__/mention-contracts.test.tsprotocol/src/host/index.tsprotocol/src/host/mention-contracts.tsprotocol/src/host/mention-schemas.tsprotocol/src/host/registry.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc2aee329e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Hardik Shingala <hardik@traycer.ai> # Conflicts: # clients/gui-app/src/lib/persist/keys.ts # clients/gui-app/src/lib/query-keys/index.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 81084064e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Capability gate, cache-write and filter-coercion fixes from the review pass on #1128, plus the provider submenu height regression #1045 introduced. - Gate both root rows on the host actually advertising the two mention methods, not just on the composer having roots. - Key the row store on the resolved (hostId, epicId, folders) identity so a host swap cannot serve another host's rows. - Merge fresh payloads over cached rows while preserving key and position; an authoritative empty now writes instead of being dropped as a placeholder. - Route the catalog refresh mutation's destination through onMutate context so a host swap mid-flight cannot apply the response to the wrong cache. - Parse integer-string issue numbers from HTML round-trips, and omit the url suffix from a serialized mention that has none. - Widen the filter popover's return-focus handoff to carry the printable character that reopened typing, and disambiguate repository labels on collision. - Bound the provider submenu again: max-h-[min(70vh,24rem)]. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
Changing State or Involvement emptied the list for the length of a round trip. The catalog only ever sweeps the DEFAULT view, so a filter it cannot answer - "State: Merged" over a cache of open pull requests - excludes every cached row the instant it is selected, leaving a lone "Searching GitHub…" row where the list was. The menu collapsed and re-expanded on every change, and while the remote was slow or rate-limit paused that empty frame read as the filter doing nothing at all. An empty local list under an in-flight search is "not answered yet", not "nothing matches", so the rows already on screen stay until the answer lands. Held per (section, query) so it is only ever a filter swap: a new query is a different question and still collapses, and a settled empty answer - however it settles - always wins over the hold. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbc25fdbe3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 16
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@clients/gui-app/src/components/chat/composer/menu/__tests__/github-mention-filter-popover.test.tsx`:
- Around line 274-282: The test currently hardcodes the internal
`"epic-1\x1fpull-requests"` store key. Update the lookup around
`useGithubMentionFilterStore.getState().filtersByKey` to derive the key through
the store’s exported key builder or a selector, reusing the existing store API
and preserving the current assertions.
In
`@clients/gui-app/src/components/chat/composer/menu/mention-step-chrome-bar.tsx`:
- Around line 121-135: Update the refresh button’s icon rendering in the visible
Button component to use AgentSpinningDots when spinner.refreshing is true, while
retaining RefreshCwIcon for the idle state. Remove the animate-spin class from
RefreshCwIcon and preserve the existing button behavior and accessibility
attributes.
In `@clients/gui-app/src/components/chat/composer/picker/suggestion-render.ts`:
- Around line 163-166: Update the mention branch in onStart to pass false
directly to isDismissedMentionQuery instead of calling inGithubMentionSection(),
ensuring every new occurrence uses the root-step punctuation rules before the
new picker session opens.
In
`@clients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.ts`:
- Around line 275-282: Update the enabled condition in useGithubMentionSearch so
it also requires supported, matching both catalog query gates. Preserve the
existing active and openSection checks, ensuring the search is disabled
immediately when host support changes to false.
In `@clients/gui-app/src/lib/composer/__tests__/tiptap-json-content.test.ts`:
- Around line 613-617: Strengthen the test around
buildAttachmentsFromJSONContent by asserting the string-input result has a
non-zero length before comparing it with the numeric-input result. Keep the
existing equality assertion to verify both paths produce the same attachment.
In `@clients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsx`:
- Around line 185-201: Extend the test around mentionProviderRegistry.entries
and the unsupported context by first creating a supported context with the same
"`#123`" query and asserting its labels include both “Resolve in Pull requests...”
and “Resolve in Issues...”. Keep the existing unsupported-context assertions to
verify those rows are absent when github.supported is false.
- Around line 240-241: Update the submenu provider tests around navigateEntry to
resolve the “Agents” and “Terminals” entries by label rather than using
entries[7] or entries[8]. Add or reuse an entryByLabel helper that returns the
matching entry with a clear failure when absent, then pass its results to
navigateEntry.
In `@clients/gui-app/src/lib/composer/mentions/github-mention-rows.ts`:
- Around line 472-482: Update referenceMatchesRow so the githubHost comparison
in the "url" branch lowercases both reference.githubHost and row.githubHost
before comparing, while preserving the existing owner, repo, and non-URL
matching behavior.
In `@clients/gui-app/src/lib/composer/mentions/mention-dismissal.ts`:
- Around line 22-33: Update the doc comment for the function containing the
inGithubSection check to name commas and semicolons, matching the punctuation
tested by query.includes(",") and query.includes(";"). Adjust the example title
accordingly so it demonstrates the actual dismissal rules without introducing
colon behavior.
In `@clients/gui-app/src/lib/composer/mentions/providers.tsx`:
- Around line 977-992: Update referenceResolveEntries to use the full
available(context) gate instead of checking only context.roots.length,
preserving the existing empty-entry behavior and aligning its comment with
rootEntry’s supported-host and non-empty-roots requirements.
- Around line 1027-1034: Update the doc comment for githubMentionSectionForStep
to describe that it returns the active GitHub section when the step is in one,
or null otherwise, rather than describing a boolean predicate.
In `@clients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.ts`:
- Around line 821-824: Update the scheduling configuration for
mention.githubSearch in the host-method policy table so typed queries share one
latest-wins coordinator lane keyed by host, scope, and section, excluding query
parameters. Preserve the existing LATEST_SCHEDULING behavior while adding the
scheduling identity required to cancel or supersede older searches.
In
`@clients/gui-app/src/stores/composer/__tests__/github-mention-catalog-store.test.ts`:
- Around line 103-118: In the test around selectGithubMentionScopeRepositories,
remove the local queryRepositories declaration, its equality/inequality
assertions, and the redundant recomputation of scopeRepositories already
represented by persisted. Keep only the assertion that the store-backed scope
result equals [ONE_REPO], since the ternary behavior is covered by the
sections-hook suite.
In `@clients/gui-app/src/stores/composer/github-mention-filter-store.ts`:
- Around line 110-120: Update selectGithubMentionFilter to apply the existing
section-specific filter coercion to persisted filters before returning them,
while leaving the default filter path unchanged. Ensure the coercion preserves
filter.repository by reference, and use the coerced result for filters returned
from state.filtersByKey.
In
`@protocol/src/common/__tests__/json-content-serializer-github-mentions.test.ts`:
- Around line 106-139: Update the test case “does not apply file-style
validation markers to either GitHub context” so each GitHub context is checked
in both “llm” and “user” formats against both “NOT FOUND” and “DELETED”. Ensure
the GithubPullRequest user-format assertion explicitly rejects its applicable
marker, covering the branch in jsonContentToMarkdown, while preserving the
existing validationResults setup and loop.
In `@protocol/src/host/__tests__/mention-contracts.test.ts`:
- Around line 346-354: The test named “accepts search responses with either row
variant and nullable notices” duplicates an earlier assertion and fails to cover
a non-null notice. Update this test around mentionGithubSearchResponseSchema to
use a valid non-null notice value while retaining both row variants, or remove
the redundant test if no additional coverage is needed.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7991bdb9-c252-40df-bc8b-bf1cce02e697
📒 Files selected for processing (67)
clients/gui-app/src/components/chat/composer/__tests__/chat-list-keymap-submit-source.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-dismissal-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.tsclients/gui-app/src/components/chat/composer/editor/extensions/attribute-helpers.tsclients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu-disabled-row.test.tsxclients/gui-app/src/components/chat/composer/menu/__tests__/composer-menu.test.tsxclients/gui-app/src/components/chat/composer/menu/__tests__/github-mention-filter-popover.test.tsxclients/gui-app/src/components/chat/composer/menu/composer-menu.tsxclients/gui-app/src/components/chat/composer/menu/github-mention-filter-popover.tsxclients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsxclients/gui-app/src/components/chat/composer/menu/mention-preview-panel.tsxclients/gui-app/src/components/chat/composer/menu/mention-step-chrome-bar.tsxclients/gui-app/src/components/chat/composer/nodes/composer-mention-decorator.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-catalog-write.test.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.tsclients/gui-app/src/components/chat/composer/picker/__tests__/use-slash-items-session.test.tsxclients/gui-app/src/components/chat/composer/picker/composer-picker-store.tsclients/gui-app/src/components/chat/composer/picker/suggestion-render.tsclients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.tsclients/gui-app/src/components/chat/composer/picker/use-mention-items.tsclients/gui-app/src/components/epic-canvas/pr/__tests__/pr-source-notice.test.tsxclients/gui-app/src/components/epic-canvas/pr/pr-detail-card.tsxclients/gui-app/src/components/epic-canvas/pr/pr-detail-header.tsxclients/gui-app/src/components/epic-canvas/pr/pr-panel-actions.tsxclients/gui-app/src/components/epic-canvas/pr/pr-source-notice.tsxclients/gui-app/src/hooks/composer/__tests__/use-epic-mention-entries.test.tsxclients/gui-app/src/hooks/composer/__tests__/use-github-mention-search.test.tsxclients/gui-app/src/hooks/composer/use-epic-mention-entries.tsclients/gui-app/src/hooks/composer/use-github-mention-catalog.tsclients/gui-app/src/hooks/composer/use-github-mention-search.tsclients/gui-app/src/lib/composer/__tests__/tiptap-json-content.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/github-mention-chrome.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/github-mention-rows.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/mention-dismissal.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsxclients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/step-chrome.test.tsclients/gui-app/src/lib/composer/mentions/github-mention-chrome.tsclients/gui-app/src/lib/composer/mentions/github-mention-display.tsxclients/gui-app/src/lib/composer/mentions/github-mention-rows.tsclients/gui-app/src/lib/composer/mentions/index.tsclients/gui-app/src/lib/composer/mentions/mention-dismissal.tsclients/gui-app/src/lib/composer/mentions/providers.tsxclients/gui-app/src/lib/composer/mentions/root-search-ranking.tsclients/gui-app/src/lib/composer/mentions/step-chrome.tsclients/gui-app/src/lib/composer/segments.tsclients/gui-app/src/lib/composer/tiptap-json-content.tsclients/gui-app/src/lib/composer/types.tsclients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.tsclients/gui-app/src/lib/persist/index.tsclients/gui-app/src/lib/persist/keys.tsclients/gui-app/src/lib/pr/pr-review-decision-label.tsclients/gui-app/src/lib/pr/pr-source-notice-message.tsclients/gui-app/src/lib/query-keys/index.tsclients/gui-app/src/lib/query-keys/mention-query-keys.tsclients/gui-app/src/stores/composer/__tests__/github-mention-catalog-store.test.tsclients/gui-app/src/stores/composer/__tests__/github-mention-filter-store.test.tsclients/gui-app/src/stores/composer/github-mention-catalog-store.tsclients/gui-app/src/stores/composer/github-mention-filter-store.tsprotocol/src/common/__tests__/json-content-serializer-github-mentions.test.tsprotocol/src/common/json-content-serializer.tsprotocol/src/host/__tests__/mention-contracts.test.tsprotocol/src/host/index.tsprotocol/src/host/mention-contracts.tsprotocol/src/host/mention-schemas.tsprotocol/src/host/registry.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2a8c25b99
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@clients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.ts`:
- Around line 321-328: The held-row key in useGithubMentionSections must include
scopeKey alongside openSection and query so hostId, currentEpicId, or
mentionRoots changes cannot retain rows from the previous scope. Update the key
passed to useHeldRowsDuringSearch and add a regression test covering a scope
change while the replacement search is in flight, ensuring stale rows are not
shown or selectable.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ed8e0264-7288-416c-bec7-da0b26597eab
📒 Files selected for processing (2)
clients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-filter-swap.test.tsxclients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.ts
Merges `main` and answers the Codex/CodeRabbit threads on #1128. The merge itself broke two files nothing conflicted in: `MentionMenuEntry` grew `updatedAt`/`archived` on main (#1127) while this branch grew `labelPrefix`. GitHub rows leave the new time slot null - their age is already composed into `detail` beside the repository, and filling both renders it twice. Correctness: - Sent-message chips render GitHub mentions. Their `path` is a synthetic token (`github-pr:org/repo#12`), so the generic chip read a basename off it and showed the raw token as the tooltip: `#4917` became `traycer#4917` with a file icon the moment the message was posted. - The live search is gated on `supported`, like the catalog reads already were. A host swap could negotiate the method away while the section stayed open. - The held-row key includes the scope. Holding rows across a host, epic or roots change offered selectable mentions the new scope cannot resolve. - Placeholder catalog responses are reported as the unanswered case rather than as rows. Same class as above: `keepPreviousData` hands over the PREVIOUS scope's answer, and every row in it is committable. - A placeholder response no longer arms the automatic stale follow-up, which spent a GitHub request deciding for a scope that had not answered yet. - `sourceStatus` and `notice` are gated on `wanted` like the rows, so a `gh-unavailable` banner cannot outlive the search that produced it. - URL host comparison is case-folded, like owner and repo already were. - `onStart` judges a new `@` by the root rules. The store can still hold the departing session's drilled step there, so `@x, y` could open the menu. - Persisted filters are coerced to their section on read - identity-preserving when there is nothing to coerce, because the selector's result identity is what decides whether to re-render. - The refresh control uses `AgentSpinningDots` rather than a spun icon. Tests: the vacuous halves are the point - marker assertions that checked for a marker the fixture never produces, a round-trip that passed if both sides went empty, absence assertions with no positive control, and store assertions comparing a local constant to itself. Category lookups go by label, not index. Not changed, with reasons in the thread replies: the menu's `min(70vh,24rem)` cap is the repository's viewport-cap idiom, not a fixed bound; the catalog's Zustand store is deliberate and outlives query `gcTime` by design. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e755e5971
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ow-up guard Two review findings on the GitHub mention picker, both about state outliving the question it answered. The live search carries `keepPreviousData` so typing does not blank the remote hits on every keystroke. That held the previous answer across ANY key change, including a host, epic, roots or section change - and those rows are merged into the new scope's list and stay selectable, so a user could commit a mention naming a pull request the current scope cannot resolve. The placeholder is now lane-scoped: kept across a query or filter change (which the merge corrects for downstream), dropped across a scope or section change. Both sides of the comparison build the lane through one function, and an unreadable key fails closed to "no placeholder" rather than to a cross-scope hold. The catalog's one-automatic-sweep-per-session guard reset whenever `allowStaleFollowUp` or `enabled` went false. Both flip inside a single menu session - stepping back to root turns the follow-up off, opening the other section disables the read - so a user moving in and out of a section whose cache the host still answers `stale: true` for enqueued a `refresh: "auto"` sweep every time. The guard now has one reset edge, the picker closing, expressed as an explicit `pickerActive` input; the scope and section stay in the stored value, where a change to either already fails the comparison. Both are covered by tests that drive the real hooks against a real QueryClient, each with a positive control for the case the fix must NOT change - the query-change hold, and the first sweep of a session. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1880fd3a7f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…uite
The search hook now reads `useReactiveHostReadiness` directly, to build its
placeholder lane from the same host id `useHostQuery` keys the cache by. This
suite mocks `useHostQuery` wholesale and passes a bare `{}` client, so that
read was never reached before and had no `getActiveHostId` to call.
Mocked rather than satisfied on the client, because the lane is not what these
four cases are about - they capture the `enabled` decision. The lane has its
own suite, which drives the real readiness path.
Signed-off-by: Hardik Shingala <hardik@traycer.ai>
…rtifact refresh Three findings from the review round on 1880fd3. Host in the auto-refresh guard. `followKey` carried epic, paths and section but not the host, while the `cacheKey` beside it always has. An app-wide composer rebinding to a second host that advertises the same epic and the same paths left every term unchanged, so that host's `stale: true` catalog read as a sweep that had already run and it never got the one refresh a session owes it. Zero-valued references. The patterns match `\d{1,7}`, which accepts `0` and `000`, while the wire row schema requires a positive number - so `@#0` classified as a resolvable reference, suppressed root's zero-match auto-close and offered a Resolve row for an identity no response can ever contain. Silent artifact refresh. `refetch()` resolves with a failed result rather than rejecting, so the button's `Promise.all` settled either way and the spinner stopped identically on success and failure; `useMentionItems` publishes `loadFailed: false`, so there was no inline surface either. Reported through `toastFromHostError`, the same manual-lane rule the GitHub catalog already follows - the automatic lanes stay silent and degrade in place. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f009aff81
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Review round on 4f009af. The visible list is the catalog's rows merged with the live search's, and the chrome's notice and banner can come from either, but the button was wired to `refreshManually` alone. With a typed query or a non-default filter, clicking "Refresh pull requests" therefore completed without touching the rows on screen or the search's own status - so a refresh pressed BECAUSE the section reported GitHub unreachable left that report standing. The search hook now exposes a `refresh` that no-ops while the observer is disabled, and the section asks both. Also stops the picker's Tab branch claiming Shift+Tab. That one is defensive, not a verified repair: by inspection the branch did match Shift+Tab, but instrumenting the handler shows it is never reached with Shift held, so the line is the right behaviour for a case that may not occur. It is deliberately untested - a test passes identically with and without it, which is the wrong kind of green. The reasoning is in the comment at the branch. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
clients/gui-app/src/lib/composer/mentions/providers.tsx (1)
953-969: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReset stale GitHub steps when availability changes.
stepEntriesstill returns cached rows andstepChromeCapabilitystill enables full chrome after support or roots disappear. Reset the active step to root, or make both methods availability-aware while preserving the back entry.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@clients/gui-app/src/lib/composer/mentions/providers.tsx` around lines 953 - 969, Update the GitHub provider’s stepEntries and stepChromeCapability methods to account for current support and configured roots before exposing cached rows or full step chrome. When GitHub is unavailable, reset the active step to the root step (or return availability-aware results) while always preserving the Mentions backEntry; retain the existing behavior when availability is valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@clients/gui-app/src/components/chat/__tests__/chat-user-message-content-github.test.tsx`:
- Around line 62-77: Update the test for ChatUserMessageContent to open the
rendered composer mention tooltip and assert it contains “traycerai/traycer#4917
· Stop the busy-loop”. Keep the existing `#4917` chip assertion, but replace the
query that only verifies the raw token is absent with a direct assertion of the
tooltip content.
---
Outside diff comments:
In `@clients/gui-app/src/lib/composer/mentions/providers.tsx`:
- Around line 953-969: Update the GitHub provider’s stepEntries and
stepChromeCapability methods to account for current support and configured roots
before exposing cached rows or full step chrome. When GitHub is unavailable,
reset the active step to the root step (or return availability-aware results)
while always preserving the Mentions backEntry; retain the existing behavior
when availability is valid.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b9301bf5-326d-45b0-b652-53bbb8a5b8d9
📒 Files selected for processing (37)
clients/gui-app/src/components/chat/__tests__/chat-user-message-content-github.test.tsxclients/gui-app/src/components/chat/chat-user-message-content.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-dismissal-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-mention-flow.test.tsxclients/gui-app/src/components/chat/composer/__tests__/composer-picker-store.test.tsclients/gui-app/src/components/chat/composer/menu/__tests__/github-mention-filter-popover.test.tsxclients/gui-app/src/components/chat/composer/menu/__tests__/mention-menu-item.test.tsxclients/gui-app/src/components/chat/composer/menu/mention-menu-item.tsxclients/gui-app/src/components/chat/composer/menu/mention-step-chrome-bar.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-filter-swap.test.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-github-mention-sections-refresh.test.tsxclients/gui-app/src/components/chat/composer/picker/__tests__/use-mention-items.test.tsclients/gui-app/src/components/chat/composer/picker/suggestion-render.tsclients/gui-app/src/components/chat/composer/picker/use-github-mention-sections.tsclients/gui-app/src/components/chat/composer/picker/use-mention-items.tsclients/gui-app/src/hooks/composer/__tests__/use-epic-mention-entries-refresh-error.test.tsxclients/gui-app/src/hooks/composer/__tests__/use-github-mention-catalog-follow-up.test.tsxclients/gui-app/src/hooks/composer/__tests__/use-github-mention-search-scope.test.tsxclients/gui-app/src/hooks/composer/__tests__/use-github-mention-search.test.tsxclients/gui-app/src/hooks/composer/use-epic-mention-entries.tsclients/gui-app/src/hooks/composer/use-github-mention-catalog.tsclients/gui-app/src/hooks/composer/use-github-mention-search.tsclients/gui-app/src/lib/composer/__tests__/tiptap-json-content.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/github-mention-rows.test.tsclients/gui-app/src/lib/composer/mentions/__tests__/providers.test.tsxclients/gui-app/src/lib/composer/mentions/__tests__/root-search-ranking.test.tsclients/gui-app/src/lib/composer/mentions/github-mention-rows.tsclients/gui-app/src/lib/composer/mentions/mention-dismissal.tsclients/gui-app/src/lib/composer/mentions/providers.tsxclients/gui-app/src/lib/composer/types.tsclients/gui-app/src/lib/host-rpc-policy/host-method-policy-table.tsclients/gui-app/src/lib/query-keys/index.tsclients/gui-app/src/stores/composer/__tests__/github-mention-catalog-store.test.tsclients/gui-app/src/stores/composer/github-mention-filter-store.tsprotocol/src/common/__tests__/json-content-serializer-github-mentions.test.tsprotocol/src/host/__tests__/mention-contracts.test.tsprotocol/src/host/registry.ts
💤 Files with no reviewable changes (1)
- clients/gui-app/src/stores/composer/tests/github-mention-catalog-store.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 03e5fbc03b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Before pushing this round I ran a cold adversarial audit over the PR's full cumulative diff — same posture as a review bot (reachable states only, no author intent), briefed on every defect class this PR's review history has surfaced. It confirmed six further defects in those same families; all are fixed in d9f0808 alongside the four thread fixes, so the diff under review has already survived one cold read:
Each fix carries its own pinning tests. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eb5a6bf90e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…rt held rows, readiness-gated follow-up, fluid menu cap Four review findings, each fixed at the class level: - The section matcher searched only `repo` and `owner/repo`, so typing the host-qualified identity the UI itself prints for cross-host name collisions dropped the row. Text matching now scores one host-qualified haystack (which subsumes the old clauses as substrings), and the reference grammar gained the three-segment `host/owner/repo#123` form, parsed with `githubHost` and matched host-aware at exact rank - a repository name cannot contain `/`, keeping the segment count unambiguous. The two-segment form stays host-agnostic. - Rows held on screen across a filter swap (deliberately, to prevent the collapse-flash) were published as ordinary selectable entries, so the funnel could claim the new filter while Enter inserted a row it never matched. MentionMenuEntry gained `disabledReason` (mention items could never be disabled; only command items could), the picker's disabled read honors it, and the sections hook reports `rowsHeld` for exactly the stand-in window - held rows render inert with a screen-reader reason until the search answers. - The auto follow-up effect marked its one-per-session key and issued the mutation without checking host readiness, so a request rejected at preflight spent the key and left the scope unrefreshed once the request context returned. The effect now defers both the mark and the send until `readiness.isReady`; it re-runs when readiness flips. - The provider submenu's height cap had been changed from main's fluid `max-h-[70vh]` to a rem-ceilinged min() that binds on effectively every desktop viewport, against the repo's fluid-sizing rule. Reverted to the viewport cap. Each fix is pinned: qualified-query matcher and three-segment parser tests with github.com and case-fold controls, a rowsHeld projection test beside the existing hold pins, provider entries carrying the disabled reason exactly while held, the mention-item disabled read, and a not-ready-then-ready follow-up test asserting zero mutations before the flip and exactly one after. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
…ests The scope's identity is order-independent everywhere it is compared - githubMentionScopeKey sorts, the follow-up key sorts - but the WIRE requests carried the caller's ordering, and the TanStack query key, the pending-refresh keys, and the refresh destination all hash the request. An order-only change in the same folder set (detach /a and re-attach it) therefore forked one logical scope into two cache slots: a refresh issued under the old ordering wrote its response to a slot the menu no longer read, and the current slot neither showed the response nor reported the refresh as pending for its 60s staleTime. The catalog hook now derives one sorted canonicalWorkspacePaths and feeds it to the cache-only request, both refresh mutations, and the follow-up key; buildSearchRequest sorts identically. Pinned by a reorder-mid-refresh test (isChecking survives the same set in reversed order while the refresh is in flight) and a search-request canonicalization test. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 734b891d33
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…path to the chrome Three review findings, each fixed at the class level: - githubMentionRowKey joined host/owner/repo verbatim while every comparison around it folds - the one key derivation the casing rule missed. A repository whose casing was renamed between the cached sweep and the live search arrived as two spellings of one artifact, and the merge appended a committable duplicate instead of replacing the stale payload. The key now folds through foldGithubIdentitySegment. - The filter popover's onCloseAutoFocus unconditionally returned focus to the composer, so closing it by clicking another control stole the focus that click had just placed and routed subsequent typing into the mention query. onInteractOutside now marks outside-interaction closes (the trigger exempt - the funnel button is a return-to-composer path like Escape), and the refocus is skipped for exactly those; Radix's default trigger-focus stays prevented on every path. - The step chrome's Filter and Refresh buttons render through a portal after the editor in DOM order, so no native traversal direction could reach them from the composer - keyboard-only users had no route to either control. Shift+Tab now moves focus into the chrome explicitly (marker attribute rendered only when a step published chrome), consuming the key only when focus actually moved. Pinned by a two-spellings merge test with a different-repo control, a row-key equality unit, an outside-click no-refocus test beside the Escape control, and handler-level Shift+Tab tests (focus lands and the key is consumed; no chrome falls through; plain Tab still commits). Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b2d4fb4e5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…bled state Four review fixes, then five pre-push audit fixes of the same class: every one collapses a second hand-written answer into the one that already existed. Review round: - Mention rows honor `entry.disabledReason`: `renderPickerItem` flowed slash items through `pickerItemDisabledReason` but hardcoded `null` for mentions, so a held row rendered actionable while the store blocked its commit. Both kinds now share the predicate. - `githubMentionToken` folds host/owner/repo through the row key's own fold: the row key merging two spellings into one row made a verbatim token a live defect - the payload respelling a merged row re-identified its attachment, minting two paths for one artifact. The tiptap rebuild fallback delegates to the same exported builder instead of restating the rule by hand. - The cross-section scope preference compares `answeredAt` (client arrival, TanStack `dataUpdatedAt`) instead of `freshnessAt`, which stamps the host's last successful GitHub reach and does not advance across a degraded re-resolution. - Root ranking rewrites a URL-shaped query to the `owner/repo#123` reference form rows actually carry, so a pasted URL's exact row takes the top tier instead of losing a fuzzy match on strings that can never contain a URL. Audit round (restatement sweep over the cumulative diff): - ONE default-host predicate: `isDefaultGithubMentionHost` (folded) lives in protocol beside the serializer that needs it; the serializer arms, the prose reference, the token builder and the ranking rewrite all call it. A row or node spelled `GitHub.com` is the default host everywhere now - prose and serialized forms no longer assert a host qualification the identity layer says does not exist. - `githubRepositoryQualification` is THE escalation walk: the filter popover's label switches on it instead of re-implementing the collision walk (format divergence stays, commented as deliberate). - Qualification distinguishes ignorance from answer: the section context's `repositories` is null until the scope resolves, and null qualifies rows at `owner/repo` - the live search can put rows from several repositories on screen before any catalog answers, and the old empty-array masquerade labelled them all bare `#123`. The comment claiming that window had no rows was false and is corrected. - The zero-match reference exemption gates on the provider's own exported `githubMentionCategoryAvailable` instead of a hand-written twin of it. Every behavioral fix is pinned by revert-probed tests. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e85e47096
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
gui-app's type-aware `eslint . --cache --fix --max-warnings 0` runs against a cold cache in CI and has hit Node's ~4GB default heap ceiling twice in a row (FATAL heap OOM, SIGABRT mid-lint) on two different heads, while the same command passes locally against a warm cache. The ubuntu runner has 16GB; 6GB of old-space is headroom, not a workaround - the alternative is rerunning the gate until garbage collection gets lucky. Signed-off-by: Hardik Shingala <hardik@traycer.ai>
… it is
`numberMatchScore` answers "is this query a number naming a row?" with
yes for bare digits (`^#?\d+$` is its own test), while
`parseGithubReferenceQuery` demanded the hash - so `@4917` ranked as
exact-number intent yet earned no `Resolve in ...` row and no
zero-match dismissal exemption, and a settled empty search closed the
picker over an artifact the section could still fetch. The parser now
accepts `^#?(\d{1,7})$`, making it the one answer both gates read; the
positive-number rule still rejects `@0`, and digits embedded in prose
stay prose. Pinned by parser tests.
Also moves the lint heap headroom into gui-app's own `lint` script:
the 4GB default OOM first hit two consecutive CI heads and then the
local hook, so a per-runner workflow env was the wrong home - the
script is the one place every invocation inherits it. The workflow
env from ff7d79f is reverted to keep the rule in one place.
Signed-off-by: Hardik Shingala <hardik@traycer.ai>
# Conflicts: # clients/gui-app/src/traycer-app.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aeebdbc9dc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Adds two
@-mention sections to the composer — Pull requests and Issues — listing GitHub items from the repos behind the composer's attached folders, plus the protocol contract the host serves them over.The sections are provider-agnostic by design: Linear issues later merge into the same Issues list rather than growing a third root row.
What you get
epic→review-requested→assigned→authored), then recency. Typed queries rank by match strength first, buckets as tiebreak.(githubHost, owner, repo, number)— the cached row keeps its position and key, the fresh row supplies the payload.(epicId, section)as a view preference only.#123,org/repo#123, a GitHub URL) are exempt from root's zero-match auto-close and offerResolve in Pull requests…navigate rows.github_pull_request/github_issuemention chips.Protocol
Two additive unary methods —
mention.githubCatalogandmention.githubSearch— bothdegrade: { kind: "unsupported" }, so an older host answers cleanly. Artifacts-style unary rather than streams, matching the existing mention surfaces.Per-provider methods rather than a generic
mention.catalog(provider)is deliberate: each method carries its own capability answer through the handshake, so "does this host serve GitHub mentions?" needs no second in-band mechanism, and a futuremention.linearCataloggets an old host's clean "no" for free. The scopes also differ in kind — GitHub's is folders → git remotes → repos, Linear's is a workspace/team selection with its own auth and its own rate budget.Rides along
setStep(current)early-returns in the picker store, so the exposedrefetch()was never called. The new per-step chrome contract routes it to the real one.max-h-[70vh]; with a 25-row result limit that is a menu that takes over the window rather than one that grew, and it affected Files just as much as the new sections. Nowmax-h-[min(70vh,24rem)], matching themin(70vh, N rem)idiom every other tall surface here already uses. Root and typed-query lists are unchanged, and short windows still resolve to the70vhterm.Notes for review
RadioGroup(WAI-ARIA radios activate on Space) — arrows and Space drive it.keepPreviousDatais lane-scoped on the search, not blanket. It is what stops typing from blanking the remote hits on each keystroke, so it is kept across a query or filter change - both of which the merged list corrects for downstream. It is dropped across a host, epic, roots or section change, which nothing downstream can correct: those rows are merged into the new scope and stay selectable. Both arms are also filtered by akindpredicate at point-of-use, so switching sections cannot insert a pull-request chip from the Issues list.(hostId, epicId, folders, section). A review round pointed out the session row store was a second copy of server data; it is deleted — root search ranks the cache-only hydration reads' answers directly, and a longgcTime(not a parallel store) carries session warmth across menu opens, so a drifted scope re-keys instead of being served stale rows.Requires the matching host change (internal
traycer-hostPR) — the sections stay hidden against a host without these methods.Follow-ups in this branch
State: Mergedover a cache of open PRs) excluded every cached row the instant it was selected, leaving a loneSearching GitHub…row for the length of a round trip. The rows on screen now hold until the answer lands, keyed per(scope, section, query)so it is only ever a filter swap — a new query still collapses, and a settled empty answer always wins over the hold.Deliberately not in this PR
Six review findings are real, confirmed against the code, and left for their own change rather than half-wired here. Each carries its reasoning on its thread; summarised so they are not read as missed.
Their threads are resolved, and none of them is fixed. This repo requires every review thread resolved before a PR can merge, so resolution on these carries no claim that the code changed — this table is the record.
githubMentionTokenomitsgithubHost, so one scope spanning two GitHub hosts collides onowner/repo#numbermentionNoMatchDismissVerdict, so an incomplete search can auto-close as an authoritative zero-matchuse-mention-items, plus a decision on hold-open vs. inline error rowsearchQuery.error, so a rejected search reads as a completed empty onenoticevocabulary rather than a per-keystroke toasthost-rpc-policyshape change, and getting it wrong silently collapses lanes meant to be distinctsourceStatus: "error"and"partial"get no banner, so a section can present an incomplete read as an authoritative empty oneThe last one is bounded by the row being a real, resolvable pull request the user can see and clicked - the list disagrees with the funnel for one round-trip, nothing broken is committed.