refactor(morfo): rename 12 events to {family}-{verb}-{variant} canonical shape (Capa 3 cluster otros)

Closes the last cluster of name-shape drift in the non-words morfos. 11
are pure cosmetic renames (declared verb already canonical); 1
includes a doctrinal correction.

Renames (verbo declarado canónico, solo el name):
- carousel.shift-slide                → shift-navigate-slide
- feed.shift-focus-item               → shift-navigate-focus-item
- feed.commit-load-more               → commit-submit-load-more
- file-upload.commit-add              → commit-set-add
- file-upload.signal-reject           → signal-warn-reject
- form.signal-invalid                 → signal-warn-invalid
- number-field.handle-scrub           → handle-drag-scrub
- range-calendar.commit-start         → commit-select-start
- range-calendar.commit-range         → commit-select-range
- tags-input.commit-add               → commit-set-add
- tags-input.signal-reject            → signal-warn-reject

Doctrinal correction:
- command.commit-invoke (declared submit + fulfill)
  → commit-submit-invoke + submit + AFFIRM (not fulfill)
  Per book cap. 22 §8 ("Error típico: contact.press + fulfill — esto
  hace que el sistema diga 'ya terminó' cuando solo ha empezado.
  Contact inicia. Commit resuelve."), the user submitting a command
  in the palette does NOT mean the command has completed. Same
  precedent as Button: celebrate-before-time is wrong. Affirm
  acknowledges the submission; the command's actual completion
  (success/failure) fires downstream from whichever morfo owns it.

Consumers updated:
- sema/components/{file-upload,form,number-field,tags-input}.ts
- soma/components/{file-upload,form,number-field,range-calendar,tags-input}/*.ts
- sema/resolver.test.ts (event name + data-event selector)

Verification:
- morfo:vocabulary: warns 19 → 7 (-12), the 7 remaining are all words.*
  (separate dev track, excluded). EXIT 0.
- vitest src/uix/sema src/uix/morfo: 195/195 pass

Doc src/docs/LIBRO_VARIACIONES_Y_EXTENSIONES.md C.3 marked RESUELTO
with full list of renames + the command intent correction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
dev 5 months ago
parent f3641347de
commit bbfefdb63d

@ -203,20 +203,23 @@ Hoy ~35 events siguen como warns en `morfo:vocabulary` porque el verbo declarado
- **Name**: `commit-unselect` se mantiene (el name ya parsea canónico ahora que `unselect` está en `SEMA_VERBS.commit`).
- **Para el libro**: añadir `unselect` a la lista de verbos canónicos de `commit` en Cap 23 §5. El par `select`/`unselect` es el natural sobre estado de selección de items.
### C.3 Otros nombres no canónicos (~19 events individuales)
Eventos con declaración canónica pero name no calza con `{family}-{verb}` (warns lint):
- `carousel.shift-slide` (declared `navigate`) — slide change, escala intra-componente
- `command.commit-invoke` (declared `submit`) — invocar comando del palette
- `file-upload.commit-add` (declared `set`) — añadir archivos
- `file-upload.signal-reject` (declared `warn`) — rechazar archivo inválido
- `form.signal-invalid` (declared `warn`) — validación fallida
- `number-field.handle-scrub` (declared `drag`) — gesto scrub del number field
- `range-calendar.commit-start` (declared `select`) — primer endpoint del rango
- `range-calendar.commit-range` (declared `select`) — rango completo
- (... y otros)
La mayoría son renames cosméticos. Pero algunos esconden preguntas doctrinales (¿es `command.commit-invoke` realmente `commit.submit` o `commit.select`?).
### C.3 Otros nombres no canónicos — RESUELTO
- **Status**: Cerrado 2026-05-25. 12 events renombrados a `{family}-{verb}-{variant}` canónico.
- **Renames mecánicos** (verbo declarado canónico, solo name):
- `carousel.shift-slide` → `shift-navigate-slide`
- `feed.shift-focus-item` → `shift-navigate-focus-item`
- `feed.commit-load-more` → `commit-submit-load-more`
- `file-upload.commit-add` → `commit-set-add`
- `file-upload.signal-reject` → `signal-warn-reject`
- `form.signal-invalid` → `signal-warn-invalid`
- `number-field.handle-scrub` → `handle-drag-scrub`
- `range-calendar.commit-start` → `commit-select-start`
- `range-calendar.commit-range` → `commit-select-range`
- `tags-input.commit-add` → `commit-set-add`
- `tags-input.signal-reject` → `signal-warn-reject`
- **Una corrección doctrinal**: `command.commit-invoke` (declared `submit + fulfill`) → `commit-submit-invoke + submit + affirm`. Cambio de intent: `fulfill` → `affirm` per Cap 22 §8 — el comando aún no se ha ejecutado al click, celebrar al click es antipatrón (mismo precedent que Button). Verb `submit` mantenido (el usuario envía su elección al sistema de comandos).
- **Consumers actualizados**: sema cascades + soma providers + resolver.test.ts.
---

@ -16,7 +16,9 @@ export const carouselMorfo = {
events: [
{
// Slide change — user-initiated (button/indicator) or auto-rotation.
name: 'shift-slide',
// Per book cap. 27 §5 shift.navigate ("Página A → página B"). Variant
// `slide` preserves the carousel-specific label.
name: 'shift-navigate-slide',
semantic: {
family: 'shift',
verb: 'navigate',

@ -12,12 +12,17 @@ export const commandMorfo = {
events: [
{
// User invoked a command (Enter on highlighted item or click).
name: 'commit-invoke',
// Per book cap. 23 `commit.submit` — the user submitted their choice
// to the command system. Intent `affirm` (not `fulfill`) per book
// cap. 22 §8 — the command's actual outcome (success / failure /
// completion) fires downstream; celebrating at the click is
// "celebrate before time". Same precedent as Button.
name: 'commit-submit-invoke',
semantic: {
family: 'commit',
verb: 'submit',
target: v.partRef('item'),
intent: 'fulfill',
intent: 'affirm',
sequence: 'post'
}
}

@ -12,8 +12,11 @@ export const feedMorfo = {
events: [
{
// User asked for more items (infinite scroll trigger / load-more
// button). Soma owns whether/when to actually fetch.
name: 'commit-load-more',
// button). Soma owns whether/when to actually fetch. Per book
// cap. 23 `commit.submit` — user submitted their request. The
// actual fetch is downstream (sustain.processing →
// commit.complete + affirm or commit.fail + risk).
name: 'commit-submit-load-more',
semantic: {
family: 'commit',
verb: 'submit',
@ -24,7 +27,8 @@ export const feedMorfo = {
},
{
// Item focused via keyboard navigation (j/k or Arrow keys).
name: 'shift-focus-item',
// Per book cap. 27 §5 `shift.navigate`.
name: 'shift-navigate-focus-item',
semantic: {
family: 'shift',
verb: 'navigate',

@ -23,7 +23,7 @@ export const fileUploadMorfo = {
}
},
{
name: 'commit-add',
name: 'commit-set-add',
semantic: {
family: 'commit',
verb: 'set',
@ -33,7 +33,7 @@ export const fileUploadMorfo = {
}
},
{
name: 'signal-reject',
name: 'signal-warn-reject',
semantic: {
family: 'signal',
verb: 'warn',

@ -22,7 +22,7 @@ export const formMorfo = {
}
},
{
name: 'signal-invalid',
name: 'signal-warn-invalid',
semantic: {
family: 'signal',
verb: 'warn',

@ -31,7 +31,7 @@ export const numberFieldMorfo = {
}
},
{
name: 'handle-scrub',
name: 'handle-drag-scrub',
semantic: {
family: 'handle',
verb: 'drag',

@ -14,7 +14,7 @@ export const rangeCalendarMorfo = {
},
events: [
{
name: 'commit-start',
name: 'commit-select-start',
semantic: {
family: 'commit',
verb: 'select',
@ -24,7 +24,7 @@ export const rangeCalendarMorfo = {
}
},
{
name: 'commit-range',
name: 'commit-select-range',
semantic: {
family: 'commit',
verb: 'select',

@ -12,7 +12,7 @@ export const tagsInputMorfo = {
},
events: [
{
name: 'commit-add',
name: 'commit-set-add',
semantic: {
family: 'commit',
verb: 'set',
@ -22,7 +22,7 @@ export const tagsInputMorfo = {
}
},
{
name: 'signal-reject',
name: 'signal-warn-reject',
semantic: {
family: 'signal',
verb: 'warn',

@ -21,12 +21,12 @@ export const fileUploadSema: Sema = {
haptic: { kind: 'tick' }
},
{
selector: onProvider({ eventName: 'commit-add' }),
selector: onProvider({ eventName: 'commit-set-add' }),
sound: soundTuning('form.commit.soft'),
haptic: { kind: 'success' }
},
{
selector: onProvider({ eventName: 'signal-reject' }),
selector: onProvider({ eventName: 'signal-warn-reject' }),
sound: soundTuning('form.commit.soft', {
contour: 'descending',
pitch: { op: 'add', value: -120 }

@ -18,7 +18,7 @@ export const formSema: Sema = {
haptic: { kind: 'success' }
},
{
selector: onProvider({ eventName: 'signal-invalid' }),
selector: onProvider({ eventName: 'signal-warn-invalid' }),
sound: sound('alert.error', { gain: 0.1 }),
haptic: { kind: 'warning' }
},

@ -32,7 +32,7 @@ export const numberFieldSema: Sema = {
haptic: { kind: 'tick', intensity: 0.18, duration: 6 }
},
{
selector: onScrubber({ eventName: 'handle-scrub' }),
selector: onScrubber({ eventName: 'handle-drag-scrub' }),
channels: ['haptic'],
haptic: { kind: 'tick', intensity: 0.08, duration: 4 }
}

@ -16,12 +16,12 @@ export const tagsInputSema: Sema = {
name: 'tags-input',
cascade: [
{
selector: onProvider({ eventName: 'commit-add' }),
selector: onProvider({ eventName: 'commit-set-add' }),
sound: soundTuning('form.commit.soft'),
haptic: { kind: 'success' }
},
{
selector: onInput({ eventName: 'signal-reject' }),
selector: onInput({ eventName: 'signal-warn-reject' }),
sound: soundTuning('form.commit.soft', {
contour: 'descending',
pitch: { op: 'add', value: -120 }

@ -386,12 +386,12 @@ describe('resolveSignature', () => {
it('file-upload rejection emits a risk warning cue', () => {
const target = makeMockTarget(
(sel) =>
sel === '[data-file-upload][data-event="signal-reject"]' || sel === '[data-file-upload]'
sel === '[data-file-upload][data-event="signal-warn-reject"]' || sel === '[data-file-upload]'
);
const eff = resolveSignature(
{
target,
name: 'signal-reject',
name: 'signal-warn-reject',
family: 'signal',
intent: 'risk'
},
@ -406,13 +406,13 @@ describe('resolveSignature', () => {
it('tags-input rejection emits a risk warning cue on the input', () => {
const target = makeMockTarget(
(sel) =>
sel === '[data-tags-input-input][data-event="signal-reject"]' ||
sel === '[data-tags-input-input][data-event="signal-warn-reject"]' ||
sel === '[data-tags-input-input]'
);
const eff = resolveSignature(
{
target,
name: 'signal-reject',
name: 'signal-warn-reject',
family: 'signal',
intent: 'risk'
},

@ -186,11 +186,11 @@ export class FileUploadProvider {
const next = this.opts.multiple.current ? [...current, ...toAdd] : toAdd;
this.opts.files.current = next;
this.opts.onFilesChange.current?.(next);
void this.runtime.trigger('commit-add', target ? { fallbackTarget: target } : undefined);
void this.runtime.trigger('commit-set-add', target ? { fallbackTarget: target } : undefined);
}
if (rejected.length > 0) {
this.opts.onReject.current?.(rejected);
void this.runtime.trigger('signal-reject', target ? { fallbackTarget: target } : undefined);
void this.runtime.trigger('signal-warn-reject', target ? { fallbackTarget: target } : undefined);
}
}

@ -124,7 +124,7 @@ export class FormProvider<TForm extends Form = Form> {
const target = this.opts.ref?.current;
if (!ok) {
void this.runtime.trigger(
'signal-invalid',
'signal-warn-invalid',
target ? { fallbackTarget: target } : undefined
);
this.focusFirstInvalid();

@ -827,7 +827,7 @@ export class NumberFieldScrubberProvider {
}
e.preventDefault();
void this.provider.runtime.trigger('handle-scrub', {
void this.provider.runtime.trigger('handle-drag-scrub', {
fallbackTarget: e.currentTarget as HTMLElement
});

@ -400,7 +400,7 @@ export class RangeCalendarProvider {
this.anchor = date;
this.previewDate = undefined;
this.opts.value.current = { start: date, end: undefined };
void this.runtime.trigger('commit-start', target ? { fallbackTarget: target } : undefined);
void this.runtime.trigger('commit-select-start', target ? { fallbackTarget: target } : undefined);
}
private clearSelection(target?: HTMLElement): void {
@ -456,7 +456,7 @@ export class RangeCalendarProvider {
this.opts.value.current = { start, end };
this.anchor = undefined;
this.previewDate = undefined;
void this.runtime.trigger('commit-range', target ? { fallbackTarget: target } : undefined);
void this.runtime.trigger('commit-select-range', target ? { fallbackTarget: target } : undefined);
}
/** Called by Day on pointermove when the user is mid-range. */

@ -92,9 +92,9 @@ export class TagsInputProvider {
private emitAddResult(result: AddTagResult, target?: HTMLElement): void {
if (result === 'added') {
void this.runtime.trigger('commit-add', { fallbackTarget: target });
void this.runtime.trigger('commit-set-add', { fallbackTarget: target });
} else if (result === 'rejected') {
void this.runtime.trigger('signal-reject', {
void this.runtime.trigger('signal-warn-reject', {
fallbackTarget: target ?? this.inputRef.current ?? undefined
});
}
@ -180,12 +180,12 @@ export class TagsInputProvider {
if (added) {
this.opts.inputValue.current = '';
void this.runtime.trigger('commit-add', {
void this.runtime.trigger('commit-set-add', {
fallbackTarget: target ?? this.inputRef.current ?? undefined
});
}
if (rejected) {
void this.runtime.trigger('signal-reject', {
void this.runtime.trigger('signal-warn-reject', {
fallbackTarget: target ?? this.inputRef.current ?? undefined
});
}
@ -208,12 +208,12 @@ export class TagsInputProvider {
}
this.opts.inputValue.current = remaining;
if (added) {
void this.runtime.trigger('commit-add', {
void this.runtime.trigger('commit-set-add', {
fallbackTarget: target ?? this.inputRef.current ?? undefined
});
}
if (rejected) {
void this.runtime.trigger('signal-reject', {
void this.runtime.trigger('signal-warn-reject', {
fallbackTarget: target ?? this.inputRef.current ?? undefined
});
}

Loading…
Cancel
Save

Powered by TurnKey Linux.