Skip to content

Plan mismatch UX: calm popup, detected display, overrides, aliases - #304

Merged
jaywedgeworth22 merged 10 commits into
mainfrom
opencode/dashboard-window-title
Oct 22, 2026
Merged

jaywedgeworth22 merged 10 commits into
mainfrom
opencode/dashboard-window-title

Conversation

@jaywedgeworth22

@jaywedgeworth22 jaywedgeworth22 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Owner requests 2026-10-21/22, OpenCode (Codex at cap; CC-176 + CC-179 claimed by OPENCODE).
Boards: CC-176, CC-179. CI is the compile gate (no Swift toolchain on this Linux seat). String grep confirms no stray Dashboard/Settings leftovers.

Summary

This PR makes plan-name mismatch handling calmer and more actionable. Users can now see the provider-detected plan alongside their entered value, resolve mismatches directly, and persist explicit choices to prevent repeated interruptions. It also standardizes the dashboard window title and terminology.

Functional changes

  • Shows the provider-reported plan beneath each platform’s entered Plan Name, with a clear mismatch explanation when the values differ.
  • Adds direct resolution actions:
    • Use detected replaces and saves the entered plan with the provider-reported value.
    • Keep mine — don’t warn records the exact provider, entered-plan, and detected-plan combination and suppresses future warnings for that combination.
  • Reworks the mismatch alert with CodeCaps branding, clarifies that entered values remain unchanged, and provides Open Settings, Continue, and Don’t show this again actions.
  • Persists global warning suppression, previously detected plans, accepted overrides, and presentation timing across launches.
  • Adds a Plan Mismatch Warnings setting. Disabling it suppresses previously known repeat detections while still allowing new provider or detected-plan mismatches to surface.
  • Improves plan comparison aliases:
    • OpenAI Pro Lite variants are treated as equivalent.
    • Cursor Ultra variants are treated as equivalent.
    • Grok Bot’s generic “Grok Bot Plan” no longer conflicts with an entered plan.
  • Keeps the main window titled CodeCaps Dashboard regardless of the selected page and renames the console sidebar section from Dashboard to Settings.
  • Updates README navigation and terminology to match the new Settings structure.

Tests

Added PlanComparison coverage for OpenAI Pro Lite aliases, Cursor Ultra aliases, genuine tier mismatches, and generic Grok Bot plans.

Outstanding review findings

  • The hourly throttle is not currently enforced because lastPresentedAt is read but never written, so unsuppressed prompts can appear more frequently than once per hour.
  • finishPresentation() clears the active presentation state while the alert modal is still in flight.
  • The platform page selects the provider’s first matching window for Detected, while the warning popup may select a different disagreeing window, so the displayed values can differ.
  • A previously accepted Keep mine mismatch is suppressed in the popup but still presented as a live mismatch on the platform page.
  • The Plan Mismatch Warnings tooltip uses a regular space instead of the intended nonbreaking sentence gap.
  • The review could not fully validate the business rules because the task description did not define them.

Summary

  • Registers github-copilot and copilot as aliases for the Copilot platform mark and classifies them for monochrome rendering.
  • Adds Copilot-aware provider resolution to companion quota items, recognizing Copilot in provider keys or lower-level quota identifiers.
  • Renders resolved Copilot companion marks in monochrome.
  • Improves recovery when a provider mark is unavailable: the first three retries occur after 1 second, retries continue every 5 seconds during the install/update window, and then settle to every 60 seconds.
  • Extends provider-logo and retry-schedule test coverage.

Test Coverage

  • PlatformLogoTests
  • ProviderMarkResolutionTests
  • ProviderMarkTripletTests

Review-Identified Follow-ups

  • The expected Copilot PNG assets are not currently produced by a generator target, so Copilot logo lookup can fall back to the dashed placeholder.
  • Pool-scoped Copilot provider keys are not included in the core monochrome-key classification.
  • The widget provider-mark resolver still lacks a Copilot-specific branch.

Summary

  • Adds asynchronous startup preloading for all bundled provider mark variants and the in-app brand mark. The preload is intended to avoid filesystem probes and placeholder rendering during the first UI draw.
  • Marks GitHub Copilot quota and fallback plan records with a "monthly" quota window, including when the remaining percentage is unknown.
  • Adds an asset inventory documenting canonical brand artwork, macOS and iOS app assets, their intended uses, and regeneration workflows.

Review Findings

  • Critical: preloadBundledMarks() mutates PlatformLogoImage static cache state from a background queue without synchronization.
  • High: The preload warms cache keys that the hinted rendering path does not read, so the intended first-render improvement is not guaranteed.

Summary

  • Made the plan mismatch warning alert’s suppression control nil-safe.
  • The “Don’t show this again” label can now be assigned without assuming the suppression button always exists.
  • Suppression is recorded only when the suppression button is present and enabled, ensuring the alert remains safe if the control is unavailable.

Impact

This hardens the plan mismatch warning dialog’s “Don’t show this again” behavior without changing the warning or navigation flow.


Summary

  • Prevents plan-mismatch warning modals from being prematurely finalized when model changes occur while an alert is already open, avoiding duplicate stacked dialogs.
  • Records the presentation time after a plan warning is actually shown, allowing the existing once-per-hour suppression to work as intended.
  • Synchronizes access to provider artwork bundle and failure state used during concurrent asset preloading and rendering.
  • Clears the cached resource bundle when artwork caches are invalidated so subsequent lookups can resolve the currently available assets.

Review Note

A remaining race was identified in PlatformLogo: bundle resolution occurs outside the lock, so an in-flight resolution can repin a bundle after invalidation has cleared it. The review finding should be addressed before merge to fully prevent stale bundle pinning.


Summary

Simplifies the plan-mismatch controls and fixes a resource-bundle cache race that could allow stale logo assets to remain pinned after cache invalidation.

Changes

  • Renamed Use detected to Use Detected. The action continues to replace the entered plan with the provider-reported value and save it.
  • Replaced Keep mine — don't warn with Keep Mine. The action continues to record the provider, entered plan name, and detected plan name as an accepted mismatch.
  • Updated the notification settings copy to use the same Keep Mine wording and explain that explicit per-platform acceptance is independent of the global warning switch, while a changed plan name warns again.
  • Added cache-generation tracking for platform logo resources. Bundle resolution that began before an invalidation can no longer restore a stale bundle afterward, allowing bundled logo variants to remain available after cache clearing.
  • Applied the same cache-generation safeguard to both cache invalidation paths.

Known Limitation

  • The Keep Mine action records accepted mismatches, but the popup path does not currently consult those suppression records. The popup may therefore continue to warn even after a user explicitly selects Keep Mine; this remains unresolved in the current patch.

Summary

  • Centralize accepted plan-mismatch overrides in the shared warning generator so an explicitly acknowledged provider, entered-plan, and detected-plan combination is suppressed for all warning callers.
  • Remove the redundant mismatch filter from the AppDelegate.
  • Align the platform detail page with the mismatch popup by displaying the detected plan from a window that actually disagrees with the entered plan, falling back to the first valid detected plan when none disagree.
  • Treat accepted mismatch combinations as resolved on the platform detail page so they are no longer shown as active mismatches or offered for resolution again.

Impact

Previously acknowledged mismatches no longer resurface in popups or other warning views. The provider detail page now identifies the same mismatching plan shown by the popup and avoids presenting already-resolved combinations as unresolved issues.

- Popup shows the transparent colour mark with CodeCaps beside it
  (About-style asset, not the app icon).
- Popup fires at most once an hour; Don't show this again checkbox
  (unchecked default) silences repeats but never first sightings of
  a new provider or changed detected plan.
- Platform pages show Detected: <plan> under Plan Name, with
  Use detected and Keep mine actions; an explicit choice never
  warns again.  Plan mismatch warnings toggle on Alerts & Alarms
  re-enables the popup.
- Alias rules: anything with pro lite/prolite is prolite (Codex);
  anything with ultra is unified_ultra (Cursor); generic
  Grok Bot Plan never mismatches.
- Window title always CodeCaps Dashboard; sidebar group back to
  SETTINGS.

Boards CC-176, CC-179.
@kody-ai

This comment has been minimized.

Comment thread Sources/CodeCaps/AppDelegate.swift
@github-actions

Copy link
Copy Markdown
Contributor
Autofix run https://github.com/Simple-With-Us/CodeCaps/actions/runs/39714598094 started for `sentry[bot]`'s tagged request. Owner/sentry request: exempt from the per-bot cap (owner rule 2026-10-20).

Official outline mark cut to the family triplets (256px color,
light-ink, dark-ink PNGs plus the source SVG), wired into the Mac
provider map as a single-colour template mark, added to the iOS
asset catalog with model mapping, and covered by the triplet and
resolution tests.  Missing-mark retry now re-probes at 1s for the
first three attempts so a late-arriving bundle heals faster.
@jaywedgeworth22

Copy link
Copy Markdown
Member Author

Added: official-outline GitHub Copilot mark (Mac triplets + source SVG, iOS imageset + mapping, test coverage) and faster early missing-mark retries (1s x3, then 5s/60s). Re the unofficial purple/3D renders: left out of the bundle deliberately (IP + template-mark reasons); they work as personal Custom marks under Logo Style.

@kody-ai

kody-ai Bot commented Oct 22, 2026

Copy link
Copy Markdown

kody code-review Kody Rules low

Settings tooltip has a non-NBSP sentence gap

The tooltip violates the approved NBSP-based sentence spacing. Build it by concatenating with sentenceGap instead of the two ASCII spaces.

Kody rule violation: Sentence gap by surface: two ASCII spaces in files, U+00A0 plus a space in rendered copy and GitHub text

Prompt for LLM
Settings tooltip has a non-NBSP sentence gap

Replace the two ASCII spaces in this rendered tooltip with `sentenceGap` or an actual U+00A0 followed by one ASCII space, because app-visible sentence boundaries must use the approved NBSP-based gap.

Kody rule violation: [Sentence gap by surface: two ASCII spaces in files, U\+00A0 plus a space in rendered copy and GitHub text](https://app.kodus.io/settings/code-review/global/kody-rules/2a52ef80-886f-4e53-994b-2f70ee73f305?teamId=69360e3a-6b41-45d2-9e49-fde78fe49457)

​

@kody-ai

kody-ai Bot commented Oct 22, 2026

Copy link
Copy Markdown

kody code-review Business Logic medium

Task description is insufficient for business logic validation.

🤔 Insufficient Task Context

I found a task linked to this PR, but it only contains minimal information (title only, no description or acceptance criteria). To perform a meaningful business rules validation, I need more details.

🔍 What I need to validate:

  • Business requirements and acceptance criteria
  • Expected behavior and business rules
  • Edge cases and constraints to consider

💡 How to improve the task context:

  • Add a description to the linked ticket
  • Include acceptance criteria or business rules
  • Describe the expected behavior after the change

⚠️ Important:

A task title alone is not sufficient to determine whether the implementation is correct or complete.


💡 This validation runs automatically only on the first review of a pull request. To run it again, comment @kody -v business-logic.

Prompt for LLM
Task description is insufficient for business logic validation.

<!-- task_context_status:weak -->
## 🤔 Insufficient Task Context

I found a task linked to this PR, but it only contains minimal information (title only, no description or acceptance criteria). To perform a meaningful business rules validation, I need more details.

### 🔍 What I need to validate:
- Business requirements and acceptance criteria
- Expected behavior and business rules
- Edge cases and constraints to consider

### 💡 How to improve the task context:
- Add a description to the linked ticket
- Include acceptance criteria or business rules
- Describe the expected behavior after the change

### ⚠️ Important:
A task title alone is not sufficient to determine whether the implementation is correct or complete.

---
> 💡 This validation runs automatically only on the first review of a pull request. To run it again, comment `@kody -v business-logic`.

​

Comment thread Sources/CodeCaps/AppDelegate.swift
Comment thread Sources/CodeCaps/AppDelegate.swift Outdated
Comment thread Sources/CodeCaps/ConsoleViews.swift
Comment thread Sources/CodeCaps/ConsoleViews.swift
icon-1024-textured.png and icon-512-alternate-teal.png have no
references anywhere.  Everything else stays: the three brand SVGs,
the black menu-bar template, the release icon master + icns, and
the two bundled Resources PNGs the app loads at runtime.
@kody-ai

This comment has been minimized.

Five appiconset PNGs were unreferenced by the manifest and mixed a
light treatment into an otherwise dark set.  assets/README.md now
maps every logo file to its surface and regeneration path so the
next seat does not have to guess.
Comment thread Sources/CodeCaps/PlatformLogo.swift
Comment thread Sources/CodeCaps/PlatformLogo.swift
Comment thread ios/CodeCapsCompanion/App/Models/CompanionQuotaModel.swift
Comment thread ios/CodeCapsCompanion/App/Models/CompanionQuotaModel.swift
Swift requires call-site argument order to match the declaration:
QuotaWindow declares remainingPercent/remainingUnknown ahead of window,
and both Copilot call sites passed window first, failing the Mac package
build with 'argument must precede argument window' at lines 64 and 80.
Reordered only; no values change.
@swu-wise

swu-wise Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Build fix from the fleet lane: the Mac package build has been failing since 03:40 UTC on the two Copilot QuotaWindow call sites - Swift requires declaration order, and QuotaWindow declares remainingPercent/remainingUnknown ahead of window. Pushed 92125ba reordering the arguments only (no values change). The 9 open Kody threads stay with the feature lane.

@kody-ai

This comment has been minimized.

Comment thread Sources/CodeCaps/PlatformLogo.swift
Comment thread Sources/CodeCaps/PlatformLogo.swift

@kody-ai kody-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found critical issues please review the requested changes

NSAlert.suppressionButton is NSButton?, so both accesses failed to
compile: the title assignment and the state read.  Optional-chained
both; when the button is absent the title set is a no-op and the state
read falls through, which is the same behavior the unwrapped code
intended.
@kody-ai

This comment has been minimized.

Three review findings on the plan-mismatch and Copilot-mark code:

- The one-hour throttle never engaged because lastPresentedAt was read
  but never written.  It is now stamped when the alert is actually
  shown, next to record(warnings).  (Two threads.)

- A model change can re-enter checkPlanMismatches while the modal is
  visible (NSAlert.runModal spins a nested run loop):  warnings()
  returns [] for a cycle already presenting, and the empty branch then
  cleared isPresenting under the visible alert, letting a second modal
  stack.  The empty branch now only finishes a cycle this call did not
  open.

- preloadBundledMarks() mutates PlatformLogoImage's cachedBundle and
  lastFailure on a background queue while the main thread reads them.
  Both are now guarded by a stateLock, with bundle resolution kept
  outside the lock.
@kody-ai

This comment has been minimized.

Comment thread Sources/CodeCaps/PlatformLogo.swift

@jaywedgeworth22 jaywedgeworth22 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[GB-Designer] UI pass: nits, not blocking. The calm popup, the CodeCaps Dashboard title and the Plan Mismatch Warnings toggle all look right, and the help text already uses two spaces. Two button labels need Title Case and a shorter form.

Comment thread Sources/CodeCaps/ConsoleViews.swift Outdated
Comment thread Sources/CodeCaps/ConsoleViews.swift Outdated
- currentBundle() could revive a stale pin:  a resolve that started
  before an invalidation pinned its result after the clear, undoing
  it.  A generation counter now bumps on every invalidation and the
  pin only lands when no invalidation raced the resolve.

- The plan-override buttons use title case ("Use Detected", "Keep
  Mine") and the Settings footnote names the same action.
@kody-ai

This comment has been minimized.

Comment thread Sources/CodeCaps/ConsoleViews.swift
…popup

Three review findings on the mismatch flow:

- "Keep Mine" recorded the accepted triple, but only AppDelegate's
  filter honored it, and only for the modal.  The acceptance check now
  lives inside PlanWarningCycle.warnings, so accepted pairs never
  become warnings for any consumer, and AppDelegate's redundant filter
  is removed.

- The page's "Detected:" picked the provider's first window while the
  popup names the disagreeing one, so the two could identify different
  plans.  detectedPlan now prefers the candidate that disagrees with
  the entered value, falling back to the first.

- An accepted pair still showed as a live mismatch on the page with a
  resolution action.  planMismatch now returns false for accepted
  triples, matching the override's documented intent.
@kody-ai

kody-ai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

⚠️ 4 Kody Rule(s) were not evaluated

These rules declare that they need repository context beyond this diff, and the review could not retrieve it, so they were not judged on this pull request:

  • Never move or delete existing app support.html URLs
  • Search fleet recall before flagging iOS verification gap
  • Ship required resource assets and fail the build when they are missing
  • Never log tokens or credentials; only safeIssues may reach the handoff file
Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

​

…et copilot, generator targets, catalog test, copy rule
@jaywedgeworth22
jaywedgeworth22 enabled auto-merge (squash) October 22, 2026 08:34
@jaywedgeworth22
jaywedgeworth22 merged commit cf43ce4 into main Oct 22, 2026
40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant