Conversation
Replace leftover 'personal, noncommercial' boilerplate with a license covering internal business use and client-services work, permit using generated Outputs in client deliverables, and carve Outputs out of the Section 2.2 commercial-exploitation restriction.
…(stops audit OOMs) (#530)
…DataForSEO timeouts (#523)
…ess (EVE-95) (#548)
… warn on upstream flakes (#542)
…-noise filters) (#540)
…er-user /mcp limit (#545)
…e page a…" (#564) This reverts commit bb099ad.
…ratchpad DO (#568)
SAM Durable Objects that exceed the memory limit mid-turn were being
re-run by Think's chat recovery, dying at the same point every time.
The bookkeeping that bounds the retry budget was OOMing too, so one
incident reached attempt 44 of a max of 10. Every attempt is a full
OpenRouter call that never reaches onChatResponse, so none of it was
metered: the production key burned ~$160/day against ~$2/day of
metered SAM spend.
- onChatRecovery returns { persist: true, continue: false }: the partial
reply is still persisted and the user still gets the terminal banner,
but no automatic re-inference is scheduled.
- continueLastTurn short-circuits the "recovery-continue" trigger so
recovery alarms already queued in stuck DOs before this deploy are
skipped without a model call.
Longer-term follow-ups (not in this PR): meter per step so interrupted
turns are still charged, and bring the turn footprint under the DO
memory limit.
Claude-Session: https://claude.ai/code/session_01Cr7Rtr4tj6HUC8WVSPc8R4
The OnboardingChatAgent Durable Object namespace has had zero invocations for months and the "onboarding" credit feature zero events since June 2026. Nothing in the app linked to /onboarding/chat any more, so the route was unreachable. Removes the agent DO, its tools, the client route and UI, the server functions, and the shared free-question cap. The SAM agent keeps the pieces it shared: ChatComposer moved to src/client/features/sam, and openseo-fact-sheet.md moved next to samChatTools. wrangler.jsonc gains migration tag v5 with deleted_classes: ["OnboardingChatAgent"]. That destroys the namespace's stored conversations, which is the intent. Alchemy derives its DO bindings from wrangler.durable_objects.bindings, so dropping the binding there is the whole change on the Alchemy side. Claude-Session: https://claude.ai/code/session_019qJewihUwwbdtYDsHa73Gc
* Fix preview propagation checks and local rank-tracking seed * Triage papercuts and clarify development workflows
… of calling every page blocked (#579)
…on disconnect (#566) * fix(integrations): search GA4/GSC pickers and clear them on disconnect Add client-side search to the GA4 and Search Console property pickers, and unlink unused OAuth grants plus drop cached picker lists on disconnect so stale accounts do not remain after the user clicks Disconnect (EVE-118). Co-authored-by: Ben Senescu <bensenescu@users.noreply.github.com> * style: format picker search and disconnect tests Co-authored-by: Ben Senescu <bensenescu@users.noreply.github.com> * refactor(integrations): reuse the shared searchable select in the GA4/GSC pickers Replaces the hand-rolled search input + native <select> pair with a shared SearchableSelect extracted from LocationSelect, so the country picker and both Google pickers are one implementation. Simplifies the disconnect grant sweep down to the loop it is, and drops the query-key indirection module in favour of inline removeQueries where disconnect happens. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(ui): keep the searchable dropdown readable under a narrow trigger Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(gsc): keep grants that a legacy unbound connection still relies on The disconnect sweep now unlinks every grant no project of the caller's uses, but connections saved before gsc_account_id existed have a NULL account and never matched, so disconnecting one project revoked the grant another project was minting tokens from. A NULL-account connection now counts as using every grant. Also tightens the GA4 no-property-bound test to the partial-sweep case its GSC twin already covers, and drops the GSC null-account service test whose invariant now lives in SQL. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(ui): keep keyboard focus in the searchable select Enter, Escape and Tab now hand focus back to the trigger instead of dropping it on the document body when the search box unmounts, so a keyboard user lands on the next control (Save property) rather than at the top of the page. Arrow keys step past disabled options, and the menu opens with the current choice highlighted like a native select. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(integrations): stop the connection card clipping the property dropdown The card shell had overflow-hidden, which cut the new absolutely positioned picker menu off after a row or two on the Integrations page. Nothing in the card needed the clip. Also drops the OAuth subject id from the pickers' search keywords: it is never shown, so nobody types it. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(ui): float the searchable menu over page scroll containers again Switching the menu from fixed to absolute put it back inside the pages' overflow-auto wrappers, so on Keyword Research and Domain Overview the country list was cut off until the page was scrolled. Back to fixed, with the width copied from the trigger instead of resolving w-full against the viewport, so the Google pickers still get a trigger-width menu. The connection card's overflow-hidden is restored since fixed escapes it. Typing now also lands the highlight on the first pickable match rather than a disabled one. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(ui): keep the searchable menu pinned to its trigger while scrolling A fixed menu left at its static position stays put when the page scrolls, so it drifted away from the trigger. Position it from the trigger's bounding rect and re-place it on scroll and resize, the way PortalMenu does. Scrolling inside the option list is ignored so it stays smooth. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * refactor(gsc,ga4): sweep unused Google grants with one correlated DELETE Disconnect looped over the caller's grants, asked per grant whether a connection still used it, and deleted one at a time. Replace that with a single `DELETE ... WHERE NOT EXISTS (connection using this grant)` per service, in the connection repositories, following the shape already used in AuthRepository. The Search Console subquery keeps the legacy NULL-account clause; Analytics does not need it (column is NOT NULL). `existsForConnectorAccount` and `unlinkUserGrant` had no other callers. The service tests that counted mocked delete-builder calls are replaced by real-SQLite repository tests that seed the account table and assert which rows survive: another user's grant, a grant another project of the caller uses, a legacy NULL-account connection, and the other service's grant. The service keeps one control-flow test: another member's connection removes the project link and never sweeps. Claude-Session: https://claude.ai/code/session_01GJirVu872xMMfto8SrWBcF * fix(integrations): simplify property search and scope account removal --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Ben Senescu <bensenescu@users.noreply.github.com>
…ar them …" (#597) This reverts commit 12fb0db421242cc864be3f16b252f59e3f9748b1.
Awaiting PostHog shutdown in the finalize step could wedge the workflow after snapshots were already written, leaving status=running so the API hid positions. Flip DB status first without awaiting telemetry, reclaim snapshot-complete blockers as completed, and add a cron watchdog. Co-authored-by: Cursor <cursoragent@cursor.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Closing: fork |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8fbe64f. Configure here.
| ); | ||
| console.log( | ||
| `[rank-check] watchdog failed stale incomplete run ${run.id}`, | ||
| ); |
There was a problem hiding this comment.
Watchdog fails active long rank checks
High Severity
reconcileStuckRankCheckRuns fails any still-incomplete run after 25 minutes without checking whether the Cloudflare workflow is still active. Queued checks are designed around a 15-minute poll window plus post, collect, and live-fallback steps, and a legal-max config (1000 keywords × 2 devices) can still be collecting past that cutoff. The fail hides already-written snapshots (results only read completed runs), frees the one-active-run slot, and makes the real finalize step skip.
Reviewed by Cursor Bugbot for commit 8fbe64f. Configure here.
| if (input.requireFullCoverage) { | ||
| if (keywordsChecked === 0 || keywordsChecked < keywordsTotal) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Coverage ignores pending device snapshots
Medium Severity
requireFullCoverage treats a run as finished when every keyword has any snapshot, not one per device. Default devices is both, so the watchdog can mark the run completed after the first device returns while mobile (or desktop) tasks are still queued or in fallback. That releases the active-run slot early and shows a finished check with a missing device series.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8fbe64f. Configure here.
| run.id, | ||
| "Rank check timed out before finalizing", | ||
| run, | ||
| ); |
There was a problem hiding this comment.
Watchdog can overwrite completed runs
Medium Severity
When coverage is incomplete, the watchdog calls failRunIfActive with the run row from the initial stuck query. That helper trusts the passed status and updateRun has no WHERE status IN ('pending','running') guard. If workflow finalize completes the same run in between, the watchdog still writes failed and positions disappear from the API.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8fbe64f. Configure here.
There was a problem hiding this comment.
Left a non-blocking comment and did not approve: Cursor Bugbot completed with unresolved findings (including a high-severity watchdog issue), so this needs human review. Assigned a reviewer from CODEOWNERS and the rank-tracking history.
Sent by Cursor Approval Agent: Pull Request Router and Approver (1)




Summary
7b0eb18onto currentorigin/maintip7b9ee0e).reconcileStuckRankCheckRuns.Files (7)
rankCheckFinalize.ts+ testrankCheckReconciler.tsRankCheckWorkflow.tsrankCheckRunGuards.tsposthog.ts(bounded shutdown)server.ts(watchdog call only — no AI-vis/Sam cron imports from fat branch)Test plan
mainis exactly these 7 filesrunningrank checks + positions visibleSupersedes fat scope of #4 for merge trust. Leave #4 open for agency WIP history; use this PR for the finalize-only ship.
Made with Cursor