Skip to content

Expose shared session inactivity settings in Settings - #14954

Draft
warp-agent-staging[bot] wants to merge 2 commits into
masterfrom
factory/shared-session-inactivity-settings
Draft

Expose shared session inactivity settings in Settings#14954
warp-agent-staging[bot] wants to merge 2 commits into
masterfrom
factory/shared-session-inactivity-settings

Conversation

@warp-agent-staging

@warp-agent-staging warp-agent-staging Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Description

Exposes the three existing shared-session (/remote-control) inactivity durations as user-configurable settings in Settings > Features > Session, below the existing "Confirm before closing shared session" toggle:

  • Revoke edit access after being inactive forinactivity_period_before_revoking_roles (default 10 min)
  • Warn before ending the session after being inactive forinactivity_period_before_warning (default 25 min)
  • End the shared session after being inactive forinactivity_period_before_ending_session (default 30 min)

No inactivity timeout behavior changes. Defaults are unchanged, the sharer inactivity ladder in app/src/terminal/view/shared_session/view_impl.rs is untouched, and what counts as "activity" is unchanged. This PR only surfaces existing knobs.

Linked Issue

Linear: APP-5313

Changes

  • app/src/terminal/shared_session/settings.rs: the three settings move from private: true to private: false with a toml_path and user-facing description, following the same pattern as ShouldConfirmCloseSession.
  • Three independent SettingsWidgets in app/src/settings_view/features_page.rsSharedSessionRevokeEditAccessWidget, SharedSessionWarningWidget, SharedSessionEndSessionWidget — each a minute-based number input, each independently searchable (row-scoped search_terms), backed by its own editor field on FeaturesPageView.
  • Each edit is validated to be a positive integer within a safe range and clamped on commit so the revoke ≤ warn ≤ end ordering always holds.

Response to review

An adversarial review surfaced five findings, all addressed in a follow-up commit:

  1. Legacy values silently dropped. Flipping private: truefalse meant existing users' custom values (stored under the old private keys) were never read from the new public location. Added a dedicated one-time migration (migrate_legacy_private_inactivity_settings, its own completion marker independent of the app's general SettingsFileMigrationComplete marker) that copies a private value across only when the public location doesn't already have one.
  2. No cross-validation at the authoritative boundary. Added SharedSessionSettings::register_and_enforce_inactivity_ordering, which corrects out-of-order values at every point they become authoritative (initial load / hand-edited settings file, cloud sync, disk hot-reload), and changed the two derived-interval helpers to use saturating_sub as defense-in-depth against two latent underflow panics found in the ladder. The ordering comparison is isolated in a single ladder_phase_order_ok predicate so a possible future "zero disables this phase" change only has to touch that one place.
  3. Overflow in minute parsing. parse_shared_session_inactivity_minutes now rejects any value above u64::MAX / 60, so the minutes→seconds conversion can't overflow.
  4. Unfilterable mega-widget. Split the single combined widget into three independent SettingsWidgets with row-scoped search terms, verified with a StubWidget-based filter test plus live search in the running app (see screenshots).
  5. Redundant doc comments — resolved by construction: the widget split removed the standalone Action enum those comments were attached to.

Testing

  • cargo build --bin warp — passes.

  • cargo fmt -- --check and cargo clippy -p warp --bin warp --all-targets -- -D warnings — pass.

  • cargo test -p warp --lib schema_validation_tests — passes.

  • cargo nextest run -p warp shared_session:: settings_view:: — 448 passed, including new tests for: legacy-migration survival / no-clobber / idempotency, ordering correction from storage and from cloud sync, a pure saturating_sub regression test, minute-parsing bounds (including the overflow case), clamp correctness/idempotency, and a filter test proving the three rows are independently searchable.

  • Manually verified end-to-end with computer use on a freshly built and launched instance (to rule out testing a stale running build): all three rows render under Features > Session with correct labels/descriptions/defaults; searching "revoke" now matches only the Revoke row, "disconnect" matches only the End row, and "inactivity" (a term shared by all three) matches all three; an edit to "Revoke edit access" persists across closing/reopening Settings; and setting it to "999" gets clamped down to the current Warn value rather than accepted as-is.

  • I have manually tested my changes locally with computer use (equivalent to ./script/run)

Screenshots / Videos

Computer-use screenshots (7)

Features > Session settings showing the three new shared-session inactivity rows (Revoke edit access / Warn before ending / End the shared session after being inactive for) with their labels, minute inputs, and description texts.
Features > Session settings showing the three new shared-session inactivity rows with their labels, minute inputs, and description texts.

Close-up of Features > Session after editing "Revoke edit access after being inactive for" to a new value, confirming the edit takes.
Close-up after editing "Revoke edit access after being inactive for", confirming the edit takes.

Features > Session settings on a freshly rebuilt instance, showing the three rows: Revoke edit access (25 min), Warn before ending (25 min), End the shared session (30 min).
Features > Session on a freshly rebuilt instance: Revoke edit access (25 min), Warn before ending (25 min), End the shared session (30 min).

Settings search for "revoke" on the fresh build shows only the "Revoke edit access after being inactive for" row under Session (Features (1)); the Warn and End rows do not appear.
Settings search for "revoke" on the fresh build shows only the "Revoke edit access after being inactive for" row (Features (1)) — confirms the widget-split fix (review finding 4).

Settings search for "disconnect" on the fresh build shows only the "End the shared session after being inactive for" row under Session (Features (1)).
Settings search for "disconnect" on the fresh build shows only the "End the shared session after being inactive for" row (Features (1)).

After entering 999 for "Revoke edit access after being inactive for" and closing/reopening Settings, the value shows 25 rather than 999, demonstrating the ordering clamp.
After entering 999 for "Revoke edit access after being inactive for" and reopening Settings, the value shows 25 (clamped to the current Warn ceiling) rather than 999.

Clamping test result from the initial verification pass: after entering 999 into "Revoke edit access after being inactive for", it was clamped down to 25 minutes (equal to the Warn ceiling), with Warn=25 and End=30.
Clamping test result from the initial verification pass, consistent with the fresh-build result above.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-IMPROVEMENT: You can now customize how long a shared session can sit idle before edit access is revoked, a warning is shown, and the session ends, in Settings > Features > Session.

Conversation: https://staging.warp.dev/conversation/62aa162e-53df-4eac-8b9e-da340c2d3b08
Run: https://oz.staging.warp.dev/runs/019ff20d-8301-756e-b971-2365db195c8a

This PR was generated with Oz.

Surfaces the three existing shared-session inactivity durations
(revoke edit access, warn, end session) as user-configurable settings
below the existing confirm-close-shared-session toggle. Values are
edited in minutes and are validated so revoke <= warn <= end always
holds (editing one field clamps it against the other two's current
values). No inactivity timeout behavior, defaults, or the sharer
inactivity ladder logic in view_impl.rs change.

The three settings move from private to public (private: false) with
a toml_path and description, matching the convention used by other
user-facing settings (e.g. ShouldConfirmCloseSession), so they persist
via the normal settings pipeline and take effect on the running
session.

APP-5313

Co-Authored-By: Warp Agent <agent@warp.dev>
@warp-agent-staging
warp-agent-staging Bot requested a review from bnavetta August 11, 2026 19:27
@cla-bot cla-bot Bot added the cla-signed label Aug 11, 2026
…split

Adversarial review of #14954 surfaced five findings; all addressed here:

1. Legacy private-store values for the three inactivity settings are now
   migrated into their new public location via a dedicated one-time
   migration (its own completion marker, independent of the general
   SettingsFileMigrationComplete marker which is already set for existing
   SettingsFile users). Only copies when the public location doesn't
   already have a value.

2. Added SharedSessionSettings::register_and_enforce_inactivity_ordering,
   which corrects out-of-order values at every point they become
   authoritative (initial load/hand-edited file, cloud sync, disk
   hot-reload), and changed the two derived-interval helpers in
   settings.rs to use saturating_sub as defense-in-depth against the two
   latent underflow panics found in the ladder. The ordering comparison is
   isolated in ladder_phase_order_ok so a future zero-disables-a-phase
   change only needs to touch that one predicate.

3. parse_shared_session_inactivity_minutes now rejects any value above
   u64::MAX / 60, preventing the *60-to-seconds conversion from
   overflowing.

4. Split the single SharedSessionInactivityWidget (one shared search_terms
   blob covering three rows) into three independent SettingsWidgets
   (SharedSessionRevokeEditAccessWidget / SharedSessionWarningWidget /
   SharedSessionEndSessionWidget), each with row-scoped search terms, each
   backed by its own editor field on FeaturesPageView (mirroring
   MouseScrollMultiplierWidget) instead of a ChildView-wrapped sub-view,
   since ChildView's dispatch boundary would have broken action routing
   for per-row widgets. This also resolves the enum_variant_names lint
   nonblocking comment and removes the redundant enum-variant doc comments
   finding, since the standalone Action enum they were attached to no
   longer exists.

5. N/A - see (4).

Added tests: legacy-migration survival/no-clobber/idempotency, ordering
correction from storage and cloud sync, a pure saturating_sub regression
test, minute-parsing bounds (including the overflow case), clamp
correctness/idempotency, and a StubWidget-based filter test proving the
three rows are independently searchable.

Verified visually with a freshly built and launched instance: all three
rows render correctly, 'revoke'/'disconnect' searches now match only
their own row, edits persist across Settings modal close/reopen, and
out-of-order input is clamped rather than accepted.

Co-Authored-By: Warp Agent <agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant