Segunda pieza de la firma de los 318 (F2). El residuo que F1 dejo se
adjudica POR CLAVE, cada acta con su medida: 150 = 84 ANOTADOS + 66 al
LEDGER + 0 sin nombre.
- Valvula nueva /* private: <razon> */ -> clase exception (vocabulario
cerrado). Corre en una CUARTA pasada, la ultima: donde una prueba mecanica
ya decidio, una firma no tiene nada que firmar. La nota va en el bloque de
comentario ENCIMA de la declaracion (al final de linea, prettier partiria
el var() - un commit de anotacion no reescribe el CSS que viene a firmar);
el paseo hacia arriba solo salta lineas que eran solo-comentario.
- private es DebtClass: clave `private - {fichero} - {selector} -
{propiedad}`, newDebt y STALE simetricos. Un privado no-derivado nuevo ya
no puede entrar sin nombre. Ledger 1088 -> 1154 (+66, 0 claves perdidas,
verificado contra el blob de HEAD, no regenerado en bloque).
- ANOTADOS 84: 59 con ficha SS5 firmada que lo dice (card, avatar, badge,
surface, switch, timeline, textarea, spinner, skeleton, metrics,
float-panel, image, toolbar, button, drawer, listbox) + 25 medidos
(proof-of-human 17: el puente UN NIVEL bajo el knob, base verbatim del
forward, medido dos veces; form 4: conmutador-identidad; 4 sueltos).
- LEDGER 66: casi todo UN patron - el conmutador de tono A MANO
([data-color=risk] { --_c-accent: var(--color-risk-solid) }) sin adoptar
el forward THM-2 (time-range-picker 19, chronos 14, time-picker 12,
date-range-picker 9...) mas las tallas prestadas de field. Se retiran el
dia que esa familia adopte la escalera de paleta.
- Contradiccion con ficha RESUELTA por medida: metrics SS5 decia que el
conmutador del icono derivaba entero de publicos - cierto para track/text,
falso para solid/contrast (leen roles crudos): 3 anotados, 2 al ledger.
timeline SS5 (pre-B') se respeta y queda señalado para reabrir.
Mutaciones (backup+restore en finally, arbol comprobado): privado nuevo ->
newDebt lo nombra y suelo ROJO; anotado -> verde; registrado -> verde;
ledger'd que gana su nota -> STALE hasta borrar la linea. --debt final:
1154 registered - 0 new - 0 stale, dos corridas. Suelo 5/5, audit 162 PASS
sin flips, tsc 0 propios, diff de los 22 css = 100% comentario (verificado
por strip programatico contra el blob de HEAD), prettier 0 regresiones.
Reach 71% -> 73% (3074/4228). El suelo (69/45) y la prosa "318" los sube F3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 claves nuevas y 4 literales anotados. Subiría más, pero medir destapó que cinco
de sus claves no pintan: el plano `overlay` le gana la superficie ENTERA.
Acuñados el desenfoque del velo `ghost` y las dos tintas de la flecha `outline`,
que se pintan por selector HERMANO desde el contenido.
⚠⚠ EL PLANO NO SÓLO SE QUEDA LA TIPOGRAFÍA: SE QUEDA EL FONDO, EL BORDE Y LA
SOMBRA. `[data-depth='overlay']` declara las tres con la misma especificidad que
`[data-tooltip-content]` y más tarde en la cascada. Medido: escribir
`--tooltip-bg`, `--tooltip-border` o `--tooltip-shadow` no mueve NADA, mientras
`--depth-overlay-surface` / `-border` / `-shadow` repintan el panel. Con
`font-family` y `line-height`, son cinco públicos que no alcanzan.
Y LA CONSECUENCIA VISUAL ES PEOR QUE LA CONTABLE: LAS TRES VARIANTES SON LA
MISMA. Medidas `solid`, `outline` y `ghost` con el panel abierto: fondo, borde y
sombra IDÉNTICOS en las tres. `outline` es indistinguible de `solid`; `ghost`
sólo se diferencia por un `backdrop-filter` que no se ve porque la superficie que
tiene delante es opaca. La máquina de variantes existe, alimenta privados, y el
plano la anula entera. → §13.
Por eso no se acuñó `ghost-bg`: lo intenté, el centinela lo delató y se retiró
antes de commitear. Las cinco que ya estaban quedan ADJUDICADAS, no retiradas:
son la FUENTE de esa máquina de variantes, y borrarlas dejaría inválidos los
privados sin arreglar nada. La corrección de fondo es la precedencia del plano —
la misma firma §12.9 que arrastran menubar, dropdown-menu y combobox.
`content-z` sí está vivo, pero en otro nodo: aterriza en el ENVOLTORIO flotante
(90 → 4321), que no lleva ningún `data-tooltip-*` y queda fuera del conjunto
medido.
Instrumento: un tooltip abre por HOVER, no por clic (`openBy: 'hover'`, como
link-preview) — con eso pasó de 0/24 a 14/24. El resto se midió con el
interruptor `open` de la demo: un panel abierto por puntero exige el ratón quieto
sobre el disparador toda la pasada, y no es medida fiable.
Gates: sonda 0 diffs en 256 valores × 8 estados · centinela 15/23 con las ocho
adjudicadas · censo 75 % · suite eidos con el rojo conocido ajeno · `rtl:check` 0
· `docs:check` 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
D-TH.6, ejecutada. El slot de tinta pasa a `fg` y el modificador interactivo
se pone delante, que es lo que theming §6.7 r7 documentaba sin guard desde
que se escribió. Value-preserving: renombra la clave en `recipes/base.ts` y
sus 793 referencias en 101 ficheros; no toca un solo valor.
claves renombradas 269 en 66 componentes
referencias 793 en 101 ficheros
censo antes/después 162 recetas · 5.203 knobs · 1.841 públicos (37 %) · 56
sin contrato — IDÉNTICO, como debe ser un rename
--names antes/después 269 desviadas → 0
Qué NO entra, y por qué:
47 `{rol}-{slot-de-rol}` canónicas: COLOR_ROLE_SLOTS pone el modificador
detrás POR CONSTRUCCIÓN (`primary-solid-hover`)
13 exentas firmadas `--focus-ring-*` es familia del sistema; el color
de `aura` es un sustantivo; `stop-color` ES una
parte de gradient-builder
47 hovers neutros por VALOR: migran a la capa de estado
(§38 + R-4.3), no se renombran — firma 3
6 ocurrencias en historia changelog, errores-toxico, PLAN-affix/background:
reescribir un registro fechado lo vuelve mentira
El clasificador vive en el censo (`--names`), no en un script suelto, para que
el guard R-5.3 consuma la MISMA gramática que el codemod. Su muta-prueba
(`__names-mutatest.ts`, 27 casos) es lo que hizo el trabajo: cazó que yo
promovía al frente CUALQUIER valor declarado por el morfo, y así
`--sidebar-width-icon` (la anchura del raíl colapsado) se convertía en
`--sidebar-icon-width` (la anchura de un icono), que es otra cosa. La firma
dice «delante lo interactivo, detrás lo dimensional y contextual»: ahora sólo
promociona el vocabulario interactivo cerrado, y lo contextual —`below`,
`loaded`, `vertical`, `icon`— se queda donde estaba. Los cinco casos de
regresión están en la muta-prueba.
También cazó que `dropdown-menu.item-bg-hover` lee `var(--color-primary-element)`:
es un hover CON VALENCIA (el palette swap de recipe-contract §2), no el hover
bespoke que §38 deprecó. Clasificar por el nombre lo habría metido en una
migración que no le toca; se clasifica por el VALOR.
Verificación (§7.4, artefacto por paso):
diff de generated/ 269 renombres 1:1 · 0 cambios de valor · 22 privados
reapuntados a los nombres nuevos (`__names-verify-diff`)
computed tag-group · field · tabs: 6.467 valores en 23 estados,
0 diffs — y comprobado en el navegador que sirve el CSS
nuevo, para que ese 0 no sea el de una copia cacheada
huérfanos 0 en código
suite eidos 434 pasan · 1 rojo, el conocido (`skin-media-player`).
`recipe-css-contract` verde: es el guard que caza el
`var()` sin fallback a un nombre que ya no se emite,
o sea el fallo exacto de un rename a medias
component:audit 163 PASS · 3 NEEDS-WORK, los tres SIN TOCAR por esto
check 0 errores en ficheros tocados (los 73 globales son de
otras sesiones de la rama; se atribuye por fichero)
rtl:check 0 · docs:check 0
formato el renombrado no alarga ninguna línea: ningún fichero
tiene más líneas de 100 chars que antes, así que no se
pasa prettier — hacerlo reformateaba 300 ficheros de
deriva ajena
Entra aquí la corrección del repaso de los 7 ya hechos:
`gradient-builder.checker-color` → `checker-fg` (el damero de transparencia;
ahí `color` era slot). Sus `stop-color-*` no se tocan.
Queda para el paso siguiente: R-5.3 no puede graduar a `error` directo
mientras los 47 hovers neutros sigan hablando el idioma viejo — o migran
antes (firma 3, ya firmada), o el guard necesita una exención greppable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Fable audit follow-through (fable_audit.md + fable-eidos-audit.md):
- RECIPE_CONTRACT.md (E2 canon): the transversal systems every recipe must
consume, enforced by component-audit R-4.1-4.6 (all at error; escape
valves /* literal */ + /* functional */; WIP tracks excluded). Stale
audit rules fixed against the current architecture (E-2.2 wrapper
imports, D-1.2 v2 9-tab union, D-3.1 single snippet, TabsVariant
mirror) - verdicts went 0/117/15 -> 75/50/5.
- Motion migration 15/15: recipes off local @keyframes onto the channel -
preset stamps (dropdown/context/select/combobox/tooltip/link-preview/
clipboard), new expand/collapse + value-flash signatures, shared-axis
reverse pair, delayed-open open-alias in the preset trigger
(PRESET_STATE_ALIASES), materials pattern for irreducible triggers
(card/timeline/tabs/nav-menu/metrics). Duration/scale hooks keep every
recipe's tuned values.
- buildScheme (fase C): full a1..a12 alpha ramp per role (was a2/a3 -
stale alphas after applyColorScheme), intentSeeds so temper starts from
the ACTIVE theme's intent mapping (risk stays orange), alpha background
self-derived from the scheme's own neutral step 1 (was hardcoded
#fff/#111); mode now forces the donor variant.
- Inventory decisions (fase D): semanticTracking axis removed (all-zero),
border-hover slot dropped (0 consumers), separator slot adopted across
line dividers (step 6, Radix divider tone), size-bundle consumption
pilot on toggle (canonical coordinates consumed, deliberate deviations
kept visible).
- Docs: building-a-component.md (the one door, 9-phase route + known
traps), PLAN-docs-reconciliation.md (fase 6 kickoff for a fresh
session), THEMING wiring updates.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A perceptible line showed across the caret base on every side but bottom: the
panel's border draws across the caret's base edge, "cutting" it off from the panel.
Add the popover's per-side fix — pull the caret base into the panel by the border
width (margin toward the panel, keyed on data-side) so the fill covers that border
and the caret's side strokes continue the panel outline seamlessly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A single-direction drop-shadow on the caret is wrong: the caret sits at the panel
edge pointing AT the trigger, so on a bottom-side tooltip (caret at the top) the
downward shadow falls onto the panel below it — a dark smudge over the content.
Remove it. The caret keeps the panel-bg fill + border edges (no black blob, no
smudge). A shadow that reads correctly would have to wrap the whole panel+caret
silhouette (content-level drop-shadow), not the caret alone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the un-clip fix (c3def5d6). With the caret no longer clipped it was
visible, but it rendered in `currentColor` (the dark text colour) — a black triangle
on a light panel. Colour it to the panel bg (a seamless caret) + the panel border on
the two exposed edges, and give it its own `drop-shadow` so the matched (light) caret
still reads against the page — the panel's box-shadow is rectangular and never reaches
the caret. This is the "matched + visible" caret (the drop-shadow-on-the-silhouette
idea) now that overflow:visible lets it show.
VERIFICATION CAVEAT: confirmed the colour at the computed-style level (polygon fill ==
panel background, was the dark text colour). Could NOT capture a stable screenshot —
the demo tooltip closes on every programmatic/cursor interaction, so the visual pop of
the drop-shadow is unverified here. If the matched caret reads too faint, bump the
drop-shadow alpha or fall back to the darker caret.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The tooltip content is `position: relative; overflow: auto`, so the caret
(`position: absolute`, containing block = the content) that pokes past the panel
edge was CLIPPED away — invisible regardless of its colour. Confirmed by measuring:
the caret sits fully outside the content box, and the content clips its overflow.
Change the content to `overflow: visible` — the same reason the popover content is
`overflow: visible` (its comment literally says "fixes the arrow that overflow:auto
used to clip"). Tooltips are short, so no inner scroll viewport is needed.
Verified in a real browser: the dark caret is now clearly visible pointing at the
trigger. Combined with a40d1573 (caret colour back to currentColor) + the earlier
`display: block` (correct arrow height → correct trigger gap), the tooltip arrow is
visible and correctly placed again.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
My previous commit (4afadfd7) over-corrected: it changed the caret fill from
`currentColor` (the panel's dark text colour — long-standing, visible) to the
panel background, aiming for a "seamless extension". On a light-on-light tooltip
that makes the caret INVISIBLE — the panel reads only because of its box-shadow,
which the separate caret element doesn't share. The user had a visible caret
before; the "correct" colour regressed it.
Revert the polygon/path colour rules (caret returns to `currentColor` = visible)
and keep ONLY the `display: block` on the SVG — that was the fix that mattered: it
removes the ~21px of inline-baseline phantom height that both misaligned the caret
and, because the positioner adds the measured arrow height to the gap, pushed the
panel too far from the trigger. So: caret visible again + panel sits at the correct
~13px gap. A properly matched-and-visible caret (bg fill + its own drop-shadow) is
deferred until it can be verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The tooltip arrow SVG carries `fill="currentColor"` / `stroke="currentColor"`
presentation attributes, so setting `fill`/`stroke` on the wrapping `<span>`
(`[data-tooltip-arrow] { fill: … }`) never reached the shapes — an element's own
presentation attribute beats an inherited value. The caret therefore painted with
`color` (the dark text colour) instead of the panel background, and the `<svg>` was
left `display: inline`, adding phantom baseline height (26px box for a 5px caret)
that misaligned it. Net effect: the caret didn't read as a caret.
Fix mirrors the popover recipe: colour the `polygon` (fill = panel bg) + `path`
(stroke = panel border) directly, and set the `<svg>` to `display: block`. The
tooltip caret is now byte-identical in treatment to the popover's (fill = content
bg, 1px border-coloured edge). Also fixes the outline variant, which had the same
span-vs-shape mistake.
Pre-existing bug, unrelated to the avoidCollisions:'flip' rollout. Verified in a
real browser: polygon fill now equals the content background, svg is block, caret
positioned correctly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
24h picker driven by a horizontal daylight gradient — drag the sun/moon
thumb across the night→day→night sky, jump with moment chips, or nudge
with hour/minute/second steppers. Inline panel + trigger/popover variants,
built on the generic Picker (deferValue) composing Slider, Button,
PickerShell, Popover and Tooltip.
- granularity (hour|minute|second) + optional band props; steppers keep a
fixed 3-column grid; shape/size propagate to panel, trigger and chips.
- fixed-tone sky palette as named recipe tokens (theme-independent).
- fix soma Tooltip.Arrow (empty children slot hid the default SVG) and
make PickerShell footer labels locale-reactive.
- floating-gap canon: --floating-gap-menu 0 -> var(--space-1); FloatingContent
reads --floating-gap via a reactive $derived (was a one-shot rAF that never
reached portaled menus -> they fell back to sideOffset, flush); nav-menu wired
to the token via CSS.
- focus-ring: exclude item/option/content from the universal archetype ring; menu
rows use the canonical highlight on :focus-visible too (no thick keyboard border,
no ring framing the whole float).
- overscroll-behavior: contain on the ScrollArea viewport + 7 overlay scroll regions
(no scroll chaining to the page).
- archetypes.css: default rules wrapped in :where() so component recipes always win.
- radius decoupled from size (Radix model) in toggle/textarea/menubar/nav-menu/
virtual-list/grid; toggle `rounded` prop.
Canon-read + token reach portaled menus pending a fresh-load check (the dev tab
cached the floating module) -- see CONTINUE-floating-gap-canon.md.
The tooltip's `delayed-open` entrance (the per-side slide, and now the bounce) NEVER
fired: the content only mounts when `open` becomes true, and the hover-delay timer
set `internalTooltipState = 'instant-open'` AT THAT MOMENT — so the content always
mounted as `instant-open` (no entrance). `delayed-open` was only ever the pending
state while the content was still unmounted. A long-standing dead animation.
Fix: the hover-delay timer now keeps `'delayed-open'` as the content mounts, so the
eidos `[data-state='delayed-open']` entrance plays. `'instant-open'` stays reserved
for focus / skip-delay (intentionally no entrance). Test updated (it asserted the
buggy `instant-open`); tooltip provider suite 4/4.
Also makes the bounce clearly perceptible (it was too subtle to notice even when
forced): scale 0.5 → 1.18 (overshoot) → 0.9 (undershoot) → 1.06 (second bounce) → 1,
over `--duration-slow`. Verified end-to-end in-browser: hover → content mounts
`delayed-open` → `animation-name: eidos-tooltip-bounce-in`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the tooltip's per-side 2px slide-in with a scale BOUNCE: grow from 0.7,
overshoot to 1.06, dip to 0.97 (the undershoot — the "rebote"), settle to 1, over
`--duration-moderate`. It scales from `transform-origin` (the floating origin,
toward the anchor), so it keeps a directional feel without per-side keyframes —
8 keyframes collapse to 2.
Bespoke recipe keyframe, NOT a registered `motion` preset: the tooltip's state is
3-valued (`delayed-open` / `instant-open` / `closed`), not the generic `open` /
`closed` the shared presets key on — so a registered preset wouldn't fire here.
This also confirms the architecture boundary: components whose state shape doesn't
match open/closed use a bespoke recipe animation, not the `motion` selector.
`instant-open` (keyboard focus) keeps no entrance; the reduced-motion block (kills
the animation) already covers the new rules — verified the bounce curve in-browser
(scale 0.7 → 1.06 → 0.97 → 1). Recipe-only change, no generator/base.css touched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the second BROKEN component from the audit (after date-range-picker).
Five errors collapse to zero:
- Morfo declares the three `emerge` events the recipe animations were
already keying off (`open`, `close`, `close-dismiss`) plus a
`texts.label` slot. `data-disabled` is now declared on `Trigger` (with
optional severity) so the recipe rule has a real contract to land on.
`aria-disabled` and `texts.label` round out the surface; the new
`tooltip.label` catalog entry ships under
`src/uix/langs/components/tooltip.ts`.
- Recipe CSS: explicit `[data-tooltip-trigger][data-disabled]` and
`[data-tooltip-trigger]:focus-visible` rules. The disabled rule
suppresses pointer events; the focus rule provides a defensive
outline so a focusable trigger shell is at least keyboard-visible.
- README: convert the old `## Pendiente deliberado` section into a
proper `## Gaps` table with explicit dispositions
(implementar/diferir/descartar), and update `## Eventos Sema` to
reflect that tooltip now declares its three emerge events instead of
claiming zero. Comparativa was already complete; the regex fix from
the previous commit picked it up.
Audit: tooltip BROKEN → PASS. Project-wide goes from 1/64/2 to 3/64/0
(PASS / NEEDS-WORK / BROKEN). No more BROKEN components.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>