astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
44 Commits (468a9d1134d697546f1b36231d6773d6324a5faa)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
468a9d1134 |
style: prettier de una sola vez sobre el repositorio (F5 del cierre, parte 3)
Formato puro: `npm run format` (dos pases; siete ficheros no convergían en el primero) sobre todo lo que .prettierignore no excluye (web/ congelado, .claude/, artefactos generados). Este commit va en .git-blame-ignore-revs. Neutralidad medida fichero a fichero, compilando y minificando con esbuild (y con el compilador de Svelte, cliente y servidor, para .svelte) la versión de HEAD y la formateada: 1 031 ficheros de código idénticos; 9 CSS que solo difieren en espacios pegados a un paréntesis (`var( --x )` frente a `var(--x)`), que CSS no tokeniza como significativos; 510 Markdown sin compilación posible (docs:check los valida). Los dos generados y el guard que dependía del formato se resolvieron en el commit anterior. Verificación sobre este árbol: npm run lint exit 0 · gate entero verde salvo focus-census, arreglado en el commit anterior y re-ejecutado (9/9): check:gate OK (src/ y scripts/ a cero) · docs:check 0/0 · arts/blocks/packs/rtl/ translations/agent · eidos:lint 0 inválidos · apps:check (boot 27/27, 0 errores) · suite 465/466 → 466/466 con el guard corregido · build de la raíz exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
3 weeks ago |
|
|
29e581c721 |
feat(active-uix)!: el boot lo compila el build del SITIO con su propio esquema, y lo que UIX escribe en <html dir> lleva marca de propiedad (fila 2 del boot, F1 del cierre)
F1 del plan de cierre del framework. Cierra el último trabajo del eje boot.
EL DEFECTO. El boot por defecto compilaba un catálogo de preferencias de UN
solo idioma (createDefaultUixPrefsSchema), y la raíz sembraba su entorno
leyendo el <html dir> que el boot acababa de escribir: un usuario árabe de
una app multiidioma no veía un parpadeo, se quedaba en LTR TODA la sesión,
porque el runtime tomaba la salida del boot como si la hubiera declarado la
página.
EL COMPILADOR POR SITIO. Una sola fusión, composeUixPrefsSchema, la consumen
createActiveUix y el boot: no puede derivar. El generador acepta --schema y
--out (el especificador boot/boot-schema.ts apunta al esquema del sitio o a
boot/default-schema.ts); los guards (sin runas, techo de tamaño, ASCII, sin
</script, valores string por atributo) son errores del COMPILADOR con mensajes
para el consumidor, porque ahora el artefacto lo produce el sitio. Un esquema
que importa el barrel $prefs se rechaza nombrándolo. scripts/uix-boot-check.ts
es el guard de rancidez: plugin de Vite que tumba el build con un artefacto
viejo (probado con vite build real) y función para CI. Delta cero por esquema:
por defecto, multiidioma con árabe, ejes redefinidos y esquema parcial.
LA MARCA DE PROPIEDAD, diseño firmado por el autor. El canon de dirección dice
que <html dir> es una proyección y nunca una fuente, con una sola excepción: el
dir del AUTOR en la plantilla o el servidor. El boot rompió la premisa de esa
excepción. Todo lo que UIX escribe en <html dir> lleva ahora
PREFS_DIR_PROJECTED_ATTR (el boot con valor «boot», cada proyección del runtime
con un token de instancia); la semilla solo adopta un dir SIN marca. Un dir
escrito por script no es una fuente: en ejecución la dirección se afirma con
prefs.setIntent('direction') o options.prefs.environment, que ganan a la
semilla. Se descartaron, midiendo, la marca con valor (cierra el script y
congela la dirección al navegar entre layouts) y la inferencia por valor.
dispose solo retira lo que todavía es SUYO: SvelteKit crea la raíz del layout
nuevo ANTES de destruir la vieja (medido), y un retiro a ciegas dejaba el
<html> de la raíz nueva sin dir, lang ni data-motion/sound/haptic (medido hoy:
los nueve atributos a null). Mismo principio que el unstamp de sema, que
comprueba data-event-id.
esbuild se declara como devDependency EXACTA 0.27.4: los bytes del boot y su
hash dependen del minificador, y una subida dentro de un rango rompería la
sincronía. Boot 15 198 B, sha256-hsqdGYcrRu3oEc0Q3G/A67ApQT3q9c/vT9zMDgxROg8=
(el hash se mueve: firmado por el autor).
VERIFICACIÓN. Constructor Opus en cuatro rondas y adversarial Opus en dos
pasadas independientes, con sus reproducciones repetidas tras cada cierre:
en Chromium, entrar en árabe y pasar a inglés y a español sigue al idioma, y al
revés también; el dir de plantilla gana antes y después de hidratar y en una
raíz recreada; una raíz recreada sobre una viva sigue al idioma con y sin boot;
tras create b → destroy a, <html> conserva lo que proyectó b. Diez defectos
declarados por el adversarial, cerrados (D1–D10): marca de propiedad, esquema
parcial que estampaba "undefined", vigilante de dev mudo, plugin sin test,
receta de CI que no cargaba en jsdom, cifras y prosa, y un vite build real que
se cae cuando el boot no compila. Mutaciones en rojo, restauradas byte a byte:
la proyección no marca · dispose sin guard de dueño (también repetida por el
coordinador: 3 rojos) · la semilla compara valor en vez de presencia · marcar
el dir del autor. Suite entera 463 ficheros / 5 437 tests, exit 0 · check 0 errores en src/ y en scripts/ (89 en web/, ledger intacto) ·
docs:check 0/0 · generate:boot dos veces byte-idéntico.
LO QUE NO CIERRA (al ledger de cierre): (1) PREEXISTENTE — en la misma
navegación entre layouts, el ActiveEidos.dispose de la raíz vieja sigue
retirando data-theme/mode/density/scaling de la raíz nueva; exige cambiar el
dispose de eidos, otra capa. (2) La propiedad de los atributos proyectados
cuelga de la marca de dir: si la plantilla declara la dirección, dispose deja
lang y data-motion puestos cuando la raíz se desmonta sin sustituta
(benigno). (3) Sin boot, un script que escribe dir antes de la primera raíz es
indistinguible de la plantilla y se adopta. (4) El vigilante de dev no
reacciona a ficheros nuevos ni a inputs fuera del root.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
3 weeks ago |
|
|
f1f686d097 |
feat(theming)!: SS16 - el guard vive donde NACE el valor, y el velo del drawer vuelve a pintar
Firma SS16, quinta aplicacion de la doctrina "la capa sostiene la pluma, no es
la dueña". El censo, el ledger y la ley del espacio cerrado auditaban SOLO
quien LEE (recetas de eidos); quien ESCRIBE la custom property por instancia
vive en soma/arts y ningun instrumento del eje lo habia enumerado jamas.
EL BUG VIVO QUE ESTO DESTAPO — y no se parcheo, se diagnostico
--drawer-overlay-opacity era DOS especies bajo un nombre: el knob de tema (el
contrato dice 62%) y el canal del arrastre (0..1). soma escribia el canal SIN
UNIDAD sobre el nombre del knob; color-mix() exige porcentaje, la funcion caia
invalida y el velo computaba rgba(0,0,0,0): NO PINTABA. Y el inline dejaba el
knob inalcanzable para cualquier tema. Se separan: el publico se queda como
knob (nadie lo escribe en runtime), el arrastre pasa a
--_drawer-overlay-progress (sin unidad, que para un multiplicador es lo
correcto) y la receta los COMPONE - calc(knob * progress) -, asi que el
arrastre ATENUA el tema en vez de destruirlo.
Medido en Chrome: reposo 0.408471 (antes rgba 0,0,0,0) - el tema LLEGA (20%
-> 0.1318, 62% -> 0.4085, 100% -> 0.6588; antes ninguno movia nada) - el
arrastre sigue (Escape real -> alpha 0; 0/0.25/0.5/1 lineal) - control
negativo: reinyectando la escritura vieja el velo vuelve a caer, o sea que la
unidad era el SINTOMA y las dos especies la enfermedad.
⚠ Estaba adjudicado EN PROSA en theming-sentinel-exceptions.ts:815 desde hacia
dias: la excepcion se trago el bug.
LOS 18 NOMBRES A SU SITIO
Clase B (11 en command/dialog/scroll-area/toast + 4 del drawer): forma publica
sin contrato y sin UN SOLO lector en el repo - una API publicada que el
framework no consume. A --_{c}-*, y los README de soma dejan de enseñarlos
como API del consumidor: ahora enseñan LA PARTE, con la formulacion verbatim
que SS15 ya habia verificado. Clase D (tree-view, gradient-picker): tenian
lector, verificados en navegador. --scrollbar-width NO se renombro por
inercia: es una escritura sobre el unico <body>, la doctrina no le llega, y
queda REGISTRADA con su razon en vez de inventarle un dueño.
LA AGUJA - src/uix/value-channels.test.ts (fichero propio, 6 tests)
Vitest y no script, porque el gate termina en la suite y eso es lo que
convierte la doctrina en ley. Deriva el vocabulario de sistema RESTANDO el
contrato a lo que emite el generador (lista derivada, nunca a mano). Barre
NUEVE raices - las siete nuevas verificadas a cero ANTES de asertarlas - y el
quinto test asserta que cada raiz declarada se anduvo de verdad: una raiz que
resuelve a cero ficheros es la puerta que nadie habria visto.
Dos correcciones al dimensionado, por medida: el arbol tiene SEIS formas de
escribir, no cuatro, y una de las que faltaban era LA CANONICA (la
--_${component}-... que SS14 y SS15 firmaron) - un guard ciego a ella habria
dado verde sobre su propio destino. Y un barrido mas ancho marcaba en rojo un
anchor-name, que en gramatica es identico a un nombre de propiedad: probado y
REVERTIDO. El instrumento miente primero.
Mutaciones: cinco, con el arbol byte a byte identico. Incluyen las dos que
prueban lo que las correcciones añaden (una clave _ DEL contrato pasa de verde
a rojo; un --_ legitimo en blocks pasa de rojo a verde).
LO QUE EL ADVERSARIAL CORRIGIO DE MI PROPIA LEY
Dictamen: "es LEY sobre la mitad que barre, y sigue siendo PROSA sobre el
absoluto que enuncia". Cierto: decia "toda escritura por instancia" y la aguja
no mira eidos, donde viven ONCE escrituras de nombres contratados. Corregido -
el enunciado nombra sus nueve raices y DECLARA sus dos fronteras (eidos, con
su expediente abierto; web/routes, congelado); las salidas son CUATRO y no
tres (la cuarta, sistema, es verde); y el registro se queda con cuatro campos
por entrada (since, reason, destination, heldBecause) con un test que exige
los cuatro - la diferencia entre un registro y un cajon.
Y la relectura con ojo de abogado encontro DOS absolutos mas, en direccion
contraria, escritos bajo "WHAT THE GUARD DOES NOT CHECK": "por instancia" no
es decidible estaticamente (el antecedente del guard es MAS ANCHO que el de la
doctrina), y el {c} de --_{c}-* no lo comprueba nadie, solo el guion bajo.
SS18 ABIERTO, y es la respuesta medida a "¿puede volver a nacer un nombre sin
dueño sin que nadie se entere?": SI, desde eidos. 11 contratadas + 18 sin
dueño, partidas en dos especies (la fundacion generando su vocabulario, que es
legitima, y las props ergonomicas del consumidor, que no es lo mismo).
dialog-overlay-opacity es el GEMELO EXACTO del velo del drawer y sigue vivo.
No es "añadir el root": distinguir las dos especies EXIGE FIRMA.
Guards: value-channels 6/6 - recipe-css-contract + reach-floor + generated-css
55/55 - docs:check 0/0 sobre 819 - --debt 1148/0/0 - tsc 0 propios - prettier
limpio.
BREAKING: los 18 nombres publicos ya no existen; el canal se lee --_{c}-* y
sigue sin ser de nadie para fijarlo. Y consumir un --{c}-* del contrato desde
un provider es ROJO desde hoy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
e16c14dec7 |
feat(eidos): el ritmo de revelado sube a config — primitives.motion.staggerViewport, y su regla emigra a la foundation
Firma opción 1 del autor (cableado EidosConfig.motion → CSS, la última entrada de PENDING_PRIVATE_RENAME). Ejecutada con el esquema completo: expediente + dos constructores en serie + adversarial, todos Opus en ultra, coordinación y supervisión de la sesión. El gancho --motion-stagger-each-default era FICCIÓN: nadie lo declaraba y su único consumo (motion.css:42) resolvía siempre al literal 70ms. Ahora: primitives.motion.staggerViewport: '70ms' (tipo + default + validación + contrato + emisión --motion-stagger-viewport en :root, molde floating-gap verbatim) y la regla [data-stagger] > [data-animation-trigger='viewport'] EMIGRA a renderMotionBlocks — donde vive la máquina entera del stagger. Con ello motion.css queda en sus dos gates de opacity (su veredicto structural, más verdadero), la entrada del registro cayó STALE POR MECÁNICA y el registro, a cero, se DESMONTA con acta (un guard que inspecciona el vacío es un falso verde); la historia completa cierra en canon/recipe-contract.md. E14 (70→20ms) queda APLAZADA con nombre: firma de diseño propia, mueve 8 blocks. Adversarial 9/9 CONFIRMADO: neutralidad término a término contra la línea base histórica en Chrome real con el IntersectionObserver disparando (0/0.07/0.14/0.21/0.28/0.35s en /blocks/team/preview) - override 999ms reescribe la cascada - nombre muerto inerte (5s en :root, cero efecto) - <Cascade> intacto con control positivo quirúrgico (solo el hijo estampado toma el token) - cero empates de hoja posibles (tres escritores en .css, especificidad decide) - el guard del espacio cerrado muerde por mutación - 126 tests, censo 73%/66/1152-0-0, docs 0/0. Sus reservas, con acta en changelog §57: el contrato gana DOS filas (--motion-stagger-each entra como (derived) al emitirse — clase preexistente de index/index-rev) - gates divergentes latentes - path del contrato sin pin. Correcciones del adversarial incluidas: dos citas muertas del ledger de blocks anotadas, el presente falso de component-audit.ts, y el absoluto de canon matizado. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
de2e136a0f |
refactor(theming)!: el indicador de navigation-menu es CANAL - y el consumidor estiliza la PARTE
Firma "(a) completada" (2026-08-26), cerrada tras rechazar la especie
`output` por abrir excepciones (clase barata - frontera de prosa - patron ya
rechazado dos veces): las cuatro hermanas --navigation-menu-indicator-
{x,y,w,h} pasan a --_ (la adjudicacion que tabs ya firmo citando a ESTE
componente como precedente), indicator-w se RETIRA del contrato, y el README
de soma deja de enseñar a saltarse la composicion.
- Flip atomico escritor+lectores. Trampa del barrido, medida: el grep del
nombre LITERAL es ciego a la forma con llaves {x,y,w,h} - escondia tres
menciones. Barrido final: 0 consumos vivos de los nombres viejos.
- indicator-w retirada con acta MEDIDA (y una auto-correccion: la primera
acta decia "con la barra cerrada" y era falso - el indicador se monta
condicional y hay 0 nodos; lo real, con transiciones CONGELADAS: solo una
regla !important de autor le llegaba, y la unica ventana donde asomaba
era el indicador montado sin rect - un subrayado de ancho cero). Contrato
44 -> 43, generated -1 linea, ningun ledger rancio.
- README de soma: las medidas siguen tabuladas como canales privados "not
consumer API"; la seccion nueva enseña la PARTE ([data-navigation-menu-
indicator] + data-state + los tres pomos thickness/bg/radius) con
ejemplos VERIFICADOS POR MEDICION (el ejemplo 1 es literalmente el
control positivo: block-size 2 -> 9px). Hueco FLAGGED sin acuñar: el
ejemplo viejo de pildora no tiene traduccion - falta un eje de forma en
la parte; en SS13.
- Registro PENDING_PRIVATE_RENAME -> UNA entrada (motion). SS14 NUEVO en
next-features: unificar tabs (--indicator-* SIN prefijo, MeasuredIndicator
:80-83, 2 claves global en el ledger) - con el hallazgo de que ningun
guard los caza HOY porque no llevan prefijo: el espacio cerrado premio al
que nombraba mejor.
- Numeros: public 3073->3072, channel 37->38, reach 73% y atHundred 65
intactos (ningun redondeo cayo), --names 4566 con 0 desviadas, centinela
nav-menu 42/43 con la misma unica adjudicacion, --debt identico.
- Dinamica verbatim: el indicador DESLIZA (left 0 -> 111px, ancho 107 ->
108.56 = rect del trigger, canal w/h == triggerRect), los nombres viejos
computan vacio en el elemento (control negativo 777/333: nada se mueve).
Guards: 78 tests verdes + soma 9/9 + mutacion por las dos caras + audit
162 PASS + docs:check 0/0.
BREAKING: los cuatro nombres publicos del indicador ya no existen y
--navigation-menu-indicator-w sale del contrato; el indicador se estiliza
por su parte y sus pomos.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
e100ea5209 |
refactor(theming)!: trece canales de valor hablan como lo que son - privados
Eje-codemod firmado 2026-08-26 (destino firmado dos veces: los 318 y la ley
del espacio cerrado). Flip atomico escritor+lectores por nombre, barrido por
git ls-files (94 ocurrencias en 36 ficheros; el barrido destapo lectores que
ninguna lista traia: el comentario del morfo de knob, dos demos, y PLAN-
background). 32 ficheros.
- background pointer-{x,y,px,py} + progress · color-swatch fill ·
emoji-picker columns · knob {angle,progress,start-angle,sweep} · menubar
panel-anchor-width · text-gradient duration -> --_{c}-*. El nombre viejo
computa vacio en los siete componentes.
- PARADO con expediente: --navigation-menu-indicator-h NO se renombra - es
una de CUATRO hermanas escritas en un literal, el README de soma las
enseña como API del consumidor (dos ejemplos de CSS de app leen -h) y -w
es clave DECLARADA del contrato. Privatizar una de cuatro parte una API
documentada. Tres opciones redactadas en next-features SS13, sin elegir;
el registro PENDING_PRIVATE_RENAME queda con DOS entradas (esta + motion),
cada una con su razon.
- La trampa del censo NO mordio y la prediccion estaba mal por un orden de
magnitud: UNA reclasificacion (color-swatch.background), no ~15 - el censo
cuenta knobs de APARIENCIA y doce canales viven en geometria o conservan
un publico hermano. public 3074->3073, channel 36->37, reach 73%,
atHundred 65: el suelo no se toca.
- Verificacion dinamica de los SIETE canales vivos por CDP (verbatim en el
acta de la sesion): el parallax sigue al puntero con la privada (translate
-28,-24 -> 32,28 = x*depth), el knob rota por teclado (-27deg -> 0deg,
arco 108 -> 135 = progress*sweep), el chip pinta su prop, columns 9/6/12
tracks (control negativo: el nombre viejo a 3 no mueve nada), el panel
toma 886px del anchor, text-gradient 8s. Estatica: sonda 7/7 a 0 diffs
reales (el unico diff, un velo de emoji-picker, reproducido 2/2 = ruido);
color-swatch sin ruta de demo declarado en voz alta (la sonda con 0 nodos
es un guard que no inspecciona nada) y medido donde monta.
- Guard mutado por sus dos caras: entrada retirada reintroducida -> STALE;
nombre viejo devuelto a una receta -> missing. Docs ANOTADOS con fecha
(la adjudicacion medida de color-swatch del 23-08 intacta), volcados solo
donde describen codigo vivo. audit 162 PASS - docs:check 0/0 - --debt
1154/0/0 sin una clave movida - --names 0 - check 0 atribuibles.
Deuda menor anotada: la fila generada de audit/theming/background.md:72 la
regenerara el --report supervisado pendiente.
BREAKING: los trece nombres publicos viejos ya no existen; el canal se lee
--_{c}-* y sigue sin ser tuyo para fijarlo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
6499eb2a4c |
feat(theming)!: la ley del espacio cerrado - un --{c}-* existe si y solo si base.ts lo declara
Firma 2026-08-26. El espacio de nombres publico queda CERRADO sobre el
contrato: no hay tercer estado. El fallback es seguridad de VALOR, no
escapatoria de contrato; declarada la clave, el fallback inline muere (el
default vive en UN sitio, base.ts).
- El barrido real del catalogo: 25 nombres propios con fallback fuera de
contrato en 10 componentes (la prosa decia 13 en 2). ONCE eran knobs de
tema y quedan DECLARADOS con su default verbatim, scope root medido:
mockup 9 (con --mockup-phone-shadow ACUNADA - un nombre cargaba shadow-4
en el marco y shadow-5 en el bisel: un nombre con dos defaults es la
mentira que la ley mata) y text-scramble 2. Fallbacks inline retirados.
- Los otros QUINCE no son knobs: 14 canales de VALOR que soma/envoltorio
escriben por instancia (destino ya firmado por la firma de los 318:
--_{c}-*; el codemod es un eje propio) y el default de motion cuyo hogar
es EidosConfig.motion (su entrada structural queda intacta). Viven en el
registro PENDING_PRIVATE_RENAME del guard - nombrados, fechados, con
destino escrito y STALE simetrico: contarlos, no bendecirlos. La firma
medida de color-swatch.fill (2026-08-23) queda INTACTA y citada.
- El guard de fantasmas endurecido al "si y solo si": un --{c}-* del propio
componente fuera de contrato es ROJO con o sin fallback; el prestamo
ajeno y el sistema conservan sus reglas. Mutaciones: var inventado con
fallback -> rojo nombrado; prestamo ajeno -> verde; entrada de registro
rancia -> rojo STALE.
- Neutralidad PROBADA: generated/base.css = +11 lineas y nada mas; computed
A/B en navegador reconstruyendo el mundo viejo inline sobre el mismo nodo
- mockup 3 nodos x 2 cromos x 6 propiedades identicos (el bisel conserva
shadow-5), text-scramble identico. mockup se midio donde monta de verdad
(/blocks/feature-split): no tiene demo propia.
- Numeros: solo no-contract 18 -> 16. El suelo NO sube y la razon importa:
la ley cerraba un hueco de CONTRATO, no de alcance - esas declaraciones
ya puntuaban public; lo que faltaba era declarar el NOMBRE.
- Efecto lateral anotado en la clave, el handoff y next-features: el crudo
var(--primitive-neutral-12) migro verbatim a base.ts y R-4.6 (que escanea
CSS) ya no lo ve - la deuda sigue, ahora nombrada en el contrato.
- docs: recipe-contract SS4 reescrito con la ley y sus corolarios (el
value-reference con-fallback queda acotado a vocabulario ajeno/sistema);
CONTINUE y next-features al dia - pendientes del eje: el codemod de los
14 canales, el cableado del canal de motion, palabras y timeline.
BREAKING: consumir un --{c}-* propio no declarado es rojo desde hoy, con o
sin fallback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
1c239bf797 |
docs(theming): precision de prosa que midio el adversarial de los 318
13/13 claims confirmados (particion re-derivada clave a clave, 22 css 100% comentario por tokenizador propio, valvula irrompible ante declaracion ajena, suelo 73/65 exacto sin holgura, canario del centinela byte-identico). Cuatro precisiones de prosa, ninguna de clasificacion: - component-audit: el bloque R-5 decia 1088/74 (cifras del 25); ahora ancla 1154/76 al baseline del 26 con fecha. - theming-census: "los 29 nombres tienen escritor en envoltorio o soma" era 28 de 29 - el 29 (scroll-frames viewport) es el hatch que su contrato firma como geometria del SITIO: su escritor es la pagina, por diseño. - CONTINUE: unidades normalizadas en la lista de contradicciones (timeline 10 knobs/5 notas - listbox 6 knobs/5 notas - proof-of-human ya decia knobs). - recipe-contract: el "(1088 -> 1087)" historico gana su "that day" para no leerse como estado. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
90b93a79e0 |
docs(theming): la firma de los 318 queda EJECUTADA - el suelo sube a 73/65
Tercera pieza (F3): los ratchets suben en el commit que los gana y la prosa "318 sin ratchet" pasa a historia fechada. - Suelo: reachPct 69 -> 73 (3074/4228; el numerador NO se movio - ninguna receta cambio un valor; el denominador cayo exactamente los 252 que dejaron de contar como no-alcanzados: 132 bridge + 36 channel + 84 anotados; los 66 del ledger SE QUEDAN dentro) y minAtHundred 45 -> 65. Mordida verificada en ambas direcciones (74/66 -> rojo con el mensaje exacto; restaurado -> 5/5). El bloque de doctrina cuenta el CIERRE del agujero, no el agujero: los dos ratchets dicen lo mismo desde dos alturas - el suelo rechaza una caida NETA, el ledger una clave sin nombre. - recipe-contract SS4: la ley completa de las CINCO salidas de un privado no-derivado (bridge mecanico - channel mecanico - anotacion private: - entrada de ledger - derivar de un publico). 1088 -> 1154 donde era estado. - CONTINUE: la firma pendiente -> EJECUTADA 2026-08-26 con su seccion ( |
1 month ago |
|
|
1ba518fcc2 |
fix(theming): lo que el adversarial del cierre midio - numeros de prosa y el exit de --debt
La verificacion adversarial del cierre (11 confirmados, 2 refutaciones de NARRACION, 7 mutaciones con arbol restaurado byte a byte) dejo cuatro correcciones, ninguna de mecanismo: - El "114" de palabras eran 117 nombres --palabras-* consumidos (103 con fallback + 14 sin, los 117 bajo --palabras-scheme-*): el punto doctrinal sale REFORZADO - todo el canal es proyeccion del scheme. Corregido en el README y en la cabecera del ledger. - Los "18 sin contrato" de recipe-contract SS4 son 23: el titulo dejaba fuera a los cinco estructurales que su propia enumeracion lista dentro. Renumerado con el desglose recontado. - --debt no fijaba exit code: un modo de chequeo que no puede fallar es medio guard. Ahora process.exitCode=1 con deuda nueva o STALE (verificado por mutacion: HEAD exit 0, con literal inyectado exit 1, restaurado). - El 5o test del suelo se llamaba "mutation probe" y no muta nada: renombrado a lo que es (canario de cordura del scanner), con la historia de donde SI se vio el rojo por mutacion. Hallazgos del adversarial que quedan registrados sin ejecutar: las fichas de docs/audit/theming estan OBSOLETAS respecto a la clase structural (--report sin re-correr; tarea aparte con supervision por ficha) - el desglose "Knobs de apariencia" de la ficha no suma (preexistente) - el suelo de reach tiene ~0,5pp de holgura por redondeo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
1 month ago |
|
|
69d69d43c6 |
feat(theming)!: R-5.1/5.2 a error contra el LEDGER DE DEUDA - el ratchet es por clave
La pieza grande del CIERRE, con la forma firmada hoy: la deuda de alcance no
se tolera en warn ni se disfraza de excepcion - se REGISTRA, clave a clave,
y desde ahi la regresion es imposible y la mejora queda contada.
- scripts/theming-census-debt.ts (NUEVO): 1088 claves (763 global + 325
literal, 74 componentes), clave `{clase} - {fichero} - {selector} -
{propiedad}` INDEPENDIENTE de linea (mover una regla no fabrica
regresion), comparacion MULTISET, generacion reproducible (dos corridas =
mismo sha256), nace prettier-limpio. NO es un fichero de excepciones: es
deuda registrada, la otra clase de acta - la valvula R-5.x exception de
los README sigue intacta y NUNCA ciega el ratchet. Los carriles WIP ENTRAN
(palabras 359 + chronos 209 = 568): la deuda es real viva donde viva, y
dejarla fuera haria del gate una afirmacion sobre dos tercios del arbol.
Con la salvedad MEDIDA de palabras escrita: sus nombres --palabras-* son
canal de VALOR del scheme del documento, no contrato de tema - sus 103
"public" del censo estan en cuestion.
- theming-census.ts: censusAudit() -> {newDebt, stale} + CLI --debt
[--write] que imprime el delta que va a cometer (regenerar en masa borra
el ratchet: el escritor grita y la cabecera lo prohibe sin firma).
- theming-reach-floor.test.ts (reescrito): newDebt=0 y stale=0 con las
claves NOMBRADAS; los techos burdos maxLiteral/maxGlobal RETIRADOS
(superseded por el por-clave: 5 regresiones ya no se esconden bajo 5
arreglos); reachPct sube a 69 como ratchet grueso - y cubre el hueco
nombrado: los 318 privados no-derivados siguen SIN ratchet por clave
(acotado por la firma a literal|global; pendiente de firma propia);
atHundred corrige su criterio (public>0, 14 -> 45: los 31 de diferencia
eran denominadores vacios, ninguno un avance real).
- component-audit.ts: filas R-5.1 y R-5.2 a ERROR consumiendo censusAudit()
(dos implementaciones de una medida son dos medidas); R-5.2 honesto sobre
los 18 sin-contrato (11 nada-que-declarar all-system/0-knobs; field-langs
cubierto POR el ledger - la entrada ES su registro; 3 consumidores de capa
calendar; mockup y text-scramble PASS con nota del idioma var(..,fallback)
sin contrato - forma real sin nombre, pendiente de decision; palabras
fuera del catalogo del audit). R-5.3 YA estaba en error (verificado,
--names 0 desviadas). El skip por censo roto ahora GRITA por consola (la
leccion del prepareWith: un guard saltado nunca es mudo - y el suelo de
vitest queda de red mecanica).
- docs: canon/recipe-contract.md SS4 y theming/reference.md SS12 reflejan la
ley (gate F3 = censo 100% ADJUDICADO); completion-checklist gana las dos
filas (exigido por el guard I5); el stub RECIPE_CONTRACT.md solo actualiza
su linea de enforcement.
Mutaciones, todas mordiendo: literal nuevo en mark -> newDebt lo nombra,
suelo rojo, R-5.1 falla; clave de aura tokenizada -> STALE rojo hasta borrar
la linea; literal sin registrar en field-langs -> R-5.2 muerde. Guards en
HEAD: component:audit 162 PASS (cero flips; los 4 NEEDS-WORK son R-1.x
ajenos), suelo 5/5, docs:check 0/0.
BREAKING: los techos maxLiteral/maxGlobal del suelo desaparecen; anadir un
literal o un global crudo a una receta exige desde ahora tokenizar, anotar
/* literal: */ o firmar la entrada en el ledger de deuda.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
1 month ago |
|
|
43b3e8a501 |
uix(theming): correcciones de la revisión de F2-B — el empate no se resuelve de oficio
Auditoría de la sesión con medición. Cinco correcciones; la primera toca código y es la que importa. 1. **`link-preview`: RESTAURADAS `font-family` y `line-height`.** Las retiré como «declaraciones muertas» apoyándome en los precedentes de `table.selected-row-fg` y del trigger de `gradient-picker`, pero **no son el mismo caso**: allí perdían por ESPECIFICIDAD, aquí empatan a (0,1,0) con el plano `[data-depth='overlay']` y decide el ORDEN DE CARGA. Retirarlas no es neutral — **fija el empate a favor del plano** y con él su 1.25 donde la receta pide `--leading-normal` (1.5), que es justo la decisión que §12.9 tiene pendiente para VEINTE componentes. Un empate por orden de carga se registra, no se resuelve dentro de un commit de tokenización. Y la medición era más débil de lo que el commit daba a entender: estable en cinco recargas **en DEV**, sin verificar en un bundle de producción. Restauradas → **0 diffs contra el estado PRE-SESIÓN** (550 valores × 5 tallas), censo de vuelta a 100 %, y las dos adjudicadas en el ledger con esa razón. §12.9 y el README dicen ahora que el par se deja declarado A PROPÓSITO. 2. **Marcas `R-5.x exception:` en 16 READMEs.** El gate del plan es «censo al 100 % o excepción escrita», y la válvula que `component-audit` lee es esa marca (`readmeException`), no la prosa. Tenía la razón documentada en veredicto, README y commit, pero sin la marca: cuando F3 active R-5.1/5.2, los 16 habrían dado error. Una marca por clase medida — forward de paleta THM-2 · conmutador de dos fuentes · eje propiedad de una capa · identidad de layout. Los tres al 100 % (`code`, `label`, `link-preview`) no la necesitan. 3. **Continuidad restaurada.** El handoff seguía diciendo «45 %» y «empieza por grid-list», y `PLAN §8` no tenía una sola línea de la sesión pese a que el protocolo lo pide por componente: una sesión nueva habría arrancado con el mapa viejo. Reescrita la agenda de `CONTINUE-theming.md` (cifras, la revisión adversarial pendiente COMO PRIMERA TAREA, la cola restante, las 8 firmas), registrado el bloque en `PLAN §8` con su tabla de 22 commits y sus seis lecciones, y actualizada la memoria del eje. 4. **`recipe-contract §4`** documenta las SEIS capacidades que R-5.4 ganó en el bloque, cada una nombrando la forma en que el instrumento mentía, más la lección que generaliza: una sonda que inspecciona pocos nodos pasa en falso — `picker-shell` medía CERO y reportaba éxito. 5. **«un paso por debajo desde lg» → «desde md»** en `tree-view`, `virtual-list` y `virtual-grid` (README + ficha). El escalón empieza en md (md→sm); los valores eran correctos (0 diffs), el texto no. Lo que esta revisión NO arregla, y queda como primera tarea del eje: **F2-B sigue sin su revisión adversarial §7.7**. Sus 21 componentes llevan sólo la medición de quien los escribió, y el plan la exige antes de cerrar un bloque. El handoff nombra las dos hipótesis concretas que hay que atacar. Gates: censo global 50 % · `--names` DESVIADAS 0 sobre 3.993 claves · `component:audit` 162 PASS / 4 NEEDS-WORK (los cuatro preexistentes, ninguno con un commit de esta sesión en su código) · R-5.4 verde en los 22 · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0 · check por fichero limpio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
2 months ago |
|
|
679dfdb291 |
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4
Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree
con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba
más dura que la del autor), sonda x2 por componente para fijar el suelo de
ruido. 34 hipótesis · 26 refutadas · 8 reales.
Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs;
command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 ·
listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen
idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens
huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano»
de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación;
eidos-lint 0 invalid.
Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command
8.091 y carousel 2.842 valores, 0 diffs):
1. command: el re-point de `--command-radius` dentro del Dialog era una
declaración muerta con comentario falso — la misma regla pone el radio a 0
y el input lee `--command-input-radius`, nunca este token (medido:
`--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px`
movía la paleta inline y no la del dialog). Retirado; comentarios y README
reescritos con lo medido.
2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo
mientras la horizontal leía `active-indicator-scale` — el token alcanzaba
media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora
lo leen las dos.
3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap`
INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por
CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y
las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es
la prueba. Canal de valor de soma, como --gp-current-gradient. Censo
carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto
(5.190 · 2.102).
4. table: `striped-row-bg` no alcanza NADA en la demo publicada —
`:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos
quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel →
PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`);
adjudicado en el ledger mientras tanto.
El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas
medidas, y la cuarta era de la sonda:
- el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input
de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el
token de reposo leía muerto (era el «falso negativo sin causa» de §13);
- el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de
`{c}-root` no lo recibían;
- `::before`/`::after` eran invisibles (el aro de buffering, el spinner);
- la no-determinación de feed no era una animación sin localizar: era la demo
aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma
`commit-settle` anima box-shadow sobre el nodo medido. Con la espera de
asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas.
Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y
que carousel convirtió en patrón — un estilo inline de otra capa es invisible
para todo análisis estático): `npm run theming:sentinel -- <c> <url>`
(scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en
todos los nodos del componente, pseudos, pase de hover, settle) + ledger
scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto
sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en
verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 ·
gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46
excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías
salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró;
y dos muertos nuevos los produjeron los propios arreglos (el blur apaga
focus-input-border; el settle desmonta el spinner de feed) — adjudicados con
su porqué. Doctrina en recipe-contract §4.
También: tres cifras de especificidad de next-features §12 recontadas (la
banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0);
y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el
velo en la celda), el comentario de listbox que mandaba pisar el privado
`--_listbox-max-height` apunta ahora al público, y quedan registrados en §13
los dos `header-z` con literal '2' y el spinner de media-player a 720ms
mientras el gemelo de feed lleva tokens.
Guards: censo global 43 % intacto · audit --only command+carousel PASS ·
eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest
eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs
0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier
limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en
HEAD y no se tocan).
Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el
arquetipo en fila+celda, y que soma lea el gap de un token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
bd032534be |
feat(census): los primitivos tipográficos se miden contra su capa — pieza 0 de F2-A
D-TH.2-b, la firma que va ANTES del bloque porque cambia el suelo del censo: medirla a mitad de camino falsearía todos los antes/después. `heading` marcaba «36 knobs, 0 % alcanzable» y eso no era deuda: era una lectura equivocada. Su receta resuelve cada eje como `var(--_heading-font-size, var(--style-h2-font-size))` — el privado es el escape POR INSTANCIA que el wrapper escribe desde una prop, y el named style es la superficie de tema, ya pública y viva. Acuñar `--heading-*` para espejarla sería un alias por eje × nivel: la clase que mató la purga del changelog §39. El criterio de qué ES un primitivo tipográfico se midió, no se supuso: o la receta SELECCIONA por `data-style` (`heading`, `text`, `s-text` — el named style es su API) o está atada entera a UN style (`code` → `--style-code-*`, `display` → `--style-hero-*`, `label` → `--style-label-*`). `code-block` queda FUERA a propósito: lee un par de tokens de style para su texto pero posee cromo de caja real, y eso sí es suyo. Detalle que costó una vuelta: la comprobación va ANTES de la de privado. Leer el privado primero puntúa el primitivo entero como inalcanzable cuando es completamente temable — por la capa que lo posee. antes 5.199 knobs · 1.837 públicos (37 %) · 894 privados · 232 sistema después 5.199 knobs · 1.837 públicos (38 %) · 788 privados · 338 sistema **Gate**: 106 knobs pasan de `private` a `system` en los SEIS primitivos y **cero** de los otros 156 se mueve — verificado componente a componente contra la versión en HEAD, no a ojo. Alcance `—` (nada que poseer) para heading, text y display; `s-text` al 100 %; `code` y `label` bajan a 7 y 2 knobs de deuda real. Informe regenerado (171 veredictos a mano intactos), veredicto de heading anotado como ejecutado, y recipe-contract §1 gana el párrafo que fija el criterio — incluida la frontera: un menú que lee `--style-label-font-family` para una etiqueta NO es un primitivo y no entra en el conjunto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
7781d6e4c8 |
feat(audit): R-5.3 — la gramática de los nombres deja de ser prosa
El canon de nombres llevaba meses documentado y sin guard, y la medición del
2026-07-01 ya decía qué le pasa a un canon así: deriva entre el 30 y el 85 %.
Había derivado. El codemod de ayer lo normalizó; esto es lo que impide que
vuelva.
R-5.3 valida una FORMA, no una lista — ahí se separa del guard de eventos, que
comprueba pertenencia a un vocabulario cerrado. La forma es: tinta = `fg`,
modificador interactivo DELANTE, y detrás lo dimensional y contextual.
No reimplementa la gramática: la consume de `theming-census --names`, que es
la misma fuente sobre la que corrió el codemod. Dos implementaciones de una
gramática son dos gramáticas que acaban discrepando — y este repo ya pagó esa
factura con `commit-resize`, un hook muerto tres meses en una receta con todos
los tests en verde.
Entra en `error` directo, sin rampa `warn`, porque su deuda murió en el mismo
pass (precedente R-4.4). Las claves en cola de migración a la capa de estado se
reportan APARTE: no son deuda de nombre, son knobs que van a desaparecer, y
renombrar lo condenado es churn.
Muta-prueba de tres caras, que es lo único que distingue un guard de un guard
que pasa sobre el vacío:
`-bg-hover` con valor de acento → ROJO
`trigger-color` → ROJO
`primary-solid-hover` → VERDE (canónica: COLOR_ROLE_SLOTS pone
el modificador detrás por construcción)
La tercera es la que importa: es el fallo que un codemod ingenuo habría
cometido sobre las 47 claves de rol, `button` entero incluido.
Doctrina en el mismo pass: recipe-contract §1 gana las dos filas que le
faltaban (tinta y estado) más la frase que las gobierna y las dos familias con
gramática propia; §4 gana la fila R-5.3; theming §6.7 una nota fechada que
acota el principio de plataforma del px/py a los ejes dimensionales. El
checklist de cierre declara la regla — lo cazó `docs:check` con su propio
guard I5, que exige que toda regla del audit esté declarada allí.
Lo que NO entra, y por qué: el tercer muro (el tipo en `defineRecipes`, molde
`PhysicalAxisKey`) está escrito y probado, y dispara sobre 17 claves — los
hovers neutros que la firma 3 manda migrar. Meterlo hoy rompería `npm run
check` a todo el mundo por una deuda que ya tiene dueño y fecha. Entra cuando
la migración a la capa de estado las vacíe; son dos líneas entonces.
component:audit 163 PASS · 3 NEEDS-WORK (badge, mockup, motion — los tres
sin tocar por esto, R-5.3 pasa en los 166)
docs:check 0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
a11805d434 |
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia. `testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que atrapa cada script», con su reparto explicito: `layer:check` mira el valor computado (quien gana la cascada) y declara su hueco (la geometria, porque `getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles); `shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio. `component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar. `canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda `--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist de recetas decia «si flota → una rung de overlay», que era incompleto. `eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y `affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un contrato ajeno), un eje = token publico + ranura, el puente reafirma `position` si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna basta sola. `audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia tabla resumen como «pendiente de doctrina explicita». Ya no lo esta. `PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba prevista en el plan; todas salieron de auditar lo construido. docs:check 0/627. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
7ea913ab11 |
refactor(eidos): la rejilla de colocacion logica se canoniza — cinco declaraciones a mano pasan a una
`lib/types.ts` ya tenia `Position`, la rejilla 3x3 FISICA, con su idioma `Extract<Position, …>` y sus consumidores (Dialog, Drawer, Toast). Lo que no tenia nombre era la otra: la LOGICA, escrita a mano cinco veces — `AffixPlacement`, `FabPlacement`, `MenuDialPlacement`, `OnionPlacement` y las cuatro esquinas de `AvatarBadgePosition`—, coincidiendo por mantenimiento manual y no por contrato. Anadir una zona a una no llegaba a las otras cuatro. Ahora hay `LOGICAL_POSITIONS` / `LogicalPosition` junto a `POSITIONS` / `Position`, y las cinco estrechan desde ella. Ambas pasan a ser consts para que `docs:vocabularies` las genere: eran las unicas props visuales compartidas que faltaban en `docs/canon/vocabularies.md`, que ya listaba tamanos, variantes, paletas, arquetipos y el vocabulario sema entero. NO son dos grafias de lo mismo, y por eso ninguna sustituye a la otra: son dos COMPORTAMIENTOS. `top-left` es la izquierda de la pantalla y no espeja nunca; `top-start` sigue la direccion de lectura — medido hoy, de `left: 0` a `right: 0` en RTL. La regla de eleccion queda escrita en los dos typedoc y en el canon generado: ¿tiene que voltearse para un lector de derecha a izquierda? Una tira fijada en `bottom-end` va en el borde de salida en ambas direcciones; un panel que se abre a la derecha fisica porque ahi hay sitio, no. Con eso se cierra EID-3, que el audit de julio dejo asentado como excepcion pero marcado «placement fisico — pendiente de doctrina explicita». La doctrina ya no esta pendiente: son dos rejillas nombradas con la regla de cuando usar cada una. Sin cambio de comportamiento: las uniones resultantes tienen los mismos miembros (`MenuDialPlacement` = la rejilla + `static`; `FabPlacement` = las cuatro esquinas + `static`; `OnionPlacement` y `AffixPlacement` = la rejilla entera; `AvatarBadgePosition` = las cuatro esquinas). check 69 = base intacta · docs:check 0/627 · component:audit los cinco PASS · layer:check 0/3 · rtl 0/178 · smoke 311/311. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
0d10b983e5 |
revert(sema): la libreria de sonido vuelve byte a byte — la retirada no era de esta sesion
Revierte la mitad D10 de `5571f3bf7` por orden del autor. La sesion era normalizar nombres de evento; la retirada de los 3 resolvers de gesto nacio de perseguir un homonimo que cree yo mismo al renombrar `SoundDirection` → `SoundContour` sin mirar el namespace de destino, y se ejecuto sin leer primero el handoff vivo del eje (`CONTINUE-sound-engine.md` — la memoria del proyecto lo marca PRIMERO) ni `PLAN-audio-player-v2.md` (gate firmado), que ni siquiera sabia que existia. La verificacion posterior salio limpia — ninguno de los seis documentos no leidos nombra los resolvers — pero limpia por suerte no es limpia por metodo. Restaurados byte a byte a su estado anterior al borrado (diff contra `5571f3bf7^` = 0 lineas): - `sema/sounds.ts` (160 lineas otra vez: resolvers, `DragSoundParams`, `SoundContour`, `clamp`, `lerp`) · `sounds.test.ts` (los 2 tests de arrastre) · `exports.ts` (los 5 re-exports) - las 4 prosas que se habian reescrito describiendo el borrado: `sema/types.ts`, `sema/components/splitter.ts`, `soma/splitter-provider.svelte.ts`, `arts/motion/types.ts` - `scripts/docs-vocabularies.ts` + `docs/canon/vocabularies.md` regenerado - la nota fechada que se añadio al §4 de `PLAN-sound-engine.md` Lo que NO se revierte, porque no depende de la libreria: D9 (el acarreo de chronos) y el guard de eventos inertes — verificados en verde tras el revert. El ledger deja constancia: D10 pasa a CONFIRMADO (retirada REVERTIDA), con el analisis conservado como evidencia PARA la sesion propia del eje de sonido — `git log -S` (un solo commit en la vida de los resolvers), `book-deviations.md` dandolos por borrados el 2026-08-06, los dos planes cerrado/rechazado — y la regla explicita: sounds.ts no se toca sin una sesion que empiece por su handoff. Verificado: sema 300/300 (con los tests restaurados dentro), guard de eventos inertes en verde, `check` 70 errores (linea base), `docs:check` 0/623. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
5571f3bf7e |
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
6f42eebfe8 |
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 |
|
|
968fff9cdf |
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 |
|
|
86fa9a1b77 |
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 |
|
|
769e426c5e |
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 |
|
|
b9d73c19b5 |
feat(sema): los toggles recuperan su CONTACTO — la voz vuelve al momento que el libro le da
Tras leer el corpus entero de sema y del motor de sonido (los tres planes, el
handoff vivo, sema.md, CANON, channels, el README del art y D.7/D.8 literales),
que es la precondicion que me estaba saltando.
1) EL CONTACTO EXISTE (directiva del autor: «1 su contact-press»)
El libro le da a un Toggle DOS momentos, y el codigo solo tenia uno:
- cap. 23 §9 empareja el Toggle con `contact.press` Y `commit.toggle`;
- cap. 22 nombra «un switch que muestra estado pressed» como contact;
- CANON §8 regla 1: «contact precede al resultado cuando hay accion directa».
switch, toggle y toggle-group declaran ahora `contact-press` (family contact,
verbo press, sequence 'pre', SIN intent por cap. 22 §11) ademas de su
`commit-toggle`. Los providers los disparan en ese orden. Solo 4 de 91 morfos
con eventos expresaban `contact`; ahora 7.
Y el reparto de la voz cambia de sitio, que es el fondo del asunto:
- el CONTACTO habla — `contact.soft` (gain 0.08, clave nueva): el «click breve
opcional» de la tabla de canales del cap. 22, un tercio de una pulsacion de
boton para que un flip nunca pese mas que una activacion;
- el COMMIT calla — `SILENT`. Es lo que pide la tabla de canales del cap. 23
(«sonido: cierre opcional»), lo que exige el Criterio 12 (ch. 7 §13) de un
control que se pulsa docenas de veces por sesion, y lo que D.5 decidio en
mayo. La consecuencia la lleva `data-state` + color, la huella de ch. 23 §3.3.
`commit.medium` —la clave que invente ayer para que sonaran— queda RETIRADA:
huerfana en cuanto la voz se mudo al contacto.
MEDIDO en navegador: un clic emite `contact-press` -> `commit-toggle`, el estado
pasa a checked, y se levantan 2 osciladores con pico 0.08. UNA sola voz, la del
contacto; el commit no sintetiza nada.
⚠️ REVERSION DOCTRINAL DECLARADA: `compile.test.ts` afirmaba, citando el ANEXO
Tabla 1, que «Toggle/Switch declara un UNICO evento; el contacto es IMPLICITO en
el gesto». El cuerpo del libro dice lo contrario donde trata el caso. El test se
actualiza dejando escrita la reversion y su procedencia, para que quien lea el
anexo sepa por que el codigo diverge.
2) D.7 VUELVE A SER CANON SIN VERSOS SUELTOS (directiva del autor)
`proof-of-human` canonizaba samples en familia `commit`: `sound()` devuelve una
firma COMPLETA y la cascada la aplica en `replace`, asi que aplastaba la
modulacion por intent que la propia entrada existe para proteger — un `fulfill`
perdia su +300 Hz / ascending / +0.05, y el fallback sintetico sonaba ciego al
intent tambien. Su cabecera afirmaba literalmente lo contrario de lo que hacia.
Ahora compone tunings con `{ op: 'add' }`: el intent conserva sus primitivos y
la regla solo aporta caracter. Un producto que quiera el ping lo registra desde
la cascada de app (capa 5b), donde un sample SI es recurso legitimo.
3) D.8 REESCRITA Y FIRMADA
La entrada decia «los packs DEBEN respetar el activeChannels del family … anadir
`sound` a `handle` tambien [es incoherente]», y el framework hace justo eso,
prescrito por sema.md §componentes continuos. La ley queda:
- `activeChannels` es el DEFAULT perceptual de la familia, no una prohibicion.
- `channels` es la palanca por evento/regla y ajusta en las DOS direcciones.
Restringir: dialog `close-after-fail`, transporte del player, VirtualList.
Ampliar: el pack del slider sobre `handle`.
- Ampliar exige justificacion perceptual escrita. La del slider es canonica: el
sonido del arrastre no es firma fija sino payload por emision — por eso
`handle` no declara `base.sound`, y por eso sema conserva TRES resolvers de
gesto cuyo unico proposito es ese sonido.
- PROHIBIDO: declarar una firma de canal que la activacion no incluye. Deja
reglas INERTES. Es comprobable por guard. Infractoras: 2 del dialog + 3 mas.
Y Announce: la propia D.8 dejo la puerta abierta («si en el futuro necesita ser
pluggable … entonces vale convertirlo en canal formal. Hoy no»). Ese futuro
llego el 2026-07-04. No fue deriva; fue no volver a escribirlo aqui.
VERIFICADO: sema+morfo 337/337 · docs:check 0/616 · check 76 = base 75 + 1 del
fichero huerfano de la auditoria · `morfo:vocabulary` limpio · prettier: el
unico aviso mio formateado, los demas ya sucios en HEAD.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2 months ago |
|
|
24d30ee1a8 |
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 |
|
|
d05ecc1aa8 |
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 ( |
2 months ago |
|
|
46ce557836 |
docs(opts): la guia enseña el puente v2, partOpts y el reparto de callbacks
Wrapper Pattern con bindProps<XOpts> target-typed y partOpts para la parte trivial; nueva seccion «Callback conventions» (bindable→setter por construccion, evento puro→aparte); la via OptsFromProps+Preserve en Types. La nota del contrato de direccion deja de exigir el cable aparte: dir entra en la bolsa como pass-through con la llamada visible en la init. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
8d1909b166 |
feat(direction): eidos comparte el contexto, y el corpus registra el endgame
La entrada eidos se parte igual que la de soma: `activeEidosDir(dir)` devuelve la AFIRMACION (prop -> ancestro) y publica en el MISMO DirectionContext — un chart eidos-only dentro de un subarbol soma afirmado (o al reves) resuelve el mismo hecho. La cola matematica va a `resolveEidosDir(dir, eidos.prefs)`, con la vista de prefs cacheada por instancia (WeakMap): construirla dentro de una funcion pura llamada por $derived era una alocacion por pasada. createChartRtl consume las dos mitades por su lado: `attr` estampa la afirmacion cruda (ausente hereda del <html> proyectado), `current`/`anchor` resuelven la cola. Corpus: - direction-contract.md §2 pasa del campo obligatorio de 4.1 al mecanismo del morfo (declaracion -> tipo condicional -> estampado; secundarios del mismo morfo; el censo como guard), §7 documenta el contexto compartido y la tabla de entradas partidas, y el checklist §8.3 pide morfo + cable. - docs/decisions.md registra la ratificacion D1-D4 del 2026-08-05 con las cuatro decisiones y su porque. - CONTINUE-direction-runtime.md §11 cierra el handoff: tabla de fases con commits, verificacion final medida, la cola pospuesta por D4 y las trampas nuevas (pathspec SIEMPRE en rama compartida; el detector de huerfanos y la ruta del import; la vista en $derived). check 77 = linea base · morfo+direction suites 131/131 · docs:check 0/566. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
01cc13d412 |
feat(direction): el flip — el atributo es la afirmacion, y undefined ACTUA
La cadena se parte en la afirmacion. `activeDir` devuelve ahora SOLO lo que
alguien eligio (prop -> contexto del ancestro) y ahi se detiene: eso es lo que
el runtime estampa y lo que cruza portales. La preferencia de la app ya no
viaja en el atributo de cada componente — llega a la pagina UNA vez, por la
proyeccion automatica de P2, y todo lo demas HEREDA.
Por que: con prefs dentro de la cadena por-componente, "nadie afirmo" era
inalcanzable — el boot por defecto siempre tiene la dimension direction, asi
que getDir() casi nunca era undefined y cada raiz del canon estampaba
dir="ltr" en una pagina sin afirmaciones. El atributo nunca llegaba a estar
AUSENTE, la herencia del DOM nunca llegaba a trabajar, y de ahi la clase
entera de islas y reenvios que este eje llevo meses parcheando.
La matematica conserva la preferencia como VALOR (no puede leer el DOM) en un
solo helper:
afirmacion -> soma.prefs.getDir() -> 'ltr' resolveDir()
- activeDir(dir) pierde el parametro soma: 57 wrappers, y 49 quedan sin
`const soma = Soma.get()` huerfano (limpiados con deteccion de identificador,
no de ruta — la primera pasada se tropezaba con 'core/soma.svelte').
- 45 colas `opts.dir.current ?? 'ltr'` -> resolveDir(this.opts.dir, this.soma).
- Los 4 getDirectionalKeys de submenus que leian opts.dir.current directo
pasan a resolvedDir — con undefined degradaban a ltr EN SILENCIO bajo rtl
ambiental.
- command: 4.1 le habia dejado `dir: null` en el runtime y el estampado manual
inline en el assert (la linea no estaba sola y el barrido no la vio). Ahora
el runtime estampa y el inline se va.
- listbox / navigation-menu: el alias assertedDir muere — tras el flip,
opts.dir ES la afirmacion.
- date-range-field-input / time-range-field-input: el reenvio dir= al Field
compuesto en sitio sobra — DirectionContext lo lleva.
- 7 wrappers renombran `resolvedDir` -> `assertedDir`: el nombre mentia.
- picker / gradient-picker: activeDir(() => undefined) = la afirmacion del
ancestro o nada — mejor que el prefs-siempre-concreto de antes.
MEDIDO en Chrome, el modelo entero:
auto UN solo [dir] en toda la pagina: el <html> de la proyeccion
(antes lo llevaba casi cada raiz del canon)
prefs rtl select sin atributo, computa rtl por herencia; el panel
portalizado SIN atributo y computa rtl (heredo del html a
traves del body)
prop rtl trigger del dropdown estampa rtl, el panel portalizado
estampa rtl (la afirmacion cruza), submenu data-side=left,
cero islas dentro
matematica slider SIN atributo con pagina rtl: click al 25% fisico da
75 y ArrowRight BAJA — resolveDir lee prefs sin que el
atributo lo haga
SSR curl de select y accordion: cero dir= en el payload
El contrato: §1 documenta la cadena partida (activeDir -> afirmacion;
resolveDir -> matematica), §6 la proyeccion automatica + la semilla y el
parrafo de SSR — el <html dir> del primer render pertenece a app.html o al
servidor (modelo react-aria).
check 77 = linea base · suites soma+active-uix+prefs+contracts 1362 tests:
los 6 de contracts y soma-attr-audit son el conjunto preexistente (A/B dos
veces en fases previas; attr-audit pasa aislado) · media-player 17/17 tras
hacer resolveDir defensivo con mocks sin prefs · rtl:check 1 (palabras) ·
docs:check 0/566.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
9158d07964 |
feat(direction): el eslabon de contexto — la composicion hereda por fisica
La cadena gana el eslabon que el usuario dejo aparcado y ahora ratifica
(2026-08-05): prop -> afirmacion del ancestro (DirectionContext) -> prefs.
Cada activeDir PUBLICA su afirmacion (prop ?? heredada) y consulta la del
ancestro antes de caer a prefs.
Por que: la cadena por-componente metia prefs en la ruta del ATRIBUTO, y el
boot por defecto SIEMPRE tiene la dimension direction (deriva del idioma,
fallback ltr) — asi que "nadie afirmo" era inalcanzable en la practica y cada
hijo del canon estampaba ltr dentro de un subarbol afirmado rtl, cortando la
herencia. La otra sesion lo midio dos veces en el campo: un menu compuesto en
sitio aterrizaba en la preferencia global (LTR chrome dentro de un player RTL),
y el panel portalizado resolvia por su cuenta aunque arreglaras lo primero. Un
solo eslabon cierra los dos agujeros, porque la capa flotante ya lleva el
opts.dir del dueno — que ahora incorpora el contexto.
Con la fisica, las convenciones se borran:
- los 3 reenvios a mano de 4.3 (natural-time-picker-panel, emoji-picker-content
x3, color-field-format-select) — el contexto los hace
- el enlace manual del submenu (dir ?? parentMenu?.opts.dir.current) — idem
- los 3 canarios dir= de media-player que la otra sesion dejo puestos a
proposito ("si al quitarlos el panel vuelve a salir LTR, el mecanismo no
llego al portal")
El canario canta: su repro exacto (media-player, manual parts, direction rtl,
float de subtitulos) da panel rtl SIN el dir= — y el volume float igual.
Medido ademas en Chrome: islas 0 en emoji-picker, natural-time-picker y
color-picker sin ningun reenvio; sliders de canal en espejo exacto (hue 210 a
0.417 del borde fisico); submenu de dropdown con data-side=left en RTL
derivado del contexto.
Regla de colocacion (documentada en direction.ts y el contrato): activeDir lee
y publica contexto de Svelte, asi que corre SIEMPRE en la init del wrapper —
nunca en constructores de provider. Los tests de provider construyen directo y
no se enteran; los 91 mocks de Soma.require() sobreviven porque getOr(undefined)
cae a traves de prefs.
Test nuevo (direction.svelte.test.ts + harnesses reales, 5/5): el hijo hereda
la afirmacion, su prop la pisa, sin afirmacion queda undefined (nunca un
default), sin ancestro cae a prefs, y la publicacion es REACTIVA.
check 77 = linea base · 71/71 en los 9 ambitos tocados · rtl:check 1
(palabras, preexistente) · docs:check 0/566. El contrato §1 pasa a cuatro
eslabones y §1 "Composition carries the assertion" documenta la fisica.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
5983b00d5f |
feat(direction): el estampado pertenece al runtime — y olvidarlo ya no compila
Era la ultima convencion manual del eje: una linea por proveedor, 49 copias de
ella, y 20 de 55 componentes que simplemente la habian olvidado. Una convencion
que hay que repetir 49 veces y que un tercio del catalogo incumple no es una
convencion — es una abstraccion que falta.
VEHICULO A, y el handoff tenia razon desde el principio. Yo habia recomendado B
(un AttrPlan del compilador de morfo) con el argumento de que A deja `dir`
invisible para `contracts.cssSelectors` y `eidos-lint`. Medido: FALSO. El linter
sólo clasifica selectores `[data-*]`, y las recetas leen la direccion con
`:dir()`, una pseudo-clase que no toca ninguno de los dos guards. El coste que
le achacaba a A no existe.
Y B no llegaba donde yo decia. Reparto real de los 49 sitios segun la bolsa que
expanden:
renderProps() 21 un AttrPlan les llegaria
runtimePart.props 27 NO les llegaria
ninguna 1
O sea B aterriza en 21 de 49 y exige migrar 28 componentes de `.props` a
`renderProps()` — que no es cosmetico: `renderProps()` emite TODOS los attrs del
morfo de esa parte. A, en cambio, inyecta en `partPropsForRegistration`, que
incluyen LAS DOS bolsas, y llega a 48 de 49 desde un solo punto. Su precedente
es literal: `id`, el marcador, `data-archetype` y `reg.attachment` ya se
inyectan ahi sin declaracion en morfo.
EL GATE ES DE TIPOS, que es el premio de verdad:
dir: SomaRuntimeDir | null // OBLIGATORIO en SomaRuntimeSources
`null` es la unica salida y dice algo cierto: este runtime no estampa direccion.
Olvidarlo es un error de compilacion, no un defecto que nadie ve hasta que
alguien abre el componente en RTL.
`dir.parts` responde la otra mitad de la pregunta del contrato — QUE elemento
lleva la pintura — por defecto `['provider']`. El censo dice que 44 de 49 son la
raiz; los cinco que no: dropdown-menu ['trigger'] (su raiz no renderiza
elemento), drawer y float-panel ['content'] (pintan en el portal), number-field
y css-field ['provider','input'].
VERIFICADO en Chrome real, pagina en LTR y direccion movida por el control de la
demo:
tabs auto -> ltr prop rtl -> rtl vuelta a auto -> ltr
dropdown-menu el TRIGGER pasa a rtl y el panel portalizado tambien
number-field raiz e input, los dos a rtl
drawer el content portalizado a rtl por la cadena de prefs
accordion sigue la cadena y vuelve, sin una sola linea en su proveedor
check: 77 con mis cambios vs 79 sin ellos (A/B con stash). El -2 esta explicado:
uno era un error preexistente de `date-range-picker-provider.svelte.test.ts` que
indexaba el tipo `{ readonly dir }` de unos props que ahora son mas anchos; el
otro es que `media-player` ya no puede compilar sin el campo (su unica linea
tocada, +1/-1, es mecanica).
Tests: 1271/1278 en `src/uix/soma` + contracts. Los 7 fallos son el conjunto
preexistente, A/B contra arbol limpio: los 6 de `contracts.test.ts` salen
identicos sin mis cambios y `soma-attr-audit` pasa aislado (flaky bajo carga).
⚠️ Un fallo mio que cazaron los tests y conviene no repetir: los proveedores con
la forma de una linea `soma.runtime(morfo, {})` recibieron `dir: null` en vez del
getter, y 12 componentes con direccion se quedaron sin estampar. Lo vieron cinco
tests de "exposes root props". Un barrido con dos formas sintacticas necesita
las dos en el mapa, no una.
Estampados a mano restantes en el catalogo: 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
c73669cde7 |
feat(direction): la composicion lleva la afirmacion — tambien en sitio
4.2 cerro el caso del portal. Faltaba el gemelo: un componente que MONTA otro componente del canon arranca dentro de si una segunda cadena. Sin la afirmacion del dueño esa cadena salta la prop, aterriza en prefs y estampa un `dir` propio — y un `dir` estampado CORTA la herencia de todo lo que cuelga. El padre afirma rtl, el hijo estampa ltr, y el subarbol se parte. Medido con las demos ya cableadas, escaneando cada panel en RTL en busca de elementos que estampen una direccion distinta a la del envoltorio flotante: natural-time-picker 1 isla [data-slider] emoji-picker 3 islas [data-command] + [data-toggle-group] x2 color-field 1 isla [data-color-field-format-select] (un Select) Preexistente: mientras el panel entero era LTR la isla no se veia. Lo que hizo 4.2 fue volverla visible. El canon pasa a enunciar UNA regla con DOS vehiculos, elegidos por geometria y no por gusto (direction-contract.md §1, "Composition carries the assertion"): a traves de un portal -> la capa flotante, una vez por overlay composicion en sitio -> la prop `dir`, en el punto de llamada Lo que se entrega es siempre la afirmacion CRUDA (`opts.dir.current`), nunca `resolvedDir`: asi "nadie afirmo" sigue siendo distinguible y la cola de prefs del hijo sigue corriendo. Verificado en Chrome real, pagina en LTR y direccion movida por el control de la demo: los tres paneles pasan a 0 islas y el area del color-picker computa por fin `rtl`. Los dos sliders de canal siguen en espejo exacto — hue 210 cae a 0.583 del borde izquierdo en LTR y a 0.417 en RTL, alpha al maximo pasa de 1.0 a 0.0 — o sea §9.12 no se ha movido. check 78 = linea base · 59/59 en los 8 ambitos · rtl:check 1 (palabras) · docs:check 0/565. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
64df3d7b37 |
feat(direction): la propagacion pertenece a la capa flotante
Un panel portalizado se renderiza FUERA del subarbol de su dueño, asi que la
herencia no lo alcanza: la afirmacion del dueño solo llega si alguien la lleva.
Eso estaba delegado en cada consumidor — siete envoltorios Content componian el
enlace al padre a mano — y quien COMPONE un popover no tenia por donde hacerlo.
Medido con <DatePicker dir="rtl"> sobre una pagina LTR: el wrapper flotante
estampaba dir="ltr", el picker-shell y su pie se disponian en LTR, y solo el
calendario espejaba. Panel partido por la mitad, el fallo del §2 del contrato.
La capa lo compone ahora una sola vez:
el dir propio de la superficie -> el dir afirmado por el proveedor DUEÑO -> omitir
- FloatingProviderOpts.dir el dueño baja su afirmacion (ya pasada por
activeDir, o sea prop -> prefs)
- FloatingContent.assertedDir donde se encuentran; lo leen los DOS estampados
del wrapper (rama nativa y rama JS)
- createFloatingShellRoot lo reenvia; es la puerta de 8 de los 10
FloatingProvider. Los 2 submenus toman el del
menu padre.
FloatingContentOpts.dir pasa a ser la prop CRUDA del Content. Resolverla ahi la
haria casi siempre concreta (prefs) y el dueño no ganaria nunca el fallback.
Se borran los 7 enlaces compuestos a mano con su soma / activeDir / parentRoot.
Sobrevive uno a proposito: dropdown-menu-sub-content lo necesita para
effectiveSide, que es matematica y quiere valor resuelto.
popover, tooltip y link-preview aceptan dir en su raiz. No estampan nada — no
renderizan elemento —; el valor existe para cruzar el portal, y es lo que
permite que los 9 componentes que componen un popover empujen su direccion al
panel.
Borrados 9 resolvedDir muertos en los proveedores Content: nadie los leia (toda
la matematica direccional consume el de la RAIZ) y el cambio de semantica de
opts.dir dejaba su docblock mintiendo.
Demos: las 7 que aceptan dir lo pasan ahora a la instancia — time-picker,
time-range-picker y color-picker no tenian control ninguno; emoji-picker y
natural-time-picker lo tenian solo en el arnes. Sin eso el camino de la PROP,
el unico que ejercita el portal, no era observable.
Verificado en Chrome real, direccion movida por el control de la demo:
date-picker Clear/Cancel/Close 15/102/209 -> 200/92/15 espejo exacto
date-range-picker 448/217/17
sin regresion dropdown-menu (raiz y submenu, data-side=left en RTL),
context-menu, menubar, select, sidebar (flyout), y tooltip
en auto sigue estampando ltr — la cola de prefs sobrevive
check 78 = linea base (A/B con stash) · 158/158 en los 20 ambitos tocados ·
rtl:check 1 (palabras, preexistente) · docs:check 0/565.
Queda documentado en el handoff un defecto PREEXISTENTE de otra familia que
esto vuelve visible: un componente eidos que monta otro componente del canon en
SITIO no le reenvia el dir, y el hijo estampa ltr cortando la herencia del
panel (natural-time-picker/Slider, emoji-picker/Command+ToggleGroup,
color-field/Select). No hay precedente de ese reenvio en eidos: es doctrina
nueva y movimiento propio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
21055bd3cc |
fix(direction): la regla de estampado era demasiado estrecha — 16 componentes la incumplian
Decision del usuario (opcion B). La regla de §2 decia «estampa si el recipe usa `:dir()`», y esa premisa es FALSA: `:dir()` no es el unico lector. Tambien leen la direccion computada del elemento las propiedades logicas (`margin-inline-*`, `text-align: start`) y —lo que lo hace casi universal— `flex-direction: row`, que se INVIERTE. En la practica, cualquier componente con maquetacion horizontal depende de la direccion. La regla honesta, ya escrita: quien acepta `dir` lo estampa. La pregunta no es SI, es EN QUE ELEMENTO — el que lleva la pintura. Y para eso hay cuatro casos, ahora documentados: raiz normal · superficie PORTALIZADA (el wrapper flotante, que la capa ya estampa porque fuera del subarbol no puede heredar) · componente con LAS DOS mitades, que necesita las dos · y geometria aplicada desde JS, que no necesita atributo. Censo: de 55 que aceptan `dir`, 20 no estampaban. Clasificados uno a uno leyendo recipe + wrapper + donde renderiza cada parte: - 16 ESTAMPAN ahora, cada uno en la parte que lleva la pintura. Los sub-partes (drawer→Content, float-panel→Content, dropdown-menu→Trigger porque su raiz no renderiza elemento) llevan comentario nombrando la pintura que cubren. - 4 NO estampan y es CORRECTO: popover, tooltip, link-preview y context-menu. Su unica pintura direccional es el panel portalizado, que ya estampa la capa flotante; y el root de context-menu no renderiza elemento ninguno. DOS DEFECTOS QUE EL BARRIDO DESTAPO, uno de ellos MIO: 1. `sidebar` pasaba el valor RESUELTO al motor flotante. Esa linea la escribi yo en §9.19: arregle que se saltara la prop y deje el otro defecto, que siempre es concreto. La capa estampa lo que recibe, asi que un flyout SIN afirmacion recibia `dir="ltr"` — forzando su subarbol a LTR dentro de una pagina RTL, que es exactamente lo que el crudo existe para impedir. Era el UNICO de once consumidores flotantes que lo hacia. De paso desaparece su `resolvedDir`: sidebar no hace matematica direccional, toda su pintura es CSS. 2. La afirmacion de la raiz NO LLEGABA al panel portalizado. `select`, `combobox` y `context-menu` resolvian su Content con `activeDir(() => dir, soma)`, sin paso por el padre — asi que `<Select dir="rtl">` movia el trigger y dejaba la lista atras. Antes del barrido no se notaba porque NINGUNA de las dos mitades estaba afirmada y coincidian por heredar las dos del `<html>`; estampar el trigger lo habria hecho VISIBLE. Compuesto el enlace en el punto de llamada, que es la forma que §1 imprime y que `dropdown-menu` y `menubar` ya usaban. El resolutor sigue sin paso por el padre. Y `color-picker`, que es el mismo caso con una regla `:dir()` REAL varada: el area mirroring vive en el panel portalizado (`color-picker.css:298,335`) mientras la matematica del thumb y el arrastre salen de la raiz. Sin el enlace, el thumb se voltea y el gradiente de debajo no — justo lo que avisa el comentario de la receta. Su wrapper ya reestampaba `data-color` por esta misma razon; le faltaba `dir`. MEDIDO en Chrome (select): la raiz pasa de NO tener atributo a estamparlo, y trigger y panel coinciden en las tres posiciones del toggle. Estructuralmente ya no pueden divergir: ambos leen `opts.dir` de la misma raiz. `check` sin errores en ninguno de los 20 (el total 80 son 77 de base mas 3 de `media-player`, que edita otra sesion). 90 tests de los componentes tocados en verde. `rtl:check` 1, el de `palabras`. `docs:check` 0/0. QUEDA, reportado y sin tocar: ningun picker de eidos reenvia `dir` a su `PopoverContent`, asi que el cromo del `picker-shell` dentro del portal (`picker-shell.css:78`, el split del pie) queda sin cubrir en los siete. Los controles interiores (Calendar, los Slider) se salvan porque reciben el crudo por su cuenta. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
e9454bebe7 |
docs(direction): la excepcion que el usuario veto — :dir() que traduce una prop logica
«NO añadas la direccion al avatar porque tambien depende de donde se situa el badge». Tiene razon, y mi regla de §2 —«si el recipe usa :dir(), acepta y estampa `dir`»— es demasiado ancha: mandaba al siguiente a hacer justo eso. NO toda regla `:dir()` afirma una direccion. `Avatar.Badge` expone la esquina con `position` en terminos LOGICOS (`top-start` / `top-end`), asi que el ancla (`inset-inline-*`) ya se voltea sola; `:dir(rtl)` solo invierte el SIGNO del `translate` fisico que hace sobresalir la insignia —por eso las cuatro reglas llevan su marcador `rtl-physical:`, es el caso sancionado de RTL-1, no un selector de lado—. `Image` es lo mismo con otro mecanismo: `object-position` no tiene palabra clave logica, asi que `:dir(rtl)` traduce a `left`/`right` el `start`/`end` que el consumidor ya eligio. En los dos, una prop `dir` seria un SEGUNDO mando para lo que el primero ya decide, y pelearia en vez de componer: el ancla logica resuelve por la direccion ambiente mientras la prop dice fijarla. Esa regla `:dir()` necesita la direccion que REALMENTE maqueto el elemento, que es la heredada, por diseño y no por descuido. El test que queda escrito: si el componente tiene vocabulario logico propio para el eje, no lleva `dir`. Un `Switch` no lo tiene —su pulgar viaja en un sentido y la direccion es el unico input—, asi que ahi si es significativo. Un `Avatar.Badge` tiene `position`, asi que no. Barrido: de los 13 recipes con `:dir()`, SOLO `avatar` e `image` tienen ademas prop logica start/end. La excepcion son exactamente esos dos. Corrige tambien lo que reporte como hallazgo: «avatar e image usan `:dir()` sin aceptar `dir`» NO es un defecto ni una decision pendiente, es el diseño correcto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
43a7880832 |
feat(direction): las charts aceptan `dir` y corren la cadena canonica
Decision del usuario. Yo habia recomendado lo contrario —dejarlas y ablandar el
contrato— y me equivocaba en el diagnostico: no era que la cadena no valiese
para eidos, era que **le faltaba el punto de entrada**.
`activeDir(getter, soma)` pide un `Soma`, y una chart solo tiene un
`ActiveEidos`. Y `ActiveEidos.prefs` es un `ActivePrefs` crudo, que no tiene
`getDir()` —ese metodo vive en la vista que mira a soma—. Por eso la cadena
"no era ejecutable" y por eso alguien puso ahi un `getComputedStyle`. La
adaptacion entre las dos superficies es TODA la diferencia:
src/uix/eidos/direction.ts → activeEidosDir(getter, prefs)
Mismos dos eslabones, mismo `Direction | undefined`, misma cola `'ltr'` en el
consumidor. Abre la puerta tambien a `avatar` e `image`, que son el mismo caso.
Fuera la lectura del DOM y fuera la copia byte-a-byte que `chart.svelte` tenia
del mismo mecanismo —dos fuentes de verdad para un hecho, y ademas el observer
vigilaba `<html dir>` mientras la lectura era del elemento, asi que un ancestro
que volteara en caliente no se veia nunca—.
⚠️ EL HALLAZGO QUE SOLO SALE MIDIENDO: **estampar `dir` en un `<svg>` no hace
nada.** El atributo lo mapea a `direction` la hoja UA de HTML, que no alcanza a
los elementos SVG: medido en Chrome, un `<svg dir="ltr">` bajo un ancestro
`dir="rtl"` sigue computando `rtl`. Yo lo habia puesto ahi y el comentario
afirmaba que servia. Va en el envoltorio HTML (`<figure data-chart-figure>`,
`<div data-chart-frame>`). Importa porque `text-anchor` es LOGICO: con el
estampado en el nodo equivocado la matematica espeja y las etiquetas no —el
fallo de §2 con otro disfraz—.
MEDIDO en Chrome, heatmap: LTR `ene/feb/mar` en x=26/90/154, celdas 26‥858;
RTL en 851/787/723, celdas 6‥838. Funnel: poligonos de 0‥226 a 193‥420,
etiquetas de 249 a 171. El toggle del topbar sigue volteandolas, ahora por
prefs y no por el DOM.
COSTE ACEPTADO, verificado: envolver una chart en `<div dir="rtl">` sin pasar la
prop ya no la voltea. Falla de forma CONSISTENTE —el estampado del envoltorio
gana sobre el ancestro, asi que matematica y pintura siguen de acuerdo— y no
con las etiquetas cruzando el grafico.
§7 del contrato deja de ser una divergencia declarada y pasa a ser la tabla de
los dos puntos de entrada. Su justificacion era ademas falsa en dos puntos: no
era "el unico sitio del catalogo" (quedan 4 mas, uno vivo en
`field-langs-switcher`), y decia que una chart no se podia voltear por subarbol
cuando `direction` se HEREDA y si se podia.
`check` 77 = linea base. `docs:check` 0/0. Tests de eidos + libs/plots: 424/425,
el fallo es `audio-player` sin morfo, preexistente y ajeno.
⚠️ No pude ver los pixeles: el panel del navegador no compone frames.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
1cb61567e5 |
feat(direction): RTL-2 — el guard del doble volteo, la forma que se me colo dos veces
Cierra §10.1, la ultima deuda del eje. `dee2c9e3a` arreglo los dos defectos pero
dejo la FORMA sin guard, y es la que sobrevivio a la migracion §6.3 y a que yo
diera el eje por cerrado en §9.19.
LA FIRMA — dentro de un bloque cuyo prelude tiene `:dir()`, la misma familia
logica (`border`/`padding`/`margin`/`inset`-`inline`) declarada en LAS DOS caras,
EXACTAMENTE UNA con valor neutro (`0`, `auto`, `none`, `initial`, `unset`,
`revert`). Ese desequilibrio ES el espejo cancelado: la propiedad ya se habia
volteado cuando la regla matchea, asi que reubicarla la devuelve al punto de
partida y la deja en el borde opuesto al de sus hermanas.
Es mas estrecha que «bloque `:dir()` con puras logicas» a proposito. Una regla
que CAMBIA un valor bajo RTL sin reubicarlo es legitima —asimetrico por diseño
existe—, y las dos caras con valor son un autor describiendo dos bordes reales.
Lo que delata el defecto es el PAR, una cara apagada. Hay un test negativo por
cada uno de esos casos, que son los que evitan que la regla se vuelva ruido.
LAS TRES DECISIONES que el handoff dejaba abiertas:
- `:dir(ltr)` tambien entra. Igual de sospechosa, y no anade ruido.
- Marcador PROPIO, `rtl-mirror: <reason>`. Reutilizar `rtl-physical:` mentiria:
aqui no hay nada fisico, y un marcador que miente es peor que ninguno. Mismo
mecanismo (`exemptLines` toma ahora el patron por parametro), dos vocabularios.
Un test comprueba que el marcador de RTL-1 NO exime a RTL-2.
- Regla aparte, `lintRtlMirror()` con su propio `RtlMirrorFinding`. Los 14 tests
de RTL-1 quedan intactos y el tipo lleva los campos que importan
(`family`/`neutral`/`payload`) en vez de forzar los de RTL-1.
VERIFICACION, en este orden:
- `rtl-lint.test.ts` 27/27 (14 de RTL-1 intactos + 13 nuevos).
- RECALL con el runner COMPLETO contra el arbol pre-arreglo: restaure los dos
ficheros de `dee2c9e3a^` sobre el arbol, corri `rtl:check` y los devolvi con
`git checkout` en el mismo bloque. **2/2 cazados** (`feed.css:147`,
`tree-view.css:211`). Probar la funcion no basta: el runner es lo que corre.
- `rtl:check` sobre HEAD: 1 error, el de `palabras`, preexistente y excluido.
- `docs:check` 0/0 sobre 564 docs. `check` 77 = linea base.
Un defecto de presentacion salio al hacerlo: el `calc()` multilinea de tree-view
partia el mensaje por el primer salto. Los campos que RTL-2 emite colapsan el
whitespace; con test.
Actualizados los textos que el handoff avisaba que quedarian obsoletos: el
`enforcement:` y §4 del contrato, la fila RTL del build contract, la fila X-1.6
del checklist, y los docblocks de `rtl-lint.ts` y `rtl-check.ts` — que son
doctrina, no adorno.
⚠️ Sigue siendo cierto lo que NINGUNA de las dos reglas ve: leen texto CSS. Un
`transform` inline escrito por JS, un preset de motion compartido y la geometria
SVG siguen necesitando el ojo en RTL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b80ccb33cb |
docs(direction): el contrato pasa a ser canon, y el corpus deja de contradecirlo
El eje estaba cerrado en CODIGO y no en DOCUMENTACION. El contrato vivia solo en
`CONTINUE-direction.md`, un handoff que `docs/README.md` declara «never a source
of truth». Un capitulo E2 lo fija ahora: `docs/canon/direction-contract.md`.
Va a canon y no a arquitectura por la misma razon que `recipe-contract.md`: es
normativo y tiene guard ejecutable. Cubre la cadena y donde corre cada eslabon;
por que `undefined` no es `'ltr'`; las DOS atributos —`dir` crudo (nativo, lo que
`:dir()` mira) y `data-dir` resuelto (opt-in, para recetas que necesitan un hook
incondicional)—; cuando el estampado es OBLIGATORIO; la doctrina de selector; las
trampas que el guard no ve; que espeja y que no; y la mitad global de prefs.
EL CORPUS SE CONTRADECIA en cuatro sitios, y dos de ellos ENSENABAN mal:
- `component-guide.md:372` daba la cadena como `prefs → 'ltr'`, DOS eslabones,
mandando al wrapper a leer prefs directamente. Eso excluye la prop.
- `soma-architecture.md` §3.4 presentaba el resolutor a pelo (`soma.prefs.getDir()`
dentro del provider) como LA forma de obtener la direccion — justo lo que el eje
retiro del catalogo.
- `html.ts` ensenaba en su JSDoc `dir?: 'ltr' | 'rtl'`, el union a mano que la
regla E-2.5 ahora prohibe. El mecanismo que ensena (extender para estrechar una
clave HTML) es correcto y sobrevive; solo cambia el ejemplo.
- `active-architecture.md:416` no listaba `lang` en la proyeccion, contra
`contracts.ts` y contra su propio test de frontera. Igual `prefs/README.md`.
Y no lo mencionaba en absoluto: el glosario (`activeDir`, `resolvedDir`,
`data-dir`, RTL-1, el escape `rtl-physical:`), `eidos.md` (RTL-1 es el TERCER
guard de deriva y faltaba junto al builder tipado y eidos-lint), `soma.md`,
`building-a-component.md` (§Known traps es exactamente donde va «la prop mueve la
matematica y deja la pintura atras»), y la tabla de atributos de la arquitectura,
que afirma «todo lo que viaja entre capas viaja por atributos» y omitia `dir`.
El checklist gana cuatro reglas y el guard que faltaba (`rtl:check` no estaba en
la matriz de aceptacion pese a que la tabla canon lo nombra), mas un recorte en
E-3.5: «todas las props visuales mapean a `data-{prop}`» leia como mandato de
estampar `data-dir`, que `:dir()` no puede ver.
DIVERGENCIA DECLARADA (§7): la familia `chart` no tiene prop ni provider y
resuelve leyendo `getComputedStyle(node).direction`. Es el unico sitio del
catalogo que hace lo que §1 prohibe. Se registra en vez de esconderse.
Tres verificadores adversariales sobre el barrido; sus hallazgos, corregidos:
RTL-1 estaba anunciado como guard de TODO el capitulo (solo cubre §4) · «nunca
lee al padre» era absoluto y borraba la composicion sancionada en el punto de
llamada · el estampado se afirmaba incondicional en un sitio y condicional en
otro · las cuatro filas nuevas usaban una aplicabilidad que ni la leyenda ni
`component-audit.ts` conocen.
`docs:check` 0 errores sobre 564 docs. `check` 77 = la linea base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b55ca6eecb |
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
F2 — lote mecánico (13 ítems): - DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString propio + suite de contrato (props.test.ts; soma.md §12 cerrado). - THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector (los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la deriva que el builder previene, demostrada en el propio doc). - MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9 tests (selectors.test.ts, matches() real con comillas/corchetes) · MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad · MOR-3 _resetCompileCache borrado (0 usos). - SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo · SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin. - SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de applyDominance → skip defensivo + timer tope de awaitExpression cancelado · SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11) + pin del path de VALOR. - accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) — verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33. F3 — censos con guard: - SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred (consumidores cableados: date/time-field vía soma.uix.timers; avatar/image vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige .schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo). - THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo comment-blanked) + las 15 declaraciones anotadas con su razón + canon recipe-contract §3/§4. - SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/ timeline pinneados (overrides documentados en call-site); media-player Batch-4 (35 hits, cero renderProps) = único batch restante, registrado. - THM-4 doctrinado en eidos.md §unused (comportamiento/composición = legítimo; deuda = eje visual sin consumidor; hotspots por lotes). F4-C — corpus documental (decisiones de usuario aplicadas): - DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL trackeada / des-link históricos) · docs:check I6-links WARN→ERROR. - DOC-1: tabla «Build contract» MIGRADA a component-guide con estados modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil. - DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures · gradient añadido a los DOS capstones (sextet real) · nota de paleta de demo-authoring corregida (universalPaletteDecls + decisión THM-2 = mecanismo universal como sucesor del tracker borrado). - DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado · EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado. SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11): - Reconciliación: los morfos ya no declaran close (delegated al Popover, de-dialoged 06-27); el agujero real era el cierre programático bypaseando dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS. - Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5 providers (14 sitios; select/commit → 'save' = commit.save+fulfill, cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito (ya suena commit-set/cancel por diseño S9). - Verificado en vivo (date-picker): Done → close·commit·fulfill·active · Cancel → close·emerge · cierre real. Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 · docs:check 0/0 con I6 en error · baseline propio 57. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
53b6f629f2 |
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 |
|
|
116594e063 |
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 |
|
|
29b121236a |
docs(book): F7.6 (2/2) — final link sweep + complete book TOC; decisions/ batch COMPLETE
The global sweep caught the last corpus links still pointing at pre-book paths: morfo chapter's s2.bis cross-ref (src/uix/README -> overview.md), authoring's E1 stratum row (active_architecture -> docs/architecture/), the related: frontmatter of decisions.md and canon/recipe-contract.md (THEMING/THEMING_GUIDE -> theming/reference + guide), and component-audit's typographic-vertebration pointer (eidos README -> architecture/eidos.md with the translated heading). README map completed as the book TOC: every chapter now has a row — theming/motion.md (the model) and theming/changelog.md (the chronicle) were the two missing. Remaining old-path references live only in chronicle docs (theming/changelog, process/) and resolve via stubs; the 11-warn baseline is all foreign targets (MOTION_SERVICE_RFC demo routes, deleted THEMING_AUDIT/PENDIENTES). F7.6 complete. The book tree is fully populated: architecture/ (8) + canon/ (2) + theming/ (7) + rfcs/ (7) + guides/ (4) + decisions/ (2). Next and last: F7.7 CLAUDE.md thinning — diff to the user first. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
6307ec86f0 |
docs(book): F7.3 (9/9) — THEMING reference translated; theming/ + canon/ batch COMPLETE
src/uix/eidos/THEMING.md (1499 L, Spanish) translated to English as docs/theming/reference.md, same s1-s38 numbering: the mental model, s1.bis (theming lives in eidos — the 2-of-3 derivation and the canonical split), the CSS layers, the 7 token layers, the 9 roles, the size canon (universal 1:1 + label step-down + container cap + the icon scale), the naming conventions, the s7/s8/s9/s13/s15/s17/s18 stubs repointed into the book (canon/tsc, theming/guide, theming/notes, theming/changelog, theming/motion), runtime overrides + builders, bundle/purge, validation tooling, s14 motion (the pickup lift), s16 anti-patterns, s19 variants canon, and the s20-s38 standing-decision stubs. One internal reconciliation applied: the s35 stub cited the control/compact/dense size archetypes that s5 declares superseded by the universal 1:1 — aligned. One stale v1 DEMO_AUTHORING s12.8 citation in s5 replaced by the v2 s6 parity rule. Stub at the old path carries the full s1-s38 map (the most sN-cited doc in the repo: code comments, CLAUDE.md, RFCs). Corpus links swept (CANON, docs map, comparison, glossary, eidos chapter, canon/tsc, theming/guide + notes). docs:check 0 errors (260 docs). F7.3 complete: docs/canon/ (tsc, recipe-contract) + docs/theming/ (reference, guide, notes, channels, motion, motion-guide, changelog). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
f4639a36fa |
docs(book): F7.3 (1/2) — canon/ chapter: TSC + Recipe Contract translated
src/uix/eidos/TSC.md (334 L) and RECIPE_CONTRACT.md (131 L), both Spanish, translated to English as docs/canon/tsc.md + docs/canon/recipe-contract.md (the E2 visual canon inside the book tree). Thin stubs at the old paths (code comments and component-audit R-4.x provenance keep resolving); corpus links swept (docs map E2 rows, authoring anti-copy law, building-a-component phase 5, comparison, getting-started, glossary, eidos chapter). docs:check 0 errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |