What happened
The T3 Code desktop backend still stops with a V8 out-of-memory error during Codex work. The UI then marks active work as failed and reports that the provider session did not survive a server restart.
This continued after the fix for #10924 shipped. That fix is present and limits provider event log records, but large Codex file-change diffs still enter durable SQLite activity data through a separate path.
Diagnosis
The fix from #12305 works for diagnostic provider logs. Post-fix provider log records on this install stay near the 64 KiB limit. The build that crashed also contains the #12305 merge commit.
The remaining unbounded path is durable activity persistence:
CodexAdapter.mapItemLifecycle attaches the full native lifecycle payload as payload.data.
ProviderRuntimeIngestion copies that data into both tool.started and tool.completed activities.
- The resulting
thread.activity-appended payload is stored in orchestration_events.
- The projection pipeline stores the same activity payload again in
projection_thread_activities.
- Thread detail reads limit activity count to 500 and decode in batches of 25, but they do not limit bytes.
projectActivityPayload drops unused diff data only after SQLite and V8 decode the full JSON.
The affected database is healthy but 15.9 GiB. It contains 12,551 file-change activity rows whose first changes[].diff field uses 5.2 GiB in each table, for 10.4 GiB across the event and projection copies. One stored diff has 49,359,322 characters. One activity row reaches 54.2 MiB. The newest 500 activities for the largest thread contain 571.7 MiB of raw JSON before decoding and projection.
The backend then aborts when V8 reaches its heap limit. Restarting clears live memory but leaves the large stored payloads, so the failure can return.
The current installed source still has this persistence path. A newer nightly exists, but no later commit has changed CodexAdapter, ProviderRuntimeIngestion, ProjectionSnapshotQuery, ActivityPayloadProjection, or the database migrations involved here.
Expected behavior: file-change lifecycle activities should persist bounded metadata such as paths, status, and omitted byte counts. They should not persist full diff text in both lifecycle rows and both SQLite stores. Existing oversized rows also need a supported repair or migration because the logger fix cannot clean stored data.
Steps to reproduce
Source-level reproduction:
- Start the desktop app with a local backend and the Codex provider.
- Send a valid Codex file-change
item/started and item/completed lifecycle event whose item.changes[].diff contains a large string.
- Let
CodexAdapter map the event and let ProviderRuntimeIngestion create activities.
- Inspect the stored
thread.activity-appended event and its projected activity row.
- Observe that the full diff exists in both
orchestration_events.payload_json and projection_thread_activities.payload_json. Both lifecycle rows can retain the payload.
- Repeat with tool-heavy work, or load a thread whose newest 500 activities contain several large file-change payloads.
- Observe rapid database growth and eventual backend heap exhaustion while T3 processes the large activity window.
A focused regression test can use a generated diff string and assert that neither persisted copy contains the full string.
Version
Current install: 0.0.43-nightly.20260920.2005, commit 7445aa733ada.
Confirmed crashes: 0.0.43-nightly.20260918.1895, commit 994654198d58. This tag is 27 commits ahead of the #12305 merge commit, so the provider logger fix was present.
Environment
- T3 Code desktop app with local backend
- Darwin 25.6.0, arm64
- Node.js 26.8.2
- Codex provider
Evidence
SQLite quick_check: ok
Database size: 15,924.2 MiB
orchestration_events: 7,907.9 MiB
projection_thread_activities: 7,737.3 MiB
thread.activity-appended payloads: 7,705.3 MiB across 209,288 rows
tool.completed payloads: 4,372.8 MiB across 54,865 rows
tool.started payloads: 3,234.9 MiB across 54,914 rows
File-change diff fields in projection:
rows: 12,551
total diff text: 5,202.4 MiB
largest diff: 48.8 MiB
The event table contains the same row count and 5,202.4 MiB of diff text.
Largest complete activity row: 54.2 MiB
Largest newest-500 activity window: 571.7 MiB
Three backend crashes on the confirmed build:
EXC_CRASH / SIGABRT
FATAL ERROR: JavaScript heap out of memory
Last-resort retained heaps ranged from about 1.6 to 1.95 GiB.
Post-fix provider log records remained bounded near 64 KiB.
No home paths, thread IDs, turn IDs, project names, commands, or payload text are included.
Related issues
Fix applied or workaround
No database write or local source patch was made. Restarting the desktop app lowers memory use for a time. Avoiding the affected heavy threads reduces the chance of another abort, but the oversized SQLite rows remain.
Filed by
Codex, GPT-5, via t3 triage
What happened
The T3 Code desktop backend still stops with a V8 out-of-memory error during Codex work. The UI then marks active work as failed and reports that the provider session did not survive a server restart.
This continued after the fix for #10924 shipped. That fix is present and limits provider event log records, but large Codex file-change diffs still enter durable SQLite activity data through a separate path.
Diagnosis
The fix from #12305 works for diagnostic provider logs. Post-fix provider log records on this install stay near the 64 KiB limit. The build that crashed also contains the #12305 merge commit.
The remaining unbounded path is durable activity persistence:
CodexAdapter.mapItemLifecycleattaches the full native lifecycle payload aspayload.data.ProviderRuntimeIngestioncopies that data into bothtool.startedandtool.completedactivities.thread.activity-appendedpayload is stored inorchestration_events.projection_thread_activities.projectActivityPayloaddrops unused diff data only after SQLite and V8 decode the full JSON.The affected database is healthy but 15.9 GiB. It contains 12,551 file-change activity rows whose first
changes[].difffield uses 5.2 GiB in each table, for 10.4 GiB across the event and projection copies. One stored diff has 49,359,322 characters. One activity row reaches 54.2 MiB. The newest 500 activities for the largest thread contain 571.7 MiB of raw JSON before decoding and projection.The backend then aborts when V8 reaches its heap limit. Restarting clears live memory but leaves the large stored payloads, so the failure can return.
The current installed source still has this persistence path. A newer nightly exists, but no later commit has changed
CodexAdapter,ProviderRuntimeIngestion,ProjectionSnapshotQuery,ActivityPayloadProjection, or the database migrations involved here.Expected behavior: file-change lifecycle activities should persist bounded metadata such as paths, status, and omitted byte counts. They should not persist full diff text in both lifecycle rows and both SQLite stores. Existing oversized rows also need a supported repair or migration because the logger fix cannot clean stored data.
Steps to reproduce
Source-level reproduction:
item/startedanditem/completedlifecycle event whoseitem.changes[].diffcontains a large string.CodexAdaptermap the event and letProviderRuntimeIngestioncreate activities.thread.activity-appendedevent and its projected activity row.orchestration_events.payload_jsonandprojection_thread_activities.payload_json. Both lifecycle rows can retain the payload.A focused regression test can use a generated diff string and assert that neither persisted copy contains the full string.
Version
Current install:
0.0.43-nightly.20260920.2005, commit7445aa733ada.Confirmed crashes:
0.0.43-nightly.20260918.1895, commit994654198d58. This tag is 27 commits ahead of the #12305 merge commit, so the provider logger fix was present.Environment
Evidence
Related issues
tool.updatedpersistence.tool.startedandtool.completedstill keep full file-change payloads.Fix applied or workaround
No database write or local source patch was made. Restarting the desktop app lowers memory use for a time. Avoiding the affected heavy threads reduces the chance of another abort, but the oversized SQLite rows remain.
Filed by
Codex, GPT-5, via
t3 triage