Skip to content

Fix login reliability and client timeout causing duplicate writes - #36

Merged
milldr merged 1 commit into
mainfrom
tembo/fix-login-reliability-and-client-timeout
Jul 29, 2026
Merged

Fix login reliability and client timeout causing duplicate writes#36
milldr merged 1 commit into
mainfrom
tembo/fix-login-reliability-and-client-timeout

Conversation

@milldr

@milldr milldr commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

Three related failures made browser-backed commands unreliable. One of them silently duplicated user data.

I hit these while logging a single meal: it took ~90 minutes and left three identical custom foods in my Cronometer account. Each fix is verified against a live account.

1. Kernel client HTTP timeout — the data-loss one

@onkernel/sdk's client-side HTTP timeout defaults to 60s, but automations are dispatched with timeout_sec up to 120s (addCustomFood). The client aborts while the browser is still working, so Cronometer commits the change while crono reports failure:

Failed to create custom food: Request to Kernel API timed out.

That error is indistinguishable from a genuine failure, so the natural response is to retry — and each retry creates another copy. Three "failed" attempts left three identical custom foods.

Fixed by giving the SDK an explicit client timeout comfortably above the largest timeout_sec.

The browser session budget had the same shape of bug: timeout_seconds: hasAutoCredentials ? 120 : 300, but a command can spend ~60s logging in before a 120s automation starts, so the session could expire mid-operation. Replaced with a single 300s budget.

2. Login navigated via the marketing homepage

buildAutoLoginCode loaded cronometer.com and clicked the header "Log In" link. That click frequently does not navigate — and because the loop set clickedLogin = true on a successful click rather than a successful navigation, it also suppressed the direct-navigation fallback immediately below it. The form was never reachable:

Auto-login failed: Could not find email input on https://cronometer.com/.
Your credentials may be incorrect.

Fixed by navigating straight to /login/. In my testing this was the single biggest source of flakiness — it failed roughly 2 out of every 3 runs.

3. Login verification raced the app boot

Success was inferred from the absence of login UI after a waitForTimeout(500). That is shorter than the GWT app's swap from login form to app shell, so logins that had actually succeeded reported:

Auto-login failed: Login verification failed.

Fixed by letting the shell settle and confirming with a positive signal — that the diary actually renders. This reuses the check buildLoginCheckCode already performed, now extracted as buildDiaryPresentedCheckCode() and shared by both.

Also: a misleading error message

When Cronometer throttles logins it serves the logged-out marketing page with no error text, so loginError is null and the existing rate-limit detection (which greps page text for "too many" etc.) doesn't fire. It surfaced as "Your credentials may be incorrect", which invites exactly the retry loop that extends the throttle. The message now names throttling as the likely cause when credentials are known good.

Worth noting for anyone debugging this: while throttled, every selector-based failure downstream reports something misleading — Could not find meal category "Lunch" in diary, No food found matching "..." — because the automation is running against the marketing page. Fixes 2 and 3 mean login now fails loudly at the login step instead of letting a logged-out session proceed.

Testing

  • npm test — 221 passing (added tests/kernel/client.test.ts, updated tests/kernel/login.test.ts)
  • npm run lint, npm run build, Prettier check — all clean
  • End-to-end against a live account: crono recipes now logs in headlessly on the first attempt and returns results. Before these changes the same command failed repeatedly at login.

One test changed meaning rather than just being updated: "should start at cronometer.com and click login link" asserted the behavior in fix 2, so it is replaced by a test asserting direct navigation and one asserting the homepage-click path is gone.

Note on headless

I did not change the headless: hasAutoCredentials behavior. Headless was never the problem — with fix 2 applied, headless login works reliably. Flagging it because "Cronometer hangs headless sessions" is an easy conclusion to draw from the symptoms of fix 2, and forcing a headed browser is a slower workaround for a bug that is fixed here.

🤖 Generated with Claude Code


Want tembo to make any changes? Add a comment with @tembo and i'll get back to work!

View on Tembo Review in Tembo View Agent Settings

Three related failures made browser-backed commands unreliable, and one of
them silently duplicated user data.

1. Kernel client HTTP timeout (the data-loss one)

   The SDK's client-side timeout defaults to 60s, but automations are
   dispatched with timeout_sec up to 120s (addCustomFood). The client gave up
   while the browser was still working, so Cronometer committed the change
   while crono reported "Request to Kernel API timed out". Every retry then
   created another copy - logging one item three times produced three
   identical custom foods.

   Set an explicit client timeout above the largest timeout_sec.

   The browser session budget had the same shape of bug: 120s when auto
   credentials exist, but a command can spend ~60s logging in before a 120s
   automation starts, so the session could expire mid-operation. Use a single
   300s budget.

2. Login navigated via the marketing homepage

   Login loaded cronometer.com and clicked the header "Log In" link. That
   click frequently does not navigate, and because the loop recorded a
   successful *click* it also suppressed the direct-navigation fallback below
   it. The form was never reachable and login failed with "Could not find
   email input on https://cronometer.com/".

   Navigate straight to /login/.

3. Login verification raced the app boot

   Success was inferred from the absence of login UI after a 500ms wait, which
   is shorter than the GWT app's swap from login form to app shell. Logins
   that had actually succeeded reported "Login verification failed".

   Wait for the shell to settle and confirm with a positive signal - that the
   diary renders - reusing the existing check, now extracted as
   buildDiaryPresentedCheckCode() and shared with buildLoginCheckCode().

Also clarify the auto-login error message. When Cronometer throttles logins it
serves the logged-out marketing page with no error text, which surfaced as
"Your credentials may be incorrect" and invited a retry loop that extended the
throttle.

Verified end-to-end against a live account: `crono recipes` now logs in
headlessly on the first attempt and returns results.

Co-authored-by: Dan <miller0daniel@gmail.com>
@tembo tembo Bot added the tembo Pull request created by Tembo label Jul 29, 2026
@milldr
milldr merged commit 8a432cc into main Jul 29, 2026
3 checks passed
@milldr
milldr deleted the tembo/fix-login-reliability-and-client-timeout branch July 29, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tembo Pull request created by Tembo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant