Skip to content

fix(mobile): render agent widgets and expire stale timelines - #14830

Closed
jakeleventhal wants to merge 4 commits into
pingdotgg:mainfrom
jakeleventhal:t3code/reopen-pr-6464
Closed

jakeleventhal wants to merge 4 commits into
pingdotgg:mainfrom
jakeleventhal:t3code/reopen-pr-6464

Conversation

@jakeleventhal

Copy link
Copy Markdown
Contributor

Adds the iOS Agent Activity home-screen widget and keeps it aligned with live connected environments. Previously its advertised families had no regular widget factory, and reconnecting could leave stale relay rows or an incorrect combined count.

Live connected environments own their widget rows. A scoped relay snapshot excludes those environments before the row cap and acknowledges its scope, so totals remain exact. Older relays fall back to an unknown count when the capped response cannot prove a total. Disconnected observations remain visible as "Last observed" until a newer observation confirms them; normal backgrounding preserves freshness until the timeline deadline.

The widget now embeds its initial layout and handles undefined first-paint props, so it renders before the first app launch. Starting a new account session clears persisted native content before fetching; same-account token refreshes preserve it. Foreground reconciliation shares one snapshot between the regular widget and Live Activity priming instead of repeating global and scoped reads. Native publication stays in the iOS adapter. Unavailable counts use a numeric sentinel at the native storage boundary because UserDefaults rejects null values; the layout renders them as unavailable.

Regular widgets publish a current timeline entry and a future expiration entry. After ten minutes without confirmation, unfinished rows become out of date, the count stops claiming to be current, and the widget shows “Open T3 to refresh”. Completed and failed outcomes remain intact. Backgrounding preserves a fresh observation until its deadline, while disconnected observations retain their last-observed distinction. Unchanged successful reads renew the deadline; failed, superseded, and already old reads do not. Live shell renewals are coalesced within a minute, and unrelated atom recomputations cannot extend freshness. New activity data refreshes when the app opens; the timeline does not fetch completion while the app is closed.

Rebased onto main, including the Expo 58 runtime fix in #14734. Continues #14608, with the requested freshness behavior and current native expiration evidence, and the original work from #6464.

Verification

  • 172 focused tests passed across mobile reconciliation/registration/layouts/timelines, relay snapshot handling, client requests, and contracts. Freshness regressions cover unchanged renewal, failed and superseded reads, slow response arrival, disconnected observations, backgrounding, and terminal outcomes.
  • Mobile, relay, client-runtime, and contracts typechecks passed; targeted lint passed.
  • Baseline native evidence at eba1c86: a fresh Xcode build succeeded on iPhone 17 Pro, iOS 26.5. Verified the embedded layout before opening the app, small and medium native widget updates, and native Live Activity creation/update.
  • The updated iOS layout registry and widget runtime bundles compile. Expo’s actual embedded widget runtime renders current, expired, completed, and failed timeline entries correctly for small, medium, and accessory-rectangular families.
  • Simulator timeline updates use clearly labeled synthetic activity data through the actual native factories. Account/race behavior is covered by coordinator tests. Physical-device APNs delivery and native placement of the lock-screen accessory widget were not verified.
  • At e9c9a19051, verified with a freshly built compatible native client on iPhone 18 Pro Max, iOS 27.0. The production iOS publisher returned a current entry and an expiration entry ten minutes later. With T3 terminated, the Home Screen transitioned to “Agent status out of date”, the unfinished row became “Out of date”, the refresh hint appeared, and the failed outcome stayed “Failed”. A continuous two-minute recording captures that transition without reopening T3. A separate already-expired terminal-only publication verifies both “Done” and “Failed” remain visible.
  • Coverage applies to iOS regular widgets and provider-independent local/relay reconciliation, including background/foreground, disconnected, multiple-environment, and account-reset states.

Current native freshness evidence (e9c9a19051)

Synthetic data is published through the production iOS adapter and native widget factory. The fresh observation was confirmed at 15:17:57 UTC, with its expiration entry scheduled for 15:27:57 UTC. T3 was terminated before capturing the fresh Home Screen and remained closed throughout the recording. No completion fetch or new app observation occurred during the wait.

Before expiration:
Fresh count and running task

After the scheduled expiration, observed by 15:28:12 UTC:
Out-of-date count and row, refresh hint, and preserved failed outcome

Continuous native recording of scheduled expiration with T3 closed

Native publisher and two scheduled entries

A separate publication whose deadline is already past preserves both terminal outcomes:
Expired terminal rows remain Failed and Done

Baseline native evidence

These captures are the baseline rendering evidence from eba1c86, before the timeline freshness follow-up.

Before: main's installed client had no Agent Activity layout before publication.
Before: missing native widget layout

After: the embedded idle layout renders before the app opens.
After: idle native widget before first app launch

After: real small and medium native widgets display the same synthetic Approval state.
After: small and medium widget Approval state

Native timeline update recording with synthetic data

Original implementation by Jake Leventhal. Audit and fixes by GPT-6.1-sol through the Codex harness in T3 Code.

jakeleventhal and others added 4 commits October 1, 2026 23:59
…kground error

expo-widgets stopped applying containerBackground for us, and the
home-screen widget never got a createWidget layout. iOS 17 then showed
"Please adopt containerBackground API" instead of agent activity.

Adopt the modifier on the home-screen views, register the widget layout,
and publish snapshots from the Live Activity refresh path. While the app
is foregrounded, regular widgets follow complete live environment shells
and reconcile them with relay snapshots scoped to the remaining
environments.

Rebased onto main as a single commit. Widget publishing goes through the
platform-split agentLiveActivity module so non-iOS builds never import
the widget, the Live Activity banner keeps the system glass tint and
hierarchical foregrounds, and environments switched off in Settings no
longer own widget rows.

Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Oct 2, 2026
@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 2, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:XL 500-999 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.

2 participants