Add captcha task-start and challenge-result events - #332
Conversation
d38c3e5 to
e6ff096
Compare
Introduce a captcha_solve_started event in the captcha category, emitted when a solver accepts a task so consumers can react to a solve in flight rather than only seeing the terminal captcha_solve_result. Factor the captcha_type enum into a shared BrowserCaptchaType schema referenced by both event payloads, and add press_and_hold to it to cover the in-VM vision solver, which already emits that value. Schema and regenerated code only; producers land separately.
The captcha events are per solver task, so an image-grid challenge that retries emits one event per round with nothing tying the rounds together. challenge_id groups them; task_id stays per task.
captcha_solve_started and captcha_solve_result describe one solver attempt each, and a single visible challenge takes several: an image grid retries with a fresh task per round. Nothing in either event says a challenge is over, and challenge_id only makes the attempts groupable. captcha_challenge_result is emitted once per challenge by a producer watching the page, which is the only vantage point that can observe the response token. status is what the page saw — solved or abandoned — and solved describes the challenge, not the flow around it, since a site can still reject a valid token.
b451071 to
381cc60
Compare
Sayan-
left a comment
There was a problem hiding this comment.
Wire format is additive and safe: the new types land in a taxonomy-only union and challenge_id is optional. Two things I'd still fix.
- Build break downstream. This deletes
BrowserCaptchaSolveResultEventDataCaptchaTypeand its constants, and renames the status constants fromSuccess/Failure/Timeout/Abandonedto prefixed forms.kernel/kerneluses both inpackages/metro-api/lib/capmonsterrelay/relay.go, line 332 for status and line 363 fornormalizeCaptchaType's signature and returns. metro-api resolves that import through areplaceonto the internal mirror, so it breaks on the next sync plus module bump rather than at merge. Worth a companion PR landed first.
The status rename also looks unintentional. oapi-codegen only dropped the prefix because nothing collided; removing the captcha-type enum changed the collision set.
captcha_challenge_result.statusissolved/abandonedonly, so a solver hard-failure and a dismissed widget are indistinguishable. Addingfailureortimeoutlater means widening a shipped SDK enum, which is the thing the rest of this PR is careful to avoid.
Nits: data is optional on the event, so required challenge_id isn't enforced. duration_ms is optional here but required on the task result.
masnwilliams
left a comment
There was a problem hiding this comment.
this now models the lifecycle correctly:
captcha_solve_resultremains task-level and may occur once per image-grid round.task_idcorrelates each task start/result pair.challenge_idgroups those task attempts.captcha_challenge_resultprovides the once-per-visible-challenge terminal signal, withsolved,failure,timeout, andabandoned.
the latest revision also preserves the existing generated Go API, requires data on the new events, requires challenge duration, and adds compatibility coverage. no remaining structural code-quality blockers from me.
this PR is schema-only, so the behavior is not complete until the producer and consumer changes land: kernel-images-private #339, kernel #3418, and managed-auth-cua-concept #55.
the remaining red e2e check is the unrelated recording-audio-duration assertion; the relevant unit, build, vet, generation, BugBot, and image-build checks pass.
Summary
captcha_solve_startedand challenge-levelcaptcha_challenge_resulttelemetrysolved,failure,timeout, orabandoneddataon both new events andduration_mson challenge resultsContract
captcha_solve_startedrecords that a solver accepted one task.task_idpairs that start with its terminalcaptcha_solve_result, whilechallenge_idgroups every task from one visible challenge. Delivery remains best-effort and unordered, so event arrival or absence does not indicate current solve state.captcha_challenge_resultis emitted once for the visible challenge.failuremeans the producer reached an explicit terminal solver failure or exhausted its attempts while the challenge remained.timeoutis reserved for an actual challenge-level wait budget.abandonedcovers observation ending without either a solved signal or an explicit terminal solver outcome.The shared captcha taxonomy keeps the legacy generated
BrowserCaptchaSolveResultEventDataCaptchaTypename and constants through a schema alias. Existing relay code therefore compiles unchanged when it updates this module.Rollout
Schema and generated image API types only; no producer behavior changes here. The public API schema and extension producer are updated in their corresponding PRs before consumers rely on the new challenge event.
Testing
go test ./lib/oapi ./lib/events/...— pass, including generated-symbol and required-field compatibility coveragego build ./...— passgo vet ./...— passgo test ./lib/capmonsterrelayonkernel/kernel#3432with this module replacement — pass without relay changestest-server-e2e— all cases exceptTestReplayRecordingIncludesAudioTrack; that unrelated test failed twice because the generated audio track ended 0.38s / 1.29s before its recording-duration threshold. The base branch has a green full e2e run on the same base commit.