Skip to content

fix(procaptcha-frictionless): share one detector assignment across widgets on a page - #3156

Merged
HughParry merged 5 commits into
mainfrom
fix/share-detector-prefetch-across-widgets
Oct 26, 2026
Merged

HughParry merged 5 commits into
mainfrom
fix/share-detector-prefetch-across-widgets

Conversation

@forgetso

@forgetso forgetso commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

takePrefetchedDetector removed the in-flight entry on claim. On a page carrying several widgets that meant the first widget shared the prefetch and every other widget issued its own provider resolve plus assignDetectorBundle.

Measured on a live integration with Chrome CDP: 8 widget instances on one page (a widget per form), bundle included twice, and 16 assign calls fire on a single page load — all within 0.0s of each other. Idling 45s adds none, so it is not a retry or polling loop; it is one call per widget per bundle include.

The guarantee delete-on-claim was protecting

Its comment said "so a retry does not reuse a pin that may have just failed". That is kept, by two narrower mechanisms:

  • a prefetch that rejects removes itself, so no later widget inherits a failed pin
  • entries go stale after 60s, so a widget rendered much later (a modal opened minutes in) starts a fresh prefetch rather than reusing an aged provider pin

Retries were never affected either way — customDetectBot only claims on a first attempt (isFirstAttempt), so a retry re-resolves by construction.

Tests

All in detectorPrefetch.test.ts, with the provider mocked:

  • every claim on the page gets the same assignment, with one provider resolve and one assign
  • a failed prefetch is not handed to a later widget
  • an entry older than a minute is not handed out, and a later prefetch replaces it instead of being blocked by it
  • different site keys / IP modes don't share

procaptcha-frictionless: 16 test files, 170 tests pass; build:tsc clean.

…dgets

takePrefetchedDetector removed the in-flight entry on claim, so on a page
carrying several widgets only the first shared the prefetch and every other
widget issued its own provider resolve plus assignDetectorBundle. One
production integration mounts a widget per form — eight on a property page,
with the bundle included twice — so a single page view cost sixteen assign
calls instead of one. That was enough on its own to push ordinary visitors
past a per-IP rate detector.

Sharing is sound: detectorSessionId binds to a bundleId in Redis purely so
the provider can resolve which cipher keys decrypt that widget's SIMD
readings (resolveBundleByDetectorSession). Widgets sharing an assignment run
the same bundle, so those are the right keys — it is a lookup, not a one-shot
token.

The guarantee delete-on-claim existed for is kept by two narrower mechanisms:
a prefetch that rejects drops itself, so no later widget inherits a failed
pin, and entries go stale after 60s so a widget mounting much later
re-resolves rather than reusing an aged provider pin. Retries were never
affected either way — customDetectBot only claims on a first attempt.

The existing single-use test asserted the mechanism rather than the
guarantee; it now pins shareability, with a sibling test for the
failed-pin case.

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

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-09-01T10:38:01Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-09-02T12:01:13Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-09-03T18:01:03Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-09-08T00:02:11Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-09T00:02:20Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-10T00:02:30Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-11T06:01:21Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-15T12:01:21Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-16T12:01:25Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-24T18:00:56Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-25T18:01:00Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-27T00:02:30Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-09-28T12:01:20Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-09-29T18:01:29Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-10-01T06:01:14Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-10-02T18:01:22Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-10-05T18:01:21Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

No updates since 2026-10-07T00:02:38Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-08T06:01:19Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-14T06:01:30Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-15T12:01:33Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-16T18:01:36Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-18T12:01:29Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-20T14:05:32Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-22T06:01:30Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

@github-actions

Copy link
Copy Markdown
Contributor

No updates since 2026-10-23T12:01:27Z (over 1 days), so this PR has been converted to draft. That stops it holding CI runners.

Nothing is lost — gh pr ready 3156, or the "Ready for review" button, picks it straight back up. Add the keep-ready label to exempt it permanently.

Converting to draft disables auto-merge, so PRs with auto-merge enabled are excluded from this entirely.

HughParry and others added 2 commits October 26, 2026 12:13
- prefetchDetector now treats an entry older than the TTL as absent, so a
  widget rendered after a minute starts a fresh prefetch instead of being
  blocked by the stale one.
- Remove detectorPrefetch.multiWidget.test.ts: it never mocked the provider,
  so it made real network calls and failed in CI when the call succeeded.
  Its TTL case moves into the mocked detectorPrefetch.test.ts alongside a new
  stale-replacement case; the others were already covered there.
- Update the module header, which still described the cache as single-use.
@HughParry

Copy link
Copy Markdown
Contributor

don't merge - currently testing that this properly works on my local

@HughParry
HughParry enabled auto-merge (squash) October 26, 2026 13:45
@HughParry
HughParry merged commit 0e4bc70 into main Oct 26, 2026
20 checks passed
@HughParry
HughParry deleted the fix/share-detector-prefetch-across-widgets branch October 26, 2026 14:54
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.

4 participants