You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/audit/theming/proof-of-human.md

18 KiB

proof-of-human — alcance de tema: análisis y propuesta

Generado por node --import tsx/esm scripts/theming-census.ts --report. Lo medido y la propuesta se regeneran; el Veredicto (§5) se conserva. Vista de conjunto: README · método y protocolo: PLAN-theming.md §1, §2, §7.

  • Medido: 2026-08-22 · Alcance: 19% — 14 de 75 knobs por token público
  • Knobs de apariencia: 79 — público 14 · privado 17 · global 29 · literal 15 · sistema 4 · excepción 16 (los dos últimos, fuera del ratio)
  • Contrato hoy (lib/recipes/base.ts): 20 pública(s) — min-height-sm, min-height-md, min-height-lg, min-height, radius, bg, border, border-width, verified-border, failed-border, locked-opacity, tolerance-opacity, guide-opacity, guide-width, trail-width, goal-width, goal-opacity, token-size, token-radius, token-focus-offset · 2 privada(s) forward — _palette-solid, _palette-element
  • Eje size: no · ficheros: clock.css, proof-of-human.css, rotate-align.css

1. Knobs fuera de alcance

1.1 Directo a primitivo global (29)

# fichero:línea selector propiedad valor
1 clock.css:29 .ck-ring fill var(--color-surface-raised)
2 clock.css:30 .ck-ring stroke var(--color-border-default)
3 clock.css:34 .ck-tick stroke var(--color-border-strong, var(--color-border-default))
4 clock.css:39 .ck-num fill var(--color-content-secondary)
5 clock.css:60 .ck-badge-num fill var(--color-content-on-solid)
6 clock.css:68 .ck-house-frame stroke var(--color-border-default)
7 clock.css:87 .ck-sill fill var(--color-content-tertiary, var(--color-content-secondary))
8 clock.css:145 .ck-hand-main, .ck-hand-tail fill var(--color-content-primary, var(--color-content-secondary))
9 clock.css:148 .ck-hub fill var(--color-content-primary, var(--color-content-secondary))
10 clock.css:178 [data-proof-of-human][data-state='verified'] .ck-roof fill var(--color-fulfill-solid)
11 clock.css:181 [data-proof-of-human][data-state='verified'] .ck-badge-dot fill var(--color-fulfill-solid)
12 proof-of-human.css:167 .poh-trace-dot[data-off-path] background var(--color-risk-solid)
13 proof-of-human.css:168 .poh-trace-dot[data-off-path] box-shadow 0 0 0 4px color-mix(in srgb, var(--color-risk-solid) 24%, transparent), var(--shadow-2)
14 proof-of-human.css:180 [data-path-trace-token]::before min-inline-size var(--touch-target)
15 proof-of-human.css:181 [data-path-trace-token]::before min-block-size var(--touch-target)
16 rotate-align.css:59 [data-rotate-align-needle]:focus-visible border-radius var(--radius-full)
17 rotate-align.css:67 [data-rotate-align-needle]::before min-inline-size var(--touch-target)
18 rotate-align.css:68 [data-rotate-align-needle]::before min-block-size var(--touch-target)
19 rotate-align.css:83 .ra-ring fill var(--color-surface-raised)
20 rotate-align.css:84 .ra-ring stroke var(--color-border-default)
21 rotate-align.css:88 .ra-tick stroke var(--color-border-strong, var(--color-border-default))
22 rotate-align.css:93 .ra-card fill var(--color-content-secondary)
23 rotate-align.css:114 .ra-post fill var(--color-content-tertiary, var(--color-content-secondary))
24 rotate-align.css:123 .ra-flag fill var(--color-risk-solid)
25 rotate-align.css:128 [data-proof-of-human][data-state='verified'] .ra-box fill var(--color-fulfill-solid)
26 rotate-align.css:131 [data-proof-of-human][data-state='verified'] .ra-flag fill var(--color-fulfill-solid)
27 rotate-align.css:136 .ra-n fill var(--color-risk-solid)
28 rotate-align.css:139 .ra-s fill var(--color-content-secondary)
29 rotate-align.css:142 .ra-hub fill var(--color-content-primary, var(--color-content-secondary))

1.2 A través de un privado (17)

# fichero:línea selector propiedad valor
1 clock.css:57 .ck-badge-dot fill var(--_proof-of-human-accent)
2 clock.css:67 .ck-house-frame fill var(--_proof-of-human-accent-soft)
3 clock.css:72 .ck-doorway fill color-mix(in srgb, var(--_proof-of-human-accent) 22%, black)
4 clock.css:75 .ck-door fill var(--_proof-of-human-accent-soft)
5 clock.css:76 .ck-door stroke var(--_proof-of-human-accent)
6 clock.css:90 .ck-roof fill var(--_proof-of-human-accent)
7 clock.css:151 .ck-hub-dot fill var(--_proof-of-human-accent-soft)
8 proof-of-human.css:96 .poh-trace-corridor stroke var(--_proof-of-human-accent-soft)
9 proof-of-human.css:104 .poh-trace-line stroke var(--_proof-of-human-accent)
10 proof-of-human.css:114 .poh-trace-trail stroke var(--_proof-of-human-accent)
11 proof-of-human.css:122 .poh-trace-start fill var(--_proof-of-human-accent)
12 proof-of-human.css:126 .poh-trace-goal stroke var(--_proof-of-human-accent)
13 proof-of-human.css:158 .poh-trace-dot background var(--_proof-of-human-accent)
14 proof-of-human.css:159 .poh-trace-dot box-shadow 0 0 0 4px color-mix(in srgb, var(--_proof-of-human-accent) 22%, transparent), var(--shadow-2)
15 rotate-align.css:98 .ra-card.n fill var(--_proof-of-human-accent)
16 rotate-align.css:117 .ra-box fill var(--_proof-of-human-accent)
17 rotate-align.css:120 .ra-slot fill color-mix(in srgb, var(--_proof-of-human-accent) 55%, black)

1.3 Literales (15)

# fichero:línea selector propiedad valor
1 clock.css:21 .ck-face, .ck-hand inline-size 100%
2 clock.css:22 .ck-face, .ck-hand block-size 100%
3 clock.css:203 0%, 13% opacity 1
4 clock.css:209 26%, 62% opacity 1
5 clock.css:220 to opacity 1
6 proof-of-human.css:87 .poh-trace-svg inline-size 100%
7 proof-of-human.css:88 .poh-trace-svg block-size 100%
8 proof-of-human.css:182 [data-path-trace-token]::before inline-size 100%
9 proof-of-human.css:183 [data-path-trace-token]::before block-size 100%
10 rotate-align.css:23 [data-rotate-align-skin] inline-size min(230px, 72%)
11 rotate-align.css:36 [data-rotate-align-dial], [data-rotate-align-needle] inline-size 100%
12 rotate-align.css:37 [data-rotate-align-dial], [data-rotate-align-needle] block-size 100%
13 rotate-align.css:77 .ra-dial, .ra-needle inline-size 100%
14 rotate-align.css:78 .ra-dial, .ra-needle block-size 100%
15 rotate-align.css:95 .ra-card font-weight 600

1.4 Excepciones firmadas (16) — fuera del ratio

Literales que llevan su anotación /* literal: <razón> */ en la propia declaración: la válvula de recipe-contract §3, la misma que honra component-audit. Una desviación firmada no es deuda — se listan para que la razón se lea, no para acuñarlas.

# fichero:línea selector propiedad valor
1 clock.css:40 .ck-num font-size 13px
2 clock.css:41 .ck-num font-weight 600
3 clock.css:61 .ck-badge-num font-size 11px
4 clock.css:62 .ck-badge-num font-weight 700
5 clock.css:103 .ck-wing fill #9ca3af
6 clock.css:112 .ck-bird-body fill #d1d5db
7 clock.css:115 .ck-bird-head fill #e5e7eb
8 clock.css:118 .ck-eye fill #111827
9 clock.css:121 .ck-glint fill #ffffff
10 clock.css:124 .ck-letter-paper fill #fefcf8
11 clock.css:125 .ck-letter-paper stroke #cbb892
12 clock.css:130 .ck-letter-flap stroke #cbb892
13 clock.css:134 .ck-stamp fill #3b82f6
14 clock.css:137 .ck-beak fill #fbbf24
15 clock.css:138 .ck-beak stroke #d97706
16 rotate-align.css:94 .ra-card font-size 13px

2. Sistema transversal (4) — informativo, fuera del ratio

Un tema los alcanza a nivel de sistema, por diseño (recipe-contract §2).

# fichero:línea selector propiedad valor
1 proof-of-human.css:144 [data-path-trace-token][data-disabled] opacity var(--opacity-disabled)
2 proof-of-human.css:147 [data-path-trace-token]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)
3 rotate-align.css:54 [data-rotate-align-needle][data-disabled] opacity var(--opacity-disabled)
4 rotate-align.css:57 [data-rotate-align-needle]:focus-visible outline var(--focus-ring-width) solid var(--focus-ring-color)

3. Privados de la receta — ¿de dónde sale su valor?

privado declaraciones valor(es) origen ¿deriva de un público?
--_proof-of-human-accent 2 var(--color-primary-solid), var(--_proof-of-human-palette-solid) global, private no
--_proof-of-human-accent-soft 2 var(--color-primary-element), var(--_proof-of-human-palette-element) global, private no
--_proof-of-human-min-h 1 var(--proof-of-human-min-height) public sí

Consumidos y no declarados en el CSS (vienen de base.ts o de un estilo inline del wrapper): --_proof-of-human-palette-element, --_proof-of-human-palette-solid.

4. Propuesta de corrección

4.1 Tokens a declarar en lib/recipes/base.ts (9)

Valor verbatim del CSS de hoy: el default no se mueve, sólo cambia quién puede moverlo. Nombres derivados de recipe-contract §1 (ejes lógicos, talla al final) y theming §6.7 (slots de color, modificador delante). Un token con DOS valores distintos es una colisión de nombre: son dos knobs, o el nombre no distingue lo que debería — se marca ⚠.

token (--proof-of-human-…) scope TSC valor propuesto usos
fill root ⚠ var(--color-surface-raised) / var(--color-content-secondary) / var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / var(--color-content-on-solid) / var(--color-primary-element) / var(--_proof-of-human-palette-element) / var(--color-content-tertiary, var(--color-content-secondary)) / #9ca3af / #d1d5db / #e5e7eb / #111827 / #ffffff / #fefcf8 / #3b82f6 / #fbbf24 / var(--color-content-primary, var(--color-content-secondary)) / var(--color-fulfill-solid) / var(--color-risk-solid) 45
stroke root ⚠ var(--color-border-default) / var(--color-border-strong, var(--color-border-default)) / var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / #cbb892 / #d97706 / var(--color-primary-element) / var(--_proof-of-human-palette-element) 18
font-size root ⚠ 13px / 11px 3
font-weight root ⚠ 600 / 700 3
bg (ya existe) root ⚠ var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / var(--color-risk-solid) 3
shadow root ⚠ var(--color-primary-solid) / var(--_proof-of-human-palette-solid) / 0 0 0 4px color-mix(in srgb, var(--color-risk-solid) 24%, transparent), var(--shadow-2) 3
width root ⚠ var(--touch-target) / min(230px, 72%) 3
height root var(--touch-target) 2
radius (ya existe) root var(--radius-full) 1

4.2 Sin nombre mecánico (13)

  • ⚠ decisión: 100% es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 10: inline-size, block-size.
  • ⚠ decisión: 1 es un valor identidad o geometría de layout, no un knob de tema — el perímetro de «knob» es D-TH.2, sin firmar — 3: opacity.

4.3 Avisos sobre los tokens propuestos (3)

  • el privado --_proof-of-human-accent debe pasar a leer este público (o desaparecer) — --proof-of-human-fill, --proof-of-human-stroke, --proof-of-human-bg, --proof-of-human-shadow
  • el privado --_proof-of-human-accent-soft debe pasar a leer este público (o desaparecer) — --proof-of-human-fill, --proof-of-human-stroke
  • ⚠ decisión: el valor es una expresión — el token puede llevar la expresión entera o sólo su término variable — --proof-of-human-width

4.4 Lo que hay que comprobar a mano (PLAN-theming §1.3 · §7.4)

  • Privado que no deriva de un público — §3 lo marca; el privado debe leer el público o desaparecer.
  • Velo o acento en el nodo equivocado (archetype: 'item' en un envoltorio, un background en shorthand que mata la capa de estado) — se mide desde el píxel hacia arriba.
  • Doble animación al mover un sello a una superficie con animación propia — registro de animationstart/animationend.
  • Diff de computed = 0 en reposo · hover · abierto · disabled · foco, por talla, antes y después.
  • Centinela por token nuevo: valor imposible en el root → el nodo lo sigue. Si no, el token miente.

5. Veredicto

Revisión 2026-08-20 — verificación previa a implementación (Opus).

Análisis (§1–§3): CORRECTO en cifras (95 · 0 · 18 · 36 · 37 · 4, reproducido), con un matiz que cambia la lectura de los literales: de los 37, al menos 20 ya llevan anotación /* literal: … */ (el papel de la carta #fefcf8, el sello #3b82f6, la paloma #fbbf24, los cielos del reloj…) — son los colores físicamente fijos que recipe-contract §3 bendice («the natural clock's skies»). El censo no ve comentarios, así que los cuenta como deuda; para R-5 son excepciones por válvula, no tokens.

Propuesta (§4.1): NO IMPLEMENTAR tal cual. La tabla colapsa en nombres inservibles (fill con 45 usos y 19 valores; stroke 18/8) porque el CSS de la escena no usa data-attrs sino clases (.ra-card, .ra-needle, .poh-trace-dot, .ra-tick…) y la derivación no puede leer la parte. Eso destapa además una deuda propia: hooks de clase en una receta eidos violan la convención (los ganchos del recipe son data-*; memoria eidos-lint-no-class-hooks) — el linter no puede clasificarlos.

Disposición (diseño a mano, no mecánico):

  1. Separar CROMO de ESCENA. Cromo (la tarjeta .ra-card/root: bg, radius, border, sombra, tipografía del HUD, --_proof-of-human-min-h) → tokens públicos normales; ahí sí valen las filas height-{sm,md,lg} de §4.1 (expresión entera calc(var(--size-{k}-control-height) * 3), patrón Sidebar con resuelto host+size:{k}; el root estampa data-size ✓).
  2. La escena NO se tokeniza por knob: sus colores son identidad del desafío (anti-bot) y ya están anotados físicamente fijos → excepciones R-5 con razón («escena del captcha, identidad fija»); completar la anotación en los ~17 literales que aún no la lleven.
  3. El acento SÍ: --_proof-of-human-accent/-accent-soft (hoy var(--color-primary-*) con forward de paleta THM-2) es el único eje de color que un tema debe alcanzar — promover a público accent/accent-soft y que los privados lo lean.
  4. Deuda aparte (no de este eje): migrar los hooks .ra-*/.poh-* a data-* del morfo — sin eso, eidos-lint seguirá ciego aquí. Anotarla, no ejecutarla de oficio (no-cascade).

Bloqueos de firma: el perímetro escena-vs-cromo (qué literales son excepción y cuáles knobs) lo firma el autor con la lista delante · la deuda de hooks de clase (eje aparte) · D-TH.2 (los 100%/opacity:1).


EJECUTADO 2026-08-20 (parcial, y el resto NO es deuda). Alcance 0 % → 14 % · contrato 0 → 20 claves públicas. El perímetro escena-vs-cromo tampoco había que firmarlo: recipe-css-contract ya exime a este componente (FIXED_TONE_COMPONENTS), así que la escena —paloma, carta, cielos del reloj— es excepción reconocida y sus literales ya van anotados. Se tokenizó el cromo: alto por talla (min-height-{sm,md,lg} + resuelto con parts: ['root']), radio, fondo, borde, bordes de veredicto, la guía del trazo (guide-*, trail-width, goal-*, tolerance-opacity, locked-opacity) y el token arrastrable.

Dos fallos propios que la verificación cazó, y merece la pena dejarlos escritos:

  1. Clave duplicada en recipes/base.ts: añadí un bloque 'proof-of-human' sin ver que ya existía uno (el forward de paleta). En un object literal la segunda gana, así que mi bloque se descartaba en silencio — el diff de computed lo delató con 28 diferencias (border-radius: 6px → 0px). Ahora hay un guard trivial que repetiré en cada componente: uniq -d sobre las claves de primer nivel.
  2. Al fusionar los bloques perdí la última clave (token-focus-offset), y el guard de tokens fantasma lo cazó: la receta consumía un nombre que ya no se declaraba.

Verificación: diff de computed = 0 sobre 406 valores en 7 estados · component:audit PASS · suite eidos sin rojos nuevos · rtl:check 0 · docs:check 0.

⚠ El centinela no sirve en esta demo: la página declara min-block-size: 340px y un degradado propio sobre [data-proof-of-human] (+page.svelte:1042-1048), así que tapa min-height y bg. Los que la demo no pisa (verified-border, tolerance-opacity) sí responden. Queda dicho en vez de darlo por verificado.

El 86 % restante son los dos ficheros de la escena (clock.css, rotate-align.css), que enganchan por CLASE (.ra-*, .poh-*) y pintan depiction: no son tokenizables sin antes migrar esos hooks a attrs del morfo — eje aparte, anotado en el README.

Powered by TurnKey Linux.