Skip to content

refactor(mobile): make outbox ownership checks explicit - #10107

Closed
t3dotgg wants to merge 1 commit into
mainfrom
t3code/debt-gzuf-8-mobile-drafts
Closed

refactor(mobile): make outbox ownership checks explicit#10107
t3dotgg wants to merge 1 commit into
mainfrom
t3code/debt-gzuf-8-mobile-drafts

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 5, 2026

Copy link
Copy Markdown
Member

The outbox load API hid partial recovery behind a boolean. Cleanup and account changes had to interpret that result separately.

Storage now reports readable messages and whether ownership is complete. Cleanup, sign-out archives, account restore, and environment removal require complete ownership. Readable messages stay available. Failed account changes keep the load error as their cause. Draft flushing owns hydration before writes.

The saved formats and image writer are unchanged. The file-backed writer remains in #9727, held for a new native runtime on each platform with compatible embedded readers and storage guards. The source comment now states that condition.

Verification

  • 130 focused tests passed across outbox, composer drafts, removal, drain, and pending-task writes.
  • Mobile tsc --noEmit passed.
  • Changed-file lint passed with one existing extra-effect-dependency warning in the drain.
  • Independent source review passed after adding incomplete-account-restore coverage.

No UI layout, native code, or runtime configuration changed. No device or browser check ran.

Created with GPT-6 Astra in Codex.

Note

Replace outbox errors-array contract with explicit complete/incomplete hydration result

  • Replaces the errors array and boolean success return on ThreadOutboxStorage.load and the manager load operation with a discriminated ThreadOutboxLoadResult / ThreadOutboxHydrationResult union carrying status and a single error object on incomplete.
  • expoThreadOutboxStorage.load no longer rejects on unreadable records or directory failures; it returns recovered messages plus incomplete status and an error, retrying on the next call.
  • Composer draft workflows in use-composer-drafts.ts (releaseUnusedComposerAttachmentFiles, archiveCloudComposerDrafts, restoreCloudComposerDrafts) now inspect the structured outbox status and abort destructive or state-changing operations before running when hydration is incomplete, surfacing the hydration error as the thrown cause.
  • useThreadOutboxDrain and clearEnvironment switch from boolean/errors checks to the new incomplete status, triggering the unreadable-record alert and retry path and blocking environment clear respectively.
  • Risk: any out-of-tree ThreadOutboxStorage implementation must adopt the new complete/incomplete load contract; the former errors array is gone. Existing storage mocks across tests are updated to the new shape.

Macroscope summarized f003089.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 5, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at f003089

Macroscope's review found this PR approvable — This is a focused mobile outbox persistence refactor that makes partial-load ownership explicit while preserving readable messages and blocking unsafe cleanup or account transitions. The production logic is localized, persisted formats and defaults are unchanged, and targeted tests cover the new failure paths.

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

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.6 KiB +72 B (+0.5%) 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.0 KiB −3 B (−0.0%) 7.3 KiB
Codex Live turn WebSocket wire 6.5 KiB 6.6 KiB +75 B (+1.1%) 7.8 KiB
Codex Live turn WebSocket decoded 57.0 KiB 57.1 KiB +88 B (+0.2%) 66.4 KiB
Codex Live turn messages 8 10 +2 (+25.0%) 21
Claude Total thread wire 13.6 KiB 13.6 KiB +4 B (+0.0%) 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.0 KiB −3 B (−0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.5 KiB 6.5 KiB +7 B (+0.1%) 7.8 KiB
Claude Live turn WebSocket decoded 57.8 KiB 57.8 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 9 9 0 (0.0%) 21

Baseline: 761d4ba · PR result: f003089 · 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: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

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

@t3dotgg

t3dotgg commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Note

🤖 Claude Fable 5.1 responding on behalf of Theo

Closing. On main, thread-outbox-manager load() already returns true only for a complete load, and every caller in use-composer-drafts.ts and use-thread-outbox-drain.ts already treats false as "do not clean up or change accounting". The storage directory read is all-or-nothing, so the new incomplete-with-recovered-messages path never carries messages. This is a type reshuffle with no behavior change on the mobile persistence path.

@t3dotgg t3dotgg closed this Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). 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.

1 participant