Skip to content

🤖 feat: sync user preferences through backend config#3455

Merged
ibetitsmike merged 12 commits into
mainfrom
mike/user-preferences-config
Jun 5, 2026
Merged

🤖 feat: sync user preferences through backend config#3455
ibetitsmike merged 12 commits into
mainfrom
mike/user-preferences-config

Conversation

@ibetitsmike
Copy link
Copy Markdown
Contributor

@ibetitsmike ibetitsmike commented Jun 4, 2026

Mux is acting on Mike's behalf.

Summary

Moves localStorage-only semantic preferences into a new typed userPreferences section in ~/.mux/config.json, while keeping localStorage as the fast frontend cache and mirror.

Background

Preferences like theme, project order, provider options, creation defaults, notification defaults, sharing defaults, review behavior, and auto-compaction thresholds were durable only in browser localStorage. That made them origin-scoped and easy to lose across desktop, browser, or port changes.

Implementation

  • Adds shared UserPreferences schema, normalization, config load/save persistence, and ORPC config.getConfig / config.saveConfig support.
  • Adds a semantic registry that maps existing localStorage keys into typed userPreferences groups.
  • Adds UserPreferencesProvider to hydrate localStorage from backend config, backfill backend config when only localStorage has values, track dirty local writes, retry failed saves with capped backoff, and prune removed project/workspace-scoped entries.
  • Adds a backend userPreferencesInitialized migration marker so stale localStorage from another browser origin cannot resurrect preferences that were already cleared from backend config.
  • Keeps first-run local backfill active until backend preferences are initialized, so an unrelated config refresh cannot delete migrated local preferences before their save completes.
  • Defers preference saves until hydration has seeded the current preference document, so early UI writes do not replace backend preferences with a single-key partial object.
  • Retries initial preference hydration after transient config load failures, so dirty local writes are saved once backend config becomes available.
  • Guards scoped preference pruning behind successful project and workspace metadata loads, so temporary list failures cannot delete project or workspace preferences.
  • Hydrates the local preference cache before startup routing so backend launch behavior is available before RouterProvider and WorkspaceProvider read it.
  • Lets preference-only saves omit taskSettings, so automatic preference sync cannot replay stale task settings over concurrent settings edits.
  • Shares enum and threshold parsing with the schema path, including legacy theme migration.
  • Adds coverage that flattened preference entries are recognized, applied, removable, non-initial backend refreshes delete stale cache keys while preserving dirty keys, backend values do not overwrite dirty keys, save retries stop on abort, initialized backend state wins over stale cache, early writes seed from full local cache, and explicit userPreferences: null still clears stored preferences.
  • Moves provider options schema to src/common/schemas so config schemas do not depend on ORPC schemas.

Validation

  • bun test src/browser/contexts/UserPreferencesContext.test.ts src/browser/contexts/ProjectContext.test.tsx src/browser/contexts/WorkspaceContext.test.tsx
  • make typecheck
  • make static-check
  • bun test src/browser/contexts/UserPreferencesContext.test.ts
  • bun test src/browser/contexts/UserPreferencesContext.test.ts src/node/config.test.ts src/node/orpc/router.test.ts src/common/orpc/schemas/api.test.ts
  • bun test src/browser/contexts/UserPreferencesContext.test.ts src/common/preferences/userPreferencesStorage.test.ts src/common/config/schemas/userPreferences.test.ts src/common/orpc/schemas/api.test.ts src/node/orpc/router.test.ts
  • make storybook-run CMD='bun x test-storybook --testTimeout 30000 --maxWorkers 1 --verbose src/browser/components/ProjectPage/ProjectPage.stories.tsx'
  • Earlier targeted suite: bun test src/browser/contexts/UserPreferencesContext.test.ts src/common/config/schemas/userPreferences.test.ts src/common/preferences/userPreferencesStorage.test.ts src/browser/hooks/usePersistedState.test.tsx src/common/config/schemas/appConfigOnDisk.test.ts src/node/config.test.ts src/node/orpc/router.test.ts

Risks

Medium risk. This touches startup config loading and preference hydration. The bridge keeps localStorage as a cache, uses a bounded startup fallback, and writes backend config through the existing settings API to limit UI churn and preserve first-paint behavior.


Generated with mux • Model: openai:gpt-5.5 • Thinking: xhigh • Cost: $226.12

Add typed backend userPreferences storage, a localStorage mirror bridge, and tests for migrating semantic preferences into config.json.

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$104.19`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=104.19 -->
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review
Copy link
Copy Markdown

coder-agents-review Bot commented Jun 4, 2026

Chat: Review in progress | View chat
Requested: 2026-06-05 04:46 UTC by @ibetitsmike
Spend: $164.77 / $200.00

deep-review v0.7.1 | Round 11 | d49bdcc..d96be7f

Last posted: Round 11, 22 findings (1 P1, 4 P2, 11 P3, 3 Nit, 3 Note), APPROVE. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P1 Author fixed (3bfee14) UserPreferencesContext.tsx:151 UserPreferencesProvider (368 lines) has zero test coverage R1 Netero Yes
CRF-2 P2 Author fixed (3bfee14) userPreferencesStorage.ts:84 Seven identical utility functions duplicated between userPreferencesStorage.ts and userPreferences.ts R1 Netero Yes
CRF-3 P3 Author fixed (3bfee14) userPreferencesStorage.ts:694 collectStoredUserPreferences exported with no production caller R1 Netero Yes
CRF-4 Note Author fixed (3bfee14) userPreferences.ts:463 Dead branch in normalizeUserPreferences for launchBehavior (LAUNCH_BEHAVIOR_KEY === "launchBehavior") R1 Netero Yes
CRF-5 Note Author fixed (3bfee14) userPreferencesStorage.ts:744 stableStringify duplicated with policyService.ts:44 R1 Netero Yes
CRF-6 P2 Author fixed (46491a7) UserPreferencesContext.tsx:328 Subscription handler hardcodes initial=false; failed initial hydration permanently skips localStorage backfill, causing data loss during first-time migration R2 Hisoka P2, Nami P2, Chopper Note Yes
CRF-7 P2 Author fixed (46491a7) UserPreferencesContext.tsx:194 Save queue drops failed saves without retry; backend stays stale until next local write, silently breaking cross-origin sync R2 Chopper P2, Mafuuu P3, Hisoka P3, Meruem P3 Yes
CRF-8 P2 Author fixed (46491a7) userPreferencesStorage.ts:242 Theme migration logic absent from localStorage-to-structured path; legacy theme names silently dropped during first-time migration R2 Razor Yes
CRF-9 P3 Author fixed (46491a7) UserPreferencesContext.tsx:176 Save queue reads taskSettings via getConfig then echoes it back in saveConfig, creating a revert window when concurrent callers modify taskSettings R2 Hisoka P2, Knov P2, Nami P3, Melody Note Yes
CRF-10 P3 Author fixed (46491a7) storage.ts:345 Doc comment says "not backend-backed elsewhere" but this PR adds backend syncing for these keys R2 Gon Yes
CRF-11 P3 Author fixed (46491a7) userPreferencesStorage.ts:108 LaunchBehavior and Theme enum values hardcoded independently in three locations; adding a variant silently fails in the storage layer R2 Melody P3, Knov P3, Razor P3 Yes
CRF-12 P3 Author fixed (46491a7) userPreferencesStorage.ts:227 Four parallel dispatch tables define the localStorage-to-schema mapping; a missing branch silently drops data with no compile-time guard R2 Meruem Yes
CRF-13 P3 Author fixed (46491a7) router.test.ts:498 No test for explicit null clearing of userPreferences via saveConfig; the destructive data-clearing path through normalizeUserPreferences(null) is unverified R2 Bisky P3, Chopper P3 Yes
CRF-14 Nit Author fixed (46491a7) userPreferencesStorage.ts:121 parseThreshold hardcodes 0 instead of importing AUTO_COMPACTION_THRESHOLD_MIN; upper bound 100 also repeated across three locations R2 Mafuuu Nit, Gon Note, Razor Nit Yes
CRF-15 Note Author fixed (46491a7) UserPreferencesContext.tsx:240 hydratedRef not reset when api changes identity without passing through null; implicit assumption that IPC client always nulls first R2 Meruem Yes
CRF-16 P3 Author fixed (36081c6) userPreferences.ts:412 normalizeUserPreferences hardcodes launch behavior values inline instead of using LaunchBehaviorSchema.options; same class as CRF-11, missed in the fix R3 Netero Yes
CRF-17 P3 Author fixed (36081c6) UserPreferencesContext.tsx:107 mirrorBackendPreferences non-initial removal path (cross-origin deletion propagation) has zero test coverage R3 Bisky Yes
CRF-18 P3 Author fixed (36081c6) UserPreferencesContext.test.ts:167 Save queue abort/cancellation behavior untested; four abort checks never exercised despite signal being wired R3 Bisky Yes
CRF-19 Nit Author fixed (36081c6) UserPreferencesContext.tsx:462 Redundant hasUserPreferenceEntry predicate in pruning cleanup; always agrees with prunedKeys.has check R3 Meruem Nit, Hisoka Note Yes
CRF-20 Nit Author fixed (36081c6) UserPreferencesContext.tsx:229 pendingSave uses null vs undefined as sentinel with no type-level guard; future editor could confuse "clear queue" with "clear preferences" R3 Meruem P3 Yes
CRF-21 P3 Author fixed (7c60e44) UserPreferencesContext.test.ts:92 mirrorBackendPreferences dirty-key guard in non-initial removal path never tested with non-empty dirty set; removing the guard causes silent data loss with no test failure R4 Bisky Yes
CRF-22 P3 Author fixed (dd7cf42) UserPreferencesContext.tsx:97 mirrorBackendPreferences write-path dirty-key guard never exercised; removing it silently reverts dirty local writes during backend sync R6 Bisky Yes

Law analysis

Effective LOC: 2401 additions. Head SHA: 28a4893. Verdict: Don't split. Enforcement: Advisory.

Net novel production logic ~1700 LOC after accounting for moved normalizer functions (~200 LOC) and schema relocation (~100 LOC). Eight concerns identified with linear dependency chain: {key constants, schema relocation} -> schema -> {storage mapping, backend persistence, hook infra} -> hydration provider -> listener wiring. No valid vertical slice. Only clean horizontal cut (250 LOC refactor extraction) does not meaningfully change review difficulty.

Round log

Round 1

Netero-only. 1 P1, 1 P2, 1 P3, 2 Note. Law: Don't split (advisory). Reviewed against d49bdcc..28a4893.

Round 2

Churn guard: PROCEED. 5/5 R1 findings addressed. Panel: Bisky, Hisoka, Mafuuu, Pariston, Meruem, Nami, Melody, Gon, Leorio, Ging-ts, Robin, Chopper, Knov (wildcard), Razor (wildcard). 3 P2, 5 P3, 1 Nit, 1 Note new. Reviewed against d49bdcc..3bfee14.

Round 3

Churn guard: PROCEED. 10/10 R2 findings addressed. Netero: 1 P3 (CRF-11 partial fix). Panel: Meruem, Mafuuu, Hisoka, Bisky, Pariston, Knov (wildcard). 3 P3, 2 Nit new. All R2 fixes verified. Reviewed against d49bdcc..46491a7.

Round 4

Churn guard: PROCEED. 5/5 R3 findings addressed. Netero: clean (1 Note, test-only export). Panel: Mafuuu, Bisky, Knov (wildcard). 1 P3 new. All R3 fixes verified. Reviewed against d49bdcc..36081c6.

Round 5

BLOCKED. CRF-21 silent. No review.

Round 6

Churn guard: PROCEED. 1/1 R4 finding addressed (7c60e44). Netero: clean. Panel: Mafuuu, Bisky, Knov (wildcard). 1 P3 new (CRF-21 sibling). Reviewed against d49bdcc..7c60e44.

Round 7

BLOCKED. CRF-22 silent. No review.

Round 8

Churn guard: PROCEED. 1/1 R6 finding addressed (dd7cf42). Netero: clean. Panel: Mafuuu, Bisky, Knov (wildcard). Bisky noted one test gap (backfill orchestration path) as non-blocking. APPROVE. All 22 findings resolved. Reviewed against d49bdcc..dd7cf42.

Round 9

Post-approval re-review. New commits pushed (dd7cf42433071f, +30 prod, +47 test). New features: backfill-active-until-initialized guard, deferred preference saves until hydration seeds. Netero: clean. Panel: Mafuuu, Hisoka, Knov (wildcard). 0 findings. Re-APPROVE. Reviewed against d49bdcc..433071f.

Round 10

Post-approval re-review. New commits pushed (433071ffb04507, +150 prod, +59 test, +7 files). New feature: pruning guard behind successful metadata loads, changes to ProjectContext/WorkspaceContext. Netero: 1 P3 (stale test name), 1 Note (dead export). Panel: Mafuuu, Hisoka, Meruem, Knov (wildcard). 0 findings. Re-APPROVE. Reviewed against d49bdcc..fb04507.

Round 11

Post-approval re-review. New commits pushed (fb04507d96be7f, +30 prod, +27 test). New feature: hydration retry after transient config load failures. Netero: same 2 non-blocking notes from R10 (stale test name, dead export). Panel: Mafuuu, Hisoka, Knov (wildcard). 0 findings. Re-APPROVE. Reviewed against d49bdcc..d96be7f.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28a4893d92

ℹ️ 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".

Comment thread src/browser/components/AppLoader/AppLoader.tsx Outdated
Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

First-pass review (Netero). This is a mechanical scan only; the full review panel has not yet reviewed this PR.

The preference schema, normalization layer, and storage mapping are well-structured. The defensive normalization approach (coerce-and-prune rather than reject) is the right call for user-facing config that may be hand-edited or carry forward from older builds. The key constant centralization and normalizer relocation are clean refactors. Test coverage on the schema and storage modules is solid.

Findings: 1 P1, 1 P2, 1 P3, 2 Notes.

The P1 is the gap worth addressing before the panel spends time on the finer points. The hydration bridge is the riskiest new component and the only one without any test or story coverage. The P2 duplication is worth resolving while both files are new and the copy-paste cost is cheap.

"418 test lines were added for the simpler modules. The most complex module got none." (Netero)

🤖 This review was automatically generated with Coder Agents.

Comment thread src/browser/contexts/UserPreferencesContext.tsx
Comment thread src/common/preferences/userPreferencesStorage.ts Outdated
Comment thread src/common/preferences/userPreferencesStorage.ts Outdated
Comment thread src/common/config/schemas/userPreferences.ts
Comment thread src/common/preferences/userPreferencesStorage.ts Outdated
Add bridge helper coverage, extract duplicated parsing helpers, remove dead localStorage collection API, and share stable stringify.

---

_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$104.19`_

<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=104.19 -->
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

Addressed coder-agents-review findings:

  • CRF-1: Added UserPreferencesContext.test.ts coverage for initial local backfill behavior, dirty local overlays, project/workspace pruning, and the in-flight save queue path.
  • CRF-2: Extracted shared preference parsing helpers into userPreferenceParsing.ts and reused them from both config normalization and localStorage registry code.
  • CRF-3: Removed the unused exported collectStoredUserPreferences production API and kept collection logic local to the registry test.
  • CRF-4: Removed the unreachable launchBehavior fallback branch from normalizeUserPreferences.
  • CRF-5: Extracted shared stable stringify logic into src/common/utils/stableStringify.ts and reused it from both the preference bridge and policy service.

Validation after fixes:

  • make static-check
  • bun test src/browser/contexts/UserPreferencesContext.test.ts src/common/config/schemas/userPreferences.test.ts src/common/preferences/userPreferencesStorage.test.ts src/browser/hooks/usePersistedState.test.tsx src/common/config/schemas/appConfigOnDisk.test.ts src/node/config.test.ts src/node/orpc/router.test.ts

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Panel review (round 2). 14 reviewers, first full panel round.

All five R1 findings are verified fixed. The shared parsing module, test coverage for bridge helpers, and stableStringify extraction are all clean.

The schema design, normalization layer, and localStorage registry are solid. The defensive coerce-and-prune approach, the dirty-key overlay, and the fingerprint-based dirty-key clearing are well thought out. The test suite for the pure logic modules is genuine and exercises real branching. Ging-ts found no TypeScript modernization issues.

New findings: 3 P2, 5 P3, 1 Nit, 1 Note.

The two P2s worth immediate attention are both in the hydration bridge. CRF-6 is a one-line fix (change false to !hydratedRef.current at line 328) that prevents data loss during first-time migration. CRF-7 is a design gap where a transient backend error silently breaks the cross-origin sync that this PR introduces. Both were flagged independently by 3-4 reviewers.

"The first run after deployment is the only time localStorage has preferences the backend has never seen. If that first getConfig fails transiently, the migration window closes silently." (Hisoka)

The external Codex finding about UserPreferencesProvider mounting inside RouterProvider (launch behavior not available for initial routing) is a real product gap. It is inherent in the architecture choice to keep localStorage as the synchronous read layer. Fixing it would require restructuring the provider hierarchy or pre-loading preferences before React renders, which is outside the scope of this PR's stated goal.

🤖 This review was automatically generated with Coder Agents.

Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
Comment thread src/common/preferences/userPreferencesStorage.ts Outdated
Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
Comment thread src/common/constants/storage.ts
Comment thread src/common/preferences/userPreferencesStorage.ts
Comment thread src/common/preferences/userPreferencesStorage.ts
Comment thread src/node/orpc/router.ts
Comment thread src/common/preferences/userPreferencesStorage.ts Outdated
Comment thread src/browser/contexts/UserPreferencesContext.tsx
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3bfee14715

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ 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".

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

Mux is acting on Mike's behalf.

Responding to coder-agents-review feedback before resolving threads:

  • CRF-6: Fixed. Config subscription refreshes now use applyBackendConfig(!hydratedRef.current), so a failed initial hydration still treats the next config event as initial and preserves localStorage backfill.
  • CRF-7: Fixed. Preference saves now retry failed writes, preserve the pending preferences, and use capped exponential backoff to avoid tight retry loops.
  • CRF-8: Fixed. The localStorage theme migration path now uses the shared parseThemePreference logic, so legacy *-light and *-dark themes migrate instead of being dropped.
  • CRF-9: Fixed. Preference-only saves now omit taskSettings, and saveConfig preserves task settings when omitted.
  • CRF-10: Fixed. The provider options storage comment now says those keys sync through userPreferences.
  • CRF-11: Fixed. Launch behavior parsing now uses LaunchBehaviorSchema.options, and theme parsing uses the shared schema-backed migration helper.
  • CRF-12: Fixed with coverage. Added a registry contract test that verifies flattened preference entries are recognized, applied, and removable.
  • CRF-13: Fixed with coverage. Added a router test for explicit userPreferences: null clearing.
  • CRF-14: Fixed. Auto-compaction threshold parsing now uses shared min and storage max constants.
  • CRF-15: Addressed. A concrete API client identity change now resets hydration state and clears dirty/current refs before the next initial backfill.

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ 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".

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Re-review (round 3). 6 reviewers verifying R2 fixes plus new code.

All 10 R2 findings are verified fixed. The save queue retry with capped exponential backoff, the startup gate for launch behavior hydration, the taskSettings isolation in saveConfig, and the theme migration sharing are all clean. Mafuuu traced four modes (contracts, lifecycle, semantic honesty, adversarial scenarios) and found no issues. Pariston confirmed the solution is proportional to the problem and addresses the actual cause, not just the symptom.

New findings: 3 P3, 2 Nit. No P2 or higher.

CRF-16 is a residual from the CRF-11 fix: the storage layer was updated to use LaunchBehaviorSchema.options but the normalizer in the same file still hardcodes the array. The other two P3s are test coverage gaps in the abort/cancellation path and the non-initial mirror removal path.

"I tried to build a case against this and couldn't. The problem is correctly understood, the solution is proportional, and the fix is at the right level." (Pariston)

"The storage mapping tests are particularly beautiful, that 'all flattened preference entries are recognized, applied, and removable' test is a proper property-level sweep across every localStorage key. Real gem." (Bisky)

🤖 This review was automatically generated with Coder Agents.

Comment thread src/common/config/schemas/userPreferences.ts Outdated
Comment thread src/browser/contexts/UserPreferencesContext.tsx
Comment thread src/browser/contexts/UserPreferencesContext.test.ts
Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
Comment thread src/browser/contexts/UserPreferencesContext.tsx
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

Mux is acting on Mike's behalf.

Responding to follow-up coder-agents-review feedback before resolving threads:

  • CRF-16: Fixed. normalizeUserPreferences now uses LaunchBehaviorSchema.options instead of an inline launch behavior list.
  • CRF-17: Fixed with coverage. Exported the mirror helper for tests and added a non-initial refresh test that verifies stale localStorage keys are removed.
  • CRF-18: Fixed with coverage. Added a save-queue abort test that verifies retrying stops after abort and does not clear dirty keys.
  • CRF-19: Fixed. Removed the redundant hasUserPreferenceEntry condition from the pruning cleanup loop.
  • CRF-20: Fixed. Replaced the null vs undefined pending-save sentinel with an explicit { value } | null wrapper.

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36081c6638

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ 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".

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Re-review (round 4). 3 reviewers verifying R3 fixes.

All 20 prior findings verified fixed. Mafuuu and Knov found no issues. Bisky found one P3 test gap: the dirty-key guard in the non-initial removal path is tested for clean keys but not for dirty keys that should be preserved.

The PR has converged well across 4 rounds. The architecture is sound, the test suite is substantive (817 lines, 27.4% density), and every correctness issue raised across 3 panel rounds has been addressed. The remaining P3 is a test refinement, not a code defect.

"The abort test genuinely exercises the signal path during retry delay. And CRF-17/CRF-18 fixes are both real." (Bisky)

🤖 This review was automatically generated with Coder Agents.

Comment thread src/browser/contexts/UserPreferencesContext.test.ts
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd7cf42109

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 597fb2030a

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx
Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

All 22 findings across 8 rounds are resolved. Approved.

This PR went through 4 panel rounds (R2: 14 reviewers, R3: 6, R4: 3, R6: 3, R8: 3) and converged from a P1 test coverage gap and P2 data loss bugs down to P3 test refinements, all fixed. The author addressed every finding with targeted fixes, added 886 lines of tests (28.7% density), and made structural improvements beyond what was requested: startup gate for launch behavior, taskSettings isolation, explicit PendingPreferenceSave type wrapper, userPreferencesInitialized migration marker, and capped exponential backoff with abort signal propagation.

Mafuuu, Knov, and Netero found zero issues on the final revision. CI is green.

Non-blocking follow-up: Bisky noted the first-time migration backfill path in hydrateUserPreferencesLocalCache (where userPreferencesInitialized is absent and userPreferences is undefined, with pre-existing localStorage) lacks a direct orchestration test. The individual helpers it calls (mirrorBackendPreferences, mergeMissingLocalPreferences) are both well-tested. This does not block merge but would lock the orchestration condition for future maintainers.

"I tried to build a case against this and couldn't. The problem is correctly understood, the solution is proportional, and the fix is at the right level." (Pariston, R3)

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is acting on Mike's behalf.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 433071f900

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx
Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Post-approval re-review (round 9). New commits since R8 approval reviewed.

Two commits added +30 production lines and +47 test lines. The new code adds:

  • A backfill-active-until-initialized guard that keeps first-run local backfill active until userPreferencesInitialized is set, preventing unrelated config refreshes from deleting migrated local preferences before their save completes.
  • Deferred preference saves until hydration has seeded the current preference document, so early UI writes don't replace backend preferences with a single-key partial object.
  • A test for the first-time migration orchestration path (addressing the non-blocking note from R8).
  • A test verifying early writes seed from the full local cache.

Netero (mechanical scan), Mafuuu (contract fidelity), Hisoka (edge cases), and Knov (wildcard) all found zero issues. Test density is now 29.5% (933 test lines). Re-approved.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb0450750b

ℹ️ 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".

Comment thread src/browser/contexts/UserPreferencesContext.tsx Outdated
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

@coder-agents-review
Copy link
Copy Markdown

@ibetitsmike ⛔ This review has reached its per-chat spend limit ($159.27 / $150.00). Further review rounds are paused.

To raise the limit and continue, comment:

/coder-agents-review set-spend-limit:200

This is a per-chat budget, separate from any account-level usage limit.

🤖 Managed by Coder Agents.

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Post-approval re-review (round 10). New commits reviewed: pruning guard behind successful metadata loads, ProjectContext/WorkspaceContext loaded/loadError state machine.

Mafuuu, Hisoka, Meruem, and Knov all found zero issues. Knov traced the loaded/loadError state machine across four reachable states and confirmed only "last attempt succeeded" permits pruning, which is the correct guard. The refreshSeq counter prevents stale errors from clobbering newer successes.

Two non-blocking notes from Netero:

  1. WorkspaceContext.test.tsx:567: test name "sets empty map on API error during load" describes the pre-PR behavior (actively clearing metadata). The PR changed this to preserve the existing map on error. The test still passes (initial state is empty, so the outcome is identical), but the name is misleading. Consider renaming to "preserves empty metadata map when initial load fails".

  2. hasUserPreferenceEntry has zero production callers (test-only export, same class as the prior R4 Note). Low maintenance cost.

Re-approved. 22 findings resolved, test density 29.7% (992 lines), CI pending (Codex Comments failure is unrelated).

🤖 This review was automatically generated with Coder Agents.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ 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".

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review set-spend-limit:200

@ibetitsmike
Copy link
Copy Markdown
Contributor Author

/coder-agents-review

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

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

Post-approval re-review (round 11). New commit adds hydration retry after transient config load failures (+30 prod, +27 test).

Netero, Mafuuu, Hisoka, and Knov all found zero new issues. The two non-blocking notes from R10 (stale test name in WorkspaceContext.test.tsx, test-only hasUserPreferenceEntry export) remain; neither blocks merge.

Test density: 30.0% (1019 lines). CI green. Re-approved.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike added this pull request to the merge queue Jun 5, 2026
Merged via the queue into main with commit c43ad98 Jun 5, 2026
24 checks passed
@ibetitsmike ibetitsmike deleted the mike/user-preferences-config branch June 5, 2026 06:10
@mux-bot mux-bot Bot mentioned this pull request Jun 5, 2026
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