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 }
1606 Commits (b59332132f551065f4a9c9a908e3ec0769d72bcc)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
b59332132f |
feat(blocks): F2.5 `testimonials` — rejilla de citas con autor
Prueba social: una cabecera sobre una rejilla responsive de tarjetas de cita, cada una con su autor (avatar · nombre · cargo). Compound —la `.Item` se repite, como feature-grid— y SIN contexto (las partes no coordinan). `<Testimonials>` + `.Header` + `.Items` + `.Item` + `.Quote` + `.Author`(slot `avatar` + `.AuthorName`/`.AuthorRole`). - `AutoGrid` de tarjetas de igual alto; `.Author` fijada al borde inferior de la tarjeta (`margin-block-start: auto`) para que una fila de citas de distinto largo alinee las caras. - La cara es del app: un `<Avatar>` con imagen o un `Avatar.Fallback` de iniciales va en el slot `avatar` (B-7). - La tarjeta del quote usa `variant="outline"` — el `soft neutral` es casi invisible en claro. Encontrado al componer (en el README del block): el tema activa solo un SUBCONJUNTO de escalas donor (`green/indigo/orange/plum/teal`); una escala no activada (`cyan/ruby/amber/jade`) en `color` cae en SILENCIO a `primary` (la regla `[data-color]` hace `var(--scale-…, primary)`). Config del tema, no bug de componente; la demo usa escalas activadas. Hueco a decisión del usuario (Gaps): la **cita única en spotlight** (grande, centrada, logo+avatar+autor) — la variante modal del dossier, el grid es minoría. Otra disposición → candidato a hermano `testimonial-spotlight`. Demo (`web/routes/blocks/testimonials/`): full-bleed + ruta `preview`, cinco citas con avatares de iniciales en cinco colores distintos. Verificado en claro/oscuro × LTR/RTL, caras alineadas al fondo. `blocks:check` verde (6 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
594e5a5db4 |
feat(blocks): F2.4 `pricing` — el primer compound CON CONTEXTO del tier
La sección de planes: un toggle de periodo sobre una fila de planes, uno destacado. Es el primer block cuyas partes se COORDINAN de verdad (no solo se repiten como en feature-grid/split): el `Switch` escribe el periodo de facturación y cada `PlanPrice` lo lee. Esa coordinación es lo que gana un contexto compartido — la forma más fuerte de compound. `<Pricing bind:period>` + `.Header` + `.Switch` + `.Plans` + `.Plan`(featured, badge) + `.PlanName`/`.PlanDescription`/`.PlanPrice`/`.PlanFeatures`/ `.PlanFeature`/`.PlanAction`. - **Contexto reactivo** (`context.ts`): la raíz provee el periodo como getter sobre un `$bindable`; el `Switch` (un `ToggleGroup`) lo escribe, el `PlanPrice` lo lee y muestra el snippet `monthly` o `annual`. Mismo patrón que `CardGroup`. `period` es bindable por si la app quiere observarlo. - **El block NUNCA formatea moneda**: la app compone `FormatNumber` dentro de los snippets de precio (B-7). El block posee el switch, no el dinero. - `.PlanAction` fija el CTA al borde inferior de la tarjeta (`margin-block-start: auto`) para que una fila de planes alinee sus botones aunque tengan distinto nº de features; `.Plan` con `align="start"` deja los checks en columna limpia; `featured` da acento (borde primary) + elevación. Demo (`web/routes/blocks/pricing/`): full-bleed + ruta `preview`, tres planes (Pro destacado en el centro) con el toggle mensual/anual vivo. Hueco a decisión del usuario (Gaps del block): la **tabla de comparación** (features × planes) — la brecha recurrente del dossier en pricing. Es una tabla, no una fila de tarjetas: candidato a hermano `pricing-table`. Presentado, no resuelto. Verificado en navegador: el toggle cambia los TRES precios a la vez (0/29/99 → 0/23/79), tarjetas de igual alto con CTAs alineados, featured con acento, en claro/oscuro × LTR/RTL. `blocks:check` verde (5 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
cd399f7c7c |
fix(eidos): el `align`/`justify`/`alignContent` de `Grid` sí aplican
`<Grid align="center">` no tenía efecto: `align-items` computaba `normal`. Los atajos `place-items`/`place-content` del recipe se emiten DESPUÉS de los longhands, y su fallback `revert-layer` —cuando el prop `placeItems`/ `placeContent` no está puesto— revertía el longhand anterior a su valor inicial, pisando en silencio lo que `align`/`justify`/`alignContent` escribían (un atajo posterior gana sobre el longhand que expande). Ahora el fallback de los atajos COMPONE los vars de los longhands en vez de revertir; si el prop del atajo sí está puesto, sigue ganando (va el último). Los grids por defecto no cambian (para ítems de grid, `align-items: normal` ≡ `stretch`). Encontrado al alinear las filas de `feature-split`. Verificado: `vitest src/uix/eidos` 353/353 · en el navegador, feature-split (filas centradas), el chart del Mockup (`align="end"` = barras a la base) y feature-grid (AutoGrid, sin cambio). Doctrina en theming/changelog §47. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
327cd26876 |
fix(blocks): feature-split — la media reversa vuelve a la fila de su copy
En las filas `reversed`, la media caía a una fila de rejilla NUEVA en vez de quedar al lado de la copy: con solo `grid-column`, el auto-placement disperso no rellena la columna 1 después de que la copy tomara la columna 2, así que el screenshot bajaba ~420px. Ahora ambas columnas se fijan a `grid-row: 1` en `md` (auto en `base`, donde apilan copy-primero), y `align-self: center` las centra vertical en la fila. Verificado: las 3 filas con la media a su lado en claro/oscuro × LTR/RTL × reversed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
08ea82d128 |
feat(blocks): F2.3b `feature-split` — la brecha nº1 del dossier, con Mockup
La sección que las 5 refs shippean y que va justo tras el hero: una afirmación de producto junto a un screenshot, alternando lados fila a fila. Otra disposición que la rejilla de iconos de `feature-grid`, así que block hermano (decisión del usuario), no una variante turbia dentro de aquél. Compound —la `.Row` se repite—: `<FeatureSplit>` + `.Row` (`reversed`, slot `media`) + `.Eyebrow` + `.Title` + `.Text` + `.Features`/`.Feature` (checklist) + `.Actions`. El block coloca; la app pone la copy y la media. - `reversed` mueve la media al lado de inicio vía `grid-column` (Box expone `gridColumn`/`order`), dejando la copy SIEMPRE primera en el DOM — el orden de lectura y el foco no cambian aunque el screenshot salte de lado. - El check de cada `.Feature` es decorativo (`aria-hidden`): la palabra lleva el significado. - La media se COMPONE con el primitivo `Mockup`: la demo enseña cromo de navegador (dashboard) y de teléfono (app), cerrando el hueco de «tratamiento de media» del dossier de raíz en vez de falsearlo. `.Row` usa un tipo limpio (no `HTMLAttributes`) porque su slot `media` colisiona con el atributo HTML homónimo; el resto de sub-partes extienden los props del componente canon que envuelven (lección de feature-grid). Demo (`web/routes/blocks/feature-split/`): full-bleed + ruta `preview`, con control del nº de filas y del lado inicial; 3 filas con Mockup navegador/teléfono. Verificado en navegador (Playwright, módulos frescos): filas alternas en claro/oscuro × LTR/RTL, `reversed`, el orden de lectura copy-primero, y los dos cromos de Mockup. `blocks:check` verde (4 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
e95ebd45f9 |
feat(eidos): `Mockup` — el primitivo de media (navegador · teléfono · liso)
La clave del dossier para el hero y las secciones de features: la brecha no es el conteo de layouts, es el TRATAMIENTO DE MEDIA. En vez de falsear un screenshot enmarcado por demo, se cierra de raíz con un componente del canon que los blocks componen. `<Mockup chrome="browser" url="acme.app"><img …/></Mockup>` — enmarca cualquier media (imagen, vídeo, AspectRatio) en cromo de dispositivo: - `browser`: ventana con barra (tres dots + pill de URL centrada) y pantalla. - `phone`: bisel oscuro redondeado con notch. - `plain` (def.): pantalla limpia enmarcada, con sombra. Es un primitivo visual eidos-native con morfo de 0 eventos, justificado igual que `aspect-ratio`/`box` (no commitea, no emerge, no reacciona — da forma a su hijo). El recipe dibuja el cromo sobre tokens del ecosistema (`--radius-*`, `--color-border-*`, `--shadow-*`, `--primitive-*`), nada de color a mano. eidos-lint: 0 invalid / 0 class-hooks (mismo patrón que aspect-ratio). Dogfood + bug arreglado de paso en `hero`: - La demo del hero deja de componer a mano el marco del screenshot y usa `<Mockup chrome="browser" url="acme.app/analytics">` con el dashboard dentro. - Arreglados dos type-errors que ya viajaban en el hero (los tapaba un filtro de svelte-check con backslashes mal escapados): los snippets `title` y `background` colisionaban con los atributos HTML homónimos y se volvían `string & Snippet`. Fix: `Omit<HTMLAttributes, 'children' | 'title'>` y renombrar el slot `background`→`backdrop`. Lección: un slot de snippet cuyo nombre sea un atributo HTML necesita Omit o un nombre distinto. Verificado en navegador: browser (dots + URL + pantalla) y phone (bisel + notch) en claro/oscuro/RTL; el hero split enseña ahora una ventana de navegador de verdad. `svelte-check` sin errores propios · eidos lint.test + morfo 131/131 · `blocks:check` verde. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
d01b3e6af5 |
feat(blocks): F2.3 `feature-grid` — el primer block compound del tier
`<FeatureGrid>` + `.Header` + `.Items` + `.Item` + `.ItemIcon`/`.ItemTitle`/ `.ItemText`: una cabecera sobre una rejilla responsive de features (icono · título · texto). Es la sección que responde «qué hace», la nº1 tras el hero. Primer block COMPOUND del tier, y aplica la regla de forma que fijamos: el `.Item` se REPITE (el app mapea sobre N features) → gana sub-componentes, donde `hero`/`site-header` usan slots de snippet (partes fijas de layout). Las partes no coordinan —sin contexto ni estado entre ellas—: la rejilla es del padre, las celdas del app. `.Items` es el envoltorio honesto de la rejilla (`AutoGrid`), que deja la cabecera fuera sin un `grid-column: 1/-1` a pelo. - El block coloca (Section · Container · AutoGrid · Surface · Heading · Text); el app pone todo el contenido por children (B-7). - `.Items` fluido por `minChildWidth` (tantas columnas como quepan) o `columns` fijas; `.Item` `align` start/center; `.ItemIcon` chip `Surface`; `.ItemTitle` `Heading` h3; `.ItemText` `Text` apagado. - `align` de sección (center/start) coloca la cabecera coherente con las columnas. Dos cosas encontradas al construir, resueltas: - **Los sub-componentes de bloque extienden los props del componente canon que envuelven** (`BoxProps`, `StackProps`, `HeadingProps`…), **no `HTMLAttributes`**: el `style: string|null` del atributo HTML crudo choca con el `style: string` del canon al hacer spread (+ "union type too complex"). - **`.ItemIcon` por defecto `solid`, no `soft`**: el soft-primary en claro es casi blanco (oklch 0.99) → el chip era invisible; solid da el chip con glifo on-solid (la tinta de contraste la pone `Surface`). Demo (`web/routes/blocks/feature-grid/`): full-bleed + ruta `preview`, con control de columnas (fluido/2/3/4), align, nº de items y dir; 6 features con iconos del canon. Hueco a decisión del usuario (en los Gaps del block): el **feature-split/ alternante** (texto junto a un screenshot, lados alternos) — la brecha nº1 del dossier — es otra disposición (filas de 2 columnas, no rejilla de iconos): probablemente un block hermano `feature-split`. Presentado, no resuelto. Verificado en navegador (Playwright, módulos frescos): center/start × claro/ oscuro × LTR/RTL, columnas fluidas y fijas, 3/4/6 items, chips visibles. `blocks:check` verde (3 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
5125502486 |
feat(blocks): F2.2 `hero` — center · split · background, por slots
Segundo block del tier. API por SLOTS DE SNIPPET, no compound: la forma se razonó con el usuario y con el paisaje de referencia. Compound se reserva para partes que COORDINAN (estado/contexto/ARIA entre ellas — Accordion, Dialog); un hero son cinco slots de layout que no se hablan entre sí y que el root arregla, así que snippets. Además el campo entero shippea marketing como copy-paste plano —nadie aplica compound a una sección—, y los slots por zona son la historia de personalización que distingue al tier del copy-paste. `<Hero layout="center|split|background" level container size>` + `eyebrow/title/description/actions/media/background/children`. - El block **envuelve** título y subtítulo en `Heading`/`Text`: así posee el `id` que nombra el `<section aria-labelledby>` y el nivel del encabezado, mientras la app pone las palabras (B-7). `eyebrow`/`actions`/`media` son contenido libre (ahí los componentes del canon SON la API). - `center` = `Stack` centrado, media debajo (ancho-capado); `split` = `Grid` de dos columnas (una sola sin media), apila en estrecho. - **`background` (cover)** — añadido por scope-approval del usuario: la media a sangre detrás de la copy, con velo de contraste (`--color-overlay` a `--opacity-scrim`), texto `on-solid` y `object-fit: cover` vía un `<style>` justificado (D-BLK.2). Son las ÚNICAS reglas que el block posee, todas sobre tokens del ecosistema — cero color a mano. Capas por orden de fuente, sin `z-index`. Demo (`web/routes/blocks/hero/`): full-bleed en la página + ruta `preview` para anchos de dispositivo, cada prop un control vivo, y el backdrop del layout cover dogfooda el sistema de color — es un `Surface color="primary" gradient` (finish aurora = `--gradient-aurora`, derivado de los roles del tema; cambia con la paleta). Mini-site compartido por las dos superficies (`HeroSite.svelte`). Encontrado al componer, registrado no resuelto: `Box`/`Surface` `flex`/`grow` no hicieron crecer un hijo flex (bars a 0-width, `flex: 0 1 auto`; la prop no la usa ningún componente shipped). La demo usó `Grid` (tracks `1fr`). Flag en el README del block y en el handoff para revisar el cableado de `--box-flex`. Verificado en navegador (Playwright headless, módulos frescos): center/split/ background × claro/oscuro × LTR/RTL, media on/off, y el landmark nombrado (región con `aria-labelledby` que resuelve al título). `blocks:check` verde (2 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
356ebf92af |
feat(button): el CTA que navega y parece botón, por composición (opción D)
El hueco que registró `site-header`: un «Empezar gratis» de cabecera tiene que
NAVEGAR y parecer botón. `Button` no crece un `href` —`Link` posee la
navegación, y un ancla se activa con Enter, no con espacio, lo cual es
correcto—: presta la pintura por composición. Lo que hacía de esa forma un
downgrade era que el `child` (asChild) descartaba la decoración; se completa el
slot.
- **eidos `<Button>`**: el `child` recibe ahora `content`, el cuerpo YA
decorado (icono · etiqueta · endIcon · spinner) en su propio snippet que
comparten las dos ramas de render. Así
`<a href {...props}>{@render content()}</a>` conserva TODOS los slots en vez
de sustituirlos (antes la flecha del sitio alpha estaba escrita a mano).
Nuevo tipo exportado `ButtonChildProps`.
- **soma / morfo**: en la forma `child` el elemento es del consumidor, así que
soma deja de estampar `type` (un `<a type="button">` es una pista de MIME
falsa). El componente pasa `type: undefined` cuando hay `child`; el provider
lo REENVÍA verbatim (antes lo re-defaulteaba a `'button'` y pisaba el drop —
el default vive en el destructure del componente); el morfo declara el attr
`type` condicional (`prop-truthy`).
- **docs**: ejemplo rancio de `index.ts` corregido (anunciaba un `asChild`/
`variant="link"` que no existen); sección «CTA que navega» en el README de
eidos con el patrón y el footgun documentado (un `<button>` en un `<form>` vía
`child` se pone su propio `type`); nota en el README de soma.
- **site-header**: el CTA de la demo usa ya la forma real (`<a>` sólido con
flecha), y el hueco pasa de «candidato a canon» a CERRADO por composición —
`Button` sigue sin `href` y `Link` sigue poseyendo la navegación, las dos
decisiones firmadas se mantienen. Actualizados PLAN/CONTINUE-blocks.
- **demo de Button**: control `child (asChild → <a>)` vivo, snippet del código
y fila de a11y explicando por qué el ancla activa solo con Enter.
Verificado en navegador (dev, restart para módulos frescos): asChild ON →
`<a href="#pricing">` sin `type`, pintura sólida completa (bg primary, tinta
blanca, 36px, padding 16px), y el slot de icono SOBREVIVE dentro del ancla
(`[data-button-icon]` + svg + body); asChild OFF → `<button type="button">`
intacto (sin regresión de submit implícito); el CTA real de `site-header` sale
`<a>` con la flecha final y 0 errores de consola. `blocks:check` verde ·
`vitest src/uix/morfo` 114/114 · `svelte-check` sin errores propios nuevos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
d38bd63faa |
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff
Documentación al día de lo que se cerró hoy y handoff para retomar mañana.
- `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la
fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu`
(arreglado en el canon, no parcheado en el block), el hueco del CTA que
navega y parece botón (registrado, no falseado) y el defecto de framework
que destapó la demo.
- `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de
heredarse. Un `Section` regalaba su padding a cada descendiente —la galería
arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display`
ajenos. `@property { inherits: false }`, radio verificado sin regresiones.
Lección: una variable que un componente escribe para SÍ MISMO debe declararse
`inherits: false`; si no, deja de ser un prop y se vuelve un contagio.
- `architecture/blocks.md` B-9: la demo de un block se construye sobre el
harness compartido y el block se enseña A SANGRE — nunca dentro de un marco
con relleno ni de una caja con scroll, porque eso cambia lo que el block
hace.
- `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta
`preview`, `DocRow`, catálogo único, ejes en el shell).
- `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla
de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe
solo para anchos de dispositivo, cada prop un control, nada de backticks en
`<Text>`, ojo con las variables que heredan), la deuda declarada que es
decisión del usuario y el estado exacto de los gates.
Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda
ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los
3 fallos ajenos conocidos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
ae7b4f8c3b |
demo(blocks): el block se ve en una página de verdad, no dentro de una caja con scroll
«¿Dónde has visto que el sticky esté por debajo del scroll?» — en ningún sitio, y la respuesta correcta era esa. Un `position: sticky` metido en un div de 460px con scroll propio no es el que va a vivir nadie: se pega al borde de una caja, no al del viewport. Estaba enseñando un comportamiento que no existe fuera de mi página. Ahora la demo presenta el block A SANGRE en la propia página: el header se pega al viewport de verdad, con el scroll de verdad. Verificado: al bajar queda en top 0, con `data-stuck`, visible y por encima de todo (hit-test), y con `offset: 48` se queda exactamente a 48. Los anchos de dispositivo (375 / 768) sí necesitan un documento propio, así que ahí —y solo ahí— se monta un iframe de la ruta `preview`. Es opt-in a propósito: en dev, dos documentos sin empaquetar a la vez agotan las conexiones del navegador (`ERR_INSUFFICIENT_RESOURCES` se llevaba por delante las DOS páginas; lo medí). Con `loading="lazy"` y bajo demanda, no molesta. Para no duplicar contenido, el mini-sitio vive en `SiteHeaderSite.svelte` y lo consumen las dos superficies: la demo lo renderiza inline con sus props y la ruta `preview` lo sirve como documento leyendo la URL. «Abrir ↗» lleva ahí. De paso: la topbar de la sección deja de ser pegajosa. Una página cuya estrella es un block que se pega no puede tener su propio cromo peleándole el borde superior — el header del block se metía debajo y el `offset` que elegías se leía como otro número. El raíl sí sigue pegado, que no compite. Verificado: `/blocks`, `/blocks/site-header` y la preview con `?dir=rtl&mode=dark` responden 200 sin desbordes ni errores de consola; `blocks:check` verde; `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
ee02c5c55f |
docs(agent): D-AG.12 y §5b firmadas — la spec, y quién prueba el eje
Dos decisiones que estaban pendientes, firmadas tras investigación a fondo
(precedente externo verificado a fecha, no de memoria).
D-AG.12 — EL CONTRATO COMO REFERENCIA
Spec normativa en `docs/spec/` (RFC-2119 + IDs `AG-n` + escalera
stable|provisional|reserved + versionado por fecha), en estado DRAFT para que
F4b se construya CONTRA ella y no al revés. La doctrina se queda con el PORQUÉ.
Conformance en DOS vehículos, que es lo que evita que la palabra sea retórica:
kit de fixtures del protocolo (PORTABLE — un tercero lo corre contra SU
implementación; semilla ScriptedAgentTransport) + agent-check (lint del repo),
ambos citando IDs de requisito en sus fallos. Las dos claims de frontera se
nombran con marcador claimed|shipped porque hoy ninguna está materializada.
Gate de promoción a 1.0: ≥2 formas de dominio + claims shipped + fixtures
verdes. Respaldo externo: MCP ya no promueve a Final sin escenario en su suite
(SEP-2484) y opera lifecycle formal con ventana de 12 meses; AG-UI se volvió
referencia por ADOPCIÓN (AWS Bedrock AgentCore, Microsoft Agent Framework), no
por publicar suite. La spec se escribe antes para gobernar; el título se gana
después.
§5b — QUIÉN PRUEBA EL EJE: form + table
El gate de F4 pedía «2 manifiestos reales» sin asignar dueños; esto rellena ese
hueco, no enmienda nada. El criterio deja de ser disponibilidad y pasa a ser
dificultad: un formato lo decide su caso peor. Y form+table no son preferencia,
son la ANATOMÍA del contrato — los args de una capacidad SON schemas (sium →
toJsonSchema, ya construido en F1) y un run ES una transacción sobre un
conjunto de ediciones. Form además dobla: agente→componente (args contra
campos) y componente→agente (elicitación) son la misma proyección en los dos
sentidos.
Chat y palabras quedan como CONSUMIDORES, no jueces. El riesgo que esto evita
era real: ambos son texto lineal, así que un manifiesto probado solo ahí
habría asumido texto en silencio (rango como selección, ediciones
secuenciales, args string) y el caso peor habría aparecido tarde. Inventario
al firmar: 170 morfos, 0 con capacidad delegate declarada.
COROLARIO — la elicitación no depende de superficie conversacional
Una pregunta tipada es un formulario en contexto (Form.AutoFields), descartable
y no-modal, que es justo lo que exige el contrato a11y (WCAG 2.2.4). La nota de
protocol.ts («materializes with the conversation surface») describía UNA opción
y se leía como necesidad: corregida ahí y en la doctrina §7.
DESCARTADO
Entrada de delegación global siempre-disponible: roza el modo ambiental, que
está FIRMADO FUERA (⚖️1), y no se recupera por la puerta de atrás. La entrada
es un patrón con pieles montado en app-land — mismo veredicto que la
review-card.
Handoff `continue-agente-2026-07.md` reescrito para mañana: la spec DRAFT es lo
primero, luego el kit de fixtures, luego F4b con los dueños ya firmados.
Verificado: agent 30/30 · agent:check limpio · docs:check sin errores nuevos
(el único es el preexistente ajeno de callout).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
d574982ab9 |
demo(blocks): el escenario va a ras — `offset: 0` volvía a ser 0
Tenías razón: con `offset` a 0 la barra quedaba a 21px del borde del marco, y
16 y 48 sumaban sobre esa deuda (37 y 69). El offset del block estaba bien;
el marco era el que mentía.
Causa: usaba un `Card` como escenario y le pasaba `padding={0}`, pero el
recipe del Card pinta con su propia variable (`--card-padding-*`), que la capa
Box no alcanza — así que se quedaban sus 20px de relleno más 1px de borde.
Un header pegado se pegaba al borde INTERIOR de ese relleno.
El escenario pasa a ser un marco desnudo (`[data-blocks-stage]` en
`blocks.css`): borde, radio, altura y su propio scroll, sin relleno. Un
escenario tiene que ir a ras o miente sobre lo que enseña.
Verificado en navegador: offset 0 → 0px del borde, 16 → 16, 48 → 48, y al
volver a 0 → 0. Cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
33328df7ae |
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la página desnuda, con un comentario que decía que el modo seguía al sistema operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para mí, inútil para quien mira la página. Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json CLAUDE.md docs scripts tsconfig.tsbuildinfo README.md node_modules src vite.config.ts STUMBLES.md package-lock.json static web audit package.json svelte.config.js worker.js build plans tmp workers del documento por el camino del sistema; densidad proyectada en :root para que la hereden también los overlays porteados; y el conmutador de tema, que alimenta el del ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados, marcando el actual y atenuando los que aún no existen. Todo persiste en localStorage, así que una recarga te deja donde estabas. El catálogo pasa a : raíl y galería leen la MISMA fuente, y un block que aterriza no hay que recordarlo en dos sitios. Las tres regiones las coloca — cromo de app-land, el papel que hace en las docs de componentes; la regla de «sin CSS» del contrato B es para el tier (), no para el sitio que lo enseña. Dentro de esas regiones todo son componentes del canon. Verificado en navegador: el botón conmuta a oscuro de verdad (fondo oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y desaparece por debajo de 64rem sin desbordes, cero errores de consola. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
50574806d6 |
demo(blocks): harness compartido de demos + site-header con contenido real
La página de demo del primer block era mala y con razón: sin cabecera, sin contexto del block, controles sueltos flotando, backticks de markdown en crudo dentro de <Text> y relleno del tipo «filler section so the page scrolls». Harness (`web/routes/blocks/_lib/BlockDemo.svelte`), escrito una vez para las 14: identidad arriba (chip, ruta de import, vuelta a la galería, título, una frase de función y chips de datos: qué compone, landmark, props, cuántas cadenas propias) → el block VIVO dentro de un marco con su propio scroll, que es una página en miniatura → panel de controles agrupado → pestañas Composición · API · A11y · Gaps · Notas, que solo aparecen si la demo las pasa. Todo con componentes del canon (Card, Tabs, Badge, Stack…): esta sección no tiene cromo de docs propio y sigue haciendo dogfooding. `DocRow` acompaña al harness porque el `Table` del canon es una tabla de DATOS (quiere un `createTable`): la documentación en prosa usa una fila de dos columnas, igual en las 14. site-header: reescrita sobre el harness con contenido creíble de producto —nav con destinos reales y descripciones, hero y secciones que dicen algo— en vez de relleno evidente, y con control vivo de los cinco props (sticky, container, breakpoint, offset, dir) más el eje de dirección. Sin backticks literales: lo que es código va en <Code>. Verificado en navegador tras el arreglo de Box: cabecera compacta, escenario con la barra a 950px que se pega al hacer scroll dentro del marco, controles en una fila y las cuatro pestañas con contenido. Cero errores de consola. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
f98c844eda |
eidos(box): las variables de cascada de Box dejan de heredarse
Bug de fondo, no de una página: `[data-box]` lee `var(--box-…)` para cada
propiedad del modelo de caja, y una custom property HEREDA por defecto. Un
`Section` —que es un Box con 64px de padding de bloque— se lo regalaba a
TODOS sus descendientes: Container, Stack, Group, Card… Cinco componentes de
layout anidados = cinco veces el padding. De ahí los cientos de píxeles de
aire muerto en la galería de blocks (que arrastraba el defecto desde F0) y en
la demo del site-header, y de ahí que el header dentro del escenario saliera
a 32px de ancho por 435 de alto: el hijo también heredaba anchos y displays
que no eran suyos.
Las 44 variables se registran con `@property { syntax:'*'; inherits:false }`
y sin valor inicial: así cada una queda «garantizada-inválida» salvo que la
ponga el PROPIO elemento, y las cadenas `var(--box-…, revert-layer)` resuelven
exactamente lo que su autor escribió — los props de ese Box, y si no, el
cascade normal.
Verificado: paddings anidados a 0 en la demo (antes 64 en cada nivel) · la
galería de blocks pasa de ~300px de aire a una cabecera compacta · el header
del escenario mide 950×49 (antes 32×435) · `vitest src/uix/eidos` 353/353 ·
barrido de regresión por /blocks y las demos de button, card, sidebar,
nav-tree y table: cero errores de consola, cero desbordes y alturas de página
sanas · `eidos-lint box` limpio · el CSS generado no cambia (la corrección
vive en el recipe).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
6b23aa7ef1 |
agent(guard): agent-check nace con la auditoría que ya tiene sujeto — anti-falsificación de actor
D-AG.11 (firmada) define SEIS auditorías. Cinco necesitan el árbol de manifiestos `src/uix/agent/components/`, que es trabajo de F4b — y el plan es explícito: el guard «nace CON el árbol, no después». Así que quedan DECLARADAS en el script y se reportan como pendientes: añadir un manifiesto las enciende, y el guard nunca puede ir por detrás de la superficie que vigila. La quinta SÍ tiene sujeto hoy y no la vigilaba nadie: F1 entregó el primitivo de actor (`$libs/actor` + el registro WeakMap privado del motor) y su invariante — que SOLO el motor acuña — no estaba protegida por nada. El token es una marca de compilación sin constructor en runtime: un forjado resuelve a null, pero un `as ActorToken` TIPA, y un contexto de actor construido a mano en el canon es exactamente la suplantación que el eje prohíbe (agent.md §5). Por eso D-AG.8 §2 dice literalmente que su defensa es el lint de agent-check, no el sistema de tipos. Dos reglas, sobre canon (uix · arts · libs · svrs · packs · web) excluyendo el arte agente: - `actor-forgery` — cast a ActorToken fuera de $agent - `actor-handbuilt` — `actor:` con valor literal (objeto/string/número) en vez de un token RECIBIDO; reenviar (`actor: opts.actor`) es la costura sancionada y calla. Los tests quedan exentos: ahí fabricar un forjado es precisamente lo que se prueba. Verificado en negativo, que un guard que nunca falla es teatro: inyectado un cast + un contexto a mano en `sema/signal.ts` → 2 hallazgos con fichero:línea y exit 1; revertido y de vuelta a limpio. `npm run agent:check` cableado junto a los demás guards del repo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
016658a0c9 |
demo(site-header): controles vivos de cada prop + ejes claro/oscuro y RTL
La demo cumplía B-9 (existe y está enlazada) pero se quedaba corta frente a la ficha del plan («claro/oscuro, 375/1280, RTL») y a la doctrina de demos como banco de pruebas: `offset`, `container` y `breakpoint` no tenían control, y la dirección no era un eje de la página. Ahora cada prop público se maneja en vivo con `ToggleGroup`/`Field` del ecosistema (nada de nativos crudos) y la página entera cuelga de un `dir` conmutable. El modo de color NO lleva control a propósito: esta sección sigue el esquema del sistema operativo por diseño del layout, así que oscuro se verifica emulando `prefers-color-scheme`. Verificado en navegador: `container` lg→sm mueve la medida (1024→480px); `breakpoint` discrimina de verdad (a 800px, con `md` se ve la nav y con `lg` aparece el drawer); RTL espeja la barra entera (marca a la derecha, acciones a la izquierda) y oscuro pinta el header sobre superficie oscura. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
3cfc030b3a |
blocks(site-header): F2.1 · primer block del tier + landmark de NavigationMenu
Arranca F2 con el patrón del tier: composición pura de canon, sin CSS propio, sin morfo y sin una sola cadena visible suya (B-7 — todo texto llega del app por snippets). El block - `Sticky` (F1.1) envuelve solo cuando `sticky` (si no, no hay wrapper que no haga nada) → el estado pegado llega al app como `[data-sticky][data-stuck]` y el tratamiento es suyo; el block no pinta. - `Container` para la medida, `Group` para la barra, `Drawer` para la navegación estrecha; `brand` / `nav` / `actions` / `mobileNav` / `mobileTrigger` son snippets del app. - El interruptor ancho/estrecho va por el `display` responsive de los componentes de layout (B-6): el block no observa nada y las dos navegaciones nunca coexisten. - Suelo de referencia (dossier §P1: TW Headers 8 + Navbars 11 + Flyout 7 · Untitled · Flowbite): adoptamos las tres agrupaciones, el estado pegado como eje visual, el drawer móvil y el FLYOUT —la brecha de paridad que el dossier señala— sin reimplementarlo: el app pasa un `NavigationMenu`. Descartado: los volcados estáticos de cada arreglo; la barra es UN layout. El banner de anuncio no se hornea aquí (es el block F2.11 o un `Banner` en `children`). Canon arreglado de paso - **`NavigationMenu` no emitía landmark**: su morfo declara `defaultElement: 'nav'` para el Provider, pero el componente de soma renderizaba un `<div>` — el componente que ES la navegación del sitio no tenía `<nav>`, justo el hueco de a11y que el dossier atribuye a todas las referencias. Corregido en el canon, no parcheado en el block. Verificado: su demo sigue abriendo flyouts, ahora bajo `<nav>`. Hueco registrado (no falseado) - Un CTA que NAVEGA y parece botón no existe hoy: `Button` no tiene `href` por decisión propia («Link posee la navegación») y `Link` no tiene variante prominente. Queda como candidato a canon en los Gaps del block; la demo usa `Link` de verdad en vez de fingirlo. Verificado en navegador: `<header aria-label>` dentro de `[data-sticky]`, `data-stuck` al hacer scroll con el header a top:0, flyout abriendo, cero nativos crudos interactivos (B-2), 375px sin desbordes con el drawer abriendo 6 enlaces, y el `<nav>` del NavigationMenu presente. `blocks:check` verde · `svelte-check` 0 errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
528af6f72d |
docs(blocks): F1 CERRADA (8/8) · registro de sidebar y su review
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
75e1fe32a1 |
uix(sidebar): review adversarial · 31 hallazgos confirmados, arreglados
Review de 6 dimensiones × 3 verificadores escépticos (135 agentes): 43 hallazgos brutos → 31 confirmados, 12 rechazados. Todos los confirmados arreglados y verificados en navegador real. Estado (los dos ejes) - `collapsible='none'` ya no deja el sidebar INALCANZABLE en móvil: la inercia del modo se limita al escritorio, que es donde «nunca colapsa» significa algo. En móvil el panel es un Drawer que arranca cerrado, el raíl está oculto y el drawer no tiene trigger propio: con el toggle inerte no había forma humana de abrir la navegación en un teléfono. - `'none'` PINTA el estado a expandido: antes `data-state`, `aria-expanded` y `useSidebar().open` podían decir «colapsado» sobre un panel plenamente visible, y ninguna regla del recipe ni el toggle podían reconciliarlo. - El estado del drawer móvil se DESCARTA al salir de la presentación móvil: abrirlo en un teléfono y rotar dos veces remontaba el Drawer ya abierto, con overlay, foco atrapado y scroll bloqueado sin tocar nada. Submenú flotante (era el nudo con más hallazgos) - Cierra también por PUNTERO: se abría en `pointerenter` de la fila, pero el único cierre por puntero vivía en el propio flyout — salir hacia la página sin cruzarlo lo dejaba pintado para siempre. - Escape funciona desde donde el foco ESTÁ (la fila), no solo dentro del sub. - Entrar/salir se resuelve en el `menu-item`, que contiene fila Y sub, así que viajar entre ambos no lo cierra. - El flag se limpia al cambiar de presentación: expandir y volver a colapsar reabría un flyout que nadie había tocado. - El motor flotante se engancha solo cuando el sub está ABIERTO, no por modo: antes `autoUpdate` (rAF + observers) corría por cada fila del raíl. - `hasSub` deja de latir a true: se limpia en el teardown del sub. A11y - Las filas del raíl recuperan NOMBRE: un tooltip solo describe (`aria-describedby`), así que con la etiqueta oculta el texto de `tooltip` pasa también a `aria-label` — incluidas las filas con submenú, que no llevan tooltip visible. - El panel off-canvas colapsado sale del tab order y del árbol de accesibilidad (`visibility: hidden` con la transición retrasada para que el deslizamiento siga animando). - El diálogo móvil recibe el mismo nombre que el landmark. - El raíl se llama «Contraer barra lateral» (lo que hace) en vez de «Redimensionar», que prometía un arrastre fuera de alcance; cursor de puntero en vez de `ew-resize`. Recipe - El signo del off-canvas se deriva de side × dirección: en RTL la fila flex se invierte, así que el negativo fijo barría el panel POR ENCIMA de la página en vez de sacarlo por su borde. - El flyout declara banda `z-index` (nuevo token `--sidebar-sub-z`); era la única superficie flotante del ecosistema sin ella. - La transición de `inline-size` (layout por frame) queda SOLO bajo el modo icono; la base anima únicamente `transform`. - El `Drawer` es el único dueño del ancho móvil (dos dueños dejaban una banda de cromo en dos tonos) y se compone con `dragToDismiss`. - Las reglas de modo icono ya no alcanzan el subárbol flotante: sus filas conservan badges y acciones. - Bloque `prefers-reduced-motion` — la traslación del panel es la mayor del sistema. Demo - Copias corregidas donde afirmaban de más: el tooltip ahora sí NOMBRA (y se explica por qué), y los anchos son rem fijos a propósito (no los alcanza el escalado; sí el interior). - Tabla de eventos y de teclado en la pestaña morfo; `onOpenChange` y una tabla de props por parte en API. - Los chips de estado se inhabilitan en `collapsible='none'`, que es lo que el componente hace; botón «show me» que pone icon + colapsado de una vez. - El trigger pasa a ser solo icono: el morfo le da `aria-label`, que pisaba cualquier texto visible. Verificado en navegador: nombres accesibles en el raíl · flyout que cierra por puntero, por foco y por Escape (con retorno de foco) y que no resucita al cambiar de modo · off-canvas fuera del tab order · RTL sacando el panel por su propio borde · z-index 80 en el flyout · drawer móvil nombrado, a ancho completo y con el panel a ras · `collapsible='none'` abrible en un teléfono. Gates: audit PASS 0E/0W · eidos-lint 47 morfo-backed / 0 invalid · svelte-check 0 errores propios · vitest src/uix/eidos 353/353 · contracts.test solo con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
59f20e2b1f |
uix(aura): el Status en dos líneas — cierra D1
La otra mitad de la dirección firmada: el anillo dice el estado como FORMA, pero la respuesta a «¿quién actúa?» es texto, y una palabra gris de 13px junto a un orbe vivo no la daba. Ahora el Status son dos renglones: Esperando tu revisión ← el estado, content-primary, peso medium la custodia es tuya ← qué significa para ti, secondary, un escalón menos Sin parte nueva: el Status ya existía y añadir un `Detail` habría sido abstracción prematura (y una pelea de layout — dos hermanos no apilan sin envoltorio). El soma renderiza las dos líneas por defecto y expone `detailText` en los snippet props, así que un consumidor que traiga sus children sigue mandando. La copia del detalle es FIJA por estado y localizada como la etiqueta (es/en): los contadores reales del run (turnos / actos) NO están en el puerto estructural, y ensancharlo para un subtítulo más bonito es una decisión, no un defecto. Queda dicho en el README por si algún día se firma. Tokens: `--aura-status-color` pasa a `content-primary` (era secondary: el peso informativo estaba en el sitio equivocado), + `-weight`, `-gap` y `-detail-color`. Verificado en Chrome real, claro y oscuro, con un run en `reviewing`: peso 500, primary sobre secondary, y las dos líneas escalando con `data-size`. Tests 478, eidos-lint 0 invalid / 0 class-hooks, morfo:vocabulary 0 errores, check en los 73 ajenos preexistentes. Con esto D1 queda cerrada entera (anillo + jerarquía). Handoff al día. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
e10eed98cc |
uix(aura): la superficie visible del agente — anillo de custodia, orbe-contorno y desenlaces expresados
Rediseño dirigido por el usuario sobre un banco de mockups con el orbe REAL
corriendo dentro. Seis frentes, todos con maquinaria existente:
ANILLO DE CUSTODIA (parte nueva `Aura.Ring`, morfo+soma+eidos)
El estado se lee como FORMA y no solo como tinte: raíl punteado en reposo,
arco que respira al ofrecerse, segmentos = pasos del plan (laten), dos arcos
enfrentados y QUIETOS esperando tu revisión (la quietud lo separa de acting),
arco que gira actuando, anillo cerrado + pulso saliente cuando te necesita.
Envuelve al Indicator (es su marco de referencia, no un hermano posicionado a
mano). El movimiento continuo son loops REGISTRADOS (data-animation-style),
nunca @keyframes de receta (R-4.5) — vienen con su puerta de reduced-motion,
donde el dash sigue distinguiendo el estado. El attr va en los hijos del SVG,
jamás en la parte: motionAttrs() estampa además data-state, del morfo ahí.
EL ORBE ES UN CONTORNO
`thickness` en el efecto orb; el hueco es real (alfa propia) sobre cualquier
fondo. Se va la rama claro/oscuro y el parámetro backgroundColor: el shader
mezclaba con el fondo y derivaba el alfa del canal máximo, o sea pintaba un
disco OPACO del color de la superficie justo en el centro (en claro un círculo
relleno; en oscuro el azul del seed). Y la receta deja de pintar su disco en
cuanto monta el canvas (:has(canvas)) — solo sobrevive donde no hay render
vivo: SSR, tests, effect={false}, sin WebGL.
COLOR = TOKENS DE ROL, PINTADO Y NO ROTADO
colorA/colorB/colorDeep (solid / solid-hover / element) resueltos con
eidos.resolveToken y pasados como hex, que es el seam que el propio arte
documenta. El hue-delta anterior se medía en OKLCH y se aplicaba en YIQ: risk
salía VERDE junto a su propio anillo naranja.
ONION EN EL IDIOMA DEL ORBE
Prop `look="solid" | "luminous"` (defecto solid: nadie más se entera). En
luminous el sector no tiene relleno — filo de luz (pasada borrosa + nítida) y
etiqueta en el color del sector; la cuña sigue siendo área táctil. El trigger
con snippet propio va BARE: sin disco, sin sombra FAB y sin el salto del hover
(el orbe ES el trigger, no su contenido). Medio anillo bottom-center y radios
44/40. El halo respira (loop pulse) y en commit-select da UNA pasada de ping
pivotando en el centro real del menú — la firma genérica de commit anima
box-shadow, que sobre un path de SVG no hace nada.
DESENLACES EXPRESADOS (el hueco real: un fallo era indistinguible de un éxito)
Tres eventos terminales con intent INTRÍNSECO — delegate-return (fulfill) /
-aborted (sin intent: un decline es ausencia, no pérdida) / -failed (loss) —
en vez de un intent dinámico, que no tiene dónde vivir: TriggerOptions no
lleva intent y el fromProp del morfo ata a un prop PÚBLICO, no a estado de
máquina. Puerto `runs?` opcional en AuraAgentSource porque activeRun ya es
null al cerrar (§0: sin él, anuncio genérico). Primeras firmas de la familia
delegate en el registro; la de loss es MOVIMIENTO (return-recoil: retirada +
descenso), no tinte — no estrena ningún hue.
MAPA SEMÁNTICO DE COLOR (demo)
Un hue = un significado en toda la superficie: gris=sin agencia ·
naranja=tu revisión · morado=él actúa · rojo=escalated (exclusivo) ·
teal=tu sí. El anillo de autoridad reusa los colores de la custodia con el
MISMO sentido (Review=risk porque vivirás en reviewing; Auto=primary porque
actúa) y los declines pasan a neutral — canon: el intent de un cancel es
`absent`. Además el anillo en reposo DELEGA (las tres autoridades abren el
run) y se cierra por transición, no siempre que no hay run.
Dos guardas del framework corrigieron el diseño por el camino:
- BK-FRAME-NO-INTENT rechazó dar intent a una familia de marco sin
justificación escrita (excepción A-1): queda el intentRationale — el motor
no emite nada y no hay evento evaluable que enmarcar, así que el retorno
consolidado es el ÚNICO sitio expresivo del desenlace.
- fallbackTarget gana sobre el target del morfo (contrato de TriggerOptions):
el sello caía en el provider. Los terminales pasan el Ring cuando existe.
Verificado en Chrome real (ventana delante: en segundo plano el navegador
congela rAF y ResizeObserver y las medidas mienten): seis estados en claro y
oscuro, y un error de transporte REAL apuntando a un puerto muerto →
delegate-return-failed · loss · return-recoil sobre el Ring · región
«Agente: falló — control devuelto».
Tests 478 (morfo 114 · soma/aura 11, +5 casos de desenlace · eidos 353),
eidos-lint 0 invalid / 0 class-hooks nuevos, morfo:vocabulary limpio,
check en los 73 errores ajenos preexistentes.
Pendiente (handoff actualizado): la jerarquía tipográfica del Status (D1
llevaba dos líneas y solo se hizo el anillo) · el pulso de commit-select se
corta si el consumidor cierra el anillo al elegir (necesita retención tipo
Presence) · D5 la superficie de composición del encargo, decisión abierta.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
245c22471b |
demo(sidebar): controles vivos de mobileBreakpoint y onOpenChange
Faltaban dos props públicos como control (regla de demo-authoring: cada prop público es un control vivo). `mobileBreakpoint` va con chips y el valor `xxl` (1536px) deja este viewport POR DEBAJO del corte, así que la presentación móvil —el `Drawer` compuesto— se puede ver sin tocar la ventana. `onOpenChange` se cablea a un contador que además enseña la doctrina: no se dispara con el estado del drawer, porque ese no es la preferencia de layout que el app persiste. Verificado en navegador: con `xxl` el shell estampa `data-mobile`, el drawer arranca CERRADO y el trigger de la página lo abre con el panel dentro de `[data-drawer-content]`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
dcce75cc20 |
uix(sidebar): el submenú flotante cierra al salir el FOCO
Se abría por hover o por foco, pero solo cerraba por puntero o Escape: un usuario de teclado que tabulara más allá del submenú dejaba una superficie abierta flotando sobre la página. El item cierra ahora en `focusout` cuando el foco sale de la fila Y de su submenú (dentro sigue abierto, para poder tabular por sus enlaces). Verificado en navegador: foco en la fila → abre; Tab → «Apollo» dentro del submenú, sigue abierto; Tab hasta salir → cerrado. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
293593307e |
uix(sidebar): el shell ocupa todo el alto de su contenedor
Un raíl de app corre de arriba abajo; el shell se quedaba a la altura de su CONTENIDO (404 de 420px en la demo), así que el panel no llegaba al borde inferior. `block-size: 100%` en el shell + el `align-items: stretch` que ya tenía llevan esa altura al panel y al inset. En un contenedor de altura automática resuelve a auto, así que no fuerza nada a quien quiera altura intrínseca. Verificado en navegador: shell y panel a 418px dentro de un contenedor de 420px (los 2px son su borde). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
21bbf9f506 |
uix(sidebar): F1.7 eidos + demo · raíl, modo icono y submenú flotante
Segunda tanda del sidebar: la capa visual, la demo canónica de 9 pestañas y la verificación en navegador real. Con esto el componente está vivo; queda el review adversarial. Eidos - Recipe con los dos ejes: off-canvas por `transform` (trabajo de compositor, el inset no reflowea) y `width` animado SOLO en modo icono, donde el inset sí tiene que seguir al raíl. El raíl NO lleva `will-change` (una franja fina tiembla a DPR fraccionario — memoria NavMenu). - Anchos como TOKENS: `--sidebar-width` 16rem · `--sidebar-width-icon` 3rem · `--sidebar-width-mobile` 18rem, más raíl, gaps, altura de fila y colores. - Tres composiciones que la capa headless no puede hacer: `Drawer` para la presentación móvil, `Tooltip` para nombrar filas en modo icono y `Badge` para los contadores. El trigger compone `Button` por el patrón `child`. - Convención de icono documentada: sobrevive el PRIMER elemento de la fila. Arreglos que destapó el navegador - **`mobile` en SSR**: sin viewport, `isAtLeast` responde «por debajo de todo» → el HTML salía con `data-mobile` y la hidratación NO lo corrige (no diffea atributos y el valor ya no cambia). Viewport desconocido = ESCRITORIO. - **Estado móvil propio** (arranca cerrado): en escritorio `open` es preferencia de layout persistida; en móvil sería un overlay tapando la página, que jamás puede ser el estado inicial. `onOpenChange` solo se dispara con el estado de escritorio. - **`open` controlado/no controlado**: se adopta el patrón de la casa (`$bindable` con default, el provider escribe siempre) — mi versión previa con estado interno no propagaba `bind:open`. - **El submenú flotante no se posicionaba**: `FloatingAnchor` resuelve su provider por CONTEXTO y el eidos envuelve la fila en un `Tooltip`, que publica el suyo → el ancla caía en el tooltip y el submenú se quedaba en `translate(0,-200%)`. Ahora el ancla se cablea directamente al provider flotante del item. Además el `<ul>` ya no se posiciona a sí mismo (colapsaba el wrapper a tamaño cero) y toma elevación del plano `overlay` por `data-depth`, como cualquier panel flotante del ecosistema. - **Tooltip vs submenú**: una fila con submenú no lleva tooltip en modo icono (dos superficies sobre el mismo ancla se pisan) — nuevo `useSidebarItemOr()`. - El item envuelve (`flex-wrap`) para que el submenú caiga en su propia línea en vez de ponerse al lado de la fila. Demo: shell de app real (grupos, badge, acción, submenú, fila deshabilitada), controles vivos de los tres props y las 9 pestañas del canon. Verificado en navegador real (Playwright): dos landmarks nombrados en el idioma activo · `aria-current="page"` en la fila activa · cada menú etiquetado por SU grupo · raíl enfocable que alterna con Enter · colapso 256→48px · off-canvas por transform · submenú flotante anclado a su fila y Escape que devuelve el foco · sema `emerge-expand/collapse` estampando en `panel` · móvil 600px = Drawer cerrado con el landmark dentro · RTL espeja el shell entero · oscuro · 0 errores de consola. Gates: `component:audit --only sidebar` PASS 0E/0W · eidos-lint 45 morfo-backed / 0 invalid / 0 class-hooks · `svelte-check` 0 errores propios · `vitest src/uix/eidos` 353/353 · `contracts.test` solo con fallos ajenos (menubar, radio-group y las claves camelCase de aura). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
e28df1817f |
docs(blocks): registro F1.7 fase morfo+soma en el plan
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
2bc5fe6bd2 |
uix(sidebar): F1.7 fase morfo+soma · contrato de 17 partes + shell headless
Primera tanda del último componente de F1, con el alcance firmado por el usuario (17 partes · submenú flotante en modo icono · sema emerge · parada tras morfo+soma). Suelo de paridad: dossier §P4, leído del `sidebar.tsx` real de shadcn (23 partes); nadie headless lo tiene (Radix/Base/Ark/React-Aria). Morfo (17 partes, 2 eventos) - DOS ejes, no uno: `data-state` (expanded|collapsed) + `data-collapsible` (offcanvas|icon|none), este último SIEMPRE estampado (shadcn solo lo pone colapsado, lo que obliga a cada regla a guardar por estado). Más `data-side` y `data-mobile`. - `panel` (no `sidebar`, que daría `data-sidebar-sidebar`) = `<aside>` NOMBRADO; `content` = `<nav>` NOMBRADO, con header y footer FUERA: así el landmark nombra la navegación y no el cromo. Ninguna referencia trae landmark. - `rail` es una parte física y un `<button>` REAL en el orden de tabulación (shadcn lo deja en tabIndex=-1, inalcanzable por teclado). - `aria-current="page"` sale del MISMO prop que `data-active`, en `menu-button` y en `menu-sub-button`. - `menu-badge` va DENTRO del control de la fila (doctrina de nav-tree: su texto entra en el nombre accesible). `separator` e `input` NO son partes: se componen el `Separator` y el `Field` canónicos. Soma - Estado controlado/no controlado con las costuras exigidas por el dossier desde v1: `open` bindable, `defaultOpen`, `onOpenChange` y `toggle()` público — sin ellas, persistencia y atajo global en app-land serían rediseño posterior. - `mobile` sale del breakpoint del SISTEMA (`uix.dom.isAtLeast`), nunca de un `matchMedia` propio; soma solo decide el hecho y estampa `data-mobile` — la presentación como `Drawer` la compone el eidos (y con ella su foco atrapado, bloqueo de scroll y descarte). - Submenú que SOBREVIVE al modo icono: `menu-sub` se vuelve superficie flotante anclada al botón de su fila (`createFloatingShellRoot` + anchor + content), se abre por hover/foco y se cierra por salida, blur o Escape devolviendo el foco al botón. shadcn los OCULTA y deja ramas enteras inalcanzables. - Dos `partRef` del morfo se resuelven last-write-wins entre instancias, así que soma da el id per-instancia (precedente `navigation-menu`): `aria-labelledby` del menú → la etiqueta de SU grupo; `aria-controls` del trigger/rail → el id del panel. Sema: pack propio con `emerge.soft` / `emerge.exit.soft` sobre `panel`, espejando nav-tree y collapsible. Langs: 4 textos (label, nav, trigger, rail). Verificado: `morfo:check` carga el contrato sin invariantes rotas · `component:audit --only sidebar` **PASS** (0E/0W) · `svelte-check` 0 errores en estos archivos · `contracts.test` solo con los 2 fallos ajenos conocidos (menubar DOM-write, radio-group data-ready). Pendiente de la siguiente tanda: eidos (raíl, anchos tokenizados, modo icono, Drawer móvil), demo y review adversarial. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
ef6bd13be3 |
uix(nav-tree): `disabled` por nodo — destino no disponible
Decisión del usuario. Un nodo deshabilitado conserva su fila (sigue siendo parte del mapa) pero pierde el `href`: no hay nada que activar con clic, Enter ni «abrir en pestaña nueva». Un `pointer-events: none` de CSS solo habría tapado el ratón. - morfo: la parte `link` gana `data-disabled` (propRef) y `aria-disabled` (literal `true` bajo `prop-truthy: disabled`). - soma: `disabled` solo aplica con `href` (un grupo sin destino lo ignora); el toggle del grupo NUNCA se deshabilita — mostrar/ocultar es control de vista, no destino. - eidos: fila en `--color-content-disabled`, sin puntero y sin hover. - demo: «Agent» va deshabilitado con badge «Soon» + filas de API y a11y. Verificado en navegador real: `<a>` sin href, `aria-disabled="true"`, `data-disabled`, color 0.79 frente a 0.61 de una fila normal, clic sin efecto, fuera del orden de tabulación (44 focusables en vez de 45), badge dentro del control. `component:audit` PASS · eidos-lint 28 morfo-backed / 0 invalid · `vitest src/uix/eidos` 353/353 · svelte-check 0 errores míos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
a7e629f9ed |
uix(nav-tree): F1.8 CERRADA · demo + navegador + review adversarial
Cierra el árbol de navegación data-driven (E-1) de F1: demo canónica de 9
pestañas con el mapa real de docs (43 nodos, 3 niveles), verificación en
navegador real y review adversarial (5 dimensiones × 3 verificadores
escépticos; 22 hallazgos brutos, 10 confirmados) con todos los confirmados
arreglados.
Arreglos del review
- sema: la parte `group` —target de los eventos emerge— se registraba SIN
`ref`, así que `runtime.trigger` lanzaba `SomaRuntimeTargetError` en
silencio y el pack no sonaba nunca (cero `data-event-*` en el grupo frente
a los de collapsible). El provider posee ahora el ref del `<ul>`.
- eidos: en una fila navegable el chevron resolvía `inline-size: 100%` como
flex-basis y ocupaba media fila (101 de 231 px en «Soma»), robándole clics
al enlace. Toggle compacto con suelo de diana de 24 px (WCAG 2.5.8).
- soma: una clave duplicada podía volver cíclico `parentByKey` y colgar la
pestaña dentro de `trailKeys` (deriva en render) → clave sufijada + aviso
del logger + guarda de ciclo en el paseo.
- soma: el colapso es CONTEXTUAL (recuerda el `activeKey` bajo el que se
hizo): cerrar la sección que lees se respeta, pero caduca al navegar
DENTRO del grupo, para que la página actual nunca quede sin fila visible.
Sigue siendo query pura, sin `$effect` que escriba estado.
- soma: `child` recibe también `children` (el árbol renderizado); antes
dejaba el landmark vacío, porque un árbol data-driven no lo puede
reautorar el consumidor.
- morfo + langs: el nombre accesible del chevron se declara en el contrato y
se localiza («Alternar sección {label}»); ya no duplica el del enlace.
- eidos: RTL completo — el glyph espeja solo (bordes lógicos), lo que no
espeja es el giro, así que bajo `[dir='rtl']` las dos rotaciones se
intercambian. El Gap «dirección del chevron en RTL» queda RESUELTO.
- demo: paridad de snippet con los controles vivos; fuera el token fantasma
`--nav-tree-rail-width` del docblock del recipe.
badge en v1 (decisión del usuario, delegada)
Está en el suelo de paridad del dossier §P5 (los 6 refs lo llevan). Se
resuelve con SNIPPET, no con recursión a nivel de eidos: el morfo declara la
parte `badge`, soma renderiza el snippet recibido (sin él, el valor crudo —
sigue siendo headless) y el wrapper de eidos pasa el `Badge` canónico. Va
DENTRO del control de la fila, así su texto entra en el nombre accesible
(«TSC, New, enlace»). `disabled` se descarta en v1 (fuera del suelo, y un
enlace de navegación deshabilitado es semánticamente dudoso); ambos quedan
registrados en la tabla de Gaps.
Verificado: `component:audit` PASS · eidos-lint 26 morfo-backed / 0 invalid ·
`svelte-check` 0 errores en estos archivos · `vitest src/uix/eidos` 353/353 ·
navegador real (Playwright): trail auto-expandido, sema estampando en el
grupo, teclado nativo, foco visible, claro y oscuro, RTL, 375 px sin
desbordes, 0 errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
549c5e5abd |
docs(agent): D-AG.12 pendiente de firma — el contrato como referencia
PLAN §5: la decisión editorial planteada con el usuario (2026-07-22) queda firmable al retomar — (a) elevar agent.md a especificación publicable («el contrato de delegación») con agent-check como suite de conformance y el checklist de amenazas como anexo; (b) nombrar las dos reclamaciones de frontera que F4/F2 ya materializan: contexto por atención y delegación como transacción; (c) posición honesta declarada (acts secuenciales v1, cliente-first, generalidad pendiente del 2º/3º consumidor). continue-agente: punto 0 del orden de trabajo → firmar D-AG.12. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
e835163103 |
uix(nav-tree): F1.8 WIP · data-driven docs nav tree (soma+sema+eidos)
Complete component, green on all static gates (audit PASS, eidos-lint 20/0, svelte-check 0, contracts clean for its parts). NOT tree-view: APG Disclosure Navigation (<nav> landmark + native links + disclosure groups), data-driven (E-1) — the app passes `nodes` + `activeHref`, the provider resolves the active node and auto-expands its ancestor trail. - morfo: nav/list/item/trigger/link/group; emerge-expand/collapse events - soma: NavTreeProvider (shared state, pure isExpanded query) + per-node NavTreeItemProvider (menubar pattern, recursive render) - sema pack: soft emerge on group disclosure (mirrors collapsible) - eidos: rail + per-depth indent recipe; own bespoke rows (not composed Link), Badge deferred to a Gap; aria-current="page" from data-active Remaining before F1.8 closes: demo + browser verify + adversarial review. Handoff: docs/process/CONTINUE-nav-tree.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
931a98b7c4 |
fix(anchor-nav): add missing soma README (contracts guard)
The soma component README was never committed with F1.6, so contracts.test's "public Soma component modules with local README docs" guard was failing and the eidos README's link to it was broken. Adds the headless-contract README; both guards go green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
1cc8a87722 |
docs(agent): continue-agente — handoff para la próxima sesión
Estado al cierre (F0/F1/F3/F4a cerradas + tabla de commits), verificación rápida al retomar, siguiente trabajo en orden (F4b chat → F2 gated → flecos), y la disciplina operativa de la rama compartida + gotchas de entorno (Ollama/OpenWebUI, pane, Chrome MCP, index:0 del stream). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
0ab40cdcee |
uix(agnt): Aura al centro de un OnionMenu — afordancias radiales por estado
La composición que pidió el usuario: el orb es el trigger central de un OnionMenu placement="center" y las afordancias de custodia aparecen como sectores contextuales — reviewing→Authorize/Reject, escalated→Approve/Deny, activo→Stop — sin fila de botones. El anillo se abre SOLO mientras la custodia espera a un humano, con re-aserción (un cierre externo sin resolver re-abre: el efecto lee onionOpen como dependencia); por click en el centro mientras actúa; se pliega al devolver el control. App-land por doctrina (agent.md §7): el framework da estados + afordancias (Aura) y componentes (OnionMenu); el app da forma a la superficie de review. Patrón documentado en el README de aura (§Patrón). E2E verificado en Chrome real contra qwen3-coder: la escalada real por doc.clear abre el anillo con el orb rojo al centro → Deny en el sector → returned(aborted, user-cancel) + «Agente: terminó — control devuelto» + documento intacto. check 0 propios · smoke agnt PASS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
d008605fac |
uix(aura): variante orb por defecto en el indicator — presencia perceptible
El aurora (banda horizontal recortada al círculo) leía estático a 32-48px (señalado por el usuario). El render vivo pasa a ser el efecto `orb` de $scene — la presencia esférica nativa: anillo respirando con ruido + luz orbitando, movimiento de silueta perceptible en tamaños pequeños y deformable por el puntero. `aurora` queda como variante para superficies grandes (`<Aura.Indicator variant="aurora">`). Modulación §F6 del orb: el estado fija la energía (forceHoverState + hoverIntensity como gain + rotateOnHover en acting/escalated) y el rol el matiz como delta de hue OKLCH sobre la identidad del shader (primary; reviewing=risk, escalated=threat). Verificado en Chrome real, estado por estado: idle recogido → planned anillo violeta → acting denso rotando → escalated rojo agitado. Demo de aura: chips de variante; scene/README: acta D4 pendiente de F3. eidos 353/353 · check 0 propios. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
97ae19da50 |
docs(agent): sección de configuración del transporte en la página agnt
La demo usaba el adaptador sin documentar cómo se configura. Nueva sección «Configuring the transport»: qué es el puerto (turn = un intercambio de cable), adapters fuera del barrel, ejemplo dev-directo vs prod-proxy (topología de credenciales), tabla completa de opciones (baseUrl · model · headers · request · fetch) y qué POSEE el adaptador como traducción de dialecto (SSE→v1, sanitización de ids, re-pairing de tool_calls, split por id en servidores que reutilizan index 0, error de cable → transport-error). README del arte: opciones inline en la entrada del adaptador. check 0 propios · smoke agnt PASS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
595040b73b |
feat(agnt): Aura como superficie de presencia de la demo con modelo real
La respuesta a «¿está pensando?» no se improvisa — es Aura, el componente
del eje construido para ello. La sección real de la página agnt bootea un
uix standalone mínimo (createActiveUix + Soma + ActiveEidos + eidos css):
legítimo porque un app compone ambos tiers, y la demo ES el app.
- Motor llama → createActiveAgent (mismas opciones bus+journal); activeRun
reactivo satisface AuraAgentSource; stream vía .engine.onEvent
- <Aura {agent}> con Indicator (orb $scene) + Status + Region + Cancel;
authorize/escalation quedan como afordancias app-level (doctrina §7)
- Verificado sobre el run real de qwen3-coder: «Inactivo» → «Propone un
plan» → announcement «Agente: terminó — control devuelto» en la Region,
doc mutado, answer en es; Cancel = Button disabled-en-idle; consola 0
check 0 propios · agent 30/30 · smoke agnt PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
447a87239c |
feat(agent): adaptador openai-chat real + carril de iniciativa del bus
El bus como eje del agente a nivel de app, cerrado en tres direcciones:
observar (agent.*), reaccionar (orca) e INICIAR — hecho de dominio → acción
orca → App.agent.start({initiative:'system'}) con clamp auto→review por
construcción. Nunca command-events. Sección doctrinal + ejemplo en la página.
Adaptador real `$agent/adapters/openai-chat` (fuera del barrel, D-AG.1c):
dialecto OpenAI chat-completions (Ollama/llama.cpp/LM Studio/proxy), SSE →
protocolo v1, sanitización bidireccional de capability ids con puntos, y
re-pairing de tool_calls al reproducir el transcript (memoria por callId).
Fix cazado en vivo: Ollama reutiliza index:0 para todas las calls del
stream — una call nueva se detecta por id distinto, jamás por index (los
args concatenados producían invalid-args en motor + 400 en el replay).
Demo viva en /active/docs/agnt contra qwen3-coder:30b real: capacidades
doc.* tipadas (sium), read snapshot-por-turno, streaming, escalada
irreversible. Ciclo completo verificado en navegador: 3 acts, 2 turnos,
doc mutado, respuesta en es, rastro entero en bus (correlationId=runId).
agent 30/30 · smoke agnt PASS · check 0 propios.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
fa71890564 |
fix(agent): conformidad bus/orca — payload del bus sin contenido de usuario
Auditoría punto-a-punto contra los README de bus y orca (12/13 conforme).
La no-conformidad real: `goal` viajaba en AgentRunBusPayload, contra la
higiene documentada de ambos (bus: «pasa correlationId y que el suscriptor
resuelva el contexto sensible del módulo»; orca: «no unnecessary private
data — la acción lo resuelve del módulo al ejecutar la acción»).
- AgentRunBusPayload = SOLO metadata (runId/initiative/autonomy/state/
outcome/reason/acts/turns); el suscriptor resuelve vía App.agent.run(runId)
- spine test prueba el patrón: 'goal' in payload === false + resolución
desde el módulo con el orca REAL
- página agnt: nota de higiene + recomendación configureEvent(
'agent.run.state', { queuePolicy: ORCA_QUEUE_REPLACE_QUEUED }) para el
evento frecuente (doctrina de colas de orca)
- PLAN-agent F4a: acta de la auditoría de conformidad
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3 months ago |
|
|
803b588ba5 |
feat(agent): F4a · marco de integración app — bus/orca/página del arte + fixes de auditoría
Auditoría del track (encargo): divergencias firmadas-sin-implementar corregidas y el marco de integración INDEPENDIENTE del componente — el agente como servicio del app, no como demo de un componente. Fixes de decisiones firmadas (con tests): - C3/D-AG.7: la iniciativa autónoma (system/scheduled) clampa auto→review — un run que el usuario no pidió jamás se auto-autoriza. - D-AG.5: presupuesto de contexto (maxContextBytes) con FIFO-trim byte-based (el goal sobrevive; resumen semántico diferido) + log del recorte. - F4c: tope por-arg (maxArgBytes) → invalid-args tipado. - D-AG.6d: schema Standard-Schema del resultado (`result?`); un mismatch vuelve como recoverable para auto-corrección y no cuenta como act. Integración app (patrón session EXACTO): - El arte posee el vocabulario `agent.*` (consts) + bus-helpers tipados que publican con bus INYECTADO (type-only $libs/bus): run.opened/state/ escalated/closed + act.applied, con source='agent' y correlationId=runId — la costura causal ligera (una delegación correlaciona de punta a punta). - defineActiveAgent cablea core.bus (junto a timers/logger). - Reacciones vía orca APP-LAND (el invariante intacto): probado con EngineOrca REAL reaccionando a agent.run.closed en integration.test. - Página del arte /active/docs/agnt (la convención que faltaba): sección Delegation en nav; artículo + playground VIVO con los 4 motores puros reales (bus log en vivo, journal WAL, contador orca, kill switch, compuertas deterministas) — cero componentes, integración pura de app. Gates: agent 26/26 · smoke agnt PASS · check 0 propios · verificado en navegador (pane + Chrome real): ciclo completo, orca archiva runs, kill switch reactivo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
6f9edfaa3b |
docs(palabras): bitácora 2026-07-22 — barrido de calidad 18/18 + Menubar.Panel + #6
Nueva sección de estado en el handoff vivo: el barrido adversarial (18/18 arreglados, 6 refutados, 7 commits verificados por test/Playwright), la infra Menubar.Panel que se commiteó ( |
3 months ago |
|
|
2803d5dddc |
docs(blocks): registro F1.6 anchor-nav · F1 = 6/8
Adversarial-review outcome (fixes + documented v1 limits) and the two piggybacked sticky type-fixes recorded; scoreboard corrected (prose F1.5 had also landed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
37e35d7a2d |
fix(sticky): sentinelRef is State + eidos types import ProviderProps
svelte-check surfaced two F1.1 type errors: the sentinel is a writable ref bound by the wrapper, so it belongs in StateProps (not ActiveProps — part() wants State<HTMLElement|null>); and the eidos types barrel must import the renamed ProviderProps export, not the internal StickyProps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
fe2d43b7ac |
uix(anchor-nav): F1.6 · scrollspy TOC (soma+eidos) + hardening
Nav landmark + native anchors; IntersectionObserver band detection (never a scroll listener + getBoundingClientRect — anti-reflow doctrine). aria-current="location", per-depth rail indent, data-active drives the eidos accent. Real-IO chromium test: band tracking + bottom dead-zone. Adversarial-review hardening: - ref-count register/unregister so duplicate hrefs / mount churn can't drop a still-referenced target (+ test) - tokenize the rail transition (--duration-fast/--ease-default) and the focus outline-offset (calc(var(--focus-ring-width) * -1)) - document two v1 limits (instant-jump dead-zone, link-order == section order) — both need a v2 observation-contract change Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |
|
|
e187ab6d72 |
docs(agent): F3 cerrada · doctrina «The review surface» — split framework/app
Cierra los dos flecos de F3 tras la corrección del usuario (la review-card con diff era anclaje en dev-tools, sin sentido a nivel framework): - agent.md §7 gana «The review surface»: el FRAMEWORK posee los estados del ciclo expresados perceptualmente (reviewing/escalated con afordancias authorize/reject/cancel — Aura ya las da) + la semántica de «propuesto por otro actor» + los anuncios atribuidos; el APP posee el CONTENIDO de lo que se revisa, en su propio dominio (un documento enseña sus bloques propuestos, un calendario sus eventos pendientes). Una tarjeta-diff estilo git es legítima en una aplicación concreta; jamás canon. - §6 fatiga de aprobación enmendada en el mismo sentido (el cambio concreto en el dominio del app, nunca prosa). - PLAN: F3 CERRADA — review resuelta como doctrina sin componente nuevo; `allowedFamilies` del primer componente actuado reubicada a F2 (su hogar natural es el piloto). Siguiente: F4 por la vía del chat. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
92d060a4fb |
fix(soma/menubar): getOrderedValues en orden DOM, no de inserción del Map (#6)
El barrido de calidad de palabras confirmó que el foco por flechas (ArrowLeft/Right,
Home/End) y el hover-slide divergían del orden visual tras navegar a un elemento con
más secciones contextuales: el `{#each}` keyeado reutiliza los triggers persistentes
y los nuevos se APPENDEAN al Map después, así que el orden de inserción ≠ orden DOM.
Ahora getOrderedValues ordena por compareDocumentPosition (query estructural,
reflow-safe), corrigiendo navigateAdjacent/focusEdge/onContentKeydown/hover-slide en
un punto. 5/5 tests del menubar verdes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
3 months ago |
|
|
2c175c5d95 |
feat(aura): fases 7–8 · README eidos + component:audit PASS — Aura completa (0–8)
Cierra el primer componente del eje agéntico de punta a punta (las 9 fases de la ruta). `component:audit` PASS. - README eidos con comparativa (5 refs adyacentes — thinking-indicators, CopilotKit activity, Vercel useChat.status, presencia colaborativa Figma/Docs, assistant-ui) reconociendo el paisaje escaso: nadie tiene una semántica perceptiva de la delegación con a11y (informe §8.3). Decisiones + Gaps con disposición. - Fixes del audit: opacity literal `0.5` → `var(--opacity-50)` (R-4.2); excepción R-1.5 documentada (único focusable = Cancel, que compone Button); `apg: 'none — …'` en el morfo (A-1.4). Gates: component:audit PASS · morfo:vocabulary limpio · eidos-lint aura 0 inválidos · recipe-contract verde. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
3 months ago |
|
|
ef85b9223d |
fix(soma/menubar): 3 errores de tipo de la infra Menubar.Panel
Reparan el commit anterior (era WIP con errores de svelte-check; runtime OK): - provider: `tabindex:-1` en los props del panel estaba duplicado (focusScope.props ya lo aporta con el mismo valor) → quitado el explícito. - menubar-panel: el prop `style` (de PrimitiveDivAttributes = `Record<string,unknown>`) no encajaba con el opt del provider (`StyleProperties`) → cast en el create. - test: `props['aria-haspopup']` no es clave estática del tipo (es atributo del morfo resuelto por renderProps en runtime) → acceso vía cast a Record. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
3 months ago |