Files

1682 lines
38 KiB
JSON

[
{
"id": "is-trusted-click",
"file": "challenges/01-is-trusted-click.html",
"category": "trusted-input",
"goal": "Click handler receives browser-trusted pointer/click events.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"notes": [
"Core debugger/CDP smoke test."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"trusted-input"
],
"requires": {},
"gate": "core"
},
{
"id": "is-trusted-keyboard",
"file": "challenges/02-is-trusted-keyboard.html",
"category": "trusted-input",
"goal": "Typing produces trusted keydown/input sequence.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#t",
"text": "hello",
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"trusted-input"
],
"requires": {},
"gate": "core"
},
{
"id": "webdriver-flag",
"file": "challenges/03-webdriver-flag.html",
"category": "fingerprint",
"goal": "Real profile has no WebDriver/headless tells.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_evaluate",
"params": {
"expression": "JSON.stringify({v:window.__verdict,r:window.__reason})"
}
}
],
"notes": [
"Environment-sensitive; classify unexpected failures as profile warnings first."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"fingerprint"
],
"requires": {},
"gate": "core"
},
{
"id": "mouse-entropy",
"file": "challenges/04-mouse-entropy.html",
"category": "pointer-humanization",
"goal": "Click is preceded by organic mousemove path.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"gate": "quality"
},
{
"id": "event-timing",
"file": "challenges/05-event-timing.html",
"category": "timing",
"goal": "Repeated clicks have plausible holds and gaps.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
}
],
"flakeRisk": "medium",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"timing"
],
"requires": {},
"thresholds": {},
"notes": [
"Timing thresholds can be tuned via ?threshold.<name>=value for slower CI or high-polling devices."
],
"gate": "core"
},
{
"id": "click-coordinates",
"file": "challenges/06-click-coordinates.html",
"category": "pointer-humanization",
"goal": "Clicks land inside target but not always exact center.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"gate": "quality"
},
{
"id": "pointer-properties",
"file": "challenges/07-pointer-properties.html",
"category": "pointer-humanization",
"goal": "Pointer events carry plausible pointerType, pressure, movement, id.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"gate": "quality"
},
{
"id": "keyboard-cadence",
"file": "challenges/08-keyboard-cadence.html",
"category": "keyboard",
"goal": "Typing emits per-character key events with non-uniform cadence.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#t",
"text": "secret"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"keyboard"
],
"requires": {},
"thresholds": {},
"notes": [
"Timing thresholds can be tuned via ?threshold.<name>=value for slower CI or high-polling devices."
],
"gate": "quality"
},
{
"id": "composition-input",
"file": "challenges/09-composition-input.html",
"category": "keyboard",
"goal": "Plain ASCII typing has correct beforeinput/input order without fake composition.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#t",
"text": "abc"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"keyboard"
],
"requires": {},
"gate": "core"
},
{
"id": "user-activation",
"file": "challenges/10-user-activation.html",
"category": "activation-gates",
"goal": "User activation unlocks clipboard/fullscreen-style gated APIs.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "CONDITIONAL"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"verdictDelayMs": 800,
"prerequisites": [
"secure origin",
"clipboard/fullscreen allowed by browser policy"
],
"flakeRisk": "high",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"activation-gates"
],
"requires": {},
"gate": "conditional"
},
{
"id": "honeypot",
"file": "challenges/11-honeypot.html",
"category": "agent-safety",
"goal": "Agent fills only visible intended field, not hidden traps.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_fill",
"params": {
"selector": "#name",
"text": "alex"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "button[type=submit]"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"agent-safety"
],
"requires": {},
"gate": "core"
},
{
"id": "fingerprint",
"file": "challenges/12-fingerprint.html",
"category": "fingerprint",
"goal": "Browser fingerprint is plausible for normal Chrome profile.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "CONDITIONAL",
"manual": "CONDITIONAL"
},
"recipe": [
{
"tool": "chrome_evaluate",
"params": {
"expression": "JSON.stringify({v:window.__verdict,r:window.__reason})"
}
}
],
"prerequisites": [
"non-headless normal Chrome profile"
],
"flakeRisk": "medium",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"fingerprint"
],
"requires": {},
"gate": "quality"
},
{
"id": "focus-order",
"file": "challenges/13-focus-order.html",
"category": "focus-keyboard",
"goal": "Pointer-driven focus precedes input and does not set focus-visible keyboard affordance.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#t",
"text": "x",
"trusted": true
}
}
],
"flakeRisk": "medium",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"focus-keyboard"
],
"requires": {},
"gate": "quality"
},
{
"id": "wheel-scroll",
"file": "challenges/14-wheel-scroll.html",
"category": "scroll",
"goal": "Scrollable element moves via wheel events, not scrollTop teleport.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_scroll",
"params": {
"selector": "#box",
"deltaY": 1200
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"scroll"
],
"requires": {},
"gate": "core"
},
{
"id": "drag-drop-datatransfer",
"file": "challenges/15-drag-drop-datatransfer.html",
"category": "drag-drop",
"goal": "HTML5 drag cycle delivers trusted events and populated DataTransfer.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_drag",
"params": {
"fromSelector": "#src",
"toSelector": "#dst",
"trusted": true
}
}
],
"notes": [
"May need CDP Input.dispatchDragEvent rather than mouse drag on some Chrome versions."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"drag-drop"
],
"requires": {},
"gate": "conditional"
},
{
"id": "contenteditable-selection",
"file": "challenges/16-contenteditable-selection.html",
"category": "editing",
"goal": "Contenteditable typing advances selection/caret like user typing.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#ed",
"text": "hello"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"editing"
],
"requires": {},
"gate": "core"
},
{
"id": "paste-clipboard",
"file": "challenges/17-paste-clipboard.html",
"category": "clipboard",
"goal": "Paste uses OS/browser clipboard path with trusted paste event and clipboardData.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#t",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "v",
"modifiers": {
"metaKey": true
},
"trusted": true
}
}
],
"prerequisites": [
"OS clipboard contains pi-chrome",
"use ctrlKey instead of metaKey on Windows/Linux"
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"clipboard"
],
"requires": {},
"gate": "conditional"
},
{
"id": "native-select",
"file": "challenges/18-native-select.html",
"category": "native-controls",
"goal": "Native select changes via trusted picker/keyboard path, not .value assignment.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#s",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "ArrowDown",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "ArrowDown",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Enter",
"trusted": true
}
}
],
"flakeRisk": "high",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"native-controls"
],
"requires": {},
"gate": "conditional"
},
{
"id": "hover-dwell",
"file": "challenges/19-hover-dwell.html",
"category": "hover",
"goal": "Hover reveal includes dwell, pointer activity, and delayed trusted confirm click.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_hover",
"params": {
"selector": "#trig",
"trusted": true
}
},
{
"tool": "wait",
"params": {
"ms": 800
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"hover"
],
"requires": {},
"gate": "core"
},
{
"id": "react-value-tracker",
"file": "challenges/20-react-value-tracker.html",
"category": "frameworks",
"goal": "Programmatic fill uses native value setter so React-style tracker sees change.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_fill",
"params": {
"selector": "#t",
"text": "react-ok"
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"frameworks"
],
"requires": {},
"gate": "core"
},
{
"id": "keyboard-modifiers",
"file": "challenges/21-keyboard-modifiers.html",
"category": "keyboard",
"goal": "Shift+a chord has correct ordering, code/key/modifier state, trusted events.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_key",
"params": {
"key": "a",
"modifiers": {
"shiftKey": true
},
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"keyboard"
],
"requires": {},
"gate": "core"
},
{
"id": "touch-events",
"file": "challenges/22-touch-events.html",
"category": "touch",
"goal": "Touch tap produces real TouchEvent/Touch surface with radius/force.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "CONDITIONAL"
},
"recipe": [
{
"tool": "chrome_tap",
"params": {
"selector": "#pad"
}
}
],
"prerequisites": [
"touch events enabled/supported"
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"touch"
],
"requires": {},
"gate": "conditional"
},
{
"id": "stack-trace-fingerprint",
"file": "challenges/23-stack-trace-fingerprint.html",
"category": "fingerprint",
"goal": "Click handler stack does not expose extension/eval automation frames.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"notes": [
"Adversarial probe; selector resolution itself can be detected by monkey-patched DOM APIs.",
"Should fail only on concrete automation URLs/Runtime frames, not generic anonymous stack formatting."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"fingerprint"
],
"requires": {},
"gate": "quality"
},
{
"id": "viewport-edge-clicks",
"file": "challenges/24-viewport-edge-clicks.html",
"category": "pointer-humanization",
"goal": "Click coordinates are valid viewport coordinates inside target.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"gate": "core"
},
{
"id": "pointer-continuity",
"file": "challenges/25-pointer-continuity.html",
"category": "pointer-humanization",
"goal": "Far-apart clicks are bridged by mid-span pointermove samples.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#a",
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#b",
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"gate": "quality"
},
{
"id": "mousemove-rate",
"file": "challenges/26-mousemove-rate.html",
"category": "pointer-humanization",
"goal": "Mouse sweep produces plausible move frequency and jitter before trusted Done click.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_hover",
"params": {
"selector": "#pad",
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go",
"trusted": true
}
}
],
"notes": [
"Needs a first-class pointer path/sweep tool for deterministic automation.",
"Timing thresholds can be tuned via ?threshold.<name>=value for slower CI or high-polling devices."
],
"flakeRisk": "high",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"pointer-humanization"
],
"requires": {},
"thresholds": {},
"gate": "quality"
},
{
"id": "scroll-momentum",
"file": "challenges/27-scroll-momentum.html",
"category": "scroll",
"goal": "Wheel gesture has trusted events with ramp/decay momentum tail.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "CONDITIONAL"
},
"recipe": [
{
"tool": "chrome_scroll",
"params": {
"selector": "#box",
"deltaY": 1600,
"trusted": true
}
}
],
"notes": [
"Physical detent mouse wheels may fail decay requirement; trackpads usually pass."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"scroll"
],
"requires": {},
"prerequisites": [
"Trackpad-like momentum; physical detent mouse wheels may fail decay requirement even for manual users."
],
"gate": "quality"
},
{
"id": "intersection-visibility",
"file": "challenges/28-intersection-visibility.html",
"category": "scroll-visibility",
"goal": "Scrolling reveals target gradually with IO/rAF samples before trusted click.",
"expected": {
"synthetic": "FAIL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_scroll",
"params": {
"selector": "#scroller",
"deltaY": 1200,
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#target",
"trusted": true
}
}
],
"flakeRisk": "medium",
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"scroll-visibility"
],
"requires": {},
"gate": "quality"
},
{
"id": "shadow-dom-controls",
"file": "challenges/29-shadow-dom-controls.html",
"category": "dom-complexity",
"goal": "Agent discovers and interacts with controls inside open Shadow DOM.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#host >>> button"
}
},
{
"tool": "chrome_type",
"params": {
"selector": "#host >>> input",
"text": "shadow-ok"
}
}
],
"notes": [
"Selector syntax is descriptive; tools may need uid from snapshot rather than CSS.",
"Current recipe uses descriptive >>> shadow selector syntax; runners must adapt to supported uids/selectors or use evaluate until bridge supports shadow piercing."
],
"manualBaseline": "unverified",
"prerequisites": [
"pi-chrome shadow-piercing selectors or shadow-root-aware snapshot uids"
],
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"dom-complexity"
],
"requires": {},
"gate": "conditional"
},
{
"id": "iframe-targeting",
"file": "challenges/30-iframe-targeting.html",
"category": "frames",
"goal": "Agent targets interactive controls inside a same-origin iframe and reports verdict to parent.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "iframe#ifr >> #insideText",
"text": "frame-ok"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "iframe#ifr >> #insideButton"
}
}
],
"notes": [
"Selector syntax is descriptive; benchmark checks whether tool exposes frame-aware uids/selectors."
],
"manualBaseline": "unverified",
"prerequisites": [
"pi-chrome currently targets frameId 0 for many actions; iframe drilling needs frame-targeting support"
],
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"frames"
],
"requires": {},
"gate": "conditional"
},
{
"id": "file-upload",
"file": "challenges/31-file-upload.html",
"category": "files",
"goal": "Agent attaches a local file to an input and page reads expected name/content.",
"expected": {
"synthetic": "PASS",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_upload_file",
"params": {
"selector": "#file",
"paths": [
"$PWD/test-suite/fixtures/pi-chrome-upload.txt"
]
}
}
],
"manualBaseline": "unverified",
"notes": [
"Recipe paths may contain $PWD; external runners should expand shell-style placeholders before calling chrome_upload_file."
],
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"files"
],
"requires": {},
"gate": "core"
},
{
"id": "keyboard-tab-navigation",
"file": "challenges/32-keyboard-tab-navigation.html",
"category": "focus-keyboard",
"goal": "Keyboard-only user flow tabs through fields and submits with Enter.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#start",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_type",
"params": {
"text": "one",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_type",
"params": {
"text": "two",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_type",
"params": {
"text": "three",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Enter",
"trusted": true
}
}
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"focus-keyboard"
],
"requires": {},
"gate": "core"
},
{
"id": "network-console-capture",
"file": "challenges/33-network-console-capture.html",
"category": "observability",
"goal": "Interaction emits console logs and fetch traffic for tool-level capture APIs.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_list_console_messages",
"params": {
"clear": true
}
},
{
"tool": "chrome_list_network_requests",
"params": {
"clear": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#go"
}
},
{
"tool": "chrome_list_console_messages",
"params": {}
},
{
"tool": "chrome_list_network_requests",
"params": {}
}
],
"notes": [
"Page verdict only checks in-page fetch result; benchmark harness should also assert captured console/network entries.",
"First chrome_list_console_messages/chrome_list_network_requests call installs capture hooks; do not move clear/list calls after click."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"difficulty": "L1",
"tags": [
"observability"
],
"requires": {},
"gate": "core"
},
{
"id": "dialog-handling",
"file": "challenges/34-dialog-handling.html",
"category": "dialogs",
"difficulty": "L2",
"goal": "Agent detects and handles alert/confirm/prompt/beforeunload browser dialogs.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "CONDITIONAL",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#promptBtn",
"trusted": true
}
},
{
"tool": "dialog",
"params": {
"type": "prompt",
"text": "pi-chrome",
"accept": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#confirmBtn",
"trusted": true
}
},
{
"tool": "dialog",
"params": {
"type": "confirm",
"accept": true
}
}
],
"requires": {
"dialogs": true
},
"prerequisites": [
"browser-dialog handling API or manual user intervention"
],
"tags": [
"dialogs",
"native-browser-ui"
],
"notes": [
"If dialog handling is unsupported, page may block after click; this is expected signal."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"gate": "conditional"
},
{
"id": "target-blank-popup",
"file": "challenges/35-target-blank-popup.html",
"category": "popups",
"difficulty": "L1",
"goal": "Agent handles target=_blank new tab, discovers it via tab list, and inspects child tab verdict.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#open",
"trusted": true
}
},
{
"tool": "chrome_tab",
"params": {
"action": "list"
}
},
{
"tool": "chrome_snapshot",
"params": {
"titleIncludes": "target blank popup"
}
}
],
"requires": {
"popups": true
},
"tags": [
"tabs",
"popup"
],
"notes": [
"Child tab writes PASS to shared localStorage; harness should verify tab count/title too."
],
"manualBaseline": "unverified",
"gradeSource": "page",
"gate": "core"
},
{
"id": "modal-focus-trap",
"file": "challenges/36-modal-focus-trap.html",
"category": "focus-keyboard",
"difficulty": "L2",
"goal": "Keyboard focus stays trapped inside modal and Escape closes with focus restoration.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#open",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Tab",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Escape",
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"modal",
"focus",
"keyboard"
],
"manualBaseline": "unverified",
"gradeSource": "page",
"gate": "core"
},
{
"id": "autocomplete-combobox",
"file": "challenges/37-autocomplete-combobox.html",
"category": "forms",
"difficulty": "L2",
"goal": "Agent uses ARIA combobox keyboard path: type filter, ArrowDown, Enter.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_type",
"params": {
"selector": "#combo",
"text": "as",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "ArrowDown",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "Enter",
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"aria",
"combobox",
"forms"
],
"manualBaseline": "unverified",
"gradeSource": "page",
"gate": "core"
},
{
"id": "spa-route-change",
"file": "challenges/38-spa-route-change.html",
"category": "spa-routing",
"difficulty": "L1",
"goal": "Agent recognizes SPA pushState navigation and completes route-local action without full reload.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_click",
"params": {
"selector": "#settings",
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#billing",
"trusted": true
}
},
{
"tool": "chrome_key",
"params": {
"key": "ArrowLeft",
"modifiers": {
"altKey": true
},
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#billing",
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#save",
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"spa",
"history",
"navigation"
],
"manualBaseline": "unverified",
"gradeSource": "page",
"notes": [
"Requires a real browser Back action (e.g. Alt+Left) to exercise popstate before Save."
],
"gate": "core"
},
{
"id": "strict-csp-fallback",
"file": "challenges/39-strict-csp-fallback.html",
"category": "csp",
"difficulty": "L2",
"gate": "core",
"goal": "Operate a page with strict CSP that blocks unsafe-eval by falling back to screenshot/viewport-coordinate input.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_screenshot",
"params": {
"path": ".pi/chrome-screenshots/strict-csp-fallback.png"
}
},
{
"tool": "chrome_click",
"params": {
"x": 310,
"y": 256,
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"csp",
"screenshot",
"coordinate-click",
"strict-csp"
],
"notes": [
"This challenge exercises the pure screenshot + viewport-coordinate path (no snapshot/evaluate needed). Note: as of the CDP CSP bypass, chrome_snapshot/chrome_evaluate DO work here even though script-src omits unsafe-eval (see challenge 42 strict-csp-evaluate). Read verdict from dashboard/localStorage after leaving the CSP page."
],
"manualBaseline": "unverified",
"gradeSource": "page"
},
{
"id": "dynamic-wait-readiness",
"file": "challenges/40-dynamic-wait-readiness.html",
"category": "lazy-loading",
"difficulty": "L1",
"gate": "core",
"goal": "Wait for an asynchronously mounted and enabled control before clicking it.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_wait_for",
"params": {
"kind": "selector",
"value": "#readyAction[data-ready=\"true\"]:not([disabled])",
"timeoutMs": 3000
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#readyAction",
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"wait",
"async-dom",
"readiness"
],
"notes": [
"Covers explicit wait primitive and avoids fixed sleep as readiness strategy."
],
"manualBaseline": "unverified",
"gradeSource": "page"
},
{
"id": "tab-lifecycle",
"file": "challenges/41-tab-lifecycle.html",
"category": "popups",
"difficulty": "L2",
"gate": "core",
"goal": "Create a new tab, inspect it, close it, return to the parent tab, and verify tab lifecycle state.",
"expected": {
"synthetic": "CONDITIONAL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_tab",
"params": {
"action": "new",
"url": "http://127.0.0.1:8765/challenges/41-tab-lifecycle.html?child=1"
}
},
{
"tool": "chrome_tab",
"params": {
"action": "list"
}
},
{
"tool": "chrome_snapshot",
"params": {
"titleIncludes": "tab lifecycle"
}
},
{
"tool": "chrome_tab",
"params": {
"action": "close",
"targetId": "<child tab id from list>"
}
},
{
"tool": "chrome_tab",
"params": {
"action": "activate",
"targetId": "<parent tab id>"
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#verify",
"trusted": true
}
}
],
"requires": {
"popups": true
},
"tags": [
"tabs",
"new-tab",
"close-tab",
"activate-tab"
],
"notes": [
"Recipe contains dynamic tab IDs; runner must substitute ids from chrome_tab list. Complements target=_blank by testing explicit new/close/activate tools."
],
"manualBaseline": "unverified",
"gradeSource": "page"
},
{
"id": "strict-csp-evaluate",
"file": "challenges/42-strict-csp-evaluate.html",
"category": "csp",
"difficulty": "L2",
"gate": "core",
"goal": "On a page with strict CSP (script-src 'self', no unsafe-eval), use chrome_evaluate + chrome_snapshot via CDP to read a JS-only secret (window.__cspToken), then submit it with trusted input.",
"expected": {
"synthetic": "FAIL",
"trusted": "PASS",
"manual": "PASS"
},
"recipe": [
{
"tool": "chrome_evaluate",
"params": {
"expression": "window.__cspToken"
}
},
{
"tool": "chrome_fill",
"params": {
"selector": "#tokenInput",
"value": "$RESULT_OF_chrome_evaluate",
"trusted": true
}
},
{
"tool": "chrome_click",
"params": {
"selector": "#verify",
"trusted": true
}
}
],
"requires": {
"cdp": true
},
"tags": [
"csp",
"evaluate",
"snapshot",
"strict-csp",
"cdp-bypass"
],
"notes": [
"Regression guard for the CDP CSP bypass: chrome_evaluate and chrome_snapshot must work even though script-src omits unsafe-eval (eval/new Function are blocked). The token is non-enumerable and never in the DOM, so it can only be obtained via chrome_evaluate. Runner must substitute the evaluate result into the fill value. synthetic FAIL is due to the trusted-click gate, not eval availability."
],
"manualBaseline": "unverified",
"gradeSource": "page"
}
]