Skip to content

[orchestrator-v2] fix(mobile): Stabilize iOS draft attachments, Hermes sort, and Home - #3923

Closed
mwolson wants to merge 138 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/ios-v2-attachment-persistence
Closed

[orchestrator-v2] fix(mobile): Stabilize iOS draft attachments, Hermes sort, and Home#3923
mwolson wants to merge 138 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/ios-v2-attachment-persistence

Conversation

@mwolson

@mwolson mwolson commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Keep CTM mobile draft image attachments working when they carry both a local id and a dataUrl.
  • Avoid a Hermes fatal in the queue UI by replacing missing Array.prototype.toSorted with a shared copy-sort helper.
  • Hide orchestration-v2 subagent threads from the mobile Home list (forks stay visible).
  • Stabilize Home native-stack options and callbacks so ordinary Home updates do not re-enter navigation through PreventRemoveProvider.
  • Normalize V2 shell active/archive membership from archivedAt so archived threads do not stick on the Home list after a missed archive delta.

Base

This branch is now built on mwolson/t3code v2-base, a merge of the shared iOS/mobile fixes line (ios-fixes-main) into t3code/codex-turn-mapping. Because GitHub diffs against t3code/codex-turn-mapping, the PR diff includes that merge (mobile keyboard/feed fixes, shell reconnect heal, serverConfig/vcsRefs caching, and the V2 thread resume completion marker) in addition to the two commits listed below. Review the two head commits for this PR's own delta.

Problem and Fix

Problem and Why it Happened Fix
CTM drafts can include image attachments with both a local id and a dataUrl. The start-turn path did not treat those dual-tagged attachments as uploads, so order and persistence broke for mobile screenshots. Treat dual-tagged attachments as uploads, strip local-only fields before persistence, and dispatch server IDs while preserving order with already-persisted attachments.
Hermes 250829098 (RN 0.85.3) does not implement Array.prototype.toSorted. CTM queue UI calls it from deriveThreadQueueWorkflowState / ThreadQueueControl, so queuing a reply or finishing a turn can crash with TypeError: undefined is not a function. Add @t3tools/shared/Array copySorted ([...values].sort) and use it on mobile-reachable call sites (threadWorkflows, ThreadRelationshipsBanner, use-thread-selection, CTM model.ts).
Orchestration-v2 subagent shells appeared in the mobile Home list, unlike the desktop sidebar. Skip threads with lineage.relationshipToParent === "subagent" when grouping Home rows; keep fork threads.
Unstable Home native-stack options and callbacks re-entered setOptions and could hit maximum update depth through PreventRemoveProvider on CTM device launches. Memoize iOS Home header options (filter menu inputs as deps; handlers via ref) and stabilize Settings / New Task callbacks and title option objects.
A dropped thread.archived shell delta (or a mis-tagged full snapshot) could keep an archived thread listed as active on Home even after the reconnect heal applied a fresh snapshot. Add normalizeShellThreadMembership and apply it to every full snapshot (reducer enrichment refreshes and reconnect heals) so active/archive membership always derives from archivedAt. The HTTP heal, forced socket snapshot, and stale-snapshot rejection it pairs with live in v2-base.

Validation

  • Targeted tests: client-runtime attachment command tests; Home subagent filter tests (including fork negative control); shared Array tests; shell-sync / shellReducer membership tests.
  • vp check (0 errors) and full vp run typecheck on the rebuilt branch.
  • Device: archived threads from a paired CTM environment leave Home after reconnect/heal.
  • Device: Release Hermes com.mwolson.t3code.v2.dev from local orchestrator-v2 integration; queued reply send after active turn finished without crash; Home list usable after nav stability fix.

Notes

Note

Stabilize iOS draft attachments, Hermes array sort, and Home screen for mobile

This is a large orchestrator-v2 stabilization PR with dozens of changes across mobile, web, server, and desktop. Key highlights:

  • iOS draft attachments: persistAttachments now correctly maps upload results back to their source positions and strips client-only fields (id, previewUri) before sending to the server.
  • Hermes sort fix: Replaces Array.prototype.toSorted (unsupported on Hermes) with a shared copySorted utility throughout mobile thread sorting.
  • Home screen (Android): Adds a floating new-task FAB, custom branded header with inline search, and persists collapsed project groups via preferences atoms.
  • Draft hero UX: Web chat view gains a centered composer for empty drafts with animated docking transitions and a DraftHeroHeadline project picker.
  • Thread feed scroll correction: ThreadFeed now auto-corrects scroll position when content underflows the viewport and shows a full-screen loading overlay during hydration.
  • iOS terminal stability: TerminalInputSequence normalizes all return keys to carriage return (\r); autoFocus prop added to control keyboard focus.
  • Shell state synchronization: makeEnvironmentShellState no longer paints cached snapshots immediately; starts in synchronizing and waits for an HTTP heal or authoritative socket snapshot.
  • Thread resume completion marker: Server and client cooperate on a synchronized marker so warm-start clients exit the syncing state faster.
  • Android terminal: Full native terminal canvas (TerminalCanvasView, GhosttyBridge) with JNI bindings, selection, scroll, and theme support.
  • Incoming share flow (iOS/Android): IncomingShareProvider and IncomingShareInbox serialize share ingestion, merge content into composer drafts idempotently, and clean up temporary files.
  • Legal pages: Marketing site gains Privacy Policy, Terms of Service, and Security Policy pages with a shared LegalPage layout component.
  • Risk: IndexedDB schema bumped from v2 to v4; upgrade path adds new object stores but no migration for existing server-config/vcs-refs data (cold start for those caches).

Macroscope summarized 47dc628.


Note

Medium Risk
Touches desktop launcher/signing behavior, auto-update state, and substantial mobile native/Expo configuration; misconfiguration could affect local iOS builds, store screenshots CI, or renderer chrome, but changes are mostly additive with tests on key desktop paths.

Overview
Adds a manual GitHub workflow to capture and validate iOS and Android store showcase screenshots (pnpm screenshots:mobile), upload artifacts, and ignore generated .showcase/ / artifacts/app-store/screenshots/ paths.

Desktop changes improve the macOS dev launcher (branded bundle with a separate launcher executable that execs in-bundle Electron, launcher version bump), context menu positioning scaled by webContents zoom, native fullscreen state exposed to the renderer via IPC/preload, nightly update release notes (setFullChangelog + HTML/markdown normalization into update state), and WSL Node engine validation during probe.

Marketing adds a shared legal document layout, index plus privacy/terms/security pages, footer links, and Grok CLI messaging/assets on the homepage (with minor harness/layout tweaks).

Mobile expands Expo config: repo-root brand assets, Personal Team local iOS builds (optional bundle id, stripped widgets/share/SiWA entitlements), more Android plugins (Gradle heap, predictive back, modern menus/alerts, crash log), DM Sans registered under native PostScript names, and a new Android T3ComposerEditor native view (chips, paste images, theming). iOS markdown shadow node now rebuilds attributed content from current children instead of stale measure-time cache. Composer iOS fonts align to DMSans-Regular / DMSans-Medium.

Also bumps electron-builder, adds minimal root app.json, extends Macroscope Effect service conventions (dependency acquisition / runtime boundaries), and minor asset/doc updates.

Reviewed by Cursor Bugbot for commit 47dc628. Bugbot is set up for automated code reviews on this repo. Configure here.

juliusmarminge and others added 17 commits July 7, 2026 15:55
…gg#3781)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
…pingdotgg#3795)

Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#3823)

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Horus Lugo <horusgoul@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com>
Co-authored-by: Alex <me@pixp.cc>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: Julius Marminge <julius@mac.lan>
Co-authored-by: codex <codex@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8bbf5543-c8a1-4f1c-8bfe-1d903c77b419

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 12, 2026
Comment thread apps/mobile/src/features/home/HomeHeader.tsx
@mwolson
mwolson marked this pull request as ready for review July 12, 2026 21:35
Comment thread packages/shared/src/Array.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

25 blocking correctness issues found. Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

You can customize Macroscope's approvability policy. Learn more.

@mwolson
mwolson force-pushed the fix/ios-v2-attachment-persistence branch from 2857eb3 to 76a88a0 Compare July 12, 2026 21:41
@mwolson mwolson changed the title fix(mobile): Stabilize CTM iOS draft attachments, Hermes sort, and Home [orchestrator-v2] fix(mobile): Stabilize CTM iOS draft attachments, Hermes sort, and Home Jul 12, 2026
mwolson added 2 commits July 12, 2026 18:53
Capture RCTFatal message and stack to Documents via a native handler so
Release Hermes aborts leave last-crash.json without a device console.
Harden the JS ErrorUtils path with a minimal write-first record, durable
fsync writes, breadcrumb max-wait flush, and an Expo AppDelegate plugin.

Skip NativeStackScreenOptions setOptions when content is unchanged so
Thread catch-up re-renders do not loop through PreventRemoveProvider and
hit maximum update depth.
CI Mobile Native Static Analysis failed on a multi-line if where the
opening brace was on the following line.
// Prefer a non-null archivedAt when the same id appears in both lists.
if (existing.archivedAt === null && thread.archivedAt !== null) {
byId.set(String(thread.id), thread);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Archive wins membership ID conflicts

Medium Severity

When the same thread id appears in both threads and archivedThreads, normalizeShellThreadMembership always prefers the copy with a non-null archivedAt. An inconsistent full snapshot that still carries a stale archived row can therefore override a fresher active row (archivedAt: null) and keep an unarchived thread off Home.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 30b5502. Configure here.

mwolson added 3 commits July 18, 2026 11:21
Completes the pingdotgg#4055 port in the v2-base merge: draft routes carry a
pre-allocated thread id, and the conditional subscription blocked
promotion to live shell data until remount. Flagged by Grok review.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 47dc628. Configure here.


Function("markShowcaseReady") { (scene: String) in
let readyPath = NSHomeDirectory() + "/Library/Caches/T3ShowcaseReadyScene"
try? scene.write(toFile: readyPath, atomically: true, encoding: .utf8)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Crash breadcrumb fsync path removed

Medium Severity

The writeSyncText function, which provided durable last-chance crash log writes, was removed from T3NativeControlsModule. This breaks the breadcrumbPersist mechanism, which still expects this native fsync path. As a result, last-minute breadcrumbs may be lost during iOS fatals, impacting crash diagnostics.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 47dc628. Configure here.

@mwolson

mwolson commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Closing for now; may reattempt later after the iOS fixes have landed on main, and have been backmerged to codex-turn-mapping.

@mwolson mwolson closed this Jul 20, 2026
juliusmarminge added a commit that referenced this pull request Jul 20, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
maria-rcks pushed a commit that referenced this pull request Aug 3, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 4, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 4, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 5, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 7, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 10, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 11, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 12, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 14, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 14, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Reuses the focused compatibility approach from closed PR #3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.