🤖 feat: sync user preferences through backend config#3455
Conversation
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 -->
|
/coder-agents-review |
|
Chat: Review in progress | View chat deep-review v0.7.1 | Round 11 | Last posted: Round 11, 22 findings (1 P1, 4 P2, 11 P3, 3 Nit, 3 Note), APPROVE. Review Finding inventoryFindings
Law analysisEffective 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 logRound 1Netero-only. 1 P1, 1 P2, 1 P3, 2 Note. Law: Don't split (advisory). Reviewed against d49bdcc..28a4893. Round 2Churn 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 3Churn 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 4Churn 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 5BLOCKED. CRF-21 silent. No review. Round 6Churn 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 7BLOCKED. CRF-22 silent. No review. Round 8Churn 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 9Post-approval re-review. New commits pushed (dd7cf42 → 433071f, +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 10Post-approval re-review. New commits pushed (433071f → fb04507, +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 11Post-approval re-review. New commits pushed (fb04507 → d96be7f, +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-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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.
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 -->
|
Addressed coder-agents-review findings:
Validation after fixes:
|
|
/coder-agents-review |
There was a problem hiding this comment.
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.
|
@codex review |
There was a problem hiding this comment.
💡 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".
|
@codex review
|
|
Codex Review: Didn't find any major issues. Keep them coming! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Responding to coder-agents-review feedback before resolving threads:
|
|
/coder-agents-review |
|
@codex review
|
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
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.
Responding to follow-up coder-agents-review feedback before resolving threads:
|
|
/coder-agents-review |
|
@codex review
|
There was a problem hiding this comment.
💡 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".
|
/coder-agents-review |
|
@codex review
|
|
Codex Review: Didn't find any major issues. Chef's kiss. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
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.
|
/coder-agents-review |
There was a problem hiding this comment.
💡 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".
|
/coder-agents-review |
|
@codex review
|
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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.
|
/coder-agents-review |
|
@codex review
|
There was a problem hiding this comment.
💡 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".
There was a problem hiding this comment.
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
userPreferencesInitializedis 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.
|
/coder-agents-review |
|
@codex review |
There was a problem hiding this comment.
💡 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".
|
/coder-agents-review |
|
@codex review |
|
@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: This is a per-chat budget, separate from any account-level usage limit.
|
There was a problem hiding this comment.
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:
-
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". -
hasUserPreferenceEntryhas 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.
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
/coder-agents-review set-spend-limit:200 |
|
/coder-agents-review |
There was a problem hiding this comment.
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.
Summary
Moves localStorage-only semantic preferences into a new typed
userPreferencessection 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
UserPreferencesschema, normalization, config load/save persistence, and ORPCconfig.getConfig/config.saveConfigsupport.userPreferencesgroups.UserPreferencesProviderto 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.userPreferencesInitializedmigration marker so stale localStorage from another browser origin cannot resurrect preferences that were already cleared from backend config.RouterProviderandWorkspaceProviderread it.taskSettings, so automatic preference sync cannot replay stale task settings over concurrent settings edits.userPreferences: nullstill clears stored preferences.src/common/schemasso 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.tsxmake typecheckmake static-checkbun test src/browser/contexts/UserPreferencesContext.test.tsbun test src/browser/contexts/UserPreferencesContext.test.ts src/node/config.test.ts src/node/orpc/router.test.ts src/common/orpc/schemas/api.test.tsbun 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.tsmake storybook-run CMD='bun x test-storybook --testTimeout 30000 --maxWorkers 1 --verbose src/browser/components/ProjectPage/ProjectPage.stories.tsx'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.tsRisks
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