Skip to content

fix: show iOS chat activity after foreground refresh#102309

Merged
steipete merged 4 commits into
openclaw:mainfrom
jmcte:codex-ios-chat-pending-state
Jul 9, 2026
Merged

fix: show iOS chat activity after foreground refresh#102309
steipete merged 4 commits into
openclaw:mainfrom
jmcte:codex-ios-chat-pending-state

Conversation

@jmcte

@jmcte jmcte commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Closes #102308

AI-assisted: yes.

What Problem This Solves

Fixes an issue where iOS users who send a chat message and return to the chat during a long-running session would see an idle-looking transcript when the latest user turn was still unanswered and the session still had active work.

Why This Change Was Made

The mobile chat view now keeps an already-owned run ID when foreground or post-send history still reports active unanswered work without a chat inFlightRun snapshot. That preserves normal stream, tool, lifecycle, timeout, and terminal-event routing. When no local run ID exists, the view renders a bounded fallback activity state until answered history/session messages, a terminal event, session switch, reset, or timeout resolves the ambiguity.

Both known and fallback activity use one presentation/send gate, so the transcript, composer, Talk affordance, and Compact action cannot disagree about whether a response is active.

The follow-up commit also moved existing session action methods into ChatViewModel+SessionActions.swift so ChatViewModel.swift stays below the SwiftLint file_length cap after adding the new active-session state.

User Impact

iOS users get visible feedback that the assistant is still working after leaving and returning to a chat during a long-running run. Send, Talk, and Compact controls stay guarded against starting conflicting work until the known or fallback activity state clears.

Evidence

Redacted before evidence:

Redacted after-fix simulator evidence:

Local validation:

swift test --filter ChatViewModelTests
Result: 166 tests passed

swift test --filter ChatStreamReplayTests
Result: 7 tests passed

swiftformat --lint apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel+SessionActions.swift --config config/swiftformat
Result: passed

pnpm native:i18n:check
Result: native-app-i18n changed=false

git diff --check
Result: passed

.agents/skills/autoreview/scripts/autoreview --mode local
Result: clean, no accepted/actionable findings

xcodegen generate
xcodebuild -project OpenClawChatProof.xcodeproj -scheme OpenClawChatProof -sdk iphonesimulator -destination 'id=DC0B43DB-F6EB-409D-89CA-E22F9DE252AA' -derivedDataPath /private/tmp/openclaw-ios-chat-proof/DerivedData build
xcrun simctl install DC0B43DB-F6EB-409D-89CA-E22F9DE252AA /private/tmp/openclaw-ios-chat-proof/DerivedData/Build/Products/Debug-iphonesimulator/OpenClawChatProof.app
xcrun simctl launch DC0B43DB-F6EB-409D-89CA-E22F9DE252AA ai.openclaw.proof.chat
xcrun simctl io DC0B43DB-F6EB-409D-89CA-E22F9DE252AA screenshot /private/tmp/openclaw-ios-chat-proof/ios-chat-after-fix-active-indicator.png
Result: after-fix simulator still captured from a temporary proof host importing this PR's OpenClawChatUI.

Maintainer follow-up validation on the updated implementation:

swiftformat --lint on the changed Swift surfaces (with existing unrelated whole-file findings excluded)
Result: passed

pnpm native:i18n:check on Blacksmith Testbox tbx_01kx2x3454zj142gk2thbk72r3
Result: passed

autoreview --mode local
Result: one compatibility warning rejected because the property exists only in this unmerged PR; no shipped API is removed

CI-specific note:

ChatViewModel.swift effective source lines after the split: 2471
CI SwiftLint file_length cap: 2500

Agent transcript logs were not included because they require explicit approval before adding them to a public issue or PR body.

@clawsweeper

clawsweeper Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 9, 2026, 3:55 AM ET / 07:55 UTC.

Summary
The PR adds a shared Apple chat activity fallback for active unanswered sessions without an inFlightRun snapshot, guards send/Talk/compact controls, moves session actions, updates Swift tests/i18n inventory, and adds a changelog entry.

PR surface: Docs +1, Other +227. Total +228 across 8 files.

Reproducibility: yes. The issue is source-reproducible: current main has session active-run metadata but renders chat activity only from chat-owned pending runs, and the before stills show the idle returned chat; I did not run a live iOS device reproduction in this read-only review.

Review metrics: 1 noteworthy metric.

  • Release-owned changelog entries: 1 added. Repository policy reserves CHANGELOG.md for release generation, so this added entry needs cleanup or release-owner acceptance before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #102308
Summary: This PR is the candidate fix for the canonical iOS chat foreground-return active-session report; the earlier in-flight-run recovery PR partially overlaps but did not cover missing chat snapshots with session activity.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Remove the CHANGELOG.md entry from the branch and keep the release-note context in the PR body.
  • Let the remaining exact-head CI jobs finish before maintainer merge.

Risk before merge

  • [P1] The branch currently edits release-owned CHANGELOG.md; that entry should be removed or explicitly accepted by the release owner before merge.

Maintainer options:

  1. Decide the mitigation before merge
    Merge the Swift/i18n/test fix after removing the release-owned changelog entry and letting exact-head CI finish.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • A mechanical cleanup can remove the release-owned changelog entry; the Swift behavior fix otherwise only needs normal maintainer review and exact-head CI.

Security
Cleared: Cleared: the diff is limited to Swift chat UI/view-model/tests, native i18n inventory, and changelog text, with no workflows, secrets, dependency resolution, package scripts, or supply-chain surfaces changed.

Review findings

  • [P3] Remove the PR-authored changelog entry — CHANGELOG.md:27
Review details

Best possible solution:

Merge the Swift/i18n/test fix after removing the release-owned changelog entry and letting exact-head CI finish.

Do we have a high-confidence way to reproduce the issue?

Yes. The issue is source-reproducible: current main has session active-run metadata but renders chat activity only from chat-owned pending runs, and the before stills show the idle returned chat; I did not run a live iOS device reproduction in this read-only review.

Is this the best way to solve the issue?

Mostly yes. The Swift behavior fix is the narrowest maintainable path I found because it reuses existing shared history metadata and avoids a gateway protocol change, but the PR should not carry a normal-PR changelog edit.

Full review comments:

  • [P3] Remove the PR-authored changelog entry — CHANGELOG.md:27
    CHANGELOG.md is release-owned in AGENTS.md; normal PRs should keep release-note context in the PR body or squash/commit message so release generation derives the entry. Please drop this line from the branch and leave the PR body evidence/context intact.
    Confidence: 0.9

Overall correctness: patch is correct
Overall confidence: 0.84

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 51bb5f684778.

Label changes

Label justifications:

  • P2: This is a normal-priority iOS chat usability bug fix with limited blast radius, focused tests, and sufficient visible proof.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): Sufficient screenshot proof: the after-fix simulator screenshot shows the Writing indicator and guarded composer, and readable before stills show the idle returned chat; the video artifact could not be decoded because ffprobe was unavailable.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient screenshot proof: the after-fix simulator screenshot shows the Writing indicator and guarded composer, and readable before stills show the idle returned chat; the video artifact could not be decoded because ffprobe was unavailable.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Sufficient screenshot proof: the after-fix simulator screenshot shows the Writing indicator and guarded composer, and readable before stills show the idle returned chat; the video artifact could not be decoded because ffprobe was unavailable.
Evidence reviewed

PR surface:

Docs +1, Other +227. Total +228 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 7 390 163 +227
Total 8 391 163 +228

Acceptance criteria:

  • [P1] git diff --check.

What I checked:

Likely related people:

  • steipete: Authored and merged the recent shared Apple chat in-flight-run recovery work and authored the current PR follow-up commit that touches the same run-ownership boundary. (role: recent area contributor; confidence: high; commits: 443c582949e3, bb658d0a6d98, 27b067f30915; files: apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatView.swift, apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift)
  • Solvely-Colin: Live PR metadata shows this person is assigned to the PR for final maintainer handling. (role: likely follow-up owner; confidence: medium; files: apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatView.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-07-09T00:27:15.163Z sha 659dce7 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-09T01:29:20.614Z sha 659dce7 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T01:36:27.621Z sha 659dce7 :: needs maintainer review before merge. :: none

@jmcte
jmcte force-pushed the codex-ios-chat-pending-state branch from ae69b8f to 760873a Compare July 8, 2026 23:57
@jmcte
jmcte force-pushed the codex-ios-chat-pending-state branch from 760873a to 659dce7 Compare July 9, 2026 00:07
@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 9, 2026
@jmcte

jmcte commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Added redacted after-fix iOS simulator proof for the review blocker:

https://github.com/jmcte/openclaw/releases/download/proof-ios-chat-pending-state-2026-07-09/ios-chat-after-fix-active-indicator.png

The screenshot was captured from a temporary simulator proof host that imports this PR's OpenClawChatUI, returns synthetic history with sessionInfo.hasActiveRun == true, no inFlightRun, and an unanswered latest user turn, then calls resumeFromForeground(). It shows the Writing indicator and guarded composer after the foreground refresh.

I also updated the PR body with the after-fix artifact and simulator proof commands.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 9, 2026
Your Name and others added 3 commits July 9, 2026 03:46
Show an activity indicator when foreground history reports session activity without a chat in-flight snapshot, while keeping unanswered turns blocked and clearing the fallback state on answers, terminal events, session changes, and timeout.
@steipete
steipete force-pushed the codex-ios-chat-pending-state branch from be6b781 to d1c1075 Compare July 9, 2026 07:46
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Maintainer follow-up is land-ready at exact head 60e7cda95e30cb64e244c14b393d6619069a84bf.

  • Preserves known pending-run identity across foreground/post-send history refresh, so later assistant, tool, lifecycle, and terminal events still correlate normally.
  • Uses the bounded synthetic Writing fallback only when the session reports active unanswered work and no local run identity exists.
  • Aligns transcript, Send, Talk, and Compact gating on the same blocking-activity fact; lifecycle terminal, session switch/reset, answered history, inactivity, and timeout all clear it.
  • Contributor proof: 166 ChatViewModel tests and 7 ChatStreamReplay tests passed; redacted before/after Simulator evidence is in the PR body.
  • Maintainer proof: native-i18n passed on Blacksmith Testbox tbx_01kx2x3454zj142gk2thbk72r3; exact-head CI run 29004262552, iOS Periphery, OpenGrep, and workflow sanity all passed.
  • Fresh autoreview has no accepted/actionable findings. The single warning was rejected because it proposed compatibility for an API introduced only by this unmerged PR.
  • scripts/pr review-validate-artifacts 102309 and OPENCLAW_TESTBOX=1 scripts/pr prepare-run 102309 passed with exact-head hosted gates.

Best fix: yes. It retains canonical run ownership when available and synthesizes presentation state only where identity is genuinely absent. Known proof gaps: none.

@steipete
steipete merged commit ccdb60e into openclaw:main Jul 9, 2026
78 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
* Preserve iOS chat activity on foreground refresh

Show an activity indicator when foreground history reports session activity without a chat in-flight snapshot, while keeping unanswered turns blocked and clearing the fallback state on answers, terminal events, session changes, and timeout.

* fix(ios): preserve foreground run ownership

* chore(ios): sync native string inventory

* chore: keep release changelog owned

---------

Co-authored-by: Your Name <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: iOS chat appears idle after returning during long-running session

3 participants