Skip to content

refactor(web,mobile): environment renderers take the resolved icon - #1

Open
amanthanvi wants to merge 3 commits into
env-icons/01-contractsfrom
env-icons/02-rename
Open

amanthanvi wants to merge 3 commits into
env-icons/01-contractsfrom
env-icons/02-rename

Conversation

@amanthanvi

@amanthanvi amanthanvi commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

What changed

resolveEnvironmentMachineKind becomes resolveEnvironmentIcon and returns the stored override itself. A plain pick of a legacy kind lands on one shared reference per kind from environmentIconForMachineKind, so memoized thread rows keep skipping across settings snapshots. EnvironmentMachineIcon (web) and EnvironmentMachineSymbol (mobile) take an icon prop and, for now, read its name back to the same seven glyphs; a name this build cannot draw falls back to the generic server.

Orchestrator V2 moved per-environment glyph resolution into shared atoms (packages/client-runtime/src/state/presentation.ts for web, apps/mobile/src/state/thread-list-environments.ts for mobile) and added call sites in scheduled tasks and the mobile settings filter. Those now carry the icon too. Native menu items take only a symbol name, so they go through environmentMachineSymbolName, which falls back to the generic server for anything that is not a curated icon.

The old name is deleted rather than aliased. isEnvironmentMachineKind stays exported, and a function still named "machine kind" returning an emoji variant invites passing one to the other, where it silently returns false.

Main now lists a machine in the T3 Connect section even when it is saved over another route, so T3 Connect can be added as a fallback. Those rows read the user's pick from that machine's own config, on web and mobile, so they match the saved list on the same screen.

Why

This is the mechanical widening that lets the next layers draw more than seven shapes. It is isolated so the churn across 42 files is one review pass. No behavior changes. At this point the stored value can only be a legacy string lifted into the named variant, so every renderer draws what it drew before. Field and prop names on the call sites stay as they are.

Stacked on pingdotgg#15511. Layer 2 of 6.

Opened on the fork because GitHub only accepts a base branch that lives in the base repository, and stacks cannot span a fork and its upstream. Layers 2 through 6 form a native stack on the fork, so merging one layer there rebases the rest. Each will be re-targeted to pingdotgg/t3code once its base merges. The entry point upstream is pingdotgg#15511.

Verification

  • Contracts server.test.ts covers the shared-reference guarantee and the fallback.
  • CommandPalette.logic.test.ts, pullRequestProjectAssignment.logic.test.ts, and BranchToolbar.logic.test.ts pass with the widened type.
  • Typecheck green for web, mobile, server, and contracts.

Claude Fable 5.1 via Claude Code

Summary by Sourcery

Pass resolved environment icons through web and mobile renderers while preserving current visuals and preparing support for richer icon types.

Enhancements:

  • Widen environment icon resolution and renderer interfaces to carry resolved icon values across web and mobile while preserving existing legacy glyph behavior.
  • Use shared references for legacy machine icons and provide generic-server fallbacks for icons unsupported by the current client.
  • Update shared presentation state, environment selectors, settings, scheduled tasks, thread lists, and other consumers to propagate the resolved icons.

Tests:

  • Add coverage for shared icon references, stored richer icon values, and renderer fallback behavior.

Chores:

  • Remove the legacy machine-kind resolver and migrate all web and mobile call sites to the resolved icon API.

@sourcery-ai sourcery-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.

Sorry @amanthanvi, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 11 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

This refactor widens environment rendering from legacy machine-kind strings to EnvironmentIcon values: the contracts resolver now preserves richer stored icons and canonicalizes plain kinds for stable references, while web and mobile renderers and all call sites consume the new value without changing the currently drawn glyphs.

Sequence diagram for resolving and rendering environment icons

sequenceDiagram
    participant Caller
    participant resolveEnvironmentIcon
    participant EnvironmentIconCache
    participant EnvironmentMachineIcon
    participant EnvironmentMachineSymbol

    Caller->>resolveEnvironmentIcon: resolveEnvironmentIcon(config)
    alt stored richer icon
        resolveEnvironmentIcon-->>Caller: stored EnvironmentIcon
    else plain legacy kind or detected machine
        resolveEnvironmentIcon->>EnvironmentIconCache: environmentIconForMachineKind(kind)
        EnvironmentIconCache-->>resolveEnvironmentIcon: shared EnvironmentIcon reference
        resolveEnvironmentIcon-->>Caller: canonical EnvironmentIcon
    end
    alt web
        Caller->>EnvironmentMachineIcon: icon=resolvedIcon
        EnvironmentMachineIcon->>EnvironmentMachineIcon: environmentMachineIcon(icon)
        EnvironmentMachineIcon-->>Caller: current glyph or server fallback
    else mobile
        Caller->>EnvironmentMachineSymbol: icon=resolvedIcon
        EnvironmentMachineSymbol->>EnvironmentMachineSymbol: isEnvironmentMachineKind(icon.name)
        EnvironmentMachineSymbol-->>Caller: current symbol or server fallback
    end
Loading

Flow diagram for legacy and richer environment icon handling

flowchart TD
    A[Server config or descriptor] --> B[resolveEnvironmentIcon]
    B --> C{Stored environmentIcon?}
    C -->|Richer icon| D[Return stored EnvironmentIcon]
    C -->|Plain legacy kind| E[environmentIconForMachineKind]
    C -->|None| F[Detected machine or server]
    F --> E
    E --> G[Return shared canonical reference]
    D --> H{Renderer supports icon name?}
    G --> H
    H -->|Yes| I[Draw existing glyph]
    H -->|No| J[Draw generic server glyph]
Loading

File-Level Changes

Change Details Files
Replace machine-kind resolution with environment-icon resolution that preserves richer stored values and canonicalizes legacy kinds.
  • Renamed the resolver and removed the obsolete API.
  • Added one shared icon object per legacy machine kind for stable memoized props.
  • Returned stored custom icon variants unchanged while using canonical variants for detection and plain picks.
  • Retained legacy machine-kind validation for renderer compatibility.
packages/contracts/src/server.ts
packages/contracts/src/server.test.ts
Widen web and mobile environment renderer interfaces to consume resolved icons with legacy-compatible drawing behavior.
  • Changed renderer props from machine kinds to EnvironmentIcon values.
  • Mapped supported named icon values to the existing seven glyphs.
  • Fell back to the generic server glyph for unsupported or richer icon variants.
  • Updated renderer helper usage and default icon construction.
apps/web/src/components/EnvironmentMachineIcon.tsx
apps/mobile/src/components/EnvironmentMachineSymbol.tsx
Migrate environment icon data through web and mobile UI call sites and view-model types.
  • Replaced resolver imports and calls across environment lists, thread rows, settings, selectors, command palettes, project badges, and pull-request flows.
  • Widened intermediate machine/icon fields and props to EnvironmentIcon.
  • Converted literal legacy defaults to canonical icon objects.
  • Preserved memoized collection and row data flows while passing icons through to renderers.
apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx
apps/mobile/src/features/connection/CloudEnvironmentRows.tsx
apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx
apps/mobile/src/features/home/HomeScreen.tsx
apps/mobile/src/features/projects/AddProjectScreen.tsx
apps/mobile/src/features/settings/SettingsClientStorageRouteScreen.tsx
apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx
apps/mobile/src/features/threads/NewTaskDraftScreen.tsx
apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
apps/mobile/src/features/threads/thread-list-v2-items.tsx
apps/web/src/components/BranchToolbar.logic.ts
apps/web/src/components/BranchToolbar.tsx
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx
apps/web/src/components/ChatView.tsx
apps/web/src/components/CommandPalette.logic.test.ts
apps/web/src/components/CommandPalette.tsx
apps/web/src/components/LegacySidebar.tsx
apps/web/src/components/ProjectEnvironmentBadge.tsx
apps/web/src/components/Sidebar.tsx
apps/web/src/components/ThreadStatusIndicators.tsx
apps/web/src/components/chat/DraftHeroHeadline.tsx
apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx
apps/web/src/components/pullRequest/pullRequestProjectAssignment.logic.ts
apps/web/src/components/settings/ConnectionsSettings.tsx
apps/web/src/components/settings/EnvironmentIconPicker.tsx
apps/web/src/components/settings/EnvironmentRow.tsx
apps/web/src/components/settings/GitHubRoutingSettings.tsx
apps/web/src/components/settings/LoadBalancingSettings.tsx
apps/web/src/components/settings/ProviderSettingsPanel.tsx
apps/web/src/components/settings/SettingInheritance.tsx
apps/web/src/components/settings/SettingsScopeSentence.tsx
apps/web/src/routes/_chat.pull-requests.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Sep 20, 2026
@amanthanvi
amanthanvi added this pull request to stack #6 September 20, 2026 09:26
@github-actions

github-actions Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 9becaed.

This comment will update automatically after the next completed run.

@amanthanvi
amanthanvi force-pushed the env-icons/02-rename branch 6 times, most recently from ac19c03 to f3732fb Compare September 21, 2026 05:17
@amanthanvi

Copy link
Copy Markdown
Owner Author

Pushed f3732fbd5d, which scopes a claim the code does not support.

The comment on the icon memoization said rows are memoized so the resolver hands back the same object across renders and across settings snapshots. That is true for a plain machine kind and false for everything else. The cache is keyed by kind, so an emoji, monogram, or image icon is returned as the decoded value and gets a fresh object from every snapshot, which repaints that row.

The comment now says which case the cache covers and which it does not, and why the gap is left open. Settings change on user action, not on a timer, so a content keyed cache would buy a repaint nobody is present to see, at the price of holding image bytes alive for as long as the cache does. Rebased onto 4d005ad44d, which carries this round's fixes to layer 1.

@amanthanvi

amanthanvi commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner Author

Rebased onto current main

Rebased the whole stack onto main at 76cc9b08f1, which was 52 commits past the previous base. All 20 commits replayed with no conflicts, and 12 of the stack's 74 files fall in the region main touched.

git range-diff against the pre-rebase tips shows 19 of the 20 commits carry an identical patch. The one that differs is refactor(web,mobile): environment renderers take the resolved icon, and the difference is context only. Main added closeOnClick to the environment MenuRadioItem in BranchToolbar.tsx, two lines above the prop this stack renames. Both changes are present in the rebased file.

A clean textual replay does not prove the stack still holds together, so I went looking for the hazard that would hide behind one. Layer 2 renames resolveEnvironmentMachineKind across 40 files, so a call site added upstream would compile against a symbol this stack deletes. The 52 commits add none.

Each layer is its own pull request, so I verified each one standing alone rather than only at the tip:

layer typecheck tests
01 contracts 4 packages, 0 errors 7 files, 290 tests
02 rename 5 packages, 0 errors 7 files, 291 tests
03 curated 5 packages, 0 errors 7 files, 296 tests
04 rich 5 packages, 0 errors 9 files, 303 tests
05 lucide 5 packages, 0 errors 10 files, 307 tests
06 image, mobile, detect 6 packages, 0 errors 11 files, 321 tests

No review thread was open when I rebased, so the force push moved commits rather than answers. Line comments from earlier rounds now anchor to the old SHAs.

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 21, 2026

@sourcery-ai sourcery-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.

Sourcery assessment

Approved.

@amanthanvi

Copy link
Copy Markdown
Owner Author

@sourcery-ai review

@sourcery-ai

sourcery-ai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Sorry @amanthanvi, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 28 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@amanthanvi

Copy link
Copy Markdown
Owner Author

Rebased onto current main, and the monogram counter lost its Intl.Segmenter branch

Rebased the stack onto main at aff9318bf4, four commits past the previous base. All 35 commits replayed with no conflicts, and 3 of the stack's 76 files fall where those four commits landed.

Those three overlaps are ConnectionsSettings.tsx, PullRequestDetailPanel.tsx, and _chat.pull-requests.tsx, and main's edits to them swap className="size-3.5" on Spinner and RefreshIcon for the new size prop. None of it touches the icon code this stack changes, and the stack adds no Spinner or RefreshIcon call site that should be using the new prop.

One thing in those four commits does bear on the stack. refactor(web): drop className overrides that repeat the base styles lowered RESTYLE_CEILING from 1247 to 1207, and main now sits at exactly 1207 with no slack, so any restyle finding this stack added would fail the gate. Each of the six layers measures exactly 1207.

The monogram count is now the same on every client

isMonogramLength in contracts and firstGrapheme on mobile each reached for Intl.Segmenter behind a typeof guard and counted code points otherwise. t3code/no-hermes-unsupported-apis is configured at error severity for packages/contracts/src/** and apps/mobile/src/** (vite.config.ts:195), and it reports the construction rather than the reference, so the guard did not satisfy it. Both branches are gone.

I deleted them rather than suppressing the rule, because the rule was right in both files. Hermes ships no segmenter, so the contracts guard accepted on the server and on web a monogram that mobile refused, and a validation bound that depends on the runtime reading it is the wrong shape for a bound. The mobile file only ever runs on Hermes, so its segmenter branch was dead in the app and live only in vitest on Node, which left three tests covering a path that never shipped.

The cost is real and worth naming. A two-cluster Devanagari conjunct or a decomposed Hangul syllable counts high, so those scripts get one cluster in a two-character monogram. In exchange every client agrees on what it will store, and the two tiles show exactly what the picker agreed to.

The write-schema split survives the change for a reason that never depended on the runtime. A decode-time bound would send a longer stored monogram through ForwardCompatibleNullable to null, and the user would get the detected glyph with nothing saying why.

Per-layer verification

Each layer is its own pull request, so each was verified standing alone rather than only at the tip.

layer typecheck lint tests restyle
01 contracts 4 packages, 0 errors 0 errors 4 files, 245 tests 1207
02 rename 5 packages, 0 errors 0 errors 5 files, 276 tests 1207
03 curated 5 packages, 0 errors 0 errors 6 files, 285 tests 1207
04 rich 5 packages, 0 errors 0 errors 9 files, 296 tests 1207
05 lucide 5 packages, 0 errors 0 errors 10 files, 300 tests 1207
06 image, mobile, detect 5 packages, 0 errors 0 errors 12 files, 327 tests 1207

The force push moved commits, so line comments from earlier rounds now anchor to the old SHAs.

@amanthanvi

Copy link
Copy Markdown
Owner Author

@sourcery-ai review

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 22, 2026

@sourcery-ai sourcery-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.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@amanthanvi

amanthanvi commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner Author

Rebased onto current main

Rebased the stack onto main at f5ef0ddb90, 72 commits past the previous base. Two layers conflicted, and main also changed the lint rules this stack has to pass.

What main changed that this stack had to follow

shadcn/no-restyle is now a lint error rather than a counted warning (pingdotgg#13210), and the ceiling script is gone. Every layer here lints with 0 errors on the files it changes.

That made one commit unnecessary. fix(web): the icon dialog keeps its spacing off DialogPanel moved the dialog's flex column into a wrapper div to keep the old ceiling from growing. Main's own ProjectIconPickerDialog now puts flex min-h-0 flex-col on DialogPanel and lets the panel's built-in space-y-4 do the spacing, so this dialog does the same from the commit that introduces it. The wrapper and that commit are gone.

The layer 3 commit that deduplicates the icon submenu's lock row said it existed for the ceiling. It still removes a duplicated row, so it stays with a message that says only that.

Conflicts

Review findings

Sourcery reviewed the last push. One finding was real and is fixed on layer 6: the web dialog let Save run while an image was still encoding, which wrote the previous image and dropped the new pick. The other two have replies on the threads. One asks mobile to hide the emoji glyph from screen readers, but mobile glyphs have been labeled on main all along. The other asks to reject a photo whose dimensions the picker did not report, which is a trade-off the code already records.

Layer 6 also drops an isEnvironmentMachineKind import the dialog stopped using.

Per-layer verification

Each layer is its own pull request, so each was checked standing alone.

layer typecheck lint tests
01 contracts 4 packages, 0 errors 0 errors 4 files, 244 tests
02 rename 5 packages, 0 errors 0 errors 5 files, 276 tests
03 curated 5 packages, 0 errors 0 errors 6 files, 285 tests
04 rich 5 packages, 0 errors 0 errors 9 files, 296 tests
05 lucide 5 packages, 0 errors 0 errors 10 files, 300 tests
06 image, mobile, detect 5 packages, 0 errors 0 errors 12 files, 327 tests

Layer 1 runs one test fewer than last time because main removed one of its own tests from settings.test.ts (pingdotgg#13115). The 12 tests this stack adds are all still there.

The force push moved commits, so line comments from earlier rounds now anchor to the old SHAs.

@amanthanvi

Copy link
Copy Markdown
Owner Author

@sourcery-ai review

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 23, 2026

@sourcery-ai sourcery-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.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@amanthanvi

amanthanvi commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner Author

Rebased onto current main

Rebased the stack onto main at 568c9bc4d0, 50 commits past the previous base. Every commit replayed with no conflicts.

Main added four web lint errors in that range: shadcn/no-raw-colors, no-unknown-classes, require-static-classes, and no-arbitrary-values. None of them fires on this stack. The web icon colors come from projectIconColors, which main had already moved to theme tokens, and of the stack's three arbitrary values, rounded-[25%] and text-[length:80cqh] are on main's allowlist for project icons and sm:w-[32rem] is a dialog width, which the rule treats as layout.

Two changes follow main:

  • refactor(server): the container marker check recovers with orElseSucceed. chore: clear Effect language service suggestions pingdotgg/t3code#13536 replaced Effect.catch(() => Effect.succeed(...)) with Effect.orElseSucceed across the server, including this file's other helpers. The container check this stack added was the last call in the old form, and the Effect language service reported it.
  • docs(user): the mobile icon path goes through the environment page. feat(mobile): manage environment and provider updates pingdotgg/t3code#13302 made Settings → Environments open a page per environment instead of expanding the row. The mobile picker still sits in the row's expanded body, which that page shows under Connection, so the user doc now names the page and the section.

Each layer typechecks with 0 errors in every package it changes, lints with 0 errors, and passes its tests, from 4 files and 244 tests at layer 1 to 12 files and 327 tests at layer 6. The fix commits cited in earlier review replies have new SHAs, and those replies now point at them.

Copilot AI balanced review requested due to automatic review settings October 4, 2026 06:08
@amanthanvi
amanthanvi force-pushed the env-icons/02-rename branch from 21f657c to 93ec64f Compare October 4, 2026 06:08

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

The web picker incorrectly marks colored named overrides as equivalent plain machine-kind selections.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

This stacked refactor widens environment rendering across contracts, web, and mobile to consume resolved EnvironmentIcon values while preserving legacy glyphs and stable references.

Changes:

  • Replaces resolveEnvironmentMachineKind with resolveEnvironmentIcon.
  • Adds shared references for legacy machine icons.
  • Updates web/mobile renderers, callers, projections, and tests.
File Description
packages/​contracts/​src/​server.ts Adds icon resolution and reference caching.
packages/​contracts/​src/​server.test.ts Tests icon resolution and identity.
packages/​client-runtime/​src/​state/​presentation.ts Projects resolved environment icons.
packages/​client-runtime/​src/​state/​presentation.test.ts Updates projection assertions.
apps/​web/​src/​routes/​_chat.pull-requests.tsx Uses resolved icons in filters.
apps/​web/​src/​components/​ThreadStatusIndicators.tsx Passes resolved remote icons.
apps/​web/​src/​components/​Sidebar.tsx Widens sidebar icon values.
apps/​web/​src/​components/​settings/​SettingsScopeSentence.tsx Renders resolved scope icons.
apps/​web/​src/​components/​settings/​SettingInheritance.tsx Widens inheritance icon data.
apps/​web/​src/​components/​settings/​ScheduledTasksSettings.tsx Updates scheduled-task icons.
apps/​web/​src/​components/​settings/​ProviderSettingsPanel.tsx Updates provider environment icons.
apps/​web/​src/​components/​settings/​LoadBalancingSettings.tsx Passes resolved row icons.
apps/​web/​src/​components/​settings/​GitHubRoutingSettings.tsx Passes resolved routing icons.
apps/​web/​src/​components/​settings/​EnvironmentRow.tsx Accepts EnvironmentIcon.
apps/​web/​src/​components/​settings/​EnvironmentIconPicker.tsx Adapts picker to resolved icons.
apps/​web/​src/​components/​settings/​ConnectionsSettings.tsx Updates connection-row icons.
apps/​web/​src/​components/​pullRequest/​pullRequestProjectAssignment.logic.ts Widens assignment metadata.
apps/​web/​src/​components/​pullRequest/​PullRequestDetailPanel.tsx Renders resolved picker icons.
apps/​web/​src/​components/​ProjectEnvironmentBadge.tsx Widens badge icon map.
apps/​web/​src/​components/​LegacySidebar.tsx Updates legacy sidebar icons.
apps/​web/​src/​components/​EnvironmentMachineIcon.tsx Accepts icons with server fallback.
apps/​web/​src/​components/​CommandPalette.tsx Widens palette environment metadata.
apps/​web/​src/​components/​CommandPalette.logic.test.ts Updates palette fixtures.
apps/​web/​src/​components/​cloud/​CloudEnvironmentConnectList.tsx Updates cloud connection icons.
apps/​web/​src/​components/​ChatView.tsx Resolves environment option icons.
apps/​web/​src/​components/​chat/​DraftHeroHeadline.tsx Builds resolved icon maps.
apps/​web/​src/​components/​BranchToolbarEnvironmentSelector.tsx Updates selector icons.
apps/​web/​src/​components/​BranchToolbar.tsx Updates toolbar icons.
apps/​web/​src/​components/​BranchToolbar.logic.ts Widens environment option type.
apps/​mobile/​src/​state/​thread-list-environments.ts Projects and caches icons.
apps/​mobile/​src/​state/​thread-list-environments.test.ts Updates projection assertions.
apps/​mobile/​src/​features/​threads/​thread-list-v2-items.tsx Widens thread-row icon props.
apps/​mobile/​src/​features/​threads/​NewTaskDraftScreen.tsx Updates draft environment icon.
apps/​mobile/​src/​features/​threads/​NewTaskContextPickerScreens.tsx Updates picker icons.
apps/​mobile/​src/​features/​settings/​SettingsScheduledTasksRouteScreen.tsx Updates task icons and menu symbols.
apps/​mobile/​src/​features/​settings/​SettingsClientStorageRouteScreen.tsx Widens cache-row icons.
apps/​mobile/​src/​features/​settings/​components/​SettingsEnvironmentFilterHeader.tsx Resolves native menu symbols.
apps/​mobile/​src/​features/​projects/​AddProjectScreen.tsx Widens project environment options.
apps/​mobile/​src/​features/​connection/​ConnectionEnvironmentRow.tsx Updates connection icon rendering.
apps/​mobile/​src/​features/​connection/​CloudEnvironmentRows.tsx Widens cloud-row icons.
apps/​mobile/​src/​features/​archive/​ArchivedThreadsScreen.tsx Widens archived-group icons.
apps/​mobile/​src/​components/​EnvironmentMachineSymbol.tsx Accepts icons with server fallback.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +97 to +98
const resolvedKind =
resolved.kind === "icon" && isEnvironmentMachineKind(resolved.name) ? resolved.name : null;
@amanthanvi

amanthanvi commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner Author

Rebased onto orchestrator V2

Rebased the stack onto main at 40596072eb, past the V2 rewrite (pingdotgg#2829). Upstream closed pingdotgg#12675 during that transition. Layer 1 is now pingdotgg#15511.

What the rebase had to adapt:

  • orchestration.ts is gone. Project icon schemas now live in project.ts, which imports the shared color, emoji, monogram, and Lucide-name leaves (layer 1).
  • V2 resolves environment glyphs in shared atoms, presentation.ts on web and thread-list-environments.ts on mobile. Both now carry the icon instead of a machine kind (layer 2).
  • Main added scheduled-task and mobile settings-filter call sites, and they draw the icon now. Native menus only take a symbol name, so anything other than a curated icon shows the generic server there.
  • The mobile theme CSS is regenerated from the merged generator script (layer 4).

Layer 1 has one new fix. An inline PNG must now carry all eight signature bytes, since Macroscope found that the old prefix check let a seven-byte value through.

Every layer passes typecheck, lint, format, and its own tests. At the top of the stack, I picked icons on web and in the iOS simulator against isolated dev state, and each client showed the other's pick.

@sourcery-ai

sourcery-ai Bot commented Oct 4, 2026

Copy link
Copy Markdown

Sourcery has withdrawn its approval of this pull request. It auto-reviews a pull request 5 times, and this push is past that limit, so the approval no longer reflects code Sourcery has read.

Comment @sourcery-ai review to get a fresh review, which can approve again.

Re-reviews, rate limits and approvals

@sourcery-ai
sourcery-ai Bot dismissed their stale review October 4, 2026 06:49

Sourcery withdrew this approval because it has stopped reviewing this pull request.

`resolveEnvironmentMachineKind` collapsed the stored override to one of
seven kinds, so every renderer saw a machine kind and nothing richer could
reach a glyph. This is the mechanical widening that lets the next changes
draw more than seven shapes, isolated so the churn is one review pass.

The resolver becomes `resolveEnvironmentIcon` and returns the override
itself. A plain pick of a legacy kind lands on one shared reference per
kind from `environmentIconForMachineKind`, so memoized thread rows keep
skipping across settings snapshots, and anything richer comes back as
stored. `EnvironmentMachineIcon` and `EnvironmentMachineSymbol` take an
`icon` prop and, for now, read its name back to the same seven glyphs,
with a name this build cannot draw falling back to the generic server.

The old name is deleted rather than aliased. `isEnvironmentMachineKind`
stays exported, and a function still named "machine kind" returning an
emoji variant invites passing one to the other, where it silently
returns false.

No behavior change. At this point the stored value can only be a legacy
string lifted into the named variant, so every renderer still draws what
it drew before. Field and prop names on the call sites stay as they are.

Claude Fable 5.1 via Claude Code
The comment read as though the shared reference kept every environment row
from repainting. It covers plain machine kinds only. An emoji, monogram, or
image icon comes back as the decoded value, so those rows repaint once per
settings change. Say that, and say why a content-keyed cache is not worth it.
Main now lists a machine in the T3 Connect section even when it is saved
over another route, so T3 Connect can be added as a fallback. Those rows
took their icon from the relay-saved map, which skips such machines, or
from the relay descriptor alone, which carries no settings. So a machine
with a picked emoji, monogram, or image showed its detected kind there and
the picked icon in the saved list on the same screen.

Web now looks up the config of every saved machine for the icon, and the
mobile available row reads the machine's config the way the connected row
already does.

Found by an independent review of the rebased stack.

Claude Opus 5.5 via Claude Code
@amanthanvi
amanthanvi force-pushed the env-icons/02-rename branch from 26a1ce0 to 9becaed Compare October 6, 2026 02:07
@sourcery-ai
sourcery-ai Bot dismissed their stale review October 6, 2026 02:07

Sourcery withdrew this approval because it has stopped reviewing this pull request.

@sourcery-ai

sourcery-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown

Sourcery has withdrawn its approval of this pull request. It auto-reviews a pull request 5 times, and this push is past that limit, so the approval no longer reflects code Sourcery has read.

Comment @sourcery-ai review to get a fresh review, which can approve again.

Re-reviews, rate limits and approvals

1 similar comment
@sourcery-ai

sourcery-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown

Sourcery has withdrawn its approval of this pull request. It auto-reviews a pull request 5 times, and this push is past that limit, so the approval no longer reflects code Sourcery has read.

Comment @sourcery-ai review to get a fresh review, which can approve again.

Re-reviews, rate limits and approvals

@sourcery-ai
sourcery-ai Bot dismissed their stale review October 6, 2026 02:07

Sourcery withdrew this approval because it has stopped reviewing this pull request.

@amanthanvi

Copy link
Copy Markdown
Owner Author

Rebased onto main 64275ae396

Main moved about 115 commits. Fixes that came out of the rebase:

Three independent review rounds over the rebased stack found these, now fixed in the layer that owns the code:

  • Layer 2: T3 Connect rows, which main now shows for machines saved over another route, show the icon the user picked on web and mobile. A test from main that the stack had dropped is back: an unknown detected kind decodes as absent.
  • Layer 6: the icon picker locks on a dropped connection and on a session that cannot change settings, on both clients, through one shared lock. On mobile, only an expanded row checks the session. The mobile sheet no longer marks a colored icon as its plain row, where a tap would have dropped the color.
  • Layer 6: a Mac Studio with M3 Ultra (Mac15,14) detects as a workstation. Comments that said every machine kind has a string form now say legacy machine kind, since container has none.

Every layer passes typecheck, lint, format, and its own tests.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants