Record why a Bluesky login renewal failed - #234
Open
pfefferle wants to merge 12 commits into
Open
Conversation
# Conflicts: # tests/phpunit/tests/wp-admin/class-test-health-check.php
# Conflicts: # tests/phpunit/tests/wp-admin/class-test-health-check.php
# Conflicts: # tests/phpunit/tests/wp-admin/class-test-health-check.php
pfefferle
marked this pull request as ready for review
August 31, 2026 13:41
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds diagnostics for OAuth login-renewal (refresh) attempts so support reports can distinguish “WP-Cron never ran” from “auth server rejected refresh” vs “transport failure,” and exposes that history in Site Health.
Changes:
- Persist refresh-attempt outcomes in a new
atmosphere_refresh_statusoption (timestamps + last error) and clear it on disconnect / fresh authorization. - Add a Site Health “Last Login Renewal” debug-info row that reports
never, “X ago”, and optionally “last failure …: ”. - Add PHPUnit coverage for the recording logic and the new Site Health row, plus uninstall cleanup and a changelog entry.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
includes/oauth/class-client.php |
Records refresh successes/failures into a dedicated option; adds session/race guards and sanitization. |
includes/wp-admin/class-health-check.php |
Adds “Last Login Renewal” Site Health debug-info field backed by the recorded refresh status. |
tests/phpunit/tests/oauth/class-test-client-refresh.php |
Adds tests for refresh-status recording paths, races, and sanitization. |
tests/phpunit/tests/wp-admin/class-test-health-check.php |
Adds tests for the new Site Health debug-info row output shapes. |
uninstall.php |
Deletes the new refresh-status option on uninstall. |
.github/changelog/fix-session-refresh-diagnostics |
Documents the end-user visible Site Health diagnostics addition. |
Suppressed comments (1)
includes/wp-admin/class-health-check.php:630
- Same timezone-offset issue as above:
human_time_diff()should receive an explicittime()second argument so the “last failure … ago” value matches timestamps recorded withtime().
\__( '%1$s (last failure %2$s ago: %3$s)', 'atmosphere' ),
$success,
\human_time_diff( (int) $status['last_failure'] ),
(string) ( $status['last_error'] ?? \__( 'unknown', 'atmosphere' ) )
);
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context: https://wordpress.org/support/topic/push-single-post/#post-18984243
Two people lost their Bluesky connection, published a post that silently never went out, and asked how often they need to reconnect. I could not answer that, because when a login renewal fails the plugin keeps no record of it at all.
mark_needs_reauth()stores that a reconnect is needed and throws away why, and there is nothing anywhere that says when the last renewal worked. Every one of these reports starts from zero.This does not fix the disconnects. It makes them legible.
Proposed changes:
Client::refresh()now records every attempt in a newatmosphere_refresh_statusoption. A success stamps the time, written after the tokens land on disk, so the timestamp only ever means "the credentials really were renewed then".invalid_grant,invalid_client,unauthorized_client) and logs it throughdebug_log(). Those three mean very different things: a consumed or replayed token, a client the auth server no longer knows, or a client barred from the grant.never, or2 hours ago, or3 days ago (last failure 1 hour ago: invalid_grant). That is the line we can ask a reporter to paste.The status lives in its own option rather than in
atmosphere_connectionon purpose. That row is written under the mid-flight disconnect and reconnect guards inrefresh_locked(), and a failure record should not have to win those guards to be saved. It is cleared on disconnect and on a fresh authorization so a new session does not inherit the old one's history.Other information:
14 new tests: the recording paths, races, and sanitizing in
Test_Client_Refresh(11 of them), and the three debug-row shapes inTest_Health_Check.Testing instructions:
You need a site connected to Bluesky.
neveron a site that has not renewed yet.wp-env run cli wp cron event run atmosphere_refresh_token. Reload Site Health Info. The row should now say how long ago, in minutes.wp-env run cli wp option patch update atmosphere_connection refresh_token nonsenseThe row should now show the last success plus a failure with an error code, and the connection should flip to needing a reconnect.
never, because the history belonged to the session that just ended.Open questions