You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/process/continue-proof-of-human-202...

236 lines
14 KiB

# ProofOfHuman — handoff (2026-07-14, rev 2)
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
Anti-bot human-verification component, **re-architected** from a single
drag-to-target widget into an **orchestrator + pluggable challenges**. Three
challenge surfaces now ship: `PathTrace`, `RotateAlign` (compass skin) and
**`Clock` (the cuckoo-clock skin over the same RotateAlign engine) — landed
this session**. Read this top-to-bottom to resume cold.
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
## ⚠️ Concurrency warning — READ FIRST
Another Claude session is working on **palabras / words** in this SAME repo and
committing to the SAME branch (`alpha-0.1-sec-dom`) concurrently. The git index
(`.git/index`) is shared, so a plain `git add` … then `git commit` can be
clobbered mid-way (it happened: their `5b1e228a words(align)` reset my staged
index). **Mitigations:** stage + commit ATOMICALLY in one command
(`git reset && git add … && git commit … && git push`); never leave files staged
across tool calls; consider working on a separate branch. Never touch
`words/**`, `palabras/**`, `chronos/**`, `web/routes/alpha/**`, `rt.css`,
`src/uix/eidos/lib/recipes/base.ts` (chronos hunk) — stage explicit paths only.
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
## The architecture (shipped)
- **`ProofOfHuman` = orchestrator.** Interaction- and purpose-agnostic. Owns the
abstract **stages** (`idle → active → verifying → verified / failed`), the
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
evaluable **verdict** (`commit-confirm / fail / cancel`), live-region
announcements and the `onSolve(telemetry)` handoff. Network-agnostic (the app
verifies with a single-use server nonce and drives `status`). Per-stage
animation lives in consumer **slots** (`stageIdle … stageFailed`).
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
- **`ProofOfHumanChallengeHost`** — the context a challenge uses to report up:
`stage` · `locked` · `begin()` · `solve(telemetry)` · `cancel()`.
- **A challenge** = its own component + morfo, consumes
`ProofOfHumanProvider.require()`, produces telemetry, drives the lifecycle.
Swapping the challenge never touches the orchestrator. Each challenge is a
headless soma triplet (Provider + two parts) that eidos SKINS.
- **Telemetry** (`ProofOfHumanTelemetry`, in `soma/components/proof-of-human/types.ts`):
base motion fields + an optional per-challenge block — `pathAdherence?` (PathTrace)
or `rotation?` (RotateAlign). Add a new block for a new challenge kind.
## Shipped challenges
### PathTrace — follow a random curved path
- Follow a per-instance random Catmull-Rom curve (pointer OR arrow keys), staying
inside a tolerance corridor; progress advances ONLY in-corridor and
monotonically. Keyboard yields real signal → no free bypass; a two-key script
can't solve it. Skin: envelope token traced to a carrier pigeon.
- Files: `morfo/components/path-trace.ts`, `soma/components/path-trace/` (curve.ts
is pure geometry), `sema/components/path-trace.ts`,
`eidos/components/proof-of-human/path-trace.svelte` (+ `.css`).
### RotateAlign — rotate to a random bearing ← the clock's engine
- Rotate a needle onto a per-instance random bearing and HOLD it steady until it
settles (pointer OR arrow keys). Composes `Gesture.rotate()`. Settle-to-lock via
`uix.timers` (each move reschedules → a wiggle never locks, stillness locks).
Detent tick fires `handle-drag` every 30°. Telemetry: `rotation` block
(totalRotationDeg / maxAngularVelDegMs / overshootCount / finalErrorDeg /
settleMs). Unwrapped `visualAngle` drives the needle transform so a CSS
transition never spins the long way round the 360→0 seam.
- Knobs: `toleranceDeg` (8) · `settleMs` (450) · `stepDeg` (6) · `seed`.
- Files: `morfo/components/rotate-align.ts`, `soma/components/rotate-align/`,
`sema/components/rotate-align.ts`,
`eidos/components/proof-of-human/rotate-align.svelte` (+ `.css`).
- **Current skin = compass**: dial + ticks + N/E/S/O + a MAILBOX target (the
pigeon's destination) + a magnetically-settling needle. Exposed as
`ProofOfHuman.RotateAlign`.
### Demo
`web/routes/uix/components/proof-of-human/+page.svelte` — a challenge switcher
(PathTrace | RotateAlign), per-challenge controls, the carrier-pigeon narrative
over the stage slots, telemetry table (pathAdherence + rotation rows).
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
## Verified
- **Tests (server + real chromium): 25/25** — both morfos, both providers
(each: pointer AND arrow trace completes with real signal; a two-key script
can't solve; Escape cancels), curve geometry.
- **End-to-end in real Chrome** — both challenges reach `verified` from a genuine
solve; incomplete/trivial attempts don't; `difficulty` visibly reshapes the
PathTrace curve; the compass renders + the needle settles.
- Type-check clean across the component; `component:audit` PASS (the two harness
false positives D-1.5/D-4.3 are documented in the eidos README).
## SHIPPED this session: the CLOCK skin (cuckoo)
Built exactly to the locked mockup spec below. What landed:
- **`eidos/components/proof-of-human/clock.svelte` + `clock.css`** — composes the
SAME soma parts (`RotateAlign.Provider/Dial/Needle`); exported as
`ProofOfHuman.Clock` (+ `ClockProps` in `types.ts`, mirroring `RotateAlignProps`).
`clock.svelte` imports `rotate-align.css` too (shared skin box + needle behavior).
- **One engine knob added** (declared deviation from "engine unchanged" — the
design needs hour-aligned targets): soma `RotateAlignProviderProps.targetSnapDeg?`
quantizes the random bearing (`buildTarget`). The Clock passes 30 → 12 possible
hours; a free bearing would miss the marked hour by up to 15° > the 8° tolerance
~47% of the time. Unit-tested (`% 30 === 0` across seeds + random).
- **Face**: ring + 11 hour ticks (12 = the house) + numbers at 3/6/9 + a
**target-hour badge** (accent circle + number, `--color-content-on-solid` text)
at r=68; the badge REPLACES the 3/6/9 numeral when it lands there; hour 12
special-cases to under the sill (y=58). Hand = tapered pointer with
counterweight and hub (content-primary), tip r=58 meeting the badge edge.
- **Cuckoo sequence** (all CSS in `clock.css`, keyed on
`[data-proof-of-human][data-state='verified']`, every `@keyframes` annotated
`/* functional: */` per R-4.5): doors swing ±118° (0.5s) → pigeon (FRONT-ON:
two eyes, beak down holding the letter) rises to peek — one 3.4s keyframe
timeline (wait 13% → peek 26% → hold 62% → fly 100%, per-segment easing via
`animation-timing-function` inside keyframes) — body stays occluded by a
`clipPath` whose bottom edge = the sill top (`$props.id()` for the clip id) →
wings appear + flap (`2.1s` delay = the 62% mark) and the bird rises, shrinks,
fades IN FRONT of the roof (pigeon drawn last). Reduced-motion: doors + peek
static, no flight. Pigeon palette = the demo bird's literal hexes (annotated
`literal:`); house/face = theme tokens; roof + badge flip to fulfill on verified.
- **Demo**: third chip (PathTrace | RotateAlign | Clock) reusing the rotate knobs;
clock-specific idle instruction; for the Clock the demo's success card is
DELAYED 3.3s (`proof-of-human:cuckoo` timer) so the cuckoo dispatch plays
uncovered, and the demo's corner stage-pigeon is suppressed in BOTH the
verifying and verified slots (the cuckoo IS the pigeon — user caught the
verifying one still showing).
## The original CLOCK spec (kept for reference)
The user's favourite skin. It reuses the RotateAlign engine unchanged — only the
visual is new. **The design is locked via a mockup** that went through several
iterations; reproduce it faithfully (the mockup is not visible in a new session,
so the spec is here).
### Concept
A cuckoo clock. "Set the clock to N" → the hand ticks to the hours (the RotateAlign
detents), and on settle the clock's little doors swing open and a **pigeon leans
out FRONT-ON with the letter in its beak, then flies off** (the cuckoo → a
messenger pigeon). This unifies the whole component's narrative: the compass
points to the mailbox, the clock dispatches the pigeon — one messenger.
### Mapping to the engine
- The needle = the clock HAND. `stepDeg` per arrow. `toleranceDeg`/`settleMs` as-is.
- The detents (every 30°) = the hours; the `handle-drag` tick per detent = the
clock ticking. Consider snapping the hand to whole hours in the skin.
- The target bearing (`Dial` snippet `targetAngle`) = the target HOUR
(`targetHour = round(targetAngle/30)`, 0→12). Mark it on the face.
- On the orchestrator `data-state='verified'` → run the cuckoo reaction.
### Visual + animation spec (from the mockup)
- **Face**: ring + 12 hour ticks + numbers at 3/6/9 (12 is replaced by the cuckoo
house). A target marker at the target hour.
- **Cuckoo house** at the TOP (12 o'clock): a little roof (triangle) over a dark
doorway interior, **two doors** (left/right) that SWING open, and a **sill** bar
in front. Doors swing via `transform-box: fill-box; transform-origin: left/right
center; transform: rotate(±118deg)`.
- **The pigeon must be FRONT-FACING** (this was the sticking point — a side-profile
bird was rejected twice). Head-on: a round head with TWO eyes, a small beak
pointing DOWN holding a little envelope, an oval body, and two wings that are
hidden until flight.
- **Sequence on verified**: doors swing open (~0.5s) → pigeon **PEEKS** — head +
letter emerge ABOVE the sill while the body stays hidden BEHIND the sill
(occlusion: draw the pigeon before the sill; the sill bar sits in front of the
lower body) → hold ~0.8s → **FLY** — the wings appear + flap (rotate, alternate)
and the bird rises, shrinks and fades up-and-away (front-on flying-toward-you).
- **CRITICAL SVG gotcha (bit me 3×)**: an SVG element that carries a `transform`
attribute for positioning — CSS `transform` OVERRIDES it entirely (jumps to the
origin). Wrap it: OUTER group keeps the position (`transform="translate(x y)"`
attr), INNER group does the CSS animation (`transform-box: fill-box`). Same fix
the compass mailbox uses.
- Doctrine: the pigeon-fly is bespoke CONTENT animation (its own CSS/rAF via
`eidos.dom`/`eidos.timers`, like the demo pigeon), NOT an `--event` recipe
`@keyframes` (R-4.5). The verdict flourish itself is the generic `commit` motion
signature. Timers via `uix.timers`, never raw `setTimeout`.
### How it was built
All four steps above were executed as specced (the hand stays continuous — no
visual snap-to-hour: with `stepDeg` 6 a 30° visual quantum would kill the
feedback per press; the TARGET is what snaps). Verified end-to-end in real
Chrome: idle face, live door-swing/peek/fly frames (light + dark), telemetry →
`verified` from genuine arrow signal, `component:audit` PASS (144/144), tests
81/81 green across the poh scopes, type-check clean on touched files.
## Verification-env gotchas
feat(proof-of-human): re-architect to orchestrator + pluggable challenge (PathTrace) Split the anti-bot component into a purpose- and interaction-agnostic orchestrator that owns the lifecycle stages + verdict, and a pluggable challenge that runs the interaction and reports up via ProofOfHumanChallengeHost. The primary challenge, PathTrace, has the user follow a random curved path by pointer OR arrow keys. This fixes the drag version's two real defects: - keyboard bypass: the accessible path now yields genuine, non-replayable behavioural signal (pathAdherence over a per-instance random curve); a two-key script can't solve it. - over-coupled abstraction: interaction + animation are decoupled from the component identity (per-stage consumer slots; challenge is pluggable). Layers: - morfo: proof-of-human slimmed to orchestrator (Provider + 3 commits); new path-trace morfo (Provider + Track + Token; handle-*). - soma: orchestrator + ProofOfHumanChallengeHost; new path-trace (seeded Catmull-Rom curve, corridor-gated monotonic progress, adherence telemetry, pointer + arrow-key input). Old drag Token/Target wrappers retired. - sema: verdict commits (proof-of-human) + trace handle earcons (path-trace). - eidos: orchestrator + PathTrace that paints the curve/corridor/trail. - demo rebuilt: carrier-pigeon skin over the per-stage slots. Auto-focuses the token when the challenge is armed so the arrow keys start the trace immediately (gated on the disabled->enabled transition). Verified: 32/32 tests (incl. arrow trace completes with real signal + two-key script can't solve, in real chromium) + visual in real Chrome (curve, failed, verified; scorer rejects instant traces). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
- The in-app Browser pane / a backgrounded Chrome tab report `visibilityState:
hidden`, which **freezes rAF** → `dom.measure` never fires (PathTrace curve never
builds). A `computer` screenshot foregrounds the tab. RotateAlign has no rAF
dependency (target computed in the constructor).
- Background throttling also stretches `setTimeout` to ≥1s — a JS solve loop with
30ms waits blows the 45s CDP budget in a backgrounded tab. **Screenshot first
(foregrounds), then run the script**, ideally in ONE `browser_batch`.
- To FILM a one-shot CSS choreography: solve + zooms in the SAME `browser_batch`
(inter-call latency between separate tool calls eats a 3.4s window), or freeze
poses with a debug `<style>` override `animation: … paused !important;
animation-delay: -1.5s !important` (restart it via `animation: none` + reflow
first — redeclaring the same animation-name does NOT restart it).
- Screenshots on the in-app Browser pane hang; use the claude-in-chrome MCP (real
Chrome). Screenshot perms are per tab-group — a fresh tab may need re-grant.
- `form_input` (with a ref) triggers Svelte `bind:value`; coordinate-typing is
unreliable. Filling via the native value-setter + `input` event also works.
- Driving a trace from JS: precompute the input sequence (arrows / pointer deltas /
rotation) — the reactive DOM doesn't update synchronously inside a JS loop, so
read state BEFORE, compute the whole sequence, dispatch. Add real waits so
`durationMs > 150` passes the demo's `auto` scorer.
- Dev server: `npm run dev` (picks a free port; was on 5174). The Edit-hook may
warn that "another chat's dev server is running" — start your own if the Browser
tools can't reach it.
## Commits (alpha-0.1-sec-dom)
- `1f7018b9` re-architecture (orchestrator + PathTrace, 40 files)
- `f897bdb6` component:audit fixes · `e1b5dec8` / `139cc2b6` docs
- `e2a20b95` PathTrace pointer test
- `c4f5b080` **RotateAlign** (engine + compass skin + demo switcher + difficulty fix)
- (this session) **Clock** — cuckoo skin + `targetSnapDeg` + demo card delay +
eidos README challenge list.
## COMPONENT COMPLETE (2026-07-14, closing pass)
The documentation debt was cleared in the closing pass: soma `rotate-align`
README written (anti-bot core, parts, props incl. `targetSnapDeg`, keyboard,
telemetry `rotation` block, sema events, compass+clock skins); eidos README
links all three morfos/challenges; the demo's Live snippet, API tab, morfo tab
and Services tab now follow the SELECTED challenge (the two challenge morfos
share `handle-*` event names, so the sema panel/tables swap instead of merging
— merged lists would collide on keyed `{#each}`). The soma orchestrator README
also gained **"Adding a new challenge"** — the 8-step recipe (morfo → langs →
soma provider → telemetry block → sema pack → eidos skin → tests → demo+gates)
with the non-negotiable invariants, distilled from how RotateAlign/Clock were
actually built.
## Still open / deferred (not blocking, out of component scope)
- Foreign blocker: `morfo:check` / `perm:check` / `morfo:vocabulary` crash repo-wide
on `text-blur.ts` (task_05ed143d) — not ours; tests + browser cover the smoke.
- Future (v2 roadmap): more challenges (hold-to-confirm, audio/cognitive for
non-motor a11y); server-driven difficulty by risk score.

Powered by TurnKey Linux.