# apen-mouse — VALIDATION RESULTS

**Spike:** `spikes/apen-mouse/`
**Date:** 2026-06-23 (Round 1)
**Source claim:** Approximate entropy (ApEn) of mouse velocity timeseries should be high (>1.0) for humans and low (<0.5) for scripted/synthetic mouse movement.

---

## Verdict: ❌ REJECTED — headless detector stands, but "CDP discriminator" framing was a test artifact

**Reason:** Vanilla headless correctly detects synthetic input as low-entropy. The "CDP showed zero events" result from Round 1 was a test runner bug — `page.mouse.move()` was being called before the page's `mouse-zone` element had finished loading. Re-running the test with a wait-for-element fix confirms ApEn fires identically on both vanilla and CDP-attached Chrome.

---

## Method

Two-condition dual test (`test.py`):
1. **Vanilla headless** Playwright Chromium
2. **CDP-attached** Chrome 148 via `playwright.chromium.connect_over_cdp()`

The probe (`demo.html`) collects mouse events inside a `mouse-zone` div and computes ApEn of the velocity timeseries. Synthetic linear mouse movement should produce ApEn < 0.5.

---

## Results

### Round 1 (initial, buggy)

| Condition | Events captured | ApEn | Notes |
|---|---|---|---|
| Vanilla headless | 11 | (calculated) | Worked |
| CDP-attached | 0 | N/A | Test runner bug — moves fired before zone loaded |

**Initial conclusion (incorrect):** "CDP shows zero events = CDP discriminator!"

### Round 1 (corrected)

Re-ran with `wait_for_selector('#mouse-zone')` fix. CDP-attached now produces same events and same ApEn as vanilla. Conclusion reverted.

---

## Why this is rejected (as a CDP discriminator)

The signal **does work as a headless detector** — synthetic input produces low ApEn identically on both vanilla and CDP-attached Chrome. But:

- It is **not** a CDP-vs-headless discriminator
- It is a subset of the broader `input-entropy` check (which already covers velEntropy + dirEntropy + apen + ieiCV)
- Shipping it separately duplicates `input-entropy` which is being integrated as the unified Phase 3 detector

**Action: superseded by `input-entropy` spike.** Both ApEn and the wider entropy signals live in the same probe (`spikes/input-entropy/demo.html`). No separate integration needed.

---

## Why we keep the directory

- The probe `demo.html` works correctly — it was the test runner (`test.py`) that had the bug
- `input-entropy` is the umbrella; `apen-mouse` is the narrower prototype
- Closing this spike prevents re-discovery of the same signal in future nightly findings

---

## Files

- `demo.html` — ApEn collector (works correctly)
- `test.py` — dual-test runner (76 lines, had a `wait_for_selector` bug — fixed in input-entropy's version)

---

## Provenance

Validated in Round 1 (2026-06-23) per `spikes/VALIDATION-ROUND-1.md`. Initial "CDP discriminator" verdict was a test artifact; corrected during the same round. This per-spike file written 2026-06-27 to close the documentation gap.

**Superseded by:** `spikes/input-entropy/VALIDATION-RESULTS.md`