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/CANON.md

366 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: UIX Semantic Canon
type: canon
audience: human + agent
authority: canonical — single source of truth for the semantic vocabulary
status: current
sources:
book: docs/Disenando_lo_que_ocurre_HOMOGENEIZADO.pdf ("Diseñando lo que ocurre", ed. homogeneizada 2026-07 — the earlier v2_3.md no longer exists)
code: src/uix/sema/verbs.ts, src/uix/sema/types.ts, src/uix/intent.ts, src/uix/sema/sema-map.ts, src/uix/morfo/types.ts
---
# UIX Semantic Canon
This is the **single source of truth** for the framework's semantic vocabulary:
the families, intents, verbs, the intent policy, the composition rules, and the
expression channels. It exists so the rest of the corpus **stops re-transcribing
the vocabulary** (which is how it silently drifted: "7 families" survived in
three docs after the canon moved to 8). Every other doc links here.
> **Need the concrete closed sets to build from** (every family's verbs and
> default hold, the intents, haptic kinds, part archetypes, palette scales,
> sizes, variants, shared strings)? They are spelled out — GENERATED from the
> code, so they never drift — in [`canon/vocabularies.md`](./canon/vocabularies.md).
> This file is the *doctrine*; that one is the *enumerated lists*.
Two anchors hold this canon honest:
- **The book** — `docs/Disenando_lo_que_ocurre_HOMOGENEIZADO.pdf` ("Diseñando
lo que ocurre", edición homogeneizada). The editorial source. Each entry
cites its chapter.
- **The code** — the runtime is the executable form. Concrete *values* (per-family
holds, channel signatures, the full verb lists with author extensions) live in
code and are **linked, not copied here**, on purpose. This doc fixes the
*doctrine*; the code fixes the *numbers*.
> Rule: if you need to state a family, an intent, a verb, or a composition rule
> in any other doc, **link this file** — do not paste a copy. A second copy is a
> future drift.
---
## 1. The canonical chain
Every perceptible event resolves through one chain (book ch. 11, §0; ch. 30):
```
event → family → verb / phase → evaluation (if any) → intent → expression channels → unified reading
```
The framework encodes this chain literally: **morfo declares** it, **soma
executes** it (`runtime.trigger`), **sema** carries the perceptual vocabulary and
dispatches channels, **eidos** materializes the visual channels. See
[architecture/active-architecture.md](./architecture/active-architecture.md) for the layer wiring;
this file is only the *vocabulary* that flows through it.
---
## 2. The 8 families
A family is **not** a component or an effect. It is *a recurring class of event
that answers one perceptual question* (book ch. 8, ch. 21). The eight are the
reduction of a wider exploratory set down to a minimal-yet-sufficient grammar
(book ch. 8 §1–3).
Canonical list: `SemaFamily` in [`src/uix/sema/types.ts`](../src/uix/sema/types.ts)
(`SemaValencedFamily | SemaTransitionalFamily`). Per-family base signature,
active channels and hold: `SEMA_MAP.families` in
[`src/uix/sema/sema-map.ts`](../src/uix/sema/sema-map.ts).
| Family | Perceptual question | Accepts intent | Book |
| --- | --- | --- | --- |
| `contact` | ¿el sistema ha sentido mi acción? | leve / anticipatory | ch. 22 |
| `commit` | ¿qué quedó fijado o tuvo consecuencia? | **fully** | ch. 23 |
| `signal` | ¿algo reclama mi atención? | **fully** | ch. 24 |
| `handle` | ¿estoy manipulando directamente este objeto? | only on `drop` | ch. 25 |
| `emerge` | ¿algo entró o salió del campo perceptivo? | normally no | ch. 26 |
| `shift` | ¿cambió el contexto / régimen? | normally no | ch. 27 |
| `sustain` | ¿esto sigue ocurriendo? | normally no | ch. 28 |
| `delegate` | ¿quién actúa ahora? | no by default | ch. 29 |
`contact`/`commit`/`signal`/`handle` are the **valenced** families;
`emerge`/`shift`/`sustain`/`delegate` are the **transitional** ones (book ch. 9).
That split is a *classification*; it no longer dictates the intent rule — the
policy (§4) does.
The perceptual question is a **demand on the expression**, not a label: a family
that fails to answer its own question has failed at the only thing it exists
for. `shift` is the case that proves it — its question IS the crossing, so a
`shift` nobody perceives crossing is the *shift invisible* of the antipattern
catalogue (ch. 34 §14), and it was exactly that here until 2026-08-11: it
sounded like a slide and did not slide (§8 rule 5; the sense it now travels in,
`data-event-direction`, in §9).
---
## 3. The 6 intents
An intent is the **evaluative modulation** of an evaluable event — a region of
the valence/activation space (Russell), **not** a color (book ch. 9 §6, ch. 10).
Canonical list: `INTENTS` in [`src/uix/intent.ts`](../src/uix/intent.ts) — owned
by UIX itself, not by a layer. Per-intent perceptual deltas: `SEMA_MAP.intents`
in [`sema-map.ts`](../src/uix/sema/sema-map.ts).
| Intent | Valence / activation | Reading | Book |
| --- | --- | --- | --- |
| `neutral` | low activation, no strong valence | notar sin tono | ch. 10 |
| `affirm` | positive, low activation | "todo va bien" (confirmación suave) | ch. 10 |
| `fulfill` | positive, mid-high activation | "objetivo cumplido" (resuelve tensión) | ch. 10 |
| `risk` | negative, moderate activation | "revisa esto" (corregible) | ch. 10 |
| `threat` | negative, high activation | "atiende ahora" (aún evitable) | ch. 10 |
| `loss` | negative, lower activation, posterior | "ya ocurrió" (consecuencia consumada) | ch. 10 |
Three distinctions the inherited semaphore (`success`/`warning`/`danger`/`info`)
collapses, and that this canon keeps apart (book ch. 10 §4):
- **`threat` ≠ `loss`** — threat convokes action *before* the consequence; loss
registers it *after*. They must not look/sound the same.
- **`affirm` ≠ `fulfill`** — soft confirmation vs resolution of a tension.
- **`info` is not an intent** — it is attentional salience → `signal.* + neutral`.
### Intent assignment — undo matrix and binary toggles (framework materialization, 2026-07-07)
Two assignment rules the catalog already practiced consistently. THIS section
is the canonical registry; they were canonized at the component-audit
checkpoint (verdicts C1/C3 — historical record in
[`audit/components/_veredictos.md`](./audit/components/_veredictos.md)):
- **The undo matrix.** Removing an item from a collection
(`commit.unselect`) = **`affirm`** — an active choice, as affirmative as
selecting it (calendar, select, combobox, grid-list, listbox). Un-marking a
binary (the uncheck direction of `commit.toggle`) = **`neutral`**.
Abandoning or clearing (`commit.reset`, `commit.cancel`) = **`neutral`**.
- **Binary toggles — two sanctioned models.** *Mark-done* semantics, where
the direction itself carries the evaluative load, use two static
directional events (checkbox: `commit-toggle-check` affirm /
`commit-toggle-uncheck` neutral). *Mode-switch* semantics, where the weight
depends on WHAT is being switched, use one event with
`intent: { fromProp: 'intent', default: 'neutral' }` so the consumer grades
it (switch, toggle, toggle-group). Choose by the question: does the ON
direction intrinsically mean progress/agreement? → static directional.
Does context decide? → `fromProp`.
---
## 4. Intent policy — `SEMA_FAMILY_POLICY`
Whether intent is *required* is set **per family by policy**, not by the
valenced/transitional split (book ch. 8 §6, ch. 9). Two independent axes, in
[`src/uix/sema/types.ts`](../src/uix/sema/types.ts) (`SEMA_FAMILY_POLICY`):
- **`intentRequirement`** (`'required' | 'optional' | 'forbidden'`) — the
compile-time gate. `'required'` (only `commit` and `signal`) → `intent` is
mandatory in `MorfoEventSemantic`. `'forbidden'` is reserved (no family uses
it today). Drives the `SemaEvent` / `MorfoEventSemantic` discriminated unions.
- **`intentGuidance`** (`'expected' | 'contextual' | 'discouraged'`) — doctrinal
hint, no type effect. `commit`/`signal` = `expected`; `contact` = `discouraged`
(book ch. 22 §11: *"el intent fuerte no debería vivir en el contacto"*); the
rest = `contextual`.
Runtime: `validateSemaEvent` throws when a `required` family is built without
intent.
---
## 5. The evaluable-vs-structural rule
> **The intent lives in the evaluable event (the message), not in the structural
> container (the frame).** (book ch. 9 — *"Qué eventos son mensaje y qué eventos
> son marco"*; restated in Appendix A.)
A modal that opens is `shift.enter-mode` (frame); the warning inside it is
`signal.warn + threat` (message). A spinner is `sustain.progress` (frame); the
failure after it is `commit.fail + risk` (message). Cargar el intent en el marco
es el antipatrón capital (book ch. 34 §5 "Modal rojo", §4 "todo lo que aparece es
alerta").
In the framework this is enforced declaratively: the event that *carries* the
intent declares it in its morfo `events[].semantic.intent`; the frame event does
not. The runtime never infers intent (book **Appendix A**: *"El intent no se
hereda implícitamente… El runtime no debe adivinar. La semántica debe estar
declarada."*). This is exactly the morfo → soma → sema → eidos contract.
---
## 6. Canonical verbs — `SEMA_VERBS`
Verbs concrete the action within a family (book ch. 8 §"niveles", ch. 22–29).
`morfo.events[].semantic.verb` MUST be in its family's set; `events[].name`
**declares the family** — `{family}-{verb}[-{nuance}]`, guaranteed by
`validateMorfo` — so sema / sound / haptic / eidos can subscribe transversally.
**Executable source of truth:** `SEMA_VERBS` in
[`src/uix/sema/verbs.ts`](../src/uix/sema/verbs.ts) — including the documented
author extensions (e.g. `commit.unselect`, `handle.zoom`, `signal.inform`),
tracked in [decisions/book-deviations.md](./decisions/book-deviations.md).
The book's base verbs, by family:
- `contact` (ch. 22): press · tap · activate · focus · trigger · release
- `commit` (ch. 23): select · toggle · save · submit · confirm · complete · fail · cancel · reset · discard · delete · restore · expire · acknowledge
- `signal` (ch. 24): announce · notify · warn · alert · emphasize · remind
- `handle` (ch. 25): pick · carry · drop · drag · resize · reorder · rotate · scroll
- `emerge` (ch. 26): present · dismiss · open · close · expand · collapse · reveal · hide
- `shift` (ch. 27): enter-mode · exit-mode · navigate · route · step · return · context
- `sustain` (ch. 28): start · progress · loading · waiting · syncing · processing · streaming · pending · retrying · end
- `delegate` (ch. 29): offer · plan · authorize · act · review · escalate · return
Verbs that look like one family but belong to another (book canon): `select` /
`toggle` / `acknowledge` are `commit` (they fix state); `edit` is expressed as
`shift.enter-mode` (régimen change), not a `handle` verb.
---
## 7. Expression channels + the owner split
The book defines **8 expression channels** (book ch. 11–20): tiempo · motion ·
presencia · profundidad · forma · color · sonido · háptica. *"El color expresa el
intent, no lo define"* (ch. 16); *"ningún canal agota la semántica"* — robustness
= a reading that survives the loss of a channel (ch. 19, ch. 33).
The framework **splits these channels by owner** (decision recorded in
[decisions/book-deviations.md](./decisions/book-deviations.md) D.8):
- **sema runtime channels** = `sound` + `haptic` only (the two in
`SemaChannelSignatures`), plus the projected `visual` meta-channel that stamps
`data-event-*` during the hold. `motion`/`color`/`presence`/`depth`/`shape`
were removed from sema.
- **eidos** materializes the visual channels (motion / presence / depth / shape /
color) by reacting in CSS to `data-event-*` + the morfo's state attrs.
**How each channel is AUTHORED** — the owner split says who materializes a
channel; this says what a component actually WRITES, which is the part authors
get wrong:
| Channel | The component writes | Where the values live |
| --- | --- | --- |
| visual (motion / color / presence / depth / shape) | nothing — it declares the EVENT; eidos reacts in CSS to `data-event-*` | eidos recipes + the token engines |
| `sound` | **one NAME**, and only when it differs from its family's default | `SEMA_MAP.sounds` — the sound pack |
| `haptic` | a categorical `kind` (`tick` / `tap` / `pulse` / `success` / …) | `HapticChannel` maps kinds to patterns |
The rule is the same in all three rows and it is the point: **a component says
WHAT occurs, never how loud, how bright or how long.**
**And the intent SELECTS; it does not modulate.** Resolution is two lookups —
`pack[name.intent]`, then `pack[name]`, then silence. A `threat` is not a
`tick` with more roughness: it is `tick.threat`, another sound, designed whole.
Where a pack ships no variant for an intent, the intent is simply ignored and
the base sounds. That is deliberate: we recognise SOUNDS, not displacements of
a parameter, and a system that bends one tone produces variants that differ on
paper and are the same to the ear.
The name itself usually comes from the map, not from the component:
`SEMA_MAP.families[f].sounds` is keyed by the event's canonical VERB, so an
`emerge` + `close` finds `close` with nothing written anywhere. A component
writes a name only when it DIFFERS.
Adding a sound means **adding a NAME to the pack**, never widening a rule.
Detail in [architecture/sema.md](./architecture/sema.md); what a recording can
and cannot carry (the intent only moves its LEVEL — physics, not policy) in
[decisions/book-deviations.md](./decisions/book-deviations.md) D.7, retired but
kept for that measurement.
So the book's 8 channels are conceptual; at runtime they are owned by different
layers. `hold` (the registration FLOOR — a minimum, never a ceiling: the
expression completes before unstamping, capped only by the channel's
engineering guard) resolves per family + intent from `SEMA_HOLDS_BY_INTENT`
([`holds.ts`](../src/uix/sema/holds.ts) — the single hold source since
2026-07-06; the duplicated per-family `SEMA_MAP` hold was removed) over the
`SEMA_DURATIONS` scale (glimpse / brief / settled / noticed / …). The ms are
the framework's MATERIALIZATION of the book's qualitative regions (cap. 32,
TABLA 32.1/32.2 — the book deliberately gives no numbers); see
[decisions/book-deviations.md](./decisions/book-deviations.md) D.12.
Persistence (lifecycle) is separate — `SignalPersistence` in
[`types.ts`](../src/uix/sema/types.ts) (book ch. 12 §6, ch. 4 §13: la huella
se declara).
---
## 8. Composition rules
Real interaction is a temporal composition of events, not one family (book ch. 30,
ch. 6 §13). The rules are derived from perceptual need, not decree (ch. 30 §3):
1. **contact precedes the result** when there is direct action (agency).
2. **sustain precedes commit** when there is a wait (continuity).
3. **threat precedes loss** — never `commit.delete + threat` (before/after the
consequence).
4. **emerge does not absorb the content's intent** — `emerge.open → signal.warn +
risk`, not `emerge.open + risk` (frame ≠ message).
5. **shift must orient** the context change (focus + title + landmark) — and it
must be PERCEIVED crossing it. A frame that swaps with nothing moving is the
*shift invisible* of the antipattern catalogue (ch. 34 §14): the user is
somewhere else and was never told they travelled. Until 2026-08-11 `shift`
was exactly that in this framework — it sounded (`slide`) and did not slide,
because `BUILTIN_SIGNATURES` had a FAMILY-keyed visual signature for
`contact`, `commit` and `delegate` and none for `shift` (`emerge` and
`signal` have theirs keyed by event name, so they were never mute). It has
one now, and it is directional:
see `data-event-direction` in §9.
6. **handle concentrates evaluation on the drop**, not the carry.
7. **every open process needs an exit** (commit / cancel / fail / persisted-warn).
On simultaneity, attentional dominance (ch. 30 §7): the evaluable event dominates
the structural; higher activation dominates lower; on a tie, the most recent.
---
## 9. Naming + the declarative layer
Name **events, not effects** (book ch. 36): `contact.press`, `commit.save +
affirm`, `signal.warn + risk` — never `redAlert`, `successToast`, `shakeError`.
The grammar is implemented as a **declarative layer above components, tokens and
patterns** (book Appendix A) — in UIX, the **morfo** map:
```
morfo declares → soma executes (runtime.trigger) → sema vocabulary + channels → eidos materializes (reads DOM)
```
Cross-layer vocabularies that anchor this:
- **Archetypes** — cross-component part classification, `ARCHETYPE_VOCABULARY` in
[`src/uix/morfo/types.ts`](../src/uix/morfo/types.ts), emitted as
`data-archetype`.
- **The `data-event-*` tokens** — the contact surface sema stamps and eidos reads
(see [architecture/sema](./architecture/sema.md)). Six: `data-event` ·
`-family` · `-intent` · `-direction` · `-phase` · `-id`.
- **Sense of traversal** — `data-event-direction`, `'forward' | 'backward'`
(`SemaDirection`). Two values because the event NAME already carries every
distinction a DECLARATION can make (`shift-enter-mode` ≠ `shift-exit-mode`);
what a name cannot carry is which way THIS occurrence went, since one
`shift-navigate` is the previous month and the next one is the following
month. So the sense is decided per emit, like `intent`, and like `intent` it
is optional — a route with no sense of its own (a month picked from a select)
stamps none, because an invented sense is worse than none. It is a SENSE, not
an axis: eidos maps it onto the inline axis, so `:dir(rtl)` flips it and no
layer above CSS knows about left or right.
---
## 10. Visual canon (sibling)
This file is the **semantic** canon. The **visual** canon — the Token Scope
Contract (`--{component}-*` public / `--_{component}-*` internal; never
`--eidos-*`/`--air-*`/`--terra-*`/`--soma-*`), the 9 color roles, the size scale,
and the variant vocabulary (`EIDOS_VARIANTS`) — lives in
[eidos/THEMING.md](./theming/reference.md) §4–7 and
[eidos/lib/types.ts](../src/uix/eidos/lib/types.ts). Variants are eidos canon, not
theme (THEMING §19): a theme re-tints what is perceptually fixed; it does not
invent families, intents or variants.
---
## Sources
- **Book** — [`docs/Disenando_lo_que_ocurre_FINAL.pdf`](./Disenando_lo_que_ocurre_FINAL.pdf)
(FINAL edition, 426 pp. — the canonical anchor, tracked in-repo; chapter map
in [`book-map.md`](./book-map.md)): families ch. 8 + 21–29 · intents
ch. 9–10 · channels ch. 11–20 · composition ch. 30 · matrices ch. 31 ·
ranges ch. 32 · accessibility ch. 19 + 33 · validation ch. 35 ·
theory→system ch. 36 · declarative layer Appendix A.
- **Code** — `verbs.ts` (`SEMA_VERBS`) · `types.ts` (`SemaFamily`,
`SEMA_FAMILY_POLICY`, `SignalPersistence`) · `intent.ts` (`INTENTS`) ·
`sema-map.ts` (`SEMA_MAP`) · `morfo/types.ts` (`ARCHETYPE_VOCABULARY`).
- **Deviations from the book** — [`decisions/book-deviations.md`](./decisions/book-deviations.md).

Powered by TurnKey Linux.