docs(process): hand-off — continue-with-stumbles-s2-s6 (verified S2/S3/S4 plans)

Continuation doc for tomorrow: full session state (C7 + eidos triage +
onion-menu/surface-subtle + functional flags + C10 reframe + S1
vocabularies), plus the three high-confidence implementation plans the
scope-stumbles-s2-s6 workflow verified against the real code (S3
part-absent condition, S2 continuous-components doctrine, S4
Gesture.rotate) with exact file:line edit maps. S5/S6 flagged for
re-scope. Foreign runed/tabbable WIP in the tree left untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
menubar-v4-safe
dev 3 months ago
parent 116594e063
commit 7f657ce6be

@ -0,0 +1,177 @@
# Continue with — STUMBLES S2–S6 + catalog coherence (hand-off 2026-07-03)
> **Kickoff for a new session**: *"Lee docs/process/continue-with-stumbles-s2-s6.md
> y continúa."* Everything below is verified against the code at commit
> `116594e0`. Working rules unchanged: respond in Castilian, docs/comments in
> English; NEVER touch `words/` `palabras/` `chronos/` `media-player` (foreign
> WIP); commit per batch, `git reset -q` + stage only your own files; commit
> messages via `-F file` (backticks in `-m` run command substitution — see the
> memory note). Each systemic fix ships its guard.
## Where things stand (verified)
- `component:audit`: **82 PASS / 48 NEEDS-WORK / 0 BROKEN**. The remaining
NEEDS-WORK is almost all **docs completeness** (E-2.3 missing README, F-1.x
sections) and **demos** (D-*, deferred to the web phase) — NOT functional.
- `npm run check`: ~**64–65 errors**, ALL pre-existing/foreign (heroscrolling +
animation demos, arts/connection, libs/reactive — the parallel runed/tabbable
port drifted the tree; my baseline earlier this session was 59). None in the
maintained catalog files I touched. Confirm with a stash-test if a number
moves: my changes were net-neutral-to-negative on the count.
- `npm run docs:check`: **0 errors, 11 warnings** (all foreign/known targets).
- `vitest src/uix/eidos`: **289/289 green** (the long-red suite was triaged).
- **Uncommitted foreign WIP in the tree** (do NOT commit): the runed/tabbable
0-dep port — `src/libs/dom/*`, `src/libs/reactive/index.ts`,
`src/arts/adom/index.ts`, `package-lock.json`, deleted `CONTINUE*.md` /
`src/audit-opus-4-6-26.md`. Another session owns these.
## Done this session (committed, on `alpha-0.1-sec-dom`)
- **C7 size-bundle** (`6001d9bb`, `e83ca6ea`): 34 recipes consume the bundle
coordinate; guard forbids the raw primitive; theming/notes size-canon row ⚠️→✅.
- **Eidos test triage** (`bbd9c467`): 15 long-red tests → 289/289. Real fixes
inside: pin-input readonly-bg declared, 5 dead tokens removed, time-picker
`size` clamped to PopoverSize (check 61→59).
- **onion-menu + surface-subtle bug** (`46d68ff2`): default export; and
`--color-surface-subtle` was a PHANTOM token → table/tree-grid headers
rendered with no background → repointed to `--color-surface-muted` (verified
in browser).
- **Functional flags + C10 reframe** (`730812c0`): 4 service E-2.2 exceptions
(format-date/number, relative-time, trans), alert-dialog R-1.1, card A-1.3.
**C10 reframed**: tier = audit verdict — stable=PASS (82), preview=NEEDS-WORK
on docs/demo only (~35, incl. mature button/table — a README gap is not
immaturity), experimental/WIP=real functional gap or foreign. C10 folds into
C8.
- **S1 — generated vocabularies appendix** (`116594e0`): `npm run docs:vocabularies`
→ `docs/canon/vocabularies.md` from the consts (STUMBLES #1). New
`ARCHETYPE_DESCRIPTIONS` in morfo/types.ts; docs-check I7 freshness guard
(negative-tested); linked from README/CANON/morfo/component-audit.
## NEXT — implement S2, S3, S4 from these VERIFIED plans
A read-only scoping workflow (`scope-stumbles-s2-s6`) mapped each against the
real code. S2/S3/S4 returned high-confidence plans (below). **S5 and S6 did the
research but did not emit a structured plan — re-scope them first** (relaunch
the workflow for just those two, or scope by hand; their prompts are in the
committed workflow script `…/workflows/scripts/scope-stumbles-s2-s6-*.js`).
### S3 — `part-absent` morfo condition (do first; cleanest, high-confidence)
The common ARIA pattern "aria-label only when there is no Label part" is not
declarable. Add the inverse of `part-present`. Four surgical edits + a test,
mirroring `part-present` exactly:
- `src/uix/morfo/types.ts` (MorfoCondition union, ~L169–175): add
`{ when: 'part-absent'; part: string }`; update the JSDoc.
- `src/uix/morfo/schema.ts` (conditionObjectSchema discriminated union,
~L143–153): add `object({ when: literal('part-absent'), part: string() })`.
The `checkCondition` part-reference validator (~L556–573) already covers it
(it doesn't discriminate) — no change there.
- `src/uix/morfo/compile.ts` (`collectConditionDeps`, ~L666–681): add the
`condition.when === 'part-absent'` branch → `partRefs.add(condition.part)`
(same as part-present).
- `src/uix/morfo/resolver.ts` (`shouldEmitMorfoEntry`, ~L39–50): add the branch
→ `return !Boolean(bindings.parts?.[condition.part])` (inverted part-present
at L44).
- Test (`compile.test.ts` / runtime test): schema accepts it; unknown-part
throws; compiler collects the dep; resolver returns the value when the part is
absent/falsy and `undefined` when present. Integration: a Dialog-like aria-label
gated on `{ when: 'part-absent', part: 'label' }`.
- **Risk**: semantics are "part not in bindings.parts OR falsy value" (not
strictly DOM-absent). Verify provider init populates the parts map for every
part (even optional-unrendered) so absence is unambiguous. Non-breaking (no
existing morfo uses it).
### S2 — "Continuous components" doctrine in `docs/architecture/sema.md`
Pure doc addition, grounded in the REAL Slider/Drawer code (verified answers to
the three open questions):
- **(a) turn hold**: `runtime.trigger()` returns a Promise that resolves AFTER
emit + the perceptual hold (`runtime.svelte.ts:742–749, 765–768`). `void
trigger()` = fire-and-forget; `await trigger()` blocks until the hold ends.
- **(b) sanctioned path**: ONLY `runtime.trigger()` — there is NO `emitEvent()`
in the codebase. Slider uses trigger exclusively (handle-pick L297, handle-drag
L263/322/330, commit-set L155); Drawer likewise (drag-start/progress/end
L661/645/679).
- **(c) throttling**: keyboard `commit-set` fires on EVERY keydown
(`SliderThumbProvider.onkeydown` L485–522) — no built-in throttle. Throttling
is drag-only, via rAF (Drawer `flushDragProgress` ~88ms L604/624–648; Slider
`queueHandleDrag` L244–260). The Slider sema cascade for handle-drag sets only
`channels:['sound','haptic']` and does NOT override pitch/gain, so per-emit
overrides stay the source of truth (`sema/components/slider.ts:30–32`).
- **Deliverable**: new `## Continuous components (drag, swipe, hold)` section
after "## The emit contract" (~L121) covering: sequence `coincident` vs `post`
(perceptual+structural indivisible vs commit-then-signal), route-through-trigger
doctrine, rAF throttling for continuous gestures, and "a cascade rule must not
override the primitives that per-emit values control". Slider = worked example.
Keep prose on the invariant ("what the Promise represents"), point to code for
tuning constants (don't hard-code ms). Verify with `docs:check`.
### S4 — `Gesture.rotate` layer (STUMBLES #3, the flagged gap)
New angular gesture layer mirroring the existing ones in
`src/uix/soma/layers/gesture/` (GestureBase → GestureDrag/GestureResize;
AxialDrag is the single-axis peer). Consumers: Knob, AngleSlider, hue ring,
clock dial.
- `layers/gesture/types.ts`: add `RotateState` (angleDelta°, angleAbsolute
0–360, angularVelocityDeg), `RotateReleaseState` (+snappedTo, dismissed),
`GestureRotateOpts` (extends GestureBaseOpts: `center` (`Active<{x,y}|'element'>`),
`referenceSize`, `direction?`, `snapPoints?`, `snapToSequential?`,
`dismissDegrees?`, `velocityThreshold?`, `wrap?=true`, onRotate/onRelease/
onDismiss/onSnapChange), `GestureRotateState`, `AngularSnap` (number = 0–1
fraction of 360 / >1 degrees / `'45deg'`/`'45°'`/`'50%'`).
- `layers/gesture/gesture.svelte.ts`: `GestureRotate extends GestureBase`.
Center detection (`'element'` → getBoundingClientRect center vs explicit
coords); angle via `atan2(dy,dx)` normalized [0,360); `unwrapDelta` for the
0/360 crossing (`|delta|>180 ? delta∓360`); velocity on the unit circle
(VelocityTracker, 100ms window / 50ms staleness — reuse the existing tracker);
override handlePointerDown/onMove/onRelease/onCancelled; `snapToAbsoluteDegrees`
+ `resolveSnapAt` with the sequential-neighbour guard (`|i-current|>1` blocked,
like AxialDrag). Export `Gesture.rotate(opts)` matching drag/resize.
- `layers/gesture/index.ts`: export the new types.
- Test (`gesture.test.ts`): center detection; angle unwrap across 0°/180°;
velocity (stationary/flick-capped/stale); snap (closest, sequential guard,
velocity projection); dismissal by absolute offset; single-pointer only.
- **Risks**: 0/360 unwrap correctness (normalize delta to [-180,180] before
distance in snap, esp. with wrap so 350°↔10° are adjacent); angular velocity
via unit-circle derivative underestimates at large radii; no CW/CCW direction
locking in v1 (defer). All dom listeners via `dom.listen` like the peers.
### S5 / S6 — re-scope, then implement
- **S5** (soma→eidos CSS-var contract, STUMBLES #7): the agent researched
`--drawer-progress`-style vars but didn't emit the plan. Re-scope to get 2–3
concrete options (e.g. a morfo `cssVars` declaration validated against provider
writes + eidos reads; or an eidos-lint cross-check of provider-written vs
recipe-consumed vars) with a recommendation. Design-open — get the tradeoffs
before implementing.
- **S6** (minor frictions): four doc notes to author from the real defs —
`state<T>()` vs `$state` (pass-by-ref vs local), `role` on a DOM-rendering
Provider (required vs omittable), `Without<>`/`PrimitiveDivAttributes`
definitions, gesture pointermove/up ownership. Land them in soma.md /
soma-architecture.md.
## After the S-series — remaining coherence plan
`docs/process/PLAN-component-coherence.md` is the master. Left:
- **C8** (heaviest): 28 missing READMEs (E-2.3) + incomplete F-1.x sections.
This is where the deferred exceptions land: announce/clipboard R-1.5
(live-region / composed-focus), natural-time-picker R-2.1 (fixed-tone sky) +
A-3.1, card/card-group/drag-drop/virtual-list. Write real Baseline/Comparativa/
Decisiones/Gaps (per-component reference research) — no skeletons.
- **C9**: motion eventful gap (which interactives should express an event
signature; criterion: high-frequency = sober, D.5).
- **Real gaps tracked, NOT silenced**: float-panel **A-3.7** (28 mutating
keyboard actions, 6 events — morfo-completeness question); **card-group** has
no morfo (morfo-first violation, `KNOWN_MISSING_MORFO` in lint.test.ts);
natural-time-picker **A-3.1**.
## Verify-before-done checklist (unchanged doctrine)
`npm run check` (compare to the drifting foreign baseline, not 59) · relevant
`vitest` scope · `component:audit --only {kebab}` per touched component ·
`npm run docs:check` after doc/vocab changes · browser check for anything
visual (Playwright from repo-root; the preview MCP is flaky — memory note).
Loading…
Cancel
Save

Powered by TurnKey Linux.