The previous DOM consolidation commit left a wrong-direction edge —
`src/uix/morfo/runtime.svelte.ts` imported `createAttrs` from
`$soma/attrs` and `attachRef`/`RefAttachment` from `$soma/provider`.
Morfo is the declaration layer; soma is one of its consumers; morfo
must not depend on soma.
Moves:
- `createAttrs` (`src/uix/soma/attrs/create-attrs.ts`) →
`src/uix/morfo/create-attrs.ts`. It's a pure morfo→data-attr-name
derivation; its natural home is alongside the morfo declarations it
derives from. Soma is a consumer like any other.
- `contracts.ts` (registerContract / assertContract / getContract)
→ `src/uix/morfo/contracts.ts`. Same reasoning: contracts derive
from a morfo's `data: [{ values }]` enum.
- `attachRef` + `RefAttachment` (extracted from
`src/uix/soma/provider/provider.svelte.ts`) →
`src/libs/reactive/attach-ref.svelte.ts`. It bridges Svelte's
`{@attach}` system with the `State` reactive box; both ends are in
libs/reactive, so it lives there.
- Bool/data-attr formatters from `src/uix/soma/attrs/helpers.ts`
(boolToStr, boolToEmptyStrOrUndef, boolToTrueOrUndef,
getDataOpenClosed, getDataChecked, getAriaChecked) →
`src/libs/dom/attrs.ts`. Pure DOM-attr value formatters with no
morfo dependency — they're libs/dom material.
Critical bug fix uncovered by the move:
`src/uix/soma/reactive/reactive.svelte.ts` was a parallel
implementation of the reactive primitive system, with its OWN
`ActiveSymbol` / `WritableSymbol` instances — different from the
ones in `$libs/reactive`. As soon as `attachRef` (now in libs)
tried to detect a soma-created `State` via `isState`, the guard
returned false and the function fell into the setter-fn branch,
throwing "ref is not a function" in 10+ form tests.
Fix: rewrite `soma/reactive/reactive.svelte.ts` as a thin re-export
of `$libs/reactive`. They now share the same symbol identities, so
every cross-layer guard works consistently.
Compatibility:
- `$soma/attrs` is now a backward-compat barrel that re-exports from
`$uix/morfo` (createAttrs, contracts) and `$libs/dom` (helpers).
Existing soma providers continue working unchanged.
- `$soma/provider/provider.svelte.ts` re-exports `attachRef` /
`RefAttachment` from libs for any importer that still uses the
legacy path.
Verified post-cleanup:
- `grep -r '$soma' src/uix/morfo` → 0 matches (no morfo→soma)
- `grep -r '$uix' src/libs` → 0 matches (no libs→uix)
- vitest 14 files / 197 tests
- smoke 68/68
- morfo-check 66/66