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

189 lines
9.2 KiB

feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
---
title: Canonical vocabularies (generated)
type: canon
audience: human + agent
authority: canonical — the closed sets, generated from the code consts
status: current
generated: npm run docs:vocabularies (do NOT edit by hand)
---
# Canonical vocabularies
> **Generated from the code — do not edit.** Run `npm run docs:vocabularies`
> to regenerate; `npm run docs:check` fails if this file drifts from the
> consts. This is the ONE place the closed sets are spelled out (the reason
> every other doc links here instead of copying a list that would go stale).
> When building a component you draw part archetypes, event families/verbs,
> intents and holds from exactly these sets (STUMBLES #1).
## Part archetypes (26)
The cross-component classification a `part` may declare
(`ARCHETYPE_VOCABULARY`, `src/uix/morfo/types.ts`). Omit it for a plain
display part that pulls no shared styling.
| Archetype | Role |
| --- | --- |
| `provider` | root context provider |
| `trigger` | activates an action or opens an overlay (button-like) |
| `field-trigger` | a field/input/select/combo trigger — NOT a button; owns the flush field-control treatment, never the generic button/popover chrome |
| `content` | primary content panel of an overlay or section |
| `overlay` | modal/dim backdrop behind content |
| `viewport` | scrollable / focusable container |
| `item` | list / tree / menu item |
| `option` | selectable option in a select-like list |
| `indicator` | visual progress / decorative state |
| `thumb` | draggable handle (slider, scroll, switch) |
| `track` | background of slider / scroll / progress |
| `label` | text label associated with a control |
| `title` | overlay or section title |
| `description` | secondary descriptive text |
| `close` | dismiss / close button |
| `action` | call-to-action button |
| `header` | section header (often above content) |
| `footer` | section footer (often below content) |
| `image` | `<img>`-based content |
| `fallback` | shown when primary content unavailable |
| `arrow` | pointer arrow (tooltip / popover) |
| `separator` | visual divider |
| `group` | grouping container for related items |
| `input` | form input element |
| `segment` | discrete sub-input (pin-input segment, OTP digit) |
| `preview` | file / link / data preview |
## Sema families (8) — default hold + persistence
Each event declares a `semantic.family`; the default perceptual hold and
persistence come from `SEMA_HOLDS_BY_INTENT` (`src/uix/sema/holds.ts`),
overridable per event. Named holds map to `SEMA_DURATIONS`.
| Family | Default hold | Persistence | Per-intent overrides |
| --- | --- | --- | --- |
| `contact` | 120ms (`glimpse`) | transient | — |
| `emerge` | 240ms (`brief`) | transient | — |
| `shift` | 600ms (`noticed`) | transient | — |
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress) Re-audit of the whole component catalog at pilot depth (91 fichas + the checkpoint verdicts in docs/audit/components/) and the executed fix packages. - P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 + API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d, component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts (role=application removed ×4, aria-selected off the Day, drp translationRef, field data-state prune, pin-input commit-set, media-player renames), 13 new sema packs + 12 morfos family-default → pack. - P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar); onValueCommit terminal-callback norm (pin-input/search/password/textarea + date/time/color-field add); typed validation reason + onInvalid (tags-input, css-field); index/onIndexChange (carousel); deselectable; openDelay/ groupSkipDelay; allowCustomValue; defaultValue prune. - P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel); touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual, 44 AAA). S6 (Field composition) + S8 (calendar-surface) pending. Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline); morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched components; per-component vitest suites green. Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md Excluded (broken by the N1 rename, left broken per user decision, not staged): words/**, palabras/**, chronos, web/routes/alpha/**. Reconciliation pending: the touch-rows ::before for checkbox/switch reverses changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed markers to a labeled-row/Field task — flagged for the user in the handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| `commit` | 240ms (`brief`) | transient | fulfill: 400ms/transient |
| `signal` | 240ms (`brief`) | transient | risk: 240ms/untilFix; threat: 240ms/untilAction; loss: 240ms/transient |
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| `handle` | 240ms (`brief`) | transient | — |
| `sustain` | 600ms (`noticed`) | stateBound | — |
| `delegate` | 600ms (`noticed`) | transient | — |
## Sema verbs, by family
The canonical verb set an event may use for each family (`SEMA_VERBS`,
`src/uix/sema/verbs.ts`). A `family.verb` pairing outside this is drift.
| Family | Verbs |
| --- | --- |
| `contact` | `press` · `tap` · `activate` · `focus` · `trigger` · `release` |
| `commit` | `select` · `unselect` · `toggle` · `save` · `submit` · `confirm` · `complete` · `fail` · `cancel` · `reset` · `discard` · `delete` · `restore` · `expire` · `acknowledge` · `apply` · `partial` · `block` · `move` · `set` · `remove` · `reorder` · `upload` |
| `signal` | `announce` · `notify` · `warn` · `alert` · `inform` · `emphasize` · `remind` |
| `handle` | `pick` · `carry` · `drop` · `drag` · `resize` · `reorder` · `rotate` · `scroll` · `zoom` |
| `emerge` | `present` · `dismiss` · `open` · `close` · `expand` · `collapse` · `reveal` · `hide` |
| `shift` | `enter-mode` · `exit-mode` · `navigate` · `route` · `step` · `return` · `context` |
| `sustain` | `start` · `progress` · `loading` · `waiting` · `syncing` · `processing` · `streaming` · `pending` · `retrying` · `upload` · `end` |
| `delegate` | `offer` · `plan` · `authorize` · `act` · `review` · `escalate` · `return` |
refactor(sema)!: el sonido se NOMBRA — un catalogo, una palabra por componente F1-F5 del PLAN-sound-names, por orden directa del autor. El componente dice UN NOMBRE y nada mas; si ese nombre es una receta sintetizada o un .wav no es asunto suyo. sound: { gain: {op:'add',value:-0.25}, -> sound: 'settle' centroid: {op:'add',value:2800}, decay: {op:'add',value:20} } EL CATALOGO (src/uix/sema/sound-names.ts) fusiona SOUND_LIBRARY y SOUND_TUNINGS en 16 nombres + SILENT: cinco niveles, cinco direcciones, cuatro caracteres, dos samples. Los nombres NO llevan familia delante y esa ley se retira POR SU MOTIVO: `{family}.{tail}` existia porque un tuning era un delta sobre una familia; un nombre es una base, y el mismo `soft` sirve a un commit y a un emerge porque la familia sigue poniendo su identidad debajo. EL REORDEN es la pieza que importa. Los packs corrian los ULTIMOS y en modo replace, asi que la eleccion del componente borraba el perfil evaluativo del intent — medido: un dialog con `threat` sonaba igual que uno neutro. Ahora el nombre se aplica sobre la base de familia y ANTES de los deltas de intent: base de familia -> EL NOMBRE -> intent -> evento -> app Con el nombre debajo, D.7 y S-07 dejan de PODER ocurrir. No se arreglan: se disuelven. `sound-names.test.ts` lo certifica para los 16 nombres, no para los 3 packs que un guard anterior muestreaba. LA PUERTA es el tipo: `Sema['cascade'].sound` acepta un nombre o SILENT. Al estrecharlo, el compilador enumero la migracion entera — 173 errores en 70 de los 71 packs — y ninguno podia colarse. `SemaCascadeRule` se queda abierto a proposito: `overrides.cascade` es la puerta de personalizacion de la app, y una app puede legitimamente autorar un sonido que el catalogo no lleva. El framework se aplica a si mismo la regla estricta. MEDIDO ANTES DE TOCAR NADA: 214 reglas autoraban 33 firmas distintas; 92 (43%) no decian mas que un volumen; 69 pisaban el `contour` del intent y no podian hacer otra cosa (es un enum, solo admite reemplazo); 5 packs llevaban un `centroid +2800` copiado que dejaba su commit en 4600 Hz — mas brillante que `signal`, la familia mas brillante del mapa— porque era el residuo aritmetico de un sample borrado (4600-1800). Las colapsaciones de firma van una a una en PLAN §5.1 con su consecuencia audible; cada una se revierte editando UNA linea. La unica grande es deliberada: navegar un calendario sonaba a gain 0.18, el valor mas alto de todo el sistema —mas que una alerta—, residuo de una de las diez cabezas de tuning que mentian (S-39). Ahora es `soft.rise`. GUARDS: `sounds-grammar.test.ts` deja de vigilar una gramatica que ya no existe y pasa a vigilar que ningun pack AUTORE (censo sobre las fuentes, con los comentarios fuera — la prosa que menciona la forma vieja no es la forma vieja, y escanear texto crudo marco cinco doc blocks). El invariante 3 del censo de packs pasa de «la cabeza del tuning no miente» a «el nombre existe». Bug propio cazado por su test: `namedSound` devolvia la entrada del catalogo POR REFERENCIA — una mutacion de un consumidor redefinia lo que un nombre significa para toda la sesion. VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline exacto · docs:check 0/618 · suite completa 7 fallos frente a 8 de la base sin mis cambios (los 6 de contracts.test son ajenos y preexistentes). QUEDA F6: retirar D.7/S-07 con su motivo, reescribir sema.md §tunings y escribir el limite fisico del WAV (playSample solo lee sampleUrl y gain, luego sobre un .wav el intent solo mueve el volumen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Sounds (16)
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form. Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo. 1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05) switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack aplicaba un tuning que restaba exactamente el gain base de la familia commit (0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un silencio por defecto no se percibe como sobriedad sino como componente roto. Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de boton (contact base 0.25) para que un flip no pese mas que una activacion. Los deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El haptico ligero no cambia. Medido despues: switch pico 0.1. Conservan el silencio, con su justificacion intacta, solo los dos donde el silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce) y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio). 2) EMITIR SILENCIO YA NO CUESTA `SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning silenciador levantaba dos osciladores, un filtro y una envolvente programada para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual. Fijado con test propio, verificado en ROJO quitando el corto. 3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*, contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*— sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el 2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit llego a poner el nombre correcto —commit.select— en la linea que usaba la clave incorrecta. form.commit.soft -> commit.soft form.commit.subtle -> commit.subtle form.toggle.silent -> commit.silent tooltip.silent -> emerge.silent tabs.select.soft -> commit.select.soft 131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed recursivo habria corrompido en silencio. La cola queda LIBRE a proposito: media-player aplica el silenciador al commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico. Quedan tres silenciadores, uno por familia con base audible, con el mismo nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2). Eso convierte la coherencia en INVARIANTE: - `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma {family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard calculo solo el -0.4 esperado de signal. - Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que ya legislaba los nombres de EVENTO. - vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a enumerar los 14 afinados por familia; el generador los extrae del const y docs:check vigila su frescura. - D.5 gana las dos notas: el renombrado y la reversion del silencio. VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 · navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25 avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio. Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player, handoffs-claude-md y audit/components/date-field registran lo que ERA cierto. DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el type-check del repo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
refactor(sema)!: el sonido se NOMBRA — un catalogo, una palabra por componente F1-F5 del PLAN-sound-names, por orden directa del autor. El componente dice UN NOMBRE y nada mas; si ese nombre es una receta sintetizada o un .wav no es asunto suyo. sound: { gain: {op:'add',value:-0.25}, -> sound: 'settle' centroid: {op:'add',value:2800}, decay: {op:'add',value:20} } EL CATALOGO (src/uix/sema/sound-names.ts) fusiona SOUND_LIBRARY y SOUND_TUNINGS en 16 nombres + SILENT: cinco niveles, cinco direcciones, cuatro caracteres, dos samples. Los nombres NO llevan familia delante y esa ley se retira POR SU MOTIVO: `{family}.{tail}` existia porque un tuning era un delta sobre una familia; un nombre es una base, y el mismo `soft` sirve a un commit y a un emerge porque la familia sigue poniendo su identidad debajo. EL REORDEN es la pieza que importa. Los packs corrian los ULTIMOS y en modo replace, asi que la eleccion del componente borraba el perfil evaluativo del intent — medido: un dialog con `threat` sonaba igual que uno neutro. Ahora el nombre se aplica sobre la base de familia y ANTES de los deltas de intent: base de familia -> EL NOMBRE -> intent -> evento -> app Con el nombre debajo, D.7 y S-07 dejan de PODER ocurrir. No se arreglan: se disuelven. `sound-names.test.ts` lo certifica para los 16 nombres, no para los 3 packs que un guard anterior muestreaba. LA PUERTA es el tipo: `Sema['cascade'].sound` acepta un nombre o SILENT. Al estrecharlo, el compilador enumero la migracion entera — 173 errores en 70 de los 71 packs — y ninguno podia colarse. `SemaCascadeRule` se queda abierto a proposito: `overrides.cascade` es la puerta de personalizacion de la app, y una app puede legitimamente autorar un sonido que el catalogo no lleva. El framework se aplica a si mismo la regla estricta. MEDIDO ANTES DE TOCAR NADA: 214 reglas autoraban 33 firmas distintas; 92 (43%) no decian mas que un volumen; 69 pisaban el `contour` del intent y no podian hacer otra cosa (es un enum, solo admite reemplazo); 5 packs llevaban un `centroid +2800` copiado que dejaba su commit en 4600 Hz — mas brillante que `signal`, la familia mas brillante del mapa— porque era el residuo aritmetico de un sample borrado (4600-1800). Las colapsaciones de firma van una a una en PLAN §5.1 con su consecuencia audible; cada una se revierte editando UNA linea. La unica grande es deliberada: navegar un calendario sonaba a gain 0.18, el valor mas alto de todo el sistema —mas que una alerta—, residuo de una de las diez cabezas de tuning que mentian (S-39). Ahora es `soft.rise`. GUARDS: `sounds-grammar.test.ts` deja de vigilar una gramatica que ya no existe y pasa a vigilar que ningun pack AUTORE (censo sobre las fuentes, con los comentarios fuera — la prosa que menciona la forma vieja no es la forma vieja, y escanear texto crudo marco cinco doc blocks). El invariante 3 del censo de packs pasa de «la cabeza del tuning no miente» a «el nombre existe». Bug propio cazado por su test: `namedSound` devolvia la entrada del catalogo POR REFERENCIA — una mutacion de un consumidor redefinia lo que un nombre significa para toda la sesion. VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline exacto · docs:check 0/618 · suite completa 7 fallos frente a 8 de la base sin mis cambios (los 6 de contracts.test son ajenos y preexistentes). QUEDA F6: retirar D.7/S-07 con su motivo, reescribir sema.md §tunings y escribir el limite fisico del WAV (playSample solo lee sampleUrl y gain, luego sobre un .wav el intent solo mueve el volumen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
THE catalogue (`SOUNDS`, `src/uix/sema/sound-names.ts`). A component names
one of these and writes nothing else: the type of a pack rule accepts a name
or `SILENT`, and nothing more. Whether a name resolves to a synthesised
recipe or to a `.wav` is decided here, never at the component.
fix(sema): el silencio deja de ser una resta y pasa a ser un valor — SILENT Directiva del autor: «el silencio no admite verbos ni intents, es universal, por lo tanto es un valor canonico que cuando se le envia al canal semantico este simplemente lo ignora y no envia nada al soundengine». LO QUE ERA. `commit.silent`, `emerge.silent` y `contact.silent` no eran silencio: eran una RESTA del gain base de su familia (-0.3, -0.2, -0.25). Por eso hacian falta tres —cada una tenia que saber que base cancelaba— y por eso el silencio tenia familia, que es el absurdo que el autor senalo. Y un cero es un NUMERO, y las capas posteriores mueven numeros. LA MEDICION QUE LO CIERRA. Los deltas de intent suman RUGOSIDAD (`risk` +0.2, `threat` +0.4), lo que cruza el umbral del AM del motor; y el modulador se conecta al AudioParam de la envolvente —y conectar a un AudioParam SUMA, no multiplica—, asi que con la envolvente en cero el tremolo pasaba a ser la senal entera. Renderizado offline con el grafo real del motor: toggle "silenciado" neutral -77.0 dBFS (mudo de verdad) toggle "silenciado" risk -13.9 dBFS <- con gain declarado 0 toggle "silenciado" threat -6.7 dBFS boton normal, referencia -9.3 dBFS El "silencio" era mas fuerte que un boton, y lo que sonaba no era el earcon: era un zumbido sin ataque ni caida, cortado en seco. La medicion que yo mismo di por buena esta manana (0.0001) solo cubria el caso neutral. LO QUE ES AHORA. `SILENT` — un valor canonico exportado por `$uix/sema`. Se declara en el slice del canal y el RESOLVER lo honra retirando ese canal de la firma. Un solo mecanismo para todos los canales, y nada aguas abajo ve jamas un string donde espera una firma. Es la forma que el propio motor ya prescribia y se estaba saltando: «muting DROPS the channel rather than scaling to zero, because a `0` still buzzes» (engine.ts). - universal por construccion: ninguna familia, ningun verbo, ningun intent puede resucitarlo, porque no queda ningun numero que mover; - liftable solo por REEMPLAZO: declarar sonido es una decision, no un delta; - `SoundOverride` lo EXCLUYE por tipo — un afinado es un delta, nunca una ausencia. Migrado: tooltip (1) y media-player (6). Los tres tunings mueren del catalogo. GUARDS. `resolver.test.ts` fija las cuatro mitades del contrato (retira el canal · universal sobre 4 familias x 4 intents · vale igual para haptic · liftable por reemplazo), verificado en ROJO. `sounds-grammar.test.ts` cambia su invariante muerta por las dos que ahora importan: ninguna clave `*.silent`, y ningun afinado que deje su familia en `gain <= 0` — silencio disfrazado. Doctrina al dia: sema.md gana la seccion «Silence is a value, not a tuning» con la medicion; D.5 marca DEROGADA su solucion de mayo y registra el porque; vocabularies.md deja de enumerar silenciadores y explica donde vive el silencio. VERIFICADO: sema 211/211 · check 76 = la base 75 + 1 error del fichero huerfano `__adv-verify-haptic-dead.test.ts` que dejo un agente de la auditoria (sin trackear, no se borra sin instruccion) · docs:check 0/616 · navegador: el transporte del player EMITE (`contact-activate`, `commit-toggle-play`) y levanta CERO osciladores · prettier limpio (el unico aviso mio, resolver.ts, formateado: +17 lineas, sin ruido). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
refactor(sema)!: el sonido se NOMBRA — un catalogo, una palabra por componente F1-F5 del PLAN-sound-names, por orden directa del autor. El componente dice UN NOMBRE y nada mas; si ese nombre es una receta sintetizada o un .wav no es asunto suyo. sound: { gain: {op:'add',value:-0.25}, -> sound: 'settle' centroid: {op:'add',value:2800}, decay: {op:'add',value:20} } EL CATALOGO (src/uix/sema/sound-names.ts) fusiona SOUND_LIBRARY y SOUND_TUNINGS en 16 nombres + SILENT: cinco niveles, cinco direcciones, cuatro caracteres, dos samples. Los nombres NO llevan familia delante y esa ley se retira POR SU MOTIVO: `{family}.{tail}` existia porque un tuning era un delta sobre una familia; un nombre es una base, y el mismo `soft` sirve a un commit y a un emerge porque la familia sigue poniendo su identidad debajo. EL REORDEN es la pieza que importa. Los packs corrian los ULTIMOS y en modo replace, asi que la eleccion del componente borraba el perfil evaluativo del intent — medido: un dialog con `threat` sonaba igual que uno neutro. Ahora el nombre se aplica sobre la base de familia y ANTES de los deltas de intent: base de familia -> EL NOMBRE -> intent -> evento -> app Con el nombre debajo, D.7 y S-07 dejan de PODER ocurrir. No se arreglan: se disuelven. `sound-names.test.ts` lo certifica para los 16 nombres, no para los 3 packs que un guard anterior muestreaba. LA PUERTA es el tipo: `Sema['cascade'].sound` acepta un nombre o SILENT. Al estrecharlo, el compilador enumero la migracion entera — 173 errores en 70 de los 71 packs — y ninguno podia colarse. `SemaCascadeRule` se queda abierto a proposito: `overrides.cascade` es la puerta de personalizacion de la app, y una app puede legitimamente autorar un sonido que el catalogo no lleva. El framework se aplica a si mismo la regla estricta. MEDIDO ANTES DE TOCAR NADA: 214 reglas autoraban 33 firmas distintas; 92 (43%) no decian mas que un volumen; 69 pisaban el `contour` del intent y no podian hacer otra cosa (es un enum, solo admite reemplazo); 5 packs llevaban un `centroid +2800` copiado que dejaba su commit en 4600 Hz — mas brillante que `signal`, la familia mas brillante del mapa— porque era el residuo aritmetico de un sample borrado (4600-1800). Las colapsaciones de firma van una a una en PLAN §5.1 con su consecuencia audible; cada una se revierte editando UNA linea. La unica grande es deliberada: navegar un calendario sonaba a gain 0.18, el valor mas alto de todo el sistema —mas que una alerta—, residuo de una de las diez cabezas de tuning que mentian (S-39). Ahora es `soft.rise`. GUARDS: `sounds-grammar.test.ts` deja de vigilar una gramatica que ya no existe y pasa a vigilar que ningun pack AUTORE (censo sobre las fuentes, con los comentarios fuera — la prosa que menciona la forma vieja no es la forma vieja, y escanear texto crudo marco cinco doc blocks). El invariante 3 del censo de packs pasa de «la cabeza del tuning no miente» a «el nombre existe». Bug propio cazado por su test: `namedSound` devolvia la entrada del catalogo POR REFERENCIA — una mutacion de un consumidor redefinia lo que un nombre significa para toda la sesion. VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline exacto · docs:check 0/618 · suite completa 7 fallos frente a 8 de la base sin mis cambios (los 6 de contracts.test son ajenos y preexistentes). QUEDA F6: retirar D.7/S-07 con su motivo, reescribir sema.md §tunings y escribir el limite fisico del WAV (playSample solo lee sampleUrl y gain, luego sobre un .wav el intent solo mueve el volumen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
A name is applied over the family base and BEFORE the intent deltas, so the
evaluative profile always survives it — which is what makes the old D.7 / S-07
class of defect impossible rather than merely forbidden.
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form. Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo. 1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05) switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack aplicaba un tuning que restaba exactamente el gain base de la familia commit (0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un silencio por defecto no se percibe como sobriedad sino como componente roto. Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de boton (contact base 0.25) para que un flip no pese mas que una activacion. Los deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El haptico ligero no cambia. Medido despues: switch pico 0.1. Conservan el silencio, con su justificacion intacta, solo los dos donde el silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce) y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio). 2) EMITIR SILENCIO YA NO CUESTA `SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning silenciador levantaba dos osciladores, un filtro y una envolvente programada para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual. Fijado con test propio, verificado en ROJO quitando el corto. 3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*, contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*— sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el 2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit llego a poner el nombre correcto —commit.select— en la linea que usaba la clave incorrecta. form.commit.soft -> commit.soft form.commit.subtle -> commit.subtle form.toggle.silent -> commit.silent tooltip.silent -> emerge.silent tabs.select.soft -> commit.select.soft 131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed recursivo habria corrompido en silencio. La cola queda LIBRE a proposito: media-player aplica el silenciador al commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico. Quedan tres silenciadores, uno por familia con base audible, con el mismo nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2). Eso convierte la coherencia en INVARIANTE: - `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma {family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard calculo solo el -0.4 esperado de signal. - Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que ya legislaba los nombres de EVENTO. - vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a enumerar los 14 afinados por familia; el generador los extrae del const y docs:check vigila su frescura. - D.5 gana las dos notas: el renombrado y la reversion del silencio. VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 · navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25 avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio. Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player, handoffs-claude-md y audit/components/date-field registran lo que ERA cierto. DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el type-check del repo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
refactor(sema)!: el sonido se NOMBRA — un catalogo, una palabra por componente F1-F5 del PLAN-sound-names, por orden directa del autor. El componente dice UN NOMBRE y nada mas; si ese nombre es una receta sintetizada o un .wav no es asunto suyo. sound: { gain: {op:'add',value:-0.25}, -> sound: 'settle' centroid: {op:'add',value:2800}, decay: {op:'add',value:20} } EL CATALOGO (src/uix/sema/sound-names.ts) fusiona SOUND_LIBRARY y SOUND_TUNINGS en 16 nombres + SILENT: cinco niveles, cinco direcciones, cuatro caracteres, dos samples. Los nombres NO llevan familia delante y esa ley se retira POR SU MOTIVO: `{family}.{tail}` existia porque un tuning era un delta sobre una familia; un nombre es una base, y el mismo `soft` sirve a un commit y a un emerge porque la familia sigue poniendo su identidad debajo. EL REORDEN es la pieza que importa. Los packs corrian los ULTIMOS y en modo replace, asi que la eleccion del componente borraba el perfil evaluativo del intent — medido: un dialog con `threat` sonaba igual que uno neutro. Ahora el nombre se aplica sobre la base de familia y ANTES de los deltas de intent: base de familia -> EL NOMBRE -> intent -> evento -> app Con el nombre debajo, D.7 y S-07 dejan de PODER ocurrir. No se arreglan: se disuelven. `sound-names.test.ts` lo certifica para los 16 nombres, no para los 3 packs que un guard anterior muestreaba. LA PUERTA es el tipo: `Sema['cascade'].sound` acepta un nombre o SILENT. Al estrecharlo, el compilador enumero la migracion entera — 173 errores en 70 de los 71 packs — y ninguno podia colarse. `SemaCascadeRule` se queda abierto a proposito: `overrides.cascade` es la puerta de personalizacion de la app, y una app puede legitimamente autorar un sonido que el catalogo no lleva. El framework se aplica a si mismo la regla estricta. MEDIDO ANTES DE TOCAR NADA: 214 reglas autoraban 33 firmas distintas; 92 (43%) no decian mas que un volumen; 69 pisaban el `contour` del intent y no podian hacer otra cosa (es un enum, solo admite reemplazo); 5 packs llevaban un `centroid +2800` copiado que dejaba su commit en 4600 Hz — mas brillante que `signal`, la familia mas brillante del mapa— porque era el residuo aritmetico de un sample borrado (4600-1800). Las colapsaciones de firma van una a una en PLAN §5.1 con su consecuencia audible; cada una se revierte editando UNA linea. La unica grande es deliberada: navegar un calendario sonaba a gain 0.18, el valor mas alto de todo el sistema —mas que una alerta—, residuo de una de las diez cabezas de tuning que mentian (S-39). Ahora es `soft.rise`. GUARDS: `sounds-grammar.test.ts` deja de vigilar una gramatica que ya no existe y pasa a vigilar que ningun pack AUTORE (censo sobre las fuentes, con los comentarios fuera — la prosa que menciona la forma vieja no es la forma vieja, y escanear texto crudo marco cinco doc blocks). El invariante 3 del censo de packs pasa de «la cabeza del tuning no miente» a «el nombre existe». Bug propio cazado por su test: `namedSound` devolvia la entrada del catalogo POR REFERENCIA — una mutacion de un consumidor redefinia lo que un nombre significa para toda la sesion. VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline exacto · docs:check 0/618 · suite completa 7 fallos frente a 8 de la base sin mis cambios (los 6 de contracts.test son ajenos y preexistentes). QUEDA F6: retirar D.7/S-07 con su motivo, reescribir sema.md §tunings y escribir el limite fisico del WAV (playSample solo lee sampleUrl y gain, luego sobre un .wav el intent solo mueve el volumen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Silence is not a name: it is `SILENT`, one canonical value for the whole
system (`$uix/sema`). Declared on a channel slice, the resolver honours it by
dropping that channel.
refactor(sema)!: el sonido se ELIGE, no se modula — evento.intent = sonido Directiva del autor, sin matices: «todo el sistema de sonido es una puta mierda... la unica solucion es evento sonido, evento.intent = sonido, y punto y nada de mierdas de que si el intent modifica nada». Tenia razon, y lo que lo destapo fue oirlo: los dieciseis nombres del catalogo anterior sonaban practicamente igual. Medido despues: cinco de ellos eran LA MISMA nota de 700 Hz a cinco volumenes, y las variantes de direccion se separaban 20 Hz. El modelo de modulacion producia teoria bonita y mush audible. LA REGLA ENTERA, y no hay mas: nombre = per-emit ?? cascada ?? pack ?? morfo ?? familia[verbo] ?? familia.default sonido = pack[`${nombre}.${intent}`] ?? pack[nombre] ?? nada Dos busquedas. El intent SELECCIONA un sonido entero; si no existe la variante se desprecia y suena la base; si no hay base, silencio. Un `threat` no es un `tick` con mas aspereza: es otro sonido —mas grave, mas rasposo, descendente— y no se pueden confundir. EL TIER DEL VERBO es lo que vacia los packs. La tabla de familia se indexa por verbo (`emerge.close → 'close'`), asi que ni un solo overlay escribe su cierre. De ~165 reglas de sonido quedan 30, en 16 de los 71 packs — y las 135 borradas no decian mas que el defecto. Para que el verbo llegue, ahora VIAJA en la señal: se calculaba y se tiraba con un `void` (hallazgo S-40), el tipo prometia que se emitia y era falso. CATALOGO NUEVO: 10 bases + 6 variantes, cada una un sonido diseñado entero. Medido en el grafo de audio real: de 240 Hz (`tick.loss`) a 1900 Hz (`step`), casi tres octavas, y las variantes evaluativas traen su propio modulador de aspereza — texturas distintas, no un tono movido. 100% sintesis a proposito: el pack por defecto no lleva binarios, funciona sin red y no puede dar 404. Los .wav quedan como pack de EJEMPLO. EL GUARD QUE FALTABA: `distinguishability` exige que dos entradas se separen en al menos DOS ejes perceptuales. Nacio en rojo contra mi propio catalogo —ocho pares casi gemelos— y dirigio el diseño hasta separarlos. Una instantanea no lo habria cazado: cada valor era exactamente el que la tabla decia; lo que faltaba era una RELACION entre entradas. GESTOS POR REPETICION (idea del autor). Un arrastre ya emite a su ritmo, asi que toca `step` (18 ms) por emision: la velocidad del gesto ES la del trinquete, como una rueda fisica. Mueren los tres resolvers que sintetizaban tono desde posicion y velocidad —la ultima aritmetica del sistema— y `handle` queda EXENTA de la memoria de frecuencia, que si no estrangularia el trinquete al primer arrastre. Perdida firmada: el ritmo lleva la velocidad, pero la posicion ya no mapea a altura. NADIE ESCRIBE PARAMETROS, ni la app. `SemaSignatureOverride.sound` y `SemaCascadeRule.sound` aceptan un nombre o SILENT. La rendija de autoria inline «para la personalizacion» sobraba: un producto REGISTRA su sonido (nombre + definicion, una vez) y lo nombra. ⚠️ BUG PROPIO durante la cirugia: al reemplazar el bloque del sonido borre tambien la aplicacion de deltas de intent, y el HAPTICO dejo de recibirlos. Lo cazaron sus tests. Restaurado — el haptico sigue modulando porque su vocabulario es categorico y sus deltas cambian el KIND, que tambien es seleccion. MUERE: los deltas de sonido del intent, las bases de sonido de familia, la capa 1.5, `op:'add'` para sonido, `mergeSoundOverride`, y `d7-intent-survives.test.ts` — vigilaba una inversion que ya no puede existir. VERIFICADO: sema+morfo+soma+sound 1108/1108 · docs:check 0/618 · la pagina `/uix/docs/sound` reescrita y medida en navegador (commit+threat → tick.threat; commit+affirm → tick, el intent se desprecia; emerge+close → close sin una linea de pack; sustain → silencio). Los 7 fallos de la suite completa son los ajenos y preexistentes de contracts.test. ⚠️ NO SE HA OIDO. Todo esta medido en el grafo de audio, no con un oido. Si `open` suena a lo que debe sonar un panel abriendose es tu decision, y se afina en un fichero. ⚠️ El estudio `/temas/sema` compila pero edita firmas crudas: su modelo es el viejo. Queda por reconvertir. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`touch` · `step` · `tick` · `open` · `close` · `slide` · `alert` · `air` · `settle` · `snap` · `tick.fulfill` · `tick.risk` · `tick.threat` · `tick.loss` · `alert.risk` · `alert.threat`
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form. Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo. 1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05) switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack aplicaba un tuning que restaba exactamente el gain base de la familia commit (0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un silencio por defecto no se percibe como sobriedad sino como componente roto. Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de boton (contact base 0.25) para que un flip no pese mas que una activacion. Los deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El haptico ligero no cambia. Medido despues: switch pico 0.1. Conservan el silencio, con su justificacion intacta, solo los dos donde el silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce) y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio). 2) EMITIR SILENCIO YA NO CUESTA `SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning silenciador levantaba dos osciladores, un filtro y una envolvente programada para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual. Fijado con test propio, verificado en ROJO quitando el corto. 3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*, contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*— sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el 2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit llego a poner el nombre correcto —commit.select— en la linea que usaba la clave incorrecta. form.commit.soft -> commit.soft form.commit.subtle -> commit.subtle form.toggle.silent -> commit.silent tooltip.silent -> emerge.silent tabs.select.soft -> commit.select.soft 131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed recursivo habria corrompido en silencio. La cola queda LIBRE a proposito: media-player aplica el silenciador al commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico. Quedan tres silenciadores, uno por familia con base audible, con el mismo nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2). Eso convierte la coherencia en INVARIANTE: - `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma {family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard calculo solo el -0.4 esperado de signal. - Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que ya legislaba los nombres de EVENTO. - vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a enumerar los 14 afinados por familia; el generador los extrae del const y docs:check vigila su frescura. - D.5 gana las dos notas: el renombrado y la reversion del silencio. VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 · navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25 avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio. Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player, handoffs-claude-md y audit/components/date-field registran lo que ERA cierto. DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el type-check del repo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
## Intents (6)
The evaluative axis (`INTENTS`, `src/uix/intent.ts`). `commit` and `signal`
require one; the intent policy per family is `SEMA_FAMILY_POLICY`.
`neutral` · `affirm` · `fulfill` · `risk` · `threat` · `loss`
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho componentes y `emerge-open` en tres. No era estetica — un preset de movimiento engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna firma y simplemente no animaba, sin romper una sola prueba. Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos, 256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran 40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y `handle-drop` ya existian en 10 y 4 componentes. `validateMorfo` cierra la puerta: un `events[].name` que no empiece por su familia ahora lanza. Visto fallar antes con un nombre pelado inyectado. Lo que el renombrado destapo, y va aqui tambien: - La receta del splitter enganchaba `commit-resize`, muerto desde `bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el catalogo de morfos — el guard que lo habria cazado en su dia. - La familia `shift` era muda en el canal visual, contra su propia doctrina (c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora tiene firma direccional: sexto atributo del sello (`data-event-direction`, `forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por `:dir()`. Medido: LTR -30px/+30px, RTL los invierte. - El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues —media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze` moria sin pintar un fotograma. Una superficie, una ranura (A-36). - 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de decision, el componente vivo). Las docs desfasadas, corregidas; los nueve DEFECTOS de codigo obsoleto quedan abiertos y sin tocar. - `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y habia tres cosas distintas deletreadas «direction». check en su linea base con 0 errores nuevos por diferencia de conjuntos · docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador medidas con raton real y rAF vivo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Directions (2)
The sense of a traversal (`SEMA_DIRECTIONS`, `src/uix/sema/types.ts`),
projected as `data-event-direction`. Per emission like the intent, and
unlike it undeclarable on the EVENT: one `shift-navigate` is the previous
month and the next one is the following month, so only the caller knows
(`TriggerOptions.direction`). Optional — most occurrences have no sense to
declare, and an invented one is worse than none.
A SENSE, never an axis: eidos maps `forward` onto the inline end and
`backward` onto the inline start, so RTL flips through `:dir(rtl)` and
nothing upstream knows about it. Distinct from `SoundContour`
(`ascending` / `descending`, `src/uix/sema/sounds.ts`), which shapes a pitch,
and from `Morfo.direction`, which names the parts that carry the `dir` stamp
(the RTL contract — see `docs/canon/direction-contract.md`).
`forward` · `backward`
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
## Hold / perceptual durations
The named perceptual scale (`SEMA_DURATIONS`, `src/uix/sema/durations.ts`);
an event `hold` is a label from here or a raw ms number.
| Label | ms |
| --- | --- |
| `subliminal` | 50 |
| `glimpse` | 120 |
| `brief` | 240 |
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress) Re-audit of the whole component catalog at pilot depth (91 fichas + the checkpoint verdicts in docs/audit/components/) and the executed fix packages. - P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 + API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d, component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts (role=application removed ×4, aria-selected off the Day, drp translationRef, field data-state prune, pin-input commit-set, media-player renames), 13 new sema packs + 12 morfos family-default → pack. - P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar); onValueCommit terminal-callback norm (pin-input/search/password/textarea + date/time/color-field add); typed validation reason + onInvalid (tags-input, css-field); index/onIndexChange (carousel); deselectable; openDelay/ groupSkipDelay; allowCustomValue; defaultValue prune. - P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel); touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual, 44 AAA). S6 (Field composition) + S8 (calendar-surface) pending. Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline); morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched components; per-component vitest suites green. Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md Excluded (broken by the N1 rename, left broken per user decision, not staged): words/**, palabras/**, chronos, web/routes/alpha/**. Reconciliation pending: the touch-rows ::before for checkbox/switch reverses changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed markers to a labeled-row/Field task — flagged for the user in the handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| `settled` | 400 |
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| `noticed` | 600 |
| `insistent` | 1200 |
| `persistent` | 3000 |
## Haptic kinds (7)
The `kind` a `haptic` channel signature may use (`HapticSignature`,
`src/uix/sema/channels.ts`). Haptic is opt-in (`new EngineSemantic({ haptic: true })`).
`tick` · `tap` · `pulse` · `thud` · `success` · `warning` · `error`
## Palette scales (33)
The donor scales a component `color` prop accepts under `intent="neutral"`
(`PALETTE_SCALES`, `src/uix/eidos/lib/types.ts`) — the per-instance override
(`<X color="teal">`). NEVER hand-count this list.
`gray` · `slate` · `blue` · `cyan` · `teal` · `green` · `yellow` · `amber` · `orange` · `red` · `pink` · `purple` · `mauve` · `sage` · `olive` · `sand` · `tomato` · `ruby` · `crimson` · `plum` · `fuchsia` · `violet` · `iris` · `indigo` · `jade` · `grass` · `brown` · `sky` · `mint` · `lime` · `gold` · `bronze` · `steel`
## Sizes (8)
The size scale (`SIZES`; the physical primitives are `SIZE_PRIMITIVE_KEYS`,
`src/uix/eidos/lib/types.ts`). `full` is a layout semantic, not a physical
tier. Each component exposes the subset its recipe supports.
Physical: `xxs` · `xs` · `sm` · `md` · `lg` · `xl` · `xxl` · layout: `full`
## Variant archetypes
The canonical variant sets per archetype (`EIDOS_VARIANTS`,
`src/uix/eidos/lib/types.ts`). A component narrows to one set; component-only
values live in its own `types.ts`.
| Archetype | Variants |
| --- | --- |
| `control` | `surface` · `outline` · `ghost` |
| `selection` | `solid` · `outline` · `ghost` |
| `chip` | `soft` · `solid` · `outline` · `ghost` |
| `marker` | `solid` · `soft` · `outline` |
| `tabs` | `line` · `surface` · `pills` · `segmented` |
feat(morfo,soma,eidos): chronos deja de tener partes que el morfo no conoce C3 cierra con `more-link` y C4 con los seis marcadores que eidos estilizaba sin declaracion. Los tres botones sin fuentes (`day-add`, `edit-action`, `search-button`) comparten una clase; `undo`/`redo` se cablean sobre la del nav; `timegrid` pasa a `time-view` porque estaba a un guion de la parte `time-grid` que vive dentro; `peek-panel` y `day-peek` quedan como partes de display puro con marcador inline. Cada una renderiza un `<button>` real cuando el morfo lo declara: una `Region` que cae a `<div>` pondria el `type` declarado sobre un no-boton. La lupa deja de ser un adorno sin `onclick`: abre una paleta `Command.Dialog` sobre TODOS los eventos, no un filtro de la vista, con `goToDate` nuevo en el provider — la generalizacion de la que `goToday` era un caso particular. El texto buscable viaja en `keywords` porque el scorer de Command lee value + keywords y NUNCA los hijos renderizados, asi que se busca por titulo, por tipo y por fecha. Y tres etiquetas que mentian en silencio: `translationRef` / `commonRef` normalizan la clave LITERAL y no consultan ningun mapa, asi que `prevMonth` / `nextMonth` / `moreEvents` y `action.undo` / `action.redo` caian al fallback ingles en una pagina `es`. Corregidas contra el catalogo, con `common.buttons.undo` / `redo` anadidas. Verificado: check 74 = base (delta cero) · 458 vitest · docs:check 0/621 · rtl:check 0/177 · eidos-lint chronos morfo-backed 32 -> 44, invalid 0 · navegador limpio en las tres vistas, con el A/B del undo medido (18 jun -> drag -> 25 jun -> undo -> 18 jun -> redo -> 25 jun) y el salto de la paleta (noviembre -> elegir Retro -> junio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Shared strings (`common.*`, 40)
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
The shared idlangref leaves (`commonLangs`, `src/uix/langs/common.ts`),
reachable via `v.commonRef(...)` or `#?common.{path}|Fallback` — reuse these
instead of re-declaring a close/cancel/clear label per component.
feat(morfo,soma,eidos): chronos deja de tener partes que el morfo no conoce C3 cierra con `more-link` y C4 con los seis marcadores que eidos estilizaba sin declaracion. Los tres botones sin fuentes (`day-add`, `edit-action`, `search-button`) comparten una clase; `undo`/`redo` se cablean sobre la del nav; `timegrid` pasa a `time-view` porque estaba a un guion de la parte `time-grid` que vive dentro; `peek-panel` y `day-peek` quedan como partes de display puro con marcador inline. Cada una renderiza un `<button>` real cuando el morfo lo declara: una `Region` que cae a `<div>` pondria el `type` declarado sobre un no-boton. La lupa deja de ser un adorno sin `onclick`: abre una paleta `Command.Dialog` sobre TODOS los eventos, no un filtro de la vista, con `goToDate` nuevo en el provider — la generalizacion de la que `goToday` era un caso particular. El texto buscable viaja en `keywords` porque el scorer de Command lee value + keywords y NUNCA los hijos renderizados, asi que se busca por titulo, por tipo y por fecha. Y tres etiquetas que mentian en silencio: `translationRef` / `commonRef` normalizan la clave LITERAL y no consultan ningun mapa, asi que `prevMonth` / `nextMonth` / `moreEvents` y `action.undo` / `action.redo` caian al fallback ingles en una pagina `es`. Corregidas contra el catalogo, con `common.buttons.undo` / `redo` anadidas. Verificado: check 74 = base (delta cero) · 458 vitest · docs:check 0/621 · rtl:check 0/177 · eidos-lint chronos morfo-backed 32 -> 44, invalid 0 · navegador limpio en las tres vistas, con el A/B del undo medido (18 jun -> drag -> 25 jun -> undo -> 18 jun -> redo -> 25 jun) y el salto de la paleta (noviembre -> elegir Retro -> junio). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`buttons.cancel` · `buttons.clear` · `buttons.close` · `buttons.decrement` · `buttons.dismiss` · `buttons.edit` · `buttons.increment` · `buttons.next` · `buttons.prev` · `buttons.redo` · `buttons.remove` · `buttons.reset` · `buttons.save` · `buttons.submit` · `buttons.undo` · `calendar.prev-month` · `calendar.next-month` · `calendar.month-select` · `calendar.year-select` · `month-grid.prev-year` · `month-grid.next-year` · `year-grid.prev-page` · `year-grid.next-page` · `date.year` · `date.month` · `date.day` · `time.hour` · `time.minute` · `time.second` · `time.day-period` · `time.time-zone` · `time.am` · `time.pm` · `time.period.dawn` · `time.period.morning` · `time.period.afternoon` · `time.period.dusk` · `time.period.night` · `time.period.late-night` · `field.empty`
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1) An agent building a component from the docs-book alone could not assign archetypes / holds / haptic kinds: the closed sets live only in code consts and the corpus (correctly) forbids copying them into prose, so they were invisible from the docs. STUMBLES #1, the top stumble. Fix: docs/canon/vocabularies.md is GENERATED from the consts by 'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled out (generated = no drift objection), which every other doc links to. It covers part archetypes (with a one-line role each), sema families with their default hold/persistence + per-intent overrides, verbs by family, intents, the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes, variant archetypes, and the shared common.* strings. - scripts/docs-vocabularies.ts imports the consts (robust — no fragile JSDoc/regex parsing) and formats them; the generation is an exported function so docs-check can compare. - Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the authoritative one-liners the appendix reads — descriptions become first-class data instead of inline union JSDoc a tool would have to parse. - docs-check gains I7: it regenerates in-memory and fails if the committed file drifts from the consts (negative-tested: corrupt -> error, regen -> green). The appendix's own counts pass I1, so I1 doubles as a second guard. - Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md (doctrine here, enumerated lists there), architecture/morfo.md (pick a part's archetype), and the component-audit minimum-package list (STUMBLES #8). docs:check 0 errors; npm run check unchanged in my files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago

Powered by TurnKey Linux.