ZEROlobby
22/22 strict⌘Kvisitor
skip to main
ADR-036
skin
——:——:——zcovenant · audit
intent· @zero/intent · 8 observation kinds · 1 pure ranker · 0 telemetry

EARL, but the receipts never leave the tab

EARL — Early Action Recognition Layer — is the 2026 spec for anticipatory UI. the canonical implementations assume rich per-user telemetry. ZERO refuses that posture (article I.4). @zero/intent ships a pure ranker, an in-memory ring buffer, and a React provider that attaches passive listeners to window. nothing is persisted, nothing is identified, nothing is sent. the cost is honestly disclosed: lower accuracy than a telemetry-rich peer.

00 · livehover · focus · click · the EARL ranker scores in real time, telemetry-spare

see your own intent shape the ranking

intent · live· EARL engine · 64-event buffer · 32ms debounce · zero telemetry · article I.4buffer0 / 64
targets · hover · focus · clickeach one carries data-intent-target
ranking · top 5no observations yet · hover above
move your cursor over a target above

EARL ranking is local-only · the buffer is empty until the operator hovers.

empty
01 · contract8 anonymous observation kinds · no identifier, no device, no session

every observation is a tuple

plate · A · ObservationKind · the closed vocabulary8 kinds
metric
intent
unit
observations
window
static · fixture
agg
count
source
packages/intent/src/types.ts
fresh
last build
kindshapesignal weight
pointer-move tracking only · feeds decelerate detector
pointer-deceleratevelocity < 0.15 px/ms within 80 px of target+0.6
pointer-enter cursor crossed into a target's bounds +0.3 (most-recent only)
pointer-leave cursor crossed out · accumulates dwell
focus keyboard or programmatic focus on target +0.4
blur focus left target · semantic only
scroll future · viewport intent
keydown keyboard activity ending on target +0.2
why anonymous tuples and not user models
a per-user model needs a per-user identifier. an identifier is the first byte of telemetry, even if the rest never ships. ZERO's design refuses the byte. the engine sees what the window saw, ranks for as long as the tab lives, and forgets.
02 · rankerrank(observations, now) · pure · deterministic

the same input always produces the same ranking

plate · B · rank · output of the build-time fixturegenerated at 1715000000000
metric
intent
unit
observations
window
static · fixture
agg
count
source
packages/intent/src/engine.ts
fresh
last build
ranktargetscoresignals
01cta-floor100%focus-on-target · keydown-on-target · pointer-decelerate-near-target
02rail-skin30%most-recent-pointer-enter
plate · C · ranker rulescap 4 · floor 0.3 · window 1500ms
metric
intent
unit
observations
window
static · fixture
agg
count
source
packages/intent/src/engine.ts
fresh
last build
rulevaluerationale
HOVER_THRESHOLD_MS 220 matches the brand's --breath tier · sub-perceptual hover ignored
RECENT_WINDOW_MS 1500 1.5s · the operator's working memory window
SCORE_FLOOR 0.3 below this is noise; do not surface a prediction
RANKING_CAP 4 UI surfaces never need more than four predictions at once
tie-break alphasame-score targets sort by id · keeps output stable
03 · ring buffercapacity-bounded · drop-oldest · in-memory only

the buffer is the only state

plate · D · RingBuffer · snapshot of the fixturesize 7 / cap 8
metric
intent
unit
observations
window
static · fixture
agg
count
source
packages/intent/src/buffer.ts
fresh
last build
ikindtargetts (relative)
01pointer-entercta-spawn-1100ms
02pointer-leavecta-spawn-980ms
03pointer-entercta-floor-740ms
04pointer-deceleratecta-floor-420ms
05focuscta-floor-280ms
06keydowncta-floor-180ms
07pointer-enterrail-skin-120ms
why an explicit ring and not an array
an array grows. growth is a leak when the operator sits on a page for hours. a fixed-capacity ring is bounded by construction; the oldest observation drops first when the buffer is full. default capacity is 64; consumers can configure it via <IntentProvider capacity={N}>.
04 · article I.4telemetry-spare by design · the privacy article

lower accuracy is the price · stated honestly

this is not the EARL paper, and that's the point
the published EARL implementations assume per-user models trained on long horizon telemetry. they are more accurate than this engine. ZERO refuses that trade-off and states the cost: this ranker is short-horizon, anonymous, and occasionally wrong. it never gets better at the cost of an identifier.
plate · E · intent · privacy posturesigned
metric
intent
unit
observations
window
static · fixture
agg
count
source
article I.4 · CONSTITUTION.md
fresh
last build
posturevalue
per-user model none
identifier none
persistence none
cross-page memory none
third-party dependenciesnone
I/O at runtime none
local-onlyhonest◆ int001a