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 }
10 Commits (c73cae0227a0b1b6f34f78f052c0f28f425a291f)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
c73cae0227 |
feat(morfo,soma): M1(ii) virtual-list/grid — el scroll declara su emisor: el host
Los tres `handle-scroll*` de virtual-list/grid estaban en la deuda del D9 como «declarados y nunca sonados». Mal clasificados: la resolucion YA estaba escrita en los dos providers como decision con su porque — el listener de scroll dispara por pixel y la familia handle es ['sound','haptic'] (trinquete `step` + tick), asi que una emision por defecto seria un clic-clic continuo bajo scroll con inercia; «apps that want scroll-driven sema feedback should wire it themselves with their own throttle / debounce policy». Lo que faltaba no era el emisor: era un sitio DECLARABLE para esa decision. Es exactamente el caso de diseño del valor `host` de D.2, estrenado aqui: el contrato declara la superficie, el emisor es la aplicacion anfitriona. - `emission: 'host'` en los tres eventos, con el porque en el docblock. - Los dos comentarios de provider apuntan al flag y corrigen la cita desfasada (`activeChannels=['haptic']` — hoy son dos canales, lo que hace la conclusion MAS cierta, no menos). - La promesa del host es viable, verificado: `provider.runtime` es campo publico — un app puede emitir con su propia politica. - Deuda D9: -3 ids. Queda UNA entrada en INERT_EVENT_DEBT: gradient-picker commit-reset (S-14), la ultima resolucion de la parte (ii). Sin cambio de conducta: cero emisiones nuevas, cero navegador que medir. Verificado: guards 309 ✓ / 6 ajenos · check 69 = base aislada, diff VACIO · prettier: virtual-list.ts limpio en HEAD queda limpio; los otros 3 ya fallaban. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
daa6461d62 |
feat(soma,morfo,eidos): M1(ii) tooltip — los tres eventos existen por fin, y el silencio queda donde estaba firmado
El morfo declaraba emerge-present / emerge-dismiss / emerge-dismiss-escape y
nadie los emitia: el SILENT del pack nunca casaba, la puerta de temas que su
propio docblock documenta no podia funcionar, y el preset present-rise que
declara `event: ['emerge-present',...]` jamas pintaba. La excepcion del censo
lo decia desde agosto: «Today's silence is accidental, not the declared
design».
El re-analisis pedido por el autor cazo lo que la primera propuesta no vio:
la firma present-rise es GLOBAL (base.css:6520), la entrada por data-state es
el workaround de la emision ausente (el comentario del provider lo dice
literal), y la semantica autorizada distingue hover (entrada) de focus
(instant-open, «appears with no entrance — its semantics») — cosa que el
evento no distingue. De ahi la opcion B firmada: el estado conserva la
entrada; la emision añade la superficie que faltaba.
Cableado con la receta F4: `present` pre→post — y SIN su `commits` (fijaba
'delayed-open' y pisaria el 'instant-open' del camino focus; los overlays
binarios conservan el suyo porque su valor es total, desviacion declarada);
dismiss ×2 ganan `targetFallback: [trigger]` (Presence sostiene el content por
la salida; el fallback cubre la carrera). Provider: emision SOLO en
transiciones reales — un open-timer cancelado no presenta nada que retirar, un
re-hover abierto no re-emite — y `handleClose` lleva la causa para distinguir
el Escape.
MEDIDO en navegador, los tres caminos y la fuga exacta:
hover present CONTENT · entrada autorizada corriendo (scale-in+fade-in),
present-rise NO — el preset gana la cascada; miedo al doble
movimiento REFUTADO en el camino delayed
focus present CONTENT con instant-open y present-rise CORRIENDO — la fuga
predicha, confirmada → silencio visual MINIMO en la receta, scoped a
[data-state='instant-open'][data-event-phase='active'];
re-medido: anims [] y la entrada delayed intacta
leave dismiss CONTENT via Presence · salida autorizada (scale-out+
fade-out), dismiss-fade no
Escape dismiss-escape CONTENT · desestampado del hold a ~240ms
Deudas limpiadas en el mismo commit (el guard lo exige): 3 ids de
INERT_EVENT_DEBT + 3 excepciones de EMISSION_EXCEPTIONS. Quedan 4 de la parte
(ii): virtual-list/grid ×3 y gradient-picker commit-reset (S-14).
Verificado: soma navegador 1278✓/1 (el timeout ajeno) · tooltip 4/4 ·
sema+morfo+contracts 552✓/6 ajenos · check 69 = base aislada, diff VACIO ·
prettier: morfo/tooltip.ts limpio en HEAD queda limpio; los 3 avisos ya
fallaban en HEAD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
1c4303b10f |
feat(morfo,sema,contracts): M1(i) — el contrato dice QUIEN dispara cada evento (D.2)
El morfo no podia decir quien emite un evento declarado: todo se presumia del runtime, y la verdad de las excepciones vivia fuera del contrato — en la lista de deuda del guard D9 y en las excepciones del censo de packs. Las tablas de eventos de los README prometian percepcion que no ocurre (la ficha M1, P1). Ejecuta la decision firmada D.2 (IMPLEMENTATION_CONTRACT): - `emission: 'runtime' | 'host' | 'external' | 'declared-only'` en MorfoEvent + literal en el schema sium. Ausente = 'runtime': las ~250 declaraciones existentes no se tocan y la presuncion sigue siendo la norma. - El guard D9 exime por DECLARACION en vez de por lista: solo los 'runtime' exigen emisor. Y si un evento eximido sigue en INERT_EVENT_DEBT, el guard FALLA con «FIXED — remove it», para que la deuda no sobreviva a su resolucion. - El pack-census gana el chequeo simetrico: una regla cuyo alcance son SOLO eventos 'declared-only' afina una percepcion que jamas estampara — muerta por definicion, sin lista de excepciones. 'host' NO cuenta como muerto: el anfitrion dispara por el runtime y la regla casa normal. Fixture con los dos casos (positivo y negativo con hermano runtime al alcance). - `morfo.md` §Step 5.5 lleva el apendice tecnico en los terminos que D.2 exige: la tabla de los cuatro valores × sus guards, y la nota doctrinal de por que NO es doctrina del libro — marcar un evento inerte como declared-only para callar al guard es ensanchar la deuda con otro nombre. La sonda temporal (flag sobre tooltip.emerge-present → correr → revertir) destapo un agujero real y lo cerro: el flag entre `name` y `semantic` hacia INVISIBLE el evento al regex del guard — ni censado ni exento. El regex tolera ahora la linea opcional, y la sonda termino dando la conducta disenada exacta: exencion + exigencia de limpiar la deuda. NADIE estrena el flag: los 7 de INERT_EVENT_DEBT quedan intactos y son la parte (ii) — siete decisiones perceptuales del autor, una a una (la de tooltip: ¿el componente mas ubicuo merece firma, o silencio declarado?). La instancia original de la ficha (los 5 pickers con close inerte) esta muerta desde la normalizacion de nombres. Verificado: suites 945 ✓ / 6 ajenos · docs 0/624 · check 69 = base aislada, diff VACIO · prettier: mis dos limpios siguen limpios, pack-census formateado (regresion mia), contracts y morfo.md ya fallaban en HEAD. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
846d201693 |
fix(eidos): E2+E3 — el modo de sistema pasa por ActiveDom y un re-derive fallido ya no desviste la pagina
E2. `createSystemColorSchemeSource` usaba `globalThis.matchMedia` +
`addEventListener` crudos: la regla de la casa (listeners de window/document
pasan por ActiveDom) y la ventana EQUIVOCADA en iframe/popup — globalThis es la
global, no la del dom. Ahora, con dom inyectado, el media query sale de
`dom.getWindow().matchMedia` y la suscripcion va por `dom.listen` (ciclo de
vida gestionado); sin dom, el camino crudo queda de fallback (serializacion
CSS / SSR). Descartada la opcion preferida de la ficha (tracker en adom,
espejo de prefers-reduced-motion) por la regla de ≥2 consumidores: leidos los
6 boots reales de web/, TODOS pasan su propio modeSource — el camino de
sistema tiene hoy cero consumidores vivos; si algun dia gana un segundo, se
promociona, y queda dicho en el comentario.
E3. `#renderSchemeCss` atrapaba el error del re-derive y devolvia '' — y
`apply()` lee '' como «sin esquema» y BORRA el <style> anterior: un cambio de
modo con semilla que no deriva no solo fallaba sin log, desvestia la pagina
del bloque que ya estaba bien puesto. Ahora `#lastSchemeCss` conserva el
ultimo bloque bueno, el catch avisa por `#uix?.logger.warn('eidos.scheme',…)`
(la superficie que ya usa sema; eidos no tiene logger propio), y retirar el
spec sigue limpiando. `applyColorScheme` no cambia: construye EAGER y una
semilla invalida sigue reventando en la cara del llamador — el silencio era
solo del re-derive.
Dos hallazgos del proceso, anotados: el validador de config es FAIL-CLOSED y
rechaza escalas donantes rotas en la puerta (por eso el rojo de E3 no puede
fabricarse via config: la inyeccion va sobre `buildScheme` mismo, passthrough
real hasta que el flag del test lo revienta — el sitio exacto del throw que la
ficha nombraba); y el stub de matchMedia del test de E2 debe dar un mql POR
QUERY, porque el tracker de reduced-motion del propio dom consulta la misma
ventana.
Ambos tests vistos MORDER el codigo viejo (stash de la implementacion, no del
test): E2 porque el query de color iba a la ventana global (jsdom: sin
matchMedia), E3 porque el bloque desaparecia.
Verificado: eidos 28/28 · sema+morfo+eidos+contracts 943 ✓ / 6 ajenos · check
69 = base aislada, diff VACIO · prettier: active-eidos.svelte.ts estaba limpio
en HEAD y queda limpio; el test ya fallaba en HEAD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
58695cd08a |
fix(morfo): M4 — la pareja [true,false] solo se infiere donde es exacta
`compileDataPlan` precalculaba el par [etiqueta-true, etiqueta-false] para todo
stateRef+enum con `falseLabel = values.find(v => v !== trueLabel)`: exacto en un
enum BINARIO (el otro miembro, da igual el orden) y dependiente del ORDEN de
declaracion desde 3 valores.
El diagnostico de la ficha se corrigio dos veces con medida:
1. «Hoy no muerde porque los stateRef booleanos usan enums binarios» — falso de
premisa: hay 12 declaraciones con 3+ (aura x3, checkbox x2, image, meter x2,
progress x2, tooltip x2). Pero tampoco muerden, por OTRA razon: bindean
strings y el runtime solo usa la pareja con `typeof raw === 'boolean'`. En
los 12 la pareja se calculaba y jamas se usaba.
2. El arreglo de la ficha («stateRef+enum exige exactamente 2 valores») habria
PROSCRITO esas 12 declaraciones legitimas — la misma clase de error que M5.
El peligro real es el emparejamiento booleano↔enum-no-binario, hoy inexistente,
y el arreglo lo hace imposible EN SILENCIO: con 3+ valores la pareja no se
calcula, un string pasa intacto (la clase viva), y un booleano LANZA
MorfoInvariantError nombrando componente-attr y la salida declarativa — que no
es un campo nuevo sino `v.mapRef(source, { true, false })`, que ya existia en
el vocabulario. Doctrina S-09: un path malo lanza, no inventa (la alternativa
era estampar `data-state="true"`).
Del re-analisis, dos rectificaciones propias que quedan anotadas: mi primera
propuesta invocaba un «guard de contratos» que NO existe (el mecanismo honesto
es el throw), y mi censo de bindings verifico 2 de 12 — la prueba real es la
suite entera: soma navegador 1278✓/1 (el timeout ajeno) con la pareja ya
retirada de los 12, ninguno lanzo.
Tests nacidos en rojo (2/3; el binario paso porque es la conducta de hoy):
binario exacto con orden invertido · 3+ con string = passthrough · 3+ con
booleano = throw con /mapRef/.
Verificado: compile 44/44 · sema+morfo+contracts 550 ✓ / 6 ajenos · soma
navegador 1278✓/1 · check 69 = base aislada, diff VACIO · prettier: ambos
ficheros ya fallaban en HEAD, no se reformatean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
b53c93e422 |
feat(morfo,sema): M5 — el matcher `state` habla el contrato de datos del morfo
El matcher aceptaba pares de strings sueltos con la promesa escrita de que «una
iteracion futura los tipara contra el contrato». La iteracion es esta, y no es
UNA puerta sino DOS — el precedente de dos ejes del framework
(allowedTargets/targetFallback, intentRequirement/intentGuidance):
- `state` se tipa con `DataPairOf<M>`, la union discriminada derivada de
`parts[].data`: attr declarado, y donde hay enum, valor del enum. Un typo en
`data-last-action` deja de compilar — la clase de deriva que semaSelector
existe para matar. La union atraviesa intacta el idioma
`Parameters<typeof semaSelector<M>>[2]` de los 67 packs: cero migraciones.
- `undeclaredState` es la puerta ABIERTA con nombre: los attrs que el morfo no
declara A PROPOSITO (data-size/data-sheet del dialog, eidos-only por
docblock). La regla que la usa dice lo que hace, en vez de colarse por un
string abierto. Un solo slot no podia imponer enum Y quedar abierto — la
rama abierta se traga a la estricta (la clase S-11).
El gate de disyuncion vive en el BUILDER, no en el censo (desviacion declarada
del punto 4 firmado, a mas fuerte): attr declarado por la puerta abierta lanza,
attr no declarado por `state` lanza, valor fuera de enum lanza — y como los
packs son modulo, revienta al IMPORTAR: ninguna suite queda verde encima.
`aria` queda abierto con la razon real escrita: su unico uso en el framework
casa el `role` del dialog, que el morfo deliberadamente no declara
(variant-dependent, lo pone el provider).
Nacidos en rojo: 4 tests runtime (enum, attr no declarado via state, attr
declarado via puerta abierta, puerta abierta funcionando) + probes
`@ts-expect-error`. Migrados los 2 usos de dialog y los 3 tests de escaping que
usaban attrs no declarados. Una arista de implementacion documentada: dentro
del cuerpo generico `DataPairOf<M>` es condicional diferido y TS no deja leer
`.attr` — una lectura estructural local, como ya hace el resto del builder.
⚠️ Nota de proceso: mi primera propuesta fue un guard de censo + corregir el
comentario — el mismo error que S-33 (lint donde el tipo puede hablar), y cai
en el en el mismo dia. El re-analisis contra las decisiones del framework lo
invirtio. La ficha M5 queda anotada como INCOMPLETA, no refutada.
Verificado: selectors 15/15 · sema+morfo+contracts 547 ✓ / 6 ajenos · check
69 = base aislada, diff VACIO · docs 0/624 · prettier: dialog.ts era mio y
queda limpio; selectors.ts/test/index ya fallaban en HEAD.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
13246a2c23 |
refactor(sema,morfo)!: M6 — los alias deprecados mueren; un nombre por concepto
`IntentExpectedFamily` y `SemaEventLabel` eran alias de compatibilidad de `IntentRequiredFamily` y `SemaEventKey`, y el codigo nuevo seguia importando el nombre viejo — la mitad de los tipos hablaba el vocabulario de antes del renombrado. La regla dura del repo (no backward-compat shims: actualiza los consumidores y borra el camino viejo) decide el destino: 13 usos migrados a los canonicos y los DOS alias borrados del tipo y del barrel. La unica duda doctrinal se resolvio antes de tocar: D.3 (book-deviations:489) nombra `IntentExpectedFamily`, pero DESCRIBE la implementacion con el nombre que existia entonces — registro historico, no prescripcion. El precedente es la casa misma: se ha renombrado vocabulario entero sin reescribir los registros de decisiones. Ademas, y declarado en la exposicion: `semaIntentExpectedFamilySchema` (const local de morfo/schema.ts, mismo vocabulario viejo) pasa a `semaIntentRequiredFamilySchema` — y el guard S-34 de contracts.test.ts, que lo busca por nombre LITERAL, se actualiza en el mismo commit; separarlos habria dejado el guard ciego un commit entero. Los 2 `as never` de compile.ts se retiran: eran vestigio de antes de que existiera `DepSink` (un `() => void` encaja en `(value: string) => void`), y el compilador lo confirma. Y `_resetCompileCache`, tercera pata de la ficha, resulto YA borrado — cero apariciones en src/; se anota para que no vuelva a la cola. Censo previo al borrado: cero consumidores de los alias en src/, web/ y scripts/ fuera de los 13 migrados. Las funciones `is/parse/toSemaEventLabel` y el tipo `ParsedSemaEventLabel` conservan su nombre: son API propia, no el alias, y su renombrado quedo explicitamente FUERA de lo firmado. Verificado: sema+morfo+contracts 541 ✓ / 6 ajenos · check 69 = base aislada, diff VACIO · prettier: types.ts era mio y queda limpio; compile.ts y contracts.test.ts ya fallaban en HEAD y no se reformatean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |
|
|
4e7d0be670 |
fix(sema,docs): S-19 — el puerto de anuncios encaja con su sumidero sin adaptador
`AnnounceFn` pedia la prioridad en una bolsa de opciones y `ActiveUix.announce`
la toma POSICIONAL, asi que el cableado que la doctrina prescribe —una sola
region viva compartida, este canal como uno de sus dos emisores— no se podia
escribir: `{ announce: uix.announce }` no compilaba. Y forzarlo era peor que no
tenerlo: el sumidero recibia un OBJETO donde lee una prioridad,
`liveRegionIds[obj]` es `undefined`, y TODO aterrizaba en la region polite — un
`threat` dejaba de interrumpir, que es justo lo que un aviso critico no puede
hacer.
La firma pasa a posicional, como el sumidero y como la fuente equivalente de
soma. Tres puertos, una sola forma. Cambio de conducta: CERO — el canal es
opt-in y ninguna raiz lo enciende hoy.
Visto en rojo antes de tocar: un test con la forma EXACTA de `uix.announce`
(`(message, priority?, timeout?)`) recibia `{priority:'assertive'}` en el hueco
de la prioridad. Tres aserciones existentes migran de bolsa a posicional — su
contrato cambia, y era el contrato defectuoso.
⚠️ Mi analisis inicial estaba equivocado y el autor lo mando revisar. Habia
concluido que el canal estaba muerto porque el runtime de soma no mete `message`
en la señal. No lo mete, cierto, pero es DISEÑO: son dos emisores para dos
publicos —soma cubre sus componentes, el canal cubre a quien usa
`EngineSemantic` sin soma y escribe su propia señal— y precisamente por eso
nada se anuncia dos veces. La propuesta de fusionarlos habria roto ese diseño;
retirada antes de escribir una linea.
`sema.md` §announce reescrito: fuera el aviso del adaptador (ya no hace falta),
dentro la razon de los dos publicos, y el aviso que SI queda — ninguna raiz
enchufa el canal, y encenderlo sin inyectar el anunciador añadiria un segundo
par de regiones vivas junto al compartido. Eso es decision aparte, sin firmar.
Verificado: announce 6 ✓ · sema+morfo+contracts 541 ✓ / 6 ajenos · check 69 =
base aislada, diff VACIO · docs 0/624 · prettier limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
455260ca34 |
fix(sema): S-30/S-38 — las cinco reglas hapticas abren la puerta que habian olvidado
Cinco reglas escribian una firma haptica sobre familias cuyo activeChannels es
['sound'] — alertdialog (pulse 0.7/60), sheet movil (tap 0.4/24), editable
shift-enter-mode, stepper shift-step y timeline emerge-reveal. El resolver
instalaba la firma, HapticChannel salia por la puerta de entrada: vibrate() 0
veces desde su nacimiento, con la intencion comentada en los propios packs.
La decision se tomo contrastando con el mundo real, no por limpieza: mi
propuesta inicial era borrar los bloques y el autor la corrigio con las
preguntas correctas — ¿que hacen las plataformas? ¿quien decide? Verificado en
las fuentes: Apple HIG prescribe haptic de warning cuando aparece una alerta
importante y tick de seleccion para cambios de valor discretos; Android pide
moderacion pero con constantes CONFIRM/REJECT. O sea: el alertdialog y el
stepper SON patrones de plataforma, y la intencion escrita en los packs era
diseño, no deriva. El framework ademas ya deja la ultima palabra a quien toca:
la puerta por regla (`channels`), la per-emit, y la haptica entera es opt-in
del producto — ensanchar estas reglas no impone vibracion a nadie.
Arreglo: `channels: ['sound', 'haptic']` en las cinco, cada una con su razon
perceptual escrita. Los 5 waivers de CHANNEL_EXCEPTIONS se retiran: el guard
del censo (punto 2, que estos waivers silenciaban desde 2026-08-06) queda
re-armado y ES el aviso automatico para la proxima vibracion con puerta
cerrada. El aviso del waiver («widening requires completing the firma») estaba
ya pagado por la defensa S-31 de kindToPattern: un {kind:'tick'} parcial
resuelve a valores finitos, nunca vibrate(NaN).
Visto en rojo DOS veces antes de verde: el censo sin waivers listando
exactamente las 5, y el e2e nuevo de resolver.test.ts (resolucion con el pack
real + HapticChannel real: 1 vibracion por regla, patron finito) ejecutado
contra los packs sin ensanchar via stash.
Verificado: censo 67/67 · resolver 30/30 · sema+morfo+contracts 540 ✓ / 6
ajenos · check 69 = base aislada, diff VACIO · prettier limpio · docs 0/624.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2 months ago |
|
|
cb1fd54d10 |
docs(process): handoff nuevo para la cola de auditorias, con el protocolo de trabajo delante
El eje perceptual quedo completo hoy (F1-F6), asi que lo que sigue ya no es «su» cola: es la cola de auditorias — sema, fable, blocks, eje B, chronos C5. Este handoff la lleva, y pone PRIMERO lo que cambio hoy de verdad: el protocolo. §0 · las cinco preguntas del autor antes de CADA accion, un item por mensaje, y parar a esperar firma. Sin puerta que permita auto-autorizarse lo mecanico: lo propuse y se corrigio en el acto. Con las dos precondiciones que hoy costaron dos rectificaciones completas — el SPEC del COMPONENTE es doctrina y se busca ANTES de diagnosticar (chronos), y se barre `docs/` antes de proponer retirar nada (S-33 esta en CANON.md y en la D.3 firmada). La regla que las resume: el codigo nunca corrige al canon; se le pone al autor la contradiccion delante. §1 · S-33 FIRMADO y sin ejecutar, con la receta y la evidencia del probe de `tsc`: el defecto es el `Exclude`, no «falta una rama». Derivar los tres cubos positivamente cierra la puerta sola al flipar el const, y la tercera rama es inerte hoy porque se teclea sobre `never` — medido, delta de conducta CERO. §2 los 6 commits de hoy · §3 las tres decisiones abiertas con su evidencia ya medida (S-35 · S-30/S-38 · S-19, esta ultima partida en dos porque (ii) cambia conducta) · §4 la cola en orden · §5 la base de verificacion, con los 6 fallos ajenos de contracts nombrados uno a uno · §6 las trampas medidas hoy, para no re-descubrirlas: la laxitud DELIBERADA del guard D9 (endurecerlo convierte 27 emisiones reales en violaciones), el panel oculto congelando la linea de tiempo, y los ficheros ya sucios en HEAD para prettier. docs:check 0/624. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
2 months ago |