Skip to content

Fix Codex transcript fallback session binding - #6993

Closed
austinywang wants to merge 53 commits into
mainfrom
issue-5550-token-count-shows-climbing-phantom-values-for
Closed

austinywang wants to merge 53 commits into
mainfrom
issue-5550-token-count-shows-climbing-phantom-values-for

Conversation

@austinywang

@austinywang austinywang commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5550

Summary

  • add a failing regression for Codex transcript fallback binding to a different rollout via loose matching
  • require Codex fallback to match session_meta.payload.id and fail closed when metadata is missing or mismatched
  • move Codex transcript identity matching into the shared agent-chat package and use one bounded locator from the app resolver and CLI

Testing

  • git diff --check
  • python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv
  • scripts/check-pbxproj.sh
  • python3 scripts/check-workspace-package-groups.py --check
  • python3 scripts/check-package-resolved-policy.py
  • local dev builds/tests not run per issue instructions; CI is the validation gate

Demo Video

N/A: bug fix for transcript file selection with no UI flow change.

Review Trigger

Ready for review on the current head after CI completes.

Checklist

  • Regression test committed before the fix commit
  • Fix committed separately from the failing regression
  • PR references Fixes #5550
  • No dev build, reload script, or bare xcodebuild run
  • No user-facing strings changed

Localization

No user-facing strings changed.

Summary by CodeRabbit

  • New Features
    • Added Codex transcript locator and identity matching with newest-first, bounded directory scanning and stricter session-id normalization.
  • Bug Fixes
    • Prevented stale Codex transcript updates via cancellation-aware, per-session background resolution.
    • Improved fallback behavior by preferring hook-recorded transcripts when present and honoring rollout session metadata and recent-day selection.
  • Tests
    • Added deterministic Codex unit tests for matching, missing metadata, authority rules, recency selection, and ended-session fallback.
  • UI / Compatibility
    • Improved iOS/Swift compiler gating and main-actor isolation for composer/transcript/terminal UI and related effects, plus accessibility-label correctness.

@vercel

vercel Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jul 5, 2026 7:17am
cmux-staging Building Building Preview, Comment Jul 5, 2026 7:17am

@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex transcript lookup now validates rollout metadata through a shared locator and resolver path. The mobile service resolves Codex transcripts before tailing, and several iOS UI paths now require newer Swift compiler checks or main-actor annotations.

Changes

Codex transcript lookup and resolution

Layer / File(s) Summary
Rollout matcher and locator
Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/CodexTranscriptIdentityMatcher.swift, Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/CodexTranscriptLocator.swift
CodexTranscriptIdentityMatcher validates session_meta ids from rollout JSONL files, and CodexTranscriptLocator scans bounded recent session directories to return the first matched transcript.
Resolver and CLI delegation
Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift, CLI/cmux.swift
AgentChatTranscriptResolver now injects now, reuses a recorded-path helper, and delegates Codex fallback lookup to CodexTranscriptLocator; cmux imports CmuxAgentChat and calls the shared locator.
Service-side Codex resolution
Sources/Mobile/AgentChat/AgentChatTranscriptService.swift
AgentChatTranscriptService adds Codex resolution tasks and keys, resolves missing Codex transcripts before history/tailer setup, and clears Codex resolution state when sessions end.
Tests and target wiring
cmuxTests/AgentChatTranscriptResolverTests.swift, cmux.xcodeproj/project.pbxproj
Adds Codex fallback tests with deterministic rollout fixtures and updates the Xcode project to compile the test file and link CmuxAgentChat.

iOS compiler guards

Layer / File(s) Summary
Liquid Glass and composer gating
Packages/iOS/CmuxMobileSupport/Sources/CmuxMobileSupport/View+MobileGlass.swift, Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Composer/ChatComposerView.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SignInView.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalComposerView.swift
Shared Liquid Glass helpers and composer/sign-in/terminal composer surfaces now use compiler(>=6.2) gates around the iOS glass branches.
Transcript and scroll UI updates
Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/ChatScrollEdgeCoordinator.swift, Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/ChatTranscriptTableView.swift, Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/TerminalInputTextView.swift, Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatFileEditCardView.swift, .github/workflows/test-ios.yml, Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/KeyboardDismissTap.swift
Scroll-edge setup, transcript table rendering, accessory-button styling, diff-line accessibility labels, workflow comments, and tap-recognizer teardown receive compiler or actor updates.
Terminal and surface runtime annotations
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePushCoordinator.swift, Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceHandle.swift, Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift, Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/TerminalHardwareKeyResolver.swift
Mobile shell teardown, notification status lookup, Ghostty surface queue handling, display-link forwarding, and key-command creation are updated with actor or async isolation changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#6216: Both PRs modify Sources/Mobile/AgentChat/AgentChatTranscriptService.swift, with the other change set affecting service ownership/injection and this one adding Codex transcript-resolution tracking and recorded-path handling.

Poem

🐇 I hop through sessions, true and bright,
I match the rollout by metadata light.
No phantom trails can fool my nose,
The glassy panes keep compiler prose.
I leave the dead panes quiet as snow.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Swiftpm Lockfiles ❌ Error cmux.xcodeproj adds the CmuxAgentChat SwiftPM package reference, but the PR omits the required root Xcode Package.resolved diff. Add the root cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved change alongside the project package-reference update.
Cmux Source Artifacts ❌ Error .claude/scheduled_tasks.lock stores runtime session/pid state, which is local tool output rather than intentional source/config. Remove .claude/scheduled_tasks.lock from the diff (or ignore it narrowly if generated locally) and keep only intentional source/config files.
Out of Scope Changes check ⚠️ Warning The PR also changes multiple unrelated iOS/UI, concurrency, and CI files that are not needed for #5550. Split the unrelated iOS, UI, compiler-gating, and CI edits into separate PRs, leaving only the Codex transcript binding work here.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main Codex transcript binding fix.
Description check ✅ Passed The PR description includes summary, testing, demo note, review trigger, and checklist items, matching the template closely.
Linked Issues check ✅ Passed The changes require exact session-id matching, fail closed on missing metadata, and avoid stale fallback, which addresses #5550.
Cmux Swift Actor Isolation ✅ Passed The diff adds explicit @MainActor boundaries and Sendable value helpers; the new unchecked Sendable pointer wrapper has documented queue-safety, and no UI store is exposed off-main.
Cmux Swift Blocking Runtime ✅ Passed No new blocking or timing-based sync appears in the changed Swift files; the Codex work uses async tasks/cancellation, not waits, sleeps, semaphores, locks, or main-queue sync.
Cmux Browser Automation Off-Main ✅ Passed PR diff doesn’t touch browser socket-routing files or any browser.* command handlers; no off-main WebKit wait routing change was introduced.
Cmux Expensive Synchronous Load ✅ Passed PASS: Main-actor service uses recordedTranscriptPath plus Task.detached for Codex scans; no new expensive sync load was moved onto a main/interactive path.
Cmux Cache Substitution Correctness ✅ Passed The Codex path uses recorded paths only when present and existing, otherwise rescans with session_meta matching; cold and stale cases are explicitly handled and tested.
Cmux No Hacky Sleeps ✅ Passed Only non-Swift change is workflow YAML, which the rule excludes; no JS/TS/shell runtime sleep/timer code was introduced.
Cmux Algorithmic Complexity ✅ Passed The new Codex lookup is explicitly bounded (day window + 2k-file cap) and delegated directly; no new nested full-collection scans or hot-path rescans were introduced.
Cmux Swift Concurrency ✅ Passed No legacy async APIs were introduced; the new Codex scan uses a stored/cancelled Task.detached, and no new DispatchQueue, Combine, or completion-handler patterns appear.
Cmux Swift @Concurrent ✅ Passed Codex scan now hops off @MainActor via Task.detached with @concurrent; no invalid @concurrent use or UI-isolated heavy async call was introduced.
Cmux Swift File And Package Boundaries ✅ Passed Codex matching moved into a small shared package; the touched app-target files are thin glue or focused fixes, and no new oversized mixed-responsibility Swift file was introduced.
Cmux Swift Logging ✅ Passed No diff-added production logging violations found; changes are functional, with only existing CLI output and debug-only logs present.
Cmux User-Facing Error Privacy ✅ Passed Diff only changes internal Codex transcript resolution and tests; no user-facing errors, alerts, or recovery copy were added or exposed.
Cmux Full Internationalization ✅ Passed New UI text uses localized APIs, and the xcstrings diff is reorder-only with unchanged locale content.
Cmux Swiftui State Layout ✅ Passed SwiftUI hunks only add actor/compiler gating and cleanup helpers; no new ObservableObject/@published, layout-changing GeometryReader, row store refs, or render-time state writes.
Cmux Architecture Rethink ✅ Passed Changed Swift uses a shared bounded locator and clear resolver/service ownership; no sleeps, polling, locks, observers, or bad lifecycle split in the diff.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR only touches transcript logic and view modifiers; no changed Swift file adds or materially changes NSWindow/NSPanel/NSWindowController/WindowGroup code.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new test/debug seam appears in production Sources; the new Codex helpers are production-used, and the existing debugSessionDump has a real RPC caller.
Cmux No Ambient Global State ✅ Passed New Codex types are constructable, instance-based injectables; no new top-level API, mutable globals, or singletons were added in production Swift.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-5550-token-count-shows-climbing-phantom-values-for

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.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a correctness bug (issue #5550) where Codex transcript fallback could bind a chat pane to the wrong conversation by scanning rollout directories and matching session IDs via substring heuristics. The fix removes the fallback scan entirely — both the mobile AgentChatTranscriptResolver and the CLI findCodexTranscriptPath now fail closed (return nil) for Codex when no hook-recorded path is present.

  • Codex fallback removal: AgentChatTranscriptResolver.transcriptPath(for:) and CLI/findCodexTranscriptPath now return nil for Codex sessions lacking a hook-recorded transcriptPath; recordedTranscriptPath(for:) is promoted to internal so AgentChatTranscriptService can guard against overwriting a hook-supplied path.
  • Focused CI regression gate: AgentChatTranscriptResolverTests is added as a dedicated -only-testing invocation in ci.yml, correctly bypassing the XCTest-summary parser that silently swallows Swift Testing failures.
  • iOS/Swift 6.2 compatibility: #if compiler(>=6.2) guards around iOS 26 glass APIs, @MainActor annotations on SwiftUI view properties, isolated deinit for MobileShellComposite, and getNotificationSettings callback bridging in MobilePushCoordinator replace several actor-isolation hazards.

Confidence Score: 5/5

Safe to merge; the behavioral change is deliberate and well-tested — Codex transcript resolution now fails closed rather than scanning directories, eliminating the wrong-conversation binding bug.

The core fix (removing the Codex directory-scan fallback) is straightforward and correct. A focused CI regression gate is in place and correctly bypasses the XCTest summary parser that silently swallows Swift Testing results. The iOS/Swift 6.2 gating and @mainactor additions address real compiler requirements without introducing new isolation hazards. The only finding is a naming redundancy between two now-identical methods, which has no runtime impact.

No files require special attention. The resolver and CLI changes are deliberate, the test coverage directly exercises the fixed invariant, and the iOS compatibility edits are mechanical.

Important Files Changed

Filename Overview
Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift Codex fallback scan removed; transcriptPath(for:) returns nil for Codex without hook-recorded path. recordedTranscriptPath promoted to internal. boundedTranscriptPath and transcriptPath are now semantically identical.
CLI/cmux.swift findCodexTranscriptPath stubbed to return nil; recentCodexSessionDirectories helper removed. CLI-side Codex transcript fallback scan eliminated, matching mobile resolver behavior.
cmuxTests/AgentChatTranscriptResolverTests.swift New Swift Testing suite; two deterministic tests verify fail-closed behavior (no hook-recorded path returns nil) and hook-authority rule (hook-recorded path trusted regardless of file content session ID).
.github/workflows/ci.yml Adds dedicated focused -only-testing invocation for AgentChatTranscriptResolverTests with set -euo pipefail, correctly bypassing the XCTest summary parser that silently swallows Swift Testing failures.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift Adds isolated deinit / MainActor.assumeIsolated compat pattern for cancelInFlightWorkForTeardown, correctly handling off-main-actor release on Swift 6.2 vs older toolchains.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePushCoordinator.swift Replaces async notificationSettings() with callback-bridged getNotificationSettings via withCheckedContinuation; passes rawValue through continuation to satisfy Swift 6 Sendable requirements.
Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/TerminalInputTextView.swift Converts TerminalHardwareKeyResolver from static-method namespace to injected instance; adds #if compiler(>=6.2) guard around prominentGlass/glass button configs.
Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/TerminalHardwareKeyResolver.swift Removes private init() namespace anti-pattern; converts static methods to instance methods with @mainactor on makeKeyCommands.
Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/KeyboardDismissTap.swift Fixes recognizer double-install by guarding installedWindow == nil before addGestureRecognizer; extracts uninstallRecognizer() called from both update and deinit.
Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Composer/ChatComposerView.swift Adds @mainactor annotations to SwiftUI computed-property accessors, #if compiler(>=6.2) guard around GlassEffectContainer, and explicit String() conversion for accessibility label interpolation.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Hook as Hook Event
    participant Service as AgentChatTranscriptService
    participant Resolver as AgentChatTranscriptResolver
    participant FS as Filesystem

    Note over Hook,FS: Before fix (bug - #5550)
    Hook->>Service: session record has no transcriptPath
    Service->>Resolver: transcriptPath(for: codexRecord)
    Resolver->>FS: scan ~/.codex/sessions for sessionID substring
    FS-->>Resolver: rollout matching substring (may be wrong session)
    Resolver-->>Service: wrong rollout path returned

    Note over Hook,FS: After fix (this PR)
    Hook->>Service: session record has hook-recorded transcriptPath
    Service->>Resolver: transcriptPath(for: codexRecord)
    Resolver->>Resolver: check recordedTranscriptPath
    alt hook-recorded path exists on disk
        Resolver-->>Service: correct hook-recorded path
    else no hook-recorded path
        Resolver-->>Service: nil returned (fail closed)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Hook as Hook Event
    participant Service as AgentChatTranscriptService
    participant Resolver as AgentChatTranscriptResolver
    participant FS as Filesystem

    Note over Hook,FS: Before fix (bug - #5550)
    Hook->>Service: session record has no transcriptPath
    Service->>Resolver: transcriptPath(for: codexRecord)
    Resolver->>FS: scan ~/.codex/sessions for sessionID substring
    FS-->>Resolver: rollout matching substring (may be wrong session)
    Resolver-->>Service: wrong rollout path returned

    Note over Hook,FS: After fix (this PR)
    Hook->>Service: session record has hook-recorded transcriptPath
    Service->>Resolver: transcriptPath(for: codexRecord)
    Resolver->>Resolver: check recordedTranscriptPath
    alt hook-recorded path exists on disk
        Resolver-->>Service: correct hook-recorded path
    else no hook-recorded path
        Resolver-->>Service: nil returned (fail closed)
    end
Loading

Reviews (36): Last reviewed commit: "Fix duplicate test source wiring" | Re-trigger Greptile

Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift Outdated
Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift Outdated
Comment thread CLI/cmux.swift Outdated
@austinywang
austinywang force-pushed the issue-5550-token-count-shows-climbing-phantom-values-for branch from 41744fd to 24bb84a Compare June 27, 2026 01:59
Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift (1)

185-196: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Unbounded recursive scan now performs file I/O per rollout — bound it to recent day directories.

The enumerator walks the entire ~/.codex/sessions/** tree with no recency ordering or limit. Previously each candidate was rejected with a cheap filename substring check (no I/O); now every .jsonl is opened and parsed via CodexTranscriptIdentityMatcher until a match is found. For an unknown/wedged session id (the exact scenario this PR targets), the loop reads and parses every rollout the user has ever accumulated. The doc comment on Line 176 says "scan recent day directories," but the code does not actually bound to recent days.

Consider enumerating the YYYY/MM/DD directories newest-first with an explicit day/file cap so per-resolution work stays bounded as the sessions tree grows. Also hoist the matcher out of the loop (one instance instead of per-file allocation on Line 192).

As per path instructions, .github/review-bot-rules/algorithmic-complexity.md: confirm "recent" Codex rollout scans are bounded (explicit limit/size cap) and not repeatedly filtering the same large set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift` around lines 185
- 196, The scan in AgentChatTranscriptResolver’s transcript lookup is unbounded
and does per-file I/O across the entire sessions tree, so update the directory
traversal to only walk recent YYYY/MM/DD rollout directories with an explicit
day/file cap and newest-first ordering. Reuse a single
CodexTranscriptIdentityMatcher instance inside the lookup helper instead of
constructing one for every JSONL candidate, and keep the search bounded so the
transcript(at:matchesSessionID:) path does not repeatedly parse the full
~/.codex/sessions hierarchy.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/CodexTranscriptIdentityMatcher.swift`:
- Around line 21-24: The authoritative session check in
CodexTranscriptIdentityMatcher should rely only on session_meta.payload.id and
not on url.lastPathComponent substring matching. Update the matching logic so
the method that compares against normalizedSessionID uses sessionMetaID(at:) as
the sole source of truth, and returns false only when that metadata is missing
or does not match. Keep the rest of the matcher behavior unchanged.

---

Outside diff comments:
In `@Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift`:
- Around line 185-196: The scan in AgentChatTranscriptResolver’s transcript
lookup is unbounded and does per-file I/O across the entire sessions tree, so
update the directory traversal to only walk recent YYYY/MM/DD rollout
directories with an explicit day/file cap and newest-first ordering. Reuse a
single CodexTranscriptIdentityMatcher instance inside the lookup helper instead
of constructing one for every JSONL candidate, and keep the search bounded so
the transcript(at:matchesSessionID:) path does not repeatedly parse the full
~/.codex/sessions hierarchy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a892623c-f7af-4aac-b6fa-470ddc5e2d9a

📥 Commits

Reviewing files that changed from the base of the PR and between 58830db and 951053f.

📒 Files selected for processing (4)
  • CLI/cmux.swift
  • Packages/macOS/CmuxFoundation/Sources/CmuxFoundation/CodexTranscriptIdentityMatcher.swift
  • Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift
  • cmuxTests/AgentChatTranscriptResolverTests.swift

@blacksmith-sh

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/test-ios.yml:
- Line 113: The iOS workflow is using a floating default runner alias, which
makes the Xcode/iOS SDK baseline nondeterministic. Update the runner selection
in the test-ios workflow so the existing vars.MACOS_RUNNER_IOS override still
works, but the fallback for the jobs using that runner is a pinned macOS image
instead of depot-macos-latest; apply this in the affected job definitions around
the runs-on settings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a57171aa-aa32-474a-bcaa-b776d749efae

📥 Commits

Reviewing files that changed from the base of the PR and between beb8420 and 31170f0.

📒 Files selected for processing (2)
  • .github/workflows/test-ios.yml
  • Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Transcript/Rows/ChatFileEditCardView.swift

Comment thread .github/workflows/test-ios.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/Mobile/AgentChat/AgentChatTranscriptService`+TitleDetection.swift:
- Around line 323-327: The nil-fallback path in ensureTailer(for:) is leaving
stale entries in failedResolutions even after
resolver.recordedTranscriptPath(for:) becomes available. Update the guard-let
fallback handling to clear any existing failedResolutions entry for the current
sessionID when a recorded path now exists, and only keep the failure marker when
there is still no recorded transcript path. Keep the logic localized around
ensureTailer(for:), failedResolutions, and
resolver.recordedTranscriptPath(for:).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97a7553a-39a8-4783-99d3-4bf885df05ee

📥 Commits

Reviewing files that changed from the base of the PR and between 31170f0 and d77049a.

📒 Files selected for processing (5)
  • .github/workflows/test-ios.yml
  • Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Parsing/CodexTranscriptLocator.swift
  • Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift
  • Sources/Mobile/AgentChat/AgentChatTranscriptService+TitleDetection.swift
  • Sources/Mobile/AgentChat/AgentChatTranscriptService.swift

Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptService+TitleDetection.swift Outdated
cmux added 3 commits June 26, 2026 23:34
…t-shows-climbing-phantom-values-for

# Conflicts:
#	Packages/iOS/CmuxAgentChatUI/Sources/CmuxAgentChatUI/Screen/ChatKeyboardTrackingViewController.swift
`applyCodexTranscriptResolution` only re-checked the pending-resolution key,
which is not updated when the registry later receives a real `transcriptPath`
from a hook. So a detached fallback scan scheduled while `transcriptPath == nil`
could, on completion, overwrite an authoritative path recorded in the meantime —
moving the chat tailer to an older/different rollout for the same session.

Before applying the scan result, bail out if the record now has a valid
recorded transcript path; the hook-recorded path is authoritative and the
fallback is only meant to fill the gap when none exists.

Found by autoreview (Codex).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
austinywang and others added 2 commits July 1, 2026 21:59
…values-for

Resolved conflicts:
- .github/swift-file-length-budget.tsv: regenerated via swift_file_length_budget.py --write-budget
- ChatScrollEdgeCoordinator.swift, ChatTranscriptTableView.swift: took origin/main
  (main superseded this branch's inline #if compiler(>=6.2) glass-API guards with the
  applyScrollEdgeEffects helper + scroll-momentum work in #7072/#7109; branch predated it)
- GhosttySurfaceView.swift: took origin/main and removed the now-orphaned
  GhosttySurfaceHandle.swift; main's GhosttySurfaceWorkQueue redesign (#7098) supersedes
  this branch's GhosttySurfaceHandle Sendable-wrapper approach for the same surface-pointer
  safety concern. Codex transcript payload (resolver realpath fix, service shutdown()/race
  guard, MobileShellComposite isolated deinit) preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptService.swift Outdated
A hook can record the authoritative Codex transcript path while an
off-main fallback scan is in flight. When that stale scan result lands,
applyDirectCodexTranscriptResolution overwrites the recorded path
because it only compares `record.transcriptPath != resolved`.

Expose the apply method as internal and add a deterministic test that
drives it with a stale scan result while the registry already holds an
existing recorded path. This commit intentionally omits the fix so CI
shows the test red; the guard follows in the next commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 19 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Sources/Mobile/AgentChat/AgentChatTranscriptService.swift Outdated
austinywang and others added 4 commits July 2, 2026 03:30
The regression test from the previous commit is Swift Testing
(@Test/#expect). The app-host "Run unit tests" step tolerates failures
by parsing only the XCTest "Executed ... (0 unexpected)" summary, which
does not count Swift Testing issues — so that test passed CI on the
previous commit even though it must fail without the fix. The intended
two-commit red proof was silently swallowed (the "silently ignored
test" pitfall).

Follow the repo's established non-tolerant pattern (BrowserSystemProxy /
Option-Alt sided-modifier): add the suite to FOCUSED_GATE_SELECTORS so it
is not folded into the tolerant shard, guard that exclusion in
test_ci_cmux_unit_test_shard.py, and run the suite through
run-app-host-xcodebuild.sh in a focused -only-testing step that
propagates xcodebuild's exit code.

With this wiring and no fix yet, CI goes genuinely red on the app-host
focused shard, proving the test catches the bug. The guard fix follows
in the next commit (CI back to green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…path

Move the recorded-transcript-path guard out of the scheduled wrapper
(applyCodexTranscriptResolution) and into the shared
applyDirectCodexTranscriptResolution, which both real callers funnel
through. The direct path used by history(...) previously had no guard: it
checks recordedTranscriptPath == nil, then awaits an off-main fallback
scan, and during that suspension a hook can record the authoritative
path — so the post-await apply could overwrite the freshly-recorded
authoritative transcript with a stale scan result. Placing the guard on
the shared path fixes that race for history(...) too and removes the
duplicated guard (addresses Greptile P1).

Behavior is unchanged except the exact bug case: when a recorded path
already exists on disk, the scan result no longer overwrites it and
resolution is treated as succeeded (failedResolutions cleared). All
recorded-path-absent cases are identical to before.

With the fix, the non-tolerant focused gate added in the previous commit
(app-host shard 4) goes back to green — the regression test now passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
…t-shows-climbing-phantom-values-for

# Conflicts:
#	.github/swift-file-length-budget.tsv
#	Sources/Mobile/AgentChat/AgentChatTranscriptResolver.swift
#	cmux.xcodeproj/project.pbxproj

This branch was successfully deployed

1 active deployment
Preview – cmux — 31ce781f Deployed Jul 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Token count shows climbing phantom values for sessions that never started

3 participants