Skip to content

fix(logout): keep Auto Login suppressed while a terminal logout is delayed - #1950

Merged
chsami merged 1 commit into
developmentfrom
claude/autologin-suppression-lapse
Oct 13, 2026
Merged

chsami merged 1 commit into
developmentfrom
claude/autologin-suppression-lapse

Conversation

@chsami

@chsami chsami commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Follow-ups from the review of #1944.

Problem

  1. TerminalLogoutPrompt.tick() requested Auto Login suppression only once and then kept retrying the logout every 600 ms. A pending AutoLoginSuppression request lapses back to ALLOWED after 15 s (AWAIT_LOGOUT_MILLIS) if the login screen has not been seen. When the logout took longer than that (combat lockout, repeated INPUT_BLOCKED), the eventual logout reached LOGIN_SCREEN unsuppressed, so Auto Login logged straight back in after the prompt had reported success.
  2. Rs2Player.logoutWithoutAutoLoginStep requested suppression even when its first read already saw LOGIN_SCREEN. That request can never complete, and for up to 15 s it held off Auto Login after a restart.
  3. TerminalLogoutPrompt throttled on System.currentTimeMillis(), and its fields were written from the host's startup/callback threads (begin/reset) and read from the script loop (tick) with no synchronization. A reset() + begin() that landed while a tick() was inside the logout step let the old tick complete and announce the new stop.

Change

  • AutoLoginSuppressionRequest gains renewal() / isRenewal() and a public PENDING_LOGOUT_MILLIS (15 s, now the source of AutoLoginSuppression.AWAIT_LOGOUT_MILLIS). new AutoLoginSuppressionRequest() behaves as before.
  • AutoLoginSuppression.renew() restarts the deadline only while a request is still pending. If a script start, an Auto Login restart or a manual login has cleared it, or it has already expired, renewing does nothing. Plain repeated request() calls still do not extend the deadline (repeatedPendingRequestsDoNotExtendDeadline is unchanged). AutoLoginPlugin sends renewals to the new AutoLoginScript.renewAutoLoginSuppression().
  • TerminalLogoutPrompt sends the first request as before. After that, on any step that is about to click logout, it renews once the last request or renewal is 5 s old (PENDING_LOGOUT_MILLIS / 3). This keeps suppression alive however long the logout is delayed. I used a renewal rather than a fresh request after the window, as the review suggested, for two reasons:
    • No gap. With a fresh request, suppression is ALLOWED between the expiry and the next tick.
    • Restarts stay respected. A fresh request would re-block Auto Login 15 s after a script start had cleared it, which is the case the "post once" comment in logoutWithoutAutoLogin guards against.
  • logoutWithoutAutoLoginStep returns LOGGED_OUT at LOGIN_SCREEN before it runs the suppression request.
  • TerminalLogoutPrompt:
    • Clock: throttles on System.nanoTime() in milliseconds, the same clock AutoLoginSuppression uses. A package-private constructor lets tests inject the clock, and the first attempt does not depend on the clock's sign.
    • Locking: begin/reset/active/message and the tick bookkeeping are synchronized. The lock is not held while the logout step runs (it blocks on the client thread) or while the notification runs (Microbot.showMessage is a modal invokeAndWait).
    • Stale ticks: each stop gets a counter. A tick whose stop was reset or replaced during the logout step neither completes the stop nor sends a suppression request for it.

Public API used by Hub PR 597 (begin, active, message, tick(), reset, tick(Supplier, Consumer)) is unchanged.

Testing

  • New and updated tests, each confirmed to fail by reverting only that fix in the main code:
    • TerminalLogoutPromptTest.delayedLogoutKeepsRenewingSuppressionUntilTheLoginScreen: logout is delayed for 45 s on a fake clock. At every tick, the last request or renewal must be under 15 s old. This fails when the renewal branch is disabled.
    • AutoLoginSuppressionTest.renewalRestartsThePendingDeadline fails when renew() does nothing. renewalNeverReblocksAClearedOrExpiredRequest and renewalAfterLogoutKeepsWaitingForManualLogin cover the restart intent.
    • TerminalLogoutStepTest.loginScreenConfirmsLogoutWithoutAnUncompletableSuppression expects 0 requests at LOGIN_SCREEN and fails with the old line order.
    • TerminalLogoutPromptTest.restartFromAnotherThreadDuringLogoutIsNotCompletedOrSuppressedByTheOldTick runs reset() + begin() on a second thread during the logout step. Without the stop counter it fails because the old tick announces the new stop. Its 5 s join timeout also catches a version that holds the lock across the logout step.
    • TerminalLogoutPromptTest.throttleUsesTheInjectedClockEvenWhenItStartsNegative fails with a nextAttemptAt = 0-style throttle. Against the original class it does not compile, because there was no way to inject a clock.
    • AutoLoginPluginSupplyStopTest checks that renewals are routed separately from requests.
  • ./gradlew :client:runUnitTests --offline: 331 classes, 2339 tests, 0 failures, 0 errors, 2 skipped. This includes ClientThreadGuardrailTest, and no baseline change was needed.
  • Live test, shaded jar from this branch, F2P account on world 301, Auto Login enabled by the probe (it was off and was turned off again afterwards). The probe used the real event bus and the real AutoLoginScript, and read isSuppressed() by reflection:
    • Control: after a plain request, suppressed was true at 14 s and false at 16 s. That is the lapse this PR fixes.
    • Renewal: request at 0 s, renewals at 5/10/15/20 s, still suppressed at 24 s. After resumeAutoLogin() (what a script start triggers), a renewal left it false, so there is no re-block.
    • Real prompt: TerminalLogoutPrompt.begin() + tick() logged out within 5 tick calls and reported done, with suppression true. logoutWithoutAutoLoginStep() at the login screen then returned LOGGED_OUT. The client stayed on LOGIN_SCREEN, still suppressed and with no Auto Login attempt logged, for about 5.5 min: from the logout at 12:07:55, through the modal completion dialog (open until 12:12:45), to the end of a 45 s watch at 12:13:30.
  • Not verified live:
    • A real logout delayed past 15 s (it would need a combat lockout). The renewal path was checked live by posting renewal events directly, and the prompt's renewal cadence only in unit tests.
    • That Auto Login would have logged back in after the control lapse. The control showed suppression turning false; I did not let it log in.
    • Hub PR 597 itself was not built against this branch. Its call sites use only unchanged public methods.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV

…layed

TerminalLogoutPrompt requested suppression once and kept retrying the
logout, but a pending request lapses after 15 s. A logout delayed past
that window reached the login screen unsuppressed and Auto Login logged
straight back in. The prompt now renews the pending request every 5 s;
a renewal only extends a request that is still pending, so it never
re-blocks Auto Login after a script start, restart or manual login
cleared it.

logoutWithoutAutoLoginStep no longer requests suppression when it is
already on the login screen, where the request could never complete.

TerminalLogoutPrompt throttles on a monotonic clock, guards its state
for begin/reset from other threads, and ignores a logout result or
suppression callback from a stop that was reset mid-tick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a5cd1191-47ed-4616-bcf2-f0f42976f00b
📥 Commits

Reviewing files that changed from the base of the PR and between c06177f and bb6db46.

📒 Files selected for processing (10)
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPlugin.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginScript.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginSuppression.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginSuppressionRequest.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/Rs2Player.java
  • runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/player/TerminalLogoutPrompt.java
  • runelite-client/src/test/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginPluginSupplyStopTest.java
  • runelite-client/src/test/java/net/runelite/client/plugins/microbot/accountselector/AutoLoginSuppressionTest.java
  • runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/player/TerminalLogoutPromptTest.java
  • runelite-client/src/test/java/net/runelite/client/plugins/microbot/util/player/TerminalLogoutStepTest.java

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

Walkthrough

Auto-login suppression requests now support renewal with a shared 15-second pending deadline. Terminal logout prompts throttle attempts, renew suppression during delayed logout, and guard against stale stop callbacks. Logout handling returns LOGGED_OUT without requesting suppression when the game is already at the login screen. Tests cover renewal, timing, and concurrent stop replacement.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to bb6db

This change keeps Auto Login suppressed while a terminal logout is delayed, and it skips the suppression request when the game is already at the login screen. No actionable merge-blocking risk was found. Unit tests cover renewal, timing and concurrent stop replacement. A live logout delayed beyond 15 seconds was not verified.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 37 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
Description check Passed The description clearly explains the suppression renewal, logout ordering, timing, concurrency changes, and validation for the changeset.
Title check Passed The title clearly summarizes the primary change: maintaining Auto Login suppression during delayed terminal logout.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@chsami
chsami merged commit 77eec06 into development Oct 13, 2026
3 checks passed
afss0 pushed a commit to afss0/Microbot that referenced this pull request Oct 14, 2026
… state

TerminalLogoutPrompt renewed its suppression request only from inside
logoutWithoutAutoLoginStep, which reaches the callback only at LOGGED_IN.
A client stuck in CONNECTION_LOST or LOADING for more than 15 s let the
request lapse, and Auto Login logged back in once the client dropped to
the login screen. The prompt now renews from its own tick on every
attempt that has not yet seen the login screen.

The prompt's first suppression is now a request followed by a renewal,
so a request another source already left pending (for example
Rs2Player.logoutWithoutAutoLogin from Inventory Setup) gets a fresh
deadline instead of lapsing before the prompt's first renewal.

A terminal stop whose prompt first sees the login screen without ever
having requested suppression (disconnect or break-handler logout) now
posts AutoLoginSuppressionRequest.loggedOut(). AutoLogin moves straight
to its suppressed logged-out state if it is still on the login screen,
and resumes on a manual login, a script start or an AutoLogin restart.
The plain logoutWithoutAutoLoginStep still requests nothing at the login
screen, and a stop that was reset or replaced mid-tick never holds.

Trim the Javadoc lines added in chsami#1950 and bump AutoLogin to 1.0.7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant