Skip to content

fix(oura): tighten auth flow — detect email-not-found, replace sleeps with conditions#71

Open
maciejwitowski wants to merge 2 commits intomainfrom
fix/oura-auth-reliability-and-perf
Open

fix(oura): tighten auth flow — detect email-not-found, replace sleeps with conditions#71
maciejwitowski wants to merge 2 commits intomainfrom
fix/oura-auth-reliability-and-perf

Conversation

@maciejwitowski
Copy link
Copy Markdown
Contributor

Summary

Oura connector reliability + performance pass, driven by manual trace analysis of ~10 successful runs and one failed run where the user was silently prompted for an OTP that would never arrive.

Two logical commits:

  1. fix(oura): surface 'email not found' as auth_failed — before this, if a user entered an email Oura didn't recognize, the connector silently proceeded to the send-code click (against the error page), then prompted for an OTP that was never sent. Now we detect Oura's "Your email not found" copy between email submit and send-code, throw a fatal auth_failed with a human-readable reason, and surface it to the UI via the existing page.setData('error', ...) plumbing per the honest-telemetry contract.

  2. perf(oura): replace sleep-based auth waits with conditions; API-first session probe — trace analysis showed ~22s of hardcoded waitForTimeout per auth flow. Replaced blind sleeps with condition-based waits. New behavior:

    • Probe /api/me right after the initial goto. If the cached session is still live, skip email/OTP entirely — repeat logins go from ~40s to ~3s.
    • Remove 3s sleep after /user/sign-in goto (next step already waits on the email input).
    • Remove 500ms sleeps between fill and click (Playwright dispatches input events synchronously).
    • Replace 3s sleep + separate error probe after email submit with a single race: whichever of next-step button / "email not found" text / timeout resolves first wins.
    • Remove 3s sleep after send-code click; replace with waitForSelector on the OTP input.
    • Replace 5s sleep + goto root + double checkLoginStatus after OTP submit with waitForSelector on a dashboard element + fetchCloudApi('/api/me') verification.

Expected impact on reliability numbers

  • First-time login: ~40s → ~20s end-to-end auth time.
  • Cached session: ~40s → ~3s (entirely new fast path — current script pays the full cost every time).
  • Condition-based waits remove two failure modes: (a) slow networks timing out a sleep before the UI renders, (b) users bailing on apparent hangs during overly-generous sleeps.

Version bump

Bumped version in both oura-playwright.json and the VERSION constant: 2.0.02.1.0. Feature-level bump because the cached-session fast path is new behavior. Publish a fresh 2.1.0 artifact rather than republishing over 2.0.0 — context-gateway's manifest.lock.json is keyed on version, and overwriting a published version silently breaks anyone with a cached resolve (see the instagram-api-playwright@2.0.3 drift that happened earlier this week).

Test plan

  • node --check passes on the updated script.
  • Live smoke test against staging needs the artifact rebuilt and the snapshot re-synced into context-gateway. Pre-existing 10-run baseline against 2.0.0 available for comparison.
  • Specifically worth re-running the "bad email" case to confirm the user now sees "email not associated with Oura account" instead of hanging on the OTP prompt.

Out of scope (flagged for later)

  • Parallelizing the tail fetches (actions 30/33/36/39 in the trace). ~3s win available if they're independent scopes. Haven't touched the scope-collection layer in this PR.
  • Tightening the button[name="selectedId"], button#submit-button compound selector. It's fragile (Auth0 identity picker can match first on some flows), but it works on current staging. Separate reliability investigation.
  • Persistent session state across runs at the runner level — would deliver far more than the /api/me probe by skipping the goto entirely, but requires runner changes outside this repo.

🤖 Generated with Claude Code

maciejwitowski and others added 2 commits April 17, 2026 12:37
When the user enters an email that is not associated with any Oura
account, Oura renders a "Your email not found" error page instead of
advancing to the send-code step. The connector previously proceeded to
click the send-code selector against the error page, then prompted the
user for an OTP that was never sent.

Detect the error text between email submit and the send-code click, and
throw a fatal auth_failed with a human-readable reason. The outer
try/catch will surface the reason via page.setData('error', ...) per
the honest telemetry contract, so the UI shows the real cause instead
of hanging on an OTP prompt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… session probe

Trace analysis across 10+ successful runs showed ~22s of hardcoded
waitForTimeout per auth flow. This cuts most of it by replacing blind
sleeps with the condition each sleep was actually waiting for.

Changes to doLogin:

- Drop the DOM-based session detection retry loop (goto root + sleep 3s
  + DOM check + sleep 2s + DOM check). Probe /api/me directly on the
  loaded dashboard origin. If the session is live we skip email/OTP
  entirely.
- Remove the 3s sleep after safeGoto(/user/sign-in). The next step
  already waitForSelector's the email input.
- Remove the 500ms sleeps between fill and click (email and OTP).
  Playwright's fill already dispatches input/change events.
- Replace the 3s sleep + separate "email not found" probe with a single
  race-based wait. Resolves as soon as either the next-step button
  appears (happy path) or the error text shows (fail fast with
  auth_failed).
- Remove the 3s sleep after clicking the send-code button. Replace with
  waitForSelector on the OTP input.
- Replace the 5s sleep + goto root + double checkLoginStatus after OTP
  submit with a waitForSelector on a dashboard-shaped element plus a
  single fetchCloudApi('/api/me') verification.

Expected per-run auth time drops from ~40s to ~20s for first-time login
and from ~40s to ~3s for repeat logins with a valid cached session
(previously paid the full auth cost every time).

Condition-based waits are also more robust than sleeps: slow networks
no longer time out before the UI renders, fast networks no longer pay
unnecessary overhead.

Bumps version to 2.1.0. This is a feature-level change (behavior is
functionally equivalent on the happy path but meaningfully faster; the
cached-session optimization adds a new fast path), not a patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Schema Health Check — 6 issue(s) found

41/47 scopes consistent | 0 missing schema files | 6 not in Gateway | 0 metadata drift | 0 orphaned

View issues

Not registered in Gateway:

Scope Connector Added in PR?
instagram.following instagram-playwright
steam.profile steam-playwright
steam.games steam-playwright
steam.friends steam-playwright
icloud_notes.notes icloud-notes-playwright
icloud_notes.folders icloud-notes-playwright

These issues should be resolved before connectors can be used by Personal Servers.

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