feat(client): behavioral human-likelihood for clearance mints (#328) - #11
Merged
Conversation
The SDK half of app#328 (PRD FR10). A session that a human actually interacts with can now present positive evidence of it and upgrade its wd_clearance token to the graded 'human-likely' trust level, which routes can require. Flow: mint clean at idle as before, then watch passively. Once there has been real interaction, summarize it once, re-mint with the aggregates attached, and stop listening. A session that never interacts sends nothing, and one upgrade happens per page load no matter how many times clearance is started or refreshed. What leaves the browser is counts, durations, variances and ratios — and nothing else. No pointer coordinates, no key identities, no form values, no DOM, no replayable event stream. The aggregates describe HOW a session moved, never WHAT it did, which is the whole difference between this and a session-replay product. A test asserts the exact field list, so the payload cannot grow without a deliberate change to the published contract. Reuses the existing BehavioralCollector rather than a parallel implementation; summarizeBehavior() maps it to the wire shape and drops everything else. Notes: - The 24-sample floor sits above the collector's own 20-sample threshold on purpose: below that, _detectMicroTremor returns a 0.5 PLACEHOLDER, and shipping it would manufacture human evidence out of a mouse twitch. - The window floor also refuses tight scripted bursts client-side, so the harder scripted case (one that paces itself) is what the server scores. - The device fingerprint — the only expensive step, one canvas + one WebGL read — is computed inside the upgrade callback, so a session that never interacts never pays for it. - Listeners are passive and removed on delivery: zero steady-state cost. - opts.behavior: false opts out entirely; tokens then stay at 'clean'.
The wdfp1 fp is the enforcement identity (tokens bind to it, the deny-list keys on it) and now has three implementations that must agree byte-for-byte. Names them, and warns against confusing it with the pipeline's server-composed device_fp — a confusion that had made manual denies inert in the app repo.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SDK half of WebDecoy/app#328 (PRD FR10) — pairs with WebDecoy/app#354.
A session that a human actually interacts with can now present positive evidence of it and upgrade its
wd_clearancetoken to the gradedhuman-likelytrust level that routes can require.Flow
Mint clean at idle exactly as before, then watch passively. Once there has been real interaction, summarize it once, re-mint with the aggregates attached, and stop listening. A session that never interacts sends nothing. One upgrade per page load, no matter how many times clearance is started or refreshed.
What leaves the browser
Counts, durations, variances and ratios — and nothing else.
Never: pointer coordinates, key identities, form values, DOM or page content, URLs, or any replayable event stream. The aggregates describe how a session moved, never what it did — the whole difference between this and a session-replay product. A test asserts the exact field list, so the payload cannot grow without a deliberate change to the published contract.
Reuses the existing
BehavioralCollectorrather than a parallel implementation;summarizeBehavior()maps it to the wire shape and drops everything else.Details worth a second look
_detectMicroTremorreturns a0.5placeholder rather than a measurement — and the server reads 0.5 as genuine human tremor. Shipping it would manufacture human evidence out of a mouse twitch.startClearance({ behavior: false })opts out entirely; tokens then stay atclean.Accessibility
A keyboard-only session produces no pointer cadence and is unscored, not scored badly —
summarizeBehaviorreturnsnullrather than a low number, so the mint stays clean instead of looking bot-like. Covered by an explicit test.Verification
10 new tests, 20/20 green in
@webdecoy/client;turbo buildclean including the DTS build.