Skip to content

feat(statistics): show the image challenge threshold - #52

Merged
forgetso merged 5 commits into
mainfrom
feat/frictionless-score-ladder
Aug 31, 2026
Merged

feat(statistics): show the image challenge threshold#52
forgetso merged 5 commits into
mainfrom
feat/frictionless-score-ladder

Conversation

@forgetso

Copy link
Copy Markdown
Member

What

Sibling to prosopo/captcha#3144, which gives the frictionless flow a second score threshold: sessions past the frictionless threshold now get a puzzle, and only those at or above a higher threshold get an image captcha.

The Statistics tab already shows the first of those, so it shows the second alongside it.

Compatibility

frictionlessThreshold keeps arriving from the API as a plain number — the portal deliberately flattens the new object back down for this endpoint, precisely because the plugin ships on its own schedule and installs update independently. Nothing about the existing row changes.

The schema is nonetheless widened to read that field as either a number or the two-rung object, collapsing to the lower rung. Without that, a payload carrying the object would fail z.number() and take the whole Statistics tab down with "Failed to load" rather than degrading. Cheap insurance against a self-hosted or future endpoint passing it straight through.

The new row renders an em dash against portals that predate the change rather than inventing a value for them.

Testing

tsc --noEmit clean (the pre-existing integrations/vite.config.ts import-assertion error is unrelated and present on main), prettier and eslint clean. Built assets aren't tracked, so nothing to regenerate here.

forgetso and others added 5 commits August 10, 2026 13:12
The portal's frictionless flow gained a second score threshold: sessions
past the frictionless threshold now get a puzzle, and only those at or
above a higher threshold get an image captcha. The Statistics tab shows
the first of those already, so it should show the second too.

`frictionlessThreshold` keeps arriving as a plain number, so nothing
about the existing row changes. It is now also read as the two-rung
object the portal uses internally and collapsed back to its lower rung,
so the tab cannot break if that shape ever reaches the plugin.

The new row is blank on portals that predate the change rather than
inventing a value for them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Prettier 3.4.1 (the version pinned in yarn.lock) collapses the
SiteSettingsInput extends clause onto fewer lines, and the new
frictionlessImageThreshold key widened the captchaSettingsLabels array
enough that phpcs wanted the whole block realigned.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The portal's ClientSettingsSchema names this field imageThreshold, not
frictionlessImageThreshold, so the row this feature adds was reading a
key that is never present and always rendered an em dash.

The level bucketing was wrong for the same reason: the score is
constrained to 0..1, so the old "< 1 means High" test matched every
real value and the Normal and Low labels were unreachable. Banded
around the portal's 0.8 default the way the sibling threshold is
banded around its 0.5 one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The upper rung arrives nested inside frictionlessThreshold, not as a
sibling of it. The row was reading a top-level field that is never sent,
so it always rendered an em dash.

An earlier attempt pointed it at the settings' own imageThreshold, which
does exist on the wire but is an unrelated image-captcha setting on a
0..1 scale — not the ladder rung the row is labelled for. Reverted.

The union that tolerates both wire shapes is load-bearing rather than
defensive: the portal has moved frictionlessThreshold to the ladder, but
records migrate in the background and the WordPress endpoint still emits
the bare number today, so an install can meet either. The transform now
splits the ladder into two flat fields instead of collapsing it and
discarding the image rung.

Banding restored to the 1.0 default: unlike the lower rung this one is
deliberately allowed above 1, because the score compared against it is a
total that server-side penalties add to. The 0.7-0.9 band from the
earlier attempt belonged to imageThreshold's 0..1 scale.

Verified against the live endpoint: settings.frictionlessThreshold is
still 0.5, so the row shows an em dash until the portal API ships the
ladder, then fills in with no further plugin change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@forgetso
forgetso merged commit eb56694 into main Aug 31, 2026
2 of 16 checks passed
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