fix(clients): keep Send enabled when session checks time out#24445

open5
main
fix/issue-24221
opened5d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 2d ago

Problem

After a successful session check, a server read taking longer than six seconds made Send grey with “This connection cannot change threads,” even though the session still held orchestration:operate. Reproduced in the real web app on main by delaying AuthSessionRepository.getById seven seconds and refreshing the existing session check with a draft entered.

Change

Use the last confirmed session grant when a recheck times out. Share that rule between web/desktop, mobile, and command availability and execution. Clear the cached grant after a non-timeout failure so a later timeout cannot restore a rejected session; a fresh successful check restores it. Server authorization remains authoritative.

Scope and approval

Fixes https://github.com/pingdotgg/t3code/issues/24221

Triaged bug via the automated issue flow. GitCafe: #24221.

Verification

  • Red proof: the cached-grant timeout test failed on main (expected false to be true); the real session-atom sequence test also failed before its fix on success → timeout → rejection → timeout. Both pass now.
  • vp test run packages/client-runtime/src/state/session.test.ts packages/client-runtime/src/state/commandPermissions.test.ts apps/mobile/src/state/session.test.ts apps/web/src/hooks/useThreadActions.permissions.test.ts: 57 passed.
  • Scoped lint on all seven changed files passed. npx tsc --noEmit -p for packages/client-runtime, apps/web, and apps/mobile: all exit 0. git diff --check passed. Main was already up to date.
  • Two independent final code reviews found no blockers. The real app also executed a persisted thread rename and restore during a cached timeout; two independently paired environments demonstrated timeout/denial/regrant in aggregate Settings permissions.

Reproduction transcript and red failure. Full evidence index, scripts, fixtures, and runtime milestones. Threshold-diff supplement.

Evidence

Before: d53873b6a4. After runtime: 09c6299d0d. Final 83d50c1a8a changes only test typing from that runtime.

Product-native browser, isolated fresh state, empty stopped thread and unsent draft, light/dark. CSS viewports 1440×900 and 390×844 at DPR 2; wide PNGs normalize to 1280×800 and narrow PNGs are 780×1688. Fonts settled and motion disabled. Each selected endpoint has an exact repeat. Diff0 is amplified 8×; DiffT16 highlights any RGB-channel delta greater than 16. What else changed: narrow raw diffs include the header sidebar-button hover/focus state; the threshold mask isolates Send. No layout or styling code changed.

FixtureRecording
V1 before1440 lightV1-before-1440-light.mp4
V1 after1440 lightV1-after-1440-light.mp4
V1 before1440 darkV1-before-1440-dark.mp4
V1 after1440 darkV1-after-1440-dark.mp4
V1 before390 lightV1-before-390-light-final.mp4
V1 before390 darkV1-before-390-dark-final.mp4
V1 after390 light/dark final verified segmentV1-head-390-verified-timeout-recovery.mp4
V2 rejection/timeout/regrantV2-head-grant-rejection-timeout-regrant.mp4
V3 aggregate timeout/denial/regrantV3-head-1440-timeout-denial-regrant.mp4
I1 persisted rename/restoreI1-head-rename-restore-during-timeout.mp4

Narrated steps and approximate playback timestamps. Durations. Original full recordings retained; head390 has a long warmup, use final ~54–63s verified segment.

Unverified proof

Threshold supplement audit confirms all four masks.

Independent proof audit: matrix incomplete. Accepted web evidence supports the central fix; this PR is not a claim of completed multi-surface verification. The Settings recording shows denial, but its recovery is log-supported rather than a clearly settled visual ending. The empty thread also does not prove preservation of existing history.

Actual Electron and native EAS iOS timeout/recovery were not captured. EAS authentication and simulator availability worked, but a current-source native dev client and Metro were not built. This is a verification gap, not a reporter information request.

The full fixture matrix is not complete: initial/no-cache and missing-scope UI, the full C1 command/destination/serial-revocation partition, a before aggregate Settings comparison, V3 narrow-light exact stability, frozen clock, and historical per-frame viewport measurements remain unverified. Negative runtime captures use a browser-local synthetic HTTP 401 through the real error pipeline, not server credential revocation. The real timeout/recovery captures are distinct from those negative fixtures. The source-data migration failed due to conflicting migration slots 68/69; reproduction used a healthy fresh isolated database instead. No live userdata was modified, and all fault-injection code was restored before publication.

Models: Claude Opus 5.5 and GPT-6.1-Sol, through T3 Code's Claude Agent and Codex harnesses.

Checks

22 successful · 6 skipped · 1 neutral
All checks passed
83d50c1

Added 5 commits

  • fix(client-runtime): a rejected session stays revoked through later timeouts09c6299
  • test(client-runtime): reproduce issue 24221, a timed-out session recheck drops a valid cached grant0c9c9f1
  • test(client-runtime): type the session recheck fixture83d50c1
  • fix(client-runtime): a timed-out session recheck keeps the last confirmed grantdbe5717
  • test(client-runtime): a session timeout after a rejection revives the rejected grantff6db1c
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This targeted fix changes how cached authentication grants affect permission checks and command authorization after session timeouts or rejections across web, mobile, and shared runtime code. The scope is limited and tested, but the authentication-sensitive behavior warrants human review.

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

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between d53873b6a4799e87afd63c8d288ef0089f5a3748 and 83d50c1a8a58207e3440b7e393c11cff865bbe52.

External image Files selected for processing: 7
  • apps/mobile/src/state/session.test.ts
  • apps/mobile/src/state/session.ts
  • apps/web/src/state/session.ts
  • packages/client-runtime/src/state/commandPermissions.test.ts
  • packages/client-runtime/src/state/commandPermissions.ts
  • packages/client-runtime/src/state/session.test.ts
  • packages/client-runtime/src/state/session.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

Walkthrough

The client runtime now preserves available session grants during timeout failures and clears carried-forward grants after other failures. Permission checks in the runtime, mobile app, and web app use the shared grant helper.

Changes: Session grant handling

Layer / File(s)Summary
Session result handling
packages/client-runtime/src/state/session.ts, packages/client-runtime/src/state/session.test.ts
The session-state atom transforms results to preserve an available grant on timeout and clear carried-forward grants after non-timeout failures. Tests cover timeout, rejection, and later success.
Permission checks and authorization
packages/client-runtime/src/state/commandPermissions.ts, packages/client-runtime/src/state/commandPermissions.test.ts
Permission checks use the current grant. Authorization falls back to the grant in the registry when session-result retrieval fails. Tests cover timeout preservation and rejection clearing the grant.
Application scope checks
apps/mobile/src/state/session.ts, apps/mobile/src/state/session.test.ts, apps/web/src/state/session.ts
Mobile and web scope checks use the shared grant helper. The mobile test mock preserves the session module’s original exports.

Priority: External image Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested labels: bugfix

Suggested reviewers: maria-rcks, macroscopeapp

Merge Risk: External image Minimal · up to 83d50

No merge-blocking issue is established; the change is ready for normal merge checks.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Description checkPassedThe description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the failure, the implementation, linked issue, focused tests, observed results, and k…
Title checkPassedThe title clearly and concisely describes the main fix: keeping Send enabled when session checks time out.
Linked Issues checkPassedIssue #24221 requires Send to remain usable after a slow session check when a prior permission grant exists. The PR adds currentSessionGrant in packages/client-runtime/src/state/session.ts. It pre…
Out of Scope Changes checkPassedThe changed files implement the session-grant rule, apply it to web, mobile, and shared command availability or authorization, and add focused tests and test mocks. The mobile and command changes supp…
Full details: Description check

Explanation

The description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the failure, the implementation, linked issue, focused tests, observed results, and known verification gaps.

Full details: Linked Issues check

Explanation

Issue #24221 requires Send to remain usable after a slow session check when a prior permission grant exists. The PR adds currentSessionGrant in packages/client-runtime/src/state/session.ts. It preserves the last grant for timeout results and clears it for non-timeout failures. Web and mobile scope checks and command permission checks use this helper. Command authorization also falls back to the current grant on retrieval timeout. The added tests cover success → timeout → rejection → timeout → success and cached-grant command behavior. These changes satisfy the active coding requirements in #24221.

Full details: Out of Scope Changes check

Explanation

The changed files implement the session-grant rule, apply it to web, mobile, and shared command availability or authorization, and add focused tests and test mocks. The mobile and command changes support the shared behavior described by the PR and do not introduce unrelated product changes. The supplied scope evidence reports no layout or styling changes.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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