feat(codex): add native Goal lifecycle controls - #7935
UI Consistency: All clear
All clear
Details
Note
Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.
🔍 Agent activity — 17 tool calls
💭 I'm checking the current PR head against prior review comments — it looks like the goalCommandsInFlightRef state issue flagged earlier has been addressed with the new goalCommandThreadKeysInFlight and goalCommandRunning state. Now I'm reviewing ChatView.tsx and state/threads.ts to verify the Goal banner ordering matches an earlier comment.
1. git_tools — codexGoal
2. git_tools — d77e078..5246dfdfe4e254323ca41d1b47e11f1d29029fc46
💭 I want to check the relevant sections of ChatView.tsx to see its current state.
3. browse_code — apps/web/src/components/ChatView.tsx
💭 I catch a typo and correct the hash to use instead: 5246dfd.
4. browse_code — apps/web/src/components/ChatView.tsx
💭 With the ordering fixed and tooltip added, I'm checking how ComposerBannerStack renders the description to confirm other banners already use Tooltip similarly, like the branch-mismatch one in the title, and verifying that wrapping TooltipTrigger's render prop around a span works without needing an extra provider given existing usage elsewhere in the file. The line-clamp-2 span should work fine since Tailwind sets it to display as a webkit box. Now I want to trace through the send-disabled logic and how goalCommandRunning is wired in, so I'll look at the relevant sections further down in the file.
5. browse_code — apps/web/src/components/ChatView.tsx
6. browse_code — apps/web/src/components/ChatView.tsx
💭 With the prior findings addressed, I'm now scanning for remaining UI-consistency issues across the scope files—checking whether the toast helper supports the "warning" type used elsewhere, verifying the icon import lines up with what other banners use, and confirming the goal-state hook's imports are sound.
7. git_tools — stackedThreadToast
8. git_tools — TargetIcon
💭 I'm tracing where TargetIcon is imported from and checking the surrounding import block for ordering issues, then moving on to look at the composer slash-command menu implementation. I'm considering whether the web composer surfaces slash commands from provider capabilities—likely it does—and noting that a change to
isUnadornedCodexCommandinvolving!directAnnotationalters existing feedback command behavior, which is more of a behavioral shift than a UI consistency concern. I want to check specific line ranges further down to look for actual UI issues.
9. browse_code — apps/web/src/components/ChatView.tsx
💭 I see how the feedback command path tracks in-flight uploads via a ref and drives the "uploading" status through feedbackSubmissions state. Now I want to check the goal path around lines 5366-5475 to compare how it's handled there.
10. browse_code — apps/web/src/components/ChatView.tsx
💭 This looks consistent — the goal command running state properly gates the send button through sendDisabledReason, and it's keyed correctly on routeThreadKey just like feedbackUploading. I'm now checking whether the Goal banner correctly displays with an "info" variant for the complete and blocked statuses. The blocked or budgetLimited states could arguably use a warning variant instead, but that's more of an aesthetic choice than something required. I want to verify ComposerBannerStack properly supports ReactNode descriptions and that TooltipTrigger works fine inside stacked banners with pointer-events-none, similar to how the branch-mismatch banner already handles this. I don't see any raw buttons bypassing shared primitives in the web app. The codexGoalBannerItem's id fallback to "unknown" is consistent with other items, and the minor max-width difference in TooltipPopup classes (max-w-96 vs max-w-80) is trivial. Now I want to check whether ComposerBannerStack already applies truncation or line-clamp styling to descriptions, and whether that could conflict with a line-clamp-2 if one gets added — so I need to read through that component.
11. browse_code — Show the full source of the ComposerBannerStack component (apps/web/src/components) including the ComposerBannerStackItem type and how description, title, icon, actions, and onDismiss are rendered, plus any Alert/AlertTitle/AlertDescription primitives it uses and their classes.
💭 I'm checking that the AlertDescription's flex column layout works fine with the line-clamp span stretching properly, and now considering whether the tooltip trigger span nested in the hidden stacked banner area causes any issues. The tooltip trigger renders as a span, so it's not keyboard-focusable, but this matches the existing pattern used by the branch-mismatch banner's
<code>element, so it's consistent. I'm double-checking the import ordering in the diff isn't a real UI consistency issue, and looking at threads.ts to confirm the Option import is present.
12. browse_code — apps/web/src/state/threads.ts
💭 That looks consistent with the existing pattern. Now I want to check whether the web composer has its own hardcoded slash-command list, since the PR adds server-side capabilities for commands like
/goal— if the menu relies on a local list rather than pulling from provider capabilities, that list might need updating too for consistency.
13. git_tools — slashCommands|slash-command|SlashCommand
💭 I want to check how
getProviderSlashCommandsForSlashMenufilters the provider slash commands, and how selecting one handlesinput.hint. I also need to verify whether/feedbackis already included in CODEX_SLASH_COMMANDS.
14. browse_code — Show getProviderSlashCommandsForSlashMenu implementation and where it's defined, and how selecting a "provider-slash-command" item in ChatComposer inserts text into the composer (does it use command.input.hint?). Also show ChatComposer.tsx lines ~1080-1150.
💭 The
/goalcommand will show up in the slash menu with its description, but that's server-side and out of scope. I'm checking whether other providers like/feedbackare advertised the same way, though that's not really relevant here. I confirm the goal command only fires when the selected provider is codex, matching how feedback works, and the active-session banner follows the same provider check. The mobile file is outside my scope since only web include patterns matter here. I trace through the toast formatting for goal status and the loading-state toast, both of which look fine with minor edge cases around invalid actions. Now I want to verify the icon import used in the diff actually comes from lucide-react by checking the relevant lines in ChatView.
15. browse_code — apps/web/src/components/ChatView.tsx
💭 I notice a duplicate import from the same module, which is more of a code-hygiene concern than a UI consistency issue. Since the review scope is about UI consistency violations specifically, I don't think this warrants flagging even though a linter would catch it. Let me focus back on genuine UI issues. The goal banner always uses an "info" variant regardless of actual status like blocked or budget-limited, which is a minor aesthetic mismatch. The goal banner also stays permanently visible without dismissal, though ordering already resolved that concern. I should check how the tooltip renders within the attached banner stack, and whether
sendDisabledReasonis properly surfaced with an appropriate aria-label when the send button is disabled. Reasons like "Sending feedback" or "Messages loading" use gerund phrasing, so "Running Goal command" fits that pattern. I'm also noting there's no distinct busy indicator for the in-flight goal state beyond the existing disabled feedback. I want to check ComposerPrimaryActions to see if sendDisabledReason maps to specific spinner states.
16. browse_code — How is the sendDisabledReason prop consumed in ChatComposer.tsx and ComposerPrimaryActions? Show the code paths where it is used (disabled state, aria-label, tooltip, spinner). Is it a union of literal strings or a free-form string type?
💭 Everything checks out consistently so far. I'm double-checking the Goal banner's lifecycle tied to session state, confirming the hook is called unconditionally as expected, and now looking at how invisible pointer-events-none styling applies within the stacked banner area. The tooltip pattern used for the Goal banner matches the established line-clamp + tooltip approach seen in ThreadErrorBanner, including the same non-interactive span trigger tradeoff around keyboard focus. I'm satisfied the previously reported issues are resolved and don't see new concrete inconsistencies, though I want to verify the Tooltip component setup once more. Since TooltipTrigger and TooltipPopup are already used elsewhere in ChatView, imports should already be in place. I'm scanning the diff for CSS changes (none found) and thinking about whether behavior changes to composer banner assembly warrant new tests — there's existing coverage for ComposerBannerStack, but I should check if there's a test specifically covering composer banner ordering that ought to include the goal banner now.
17. git_tools — parkedThreadBannerItem|banner ordering|composerBannerItems
💭 I don't see tests for ordering, and that's fine since it's not required. Scanning once more for UI-consistency issues, the send-block condition looks correct since it now checks both the in-flight ref and state existing. I'm noting that goalCommandRunning is keyed by routeThreadKey while submittedThreadKey uses activeThreadKey for staleness checks, which I should verify is consistent with the in-flight set's keying. Checking the finally block and unmount behavior, plus the Goal banner's id usage against activeThreadId — both look fine, no real findings here. Given there's a conflict between the "All clear" plain-text instruction and the required JSON schema, I'll resolve it by setting a success state with title "UI Consistency: All clear" and keeping the summary field exactly as "All clear".
Agent Credits: 365 credits