fix(server): a stored boolean settledOverride no longer stops startup#28314

merged2
main
fix/issue-28279
opened11d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 9d ago

Problem

A stored thread projection row with a boolean settledOverride (true or false) stops the desktop app and server from starting (T3 Code could not start (code=1)). Startup recovery decodes the row with the thread schema, which only allows "settled" | "active" | null, and the resulting SchemaError aborts the startup phase. Rolling back does not help, because older builds use the same schema. Only the projection row is wrong: no current writer produces the boolean, and the event tables do not contain it.

Reproduced on main (15fe283272) with a fresh isolated server. I ran a real Claude thread, killed the server with SIGKILL so its provider session stayed ready (which puts the thread in the startup recovery set), and set the row's settledOverride to true. The restart exited with code 1: ProjectionStoreReadError → SchemaError: Expected "settled" | "active" | null | undefined at ["settledOverride"]. false fails the same way. When the bad thread is not in the recovery set, the server starts, but sending to that thread fails.

Change

Migration 077 (RepairBooleanSettledOverride) rewrites a stored boolean settledOverride in orchestration_v2_projection_threads: true becomes "settled" (the reporter's manual workaround) and false becomes null. It skips rows whose payload is not valid JSON and leaves every other row untouched. Repairing the stored data, rather than decoding leniently, means the startup decode and the SQL readers that use json_extract on settledOverride (shell index, settled pagination, search, auto-settle) all see the same value. The contracts schema stays strict.

Scope and approval

Fixes pingdotgg/t3code#28279

Verification

  • 077_RepairBooleanSettledOverride.test.ts runs migrations through 76, then stores true, false, "settled", "active", null and an absent settledOverride, then runs 077. It asserts that true becomes "settled", false becomes JSON null, the other four rows stay byte-identical, and the repaired row decodes with OrchestrationV2AppThreadJson. It fails on the test-only commit 938b709724 (rows unchanged: "type": "true" / "false") and passes at head.
  • Migrations.test.ts, reconcileV2PreviewMigration.test.ts and servicePreflight.test.ts pass. vp run check:changed passes (format, lint, knip, typecheck, tests).
  • Runtime transcript: identical copies of the same synthetic database (the thread above, settledOverride: true, session ready), each started with t3 serve:
Before (15fe283272)After (71e4bbc545)
server runtime startup failed
ServerRuntimeStartupError: Server runtime startup failed before command readiness.
SchemaError: Expected "settled" | "active" | null | undefined
server exits
V2 orchestration recovery completed
migrations recorded: 77, stored settledOverride now "settled"
t3 thread show reads the thread (completed claudeAgent/claude-haiku-5-5)
  • The false variant also exits with code 1 on main.
  • Not checked: the macOS desktop app itself. The failure and the fix sit in the shared server startup path, which I ran on Linux.

Model: Claude Opus 5.5 (lead, tests, implementation, review B) and GPT-6.1 Sol (review A), via T3 Code.

🤖 Generated with Claude Code

Checks

24 successful · 17 skipped
All checks passed
71e4bbc

Added 2 commits

  • fix(server): repair stored boolean settledOverride so startup recovery can read threads71e4bbc
  • test(server): reproduce #28279 stored boolean settledOverride survives migrations938b709
Synced from GitHub

Approvability

Verdict: Approved at 71e4bbc

Macroscope's review found this PR approvable — This migration repairs invalid boolean thread-settlement values that prevent server startup, leaving valid values and other fields unchanged. The narrowly scoped repair is supported by reported migration tests and a successful before/after startup reproduction.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded21.6 KiB21.6 KiB0 B (0.0%)24.4 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB+29 B (+0.6%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.3 KiB+29 B (+2.3%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.9 KiB21.9 KiB+41 B (+0.2%)24.4 KiB✅
ClaudeLive turn messages12+1 (+100.0%)8✅

Baseline: 5fe18d7 · PR result: 71e4bbc · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between 5fe18d79ac835e0f193ad61325e5b7d69a317bcf and 71e4bbc545db5c1836e5a9d3ae5f90b0ef85fdfd.

External image Files selected for processing: 4
  • apps/server/src/persistence/Migrations.ts
  • apps/server/src/persistence/Migrations/077_RepairBooleanSettledOverride.test.ts
  • apps/server/src/persistence/Migrations/077_RepairBooleanSettledOverride.ts
  • apps/server/src/persistence/reconcileV2PreviewMigration.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Walkthrough

Migration 77 repairs boolean settledOverride values in valid thread projection JSON. The migration is added to the ordered registry, and tests cover the value conversions and migration sequence.

Changes: Thread projection repair

Layer / File(s)Summary
Implement and register migration 77
apps/server/src/persistence/Migrations/077_RepairBooleanSettledOverride.ts, apps/server/src/persistence/Migrations.ts, apps/server/src/persistence/Migrations/077_RepairBooleanSettledOverride.test.ts, apps/server/src/persistence/reconcileV2PreviewMigration.test.ts
Migration 77 changes boolean true to "settled" and false to null in valid projection JSON. It is added to the ordered migration registry. Tests check other values, timestamp retention, thread decoding, and migration sequence expectations.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested labels: bugfix, size:S

Suggested reviewers: t3dotgg

Merge Risk: External image Minimal · up to 71e4b

The migration repairs boolean overrides before thread state is loaded. No merge-blocking risk remains identified.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the primary fix: preventing a stored boolean settledOverride from blocking startup.
Description checkPassedThe description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the failure, the migration behavior, linked issue, focused tests, runtime results, and the…
Linked Issues checkPassedIssue [#28279] requires startup recovery to handle thread projections with boolean settledOverride. Migration 077 is registered and rewrites valid boolean values in `orchestration_v2_projection_thre…
Out of Scope Changes checkPassedThe changes stay within [#28279]. They add the required repair migration, register migration 077, and add migration and migration-integration test coverage. No unrelated behavior or product area is ch…
Full details: Description check

Explanation

The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the failure, the migration behavior, linked issue, focused tests, runtime results, and the untested macOS desktop app.

Full details: Linked Issues check

Explanation

Issue [#28279] requires startup recovery to handle thread projections with boolean settledOverride. Migration 077 is registered and rewrites valid boolean values in orchestration_v2_projection_threads: true becomes "settled" and false becomes JSON null. The migration test verifies both repairs, preserves settledAt, preserves non-boolean and absent values, and decodes the repaired thread with OrchestrationV2AppThreadJson.

Full details: Out of Scope Changes check

Explanation

The changes stay within [#28279]. They add the required repair migration, register migration 077, and add migration and migration-integration test coverage. No unrelated behavior or product area is changed.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

[gpt-6.1-sol][Codex] on behalf of shivam.

Stopping our issue-watch work now that you own this. These results cover main and our unpublished fix, not this PR's head 71e4bbc545db5c1836e5a9d3ae5f90b0ef85fdfd.

On physical shiv, macOS 27.0.1 arm64, source-built T3 Code 0.1.6 / Electron 44.10.0, I reproduced the desktop code=1 failure on main 15fe2832727893cbdd2214383f9f971474849695. The isolated synthetic release-launch fixture had JSON settledOverride: true and a pending message-capable runtime request so the thread entered startup recovery. The backend failed in ProjectionStore.getRuntimeRecoveryProjection with the reported settledOverride schema error. Healthy and "settled" controls opened normally. No real provider turns or live user state were used.

Before, macOS desktop on main:

https://github.com/user-attachments/assets/1c1c898e-51f7-40b6-bc29-0c3b2519d8ac

Our unpublished commit 04ddd4c426abe8df27fd9c59e4f2d6fb8b950815 used a projection-only migration with the same true → "settled", false → null mapping. On the same Mac and corrupted fixture, startup recorded migration 77, SQL changed the boolean to the canonical string, both runtime-recovery spans succeeded, and the desktop opened the seeded thread and rendered its message. The recording below is from that unpublished commit, not your build.

After, macOS desktop on our unpublished repair:

https://github.com/user-attachments/assets/f1c486cd-4193-4c4c-a1f0-26f25e232a01

On corex, the migration regression failed on main with the exact decoder error. With our repair, the focused migration/preview-upgrade/timestamp tests passed, 3 files / 7 tests. vp run check:changed also passed, including 4 test files / 15 tests. Coverage included booleans, both canonical strings, null, absent field, numeric 1 remaining untouched, and preservation of the rest of each payload. A fresh independent Codex review found no issues.

Unverified: your PR, the original writer and reporter database, packaged releases, other desktop platforms, and malformed values introduced after the one-time migration. The false case passed the migration/recovery test but was not separately launched in the Mac app. Two evidence workers hit a Codex API 400 after the successful true-case capture; I recovered and inspected the SQL, successful spans, app screenshot and recording frames over SSH. No branch was pushed and no competing PR was opened.