Anexo H — Heurísticas de calidad de código y de usabilidad

Estado: APROBADO Y EN PRODUCCIÓN. No queda ninguna decisión abierta: la forma (D-043 y D-044), los interruptores (D-045 y D-046), el tablero (D-047) y las severidades iniciales con el peso de la accesibilidad (D-048, sección 10) están decididos. El documento está publicado en los ocho idiomas del método y sus dos prompts forman parte de la API de prompts: desde ahí, build/prompts.mjs exige el texto inglés idéntico byte a byte en los ocho o la construcción falla. Fecha: 2026-10-22.

Registro de las decisiones de este anexo: docs/DECISIONES.md, D-043 a D-048. El tablero de cumplimiento (sección 12) quedó decidido con dos cifras en D-047. El trabajo de implementación vive en PND-002.

1. Qué falta hoy, y por qué

El peldaño 9 ya mide el código y lo hace con una compuerta que no deja pasar: un formateador único, límites de tamaño (trescientas líneas por archivo, cuarenta por función), complejidad por función, código duplicado, código muerto, dependencias declaradas y usadas, cobertura con trinquete y pruebas de mutación donde hay usuarios reales. El número queda escrito en docs/CODE_QUALITY.md. Eso está resuelto.

Lo que no está resuelto es la otra mitad del producto. Verifiqué el corpus de peldaños: no hay una sola mención a usabilidad, a personas/perfiles ni a agrupación funcional. La interfaz se sostiene hoy en dos cosas: la captura que el dueño mira diez segundos y los casos de prueba manual. Las dos son buenas y las dos son humanas, caras y olvidadizas. Un sistema puede pasar la compuerta de calidad con honores y ser inusable: todo verde, y la persona no encuentra dónde cobrar.

Y hay un problema de segunda capa que sí es técnico pero se nota en la interfaz: cuando el mismo producto lo usan varios perfiles (administración, operación, consulta, cliente), las funcionalidades se habilitan en tres lugares distintos —la base, el menú y el guard de la ruta— que se escriben en momentos distintos y se desincronizan solos. El síntoma es siempre el mismo: alguien ve un botón que no le corresponde, o peor, alguien que sí tiene el permiso no encuentra la pantalla.

Las dos heurísticas que siguen atacan esas dos cosas con la misma forma: un catálogo corto de enunciados verificables, unos pocos instrumentos que los miden solos, y una vía de excepción declarada para cuando el proyecto necesita salirse.

2. El modelo: tres capas, una sola forma de regla

La tentación es hacer una lista de reglas y atarla al stack del primer proyecto. Eso envejece mal: la regla de React no aplica en Angular, la de Angular no aplica en un servidor con plantillas, y en dos años media lista queda muerta. La propuesta separa tres capas.

Capa 1 — Núcleo agnóstico (no se negocia). Enunciados sobre resultados, no sobre herramientas. "Hay un solo formateador y nadie discute con él" aplica igual en TypeScript, PHP o Go. El núcleo se enumera con identificadores estables y no cambia de proyecto en proyecto.

Capa 2 — Adaptador por stack (configurable). Para cada regla del núcleo, cada familia de frontend declara con qué se mide y con qué umbral. Un proyecto React con Vite, uno Next, uno Angular, uno de servidor con plantillas, uno mobile y uno de línea de comandos son seis adaptadores distintos del mismo núcleo. Acá vive todo lo que el usuario pidió como "configurable por frontend".

Capa 3 — Decisiones del proyecto (declaradas). Los umbrales concretos y las exenciones. No se inventan: se piden al dueño y quedan escritas, igual que el dimensionamiento del peldaño de arquitectura. Si un umbral no está declarado, corre el del adaptador y queda registrado como tal.

Cada regla se escribe siempre con la misma ficha de seis campos:

CampoQué contiene
idIdentificador estable (CQ-07, UX-12). No se reutiliza nunca.
EnunciadoUna sola oración, en imperativo, sobre un resultado observable.
Por quéEl daño concreto que evita. Si no hay daño, la regla sobra.
Cómo se verificaEl instrumento: compuerta automática, consulta a la matriz, prueba de extremo a extremo o caso manual.
SeveridadBLOQUEA (la compuerta da rojo y no se cierra el bloque), AVISA (abre un pendiente), REGISTRA (solo queda en el documento).
Aplica aPerfiles donde rige. Fuera de ellos no corre, y eso no es una excepción: es alcance.

La excepción se declara, nunca se omite. Una regla se apaga con un registro de cuatro campos: identificador, motivo en una línea, quién lo autoriza (el dueño, no el agente) y fecha de revisión. Una regla apagada sin registro es un fallo de la compuerta, no una decisión. Es el mismo criterio que el método ya usa para no aceptar un límite subido "para pasar".

3. Los cuatro instrumentos

Ninguna heurística sirve si su verificación es una opinión. Son cuatro, y cada regla declara a cuál pertenece.

  1. Compuerta automática. Corre en cada push y en el cierre de bloque. Devuelve verde o rojo. Es barata, es repetible y no discute. Mide todo lo que se puede contar.
  2. Consulta a la matriz. La matriz de funcionalidades por perfil (ver B2) es un artefacto declarativo; el menú, el ruteo y los permisos se derivan de ella. Comprobar la matriz es comprobar la interfaz. Es la pieza que convierte una parte de la usabilidad en algo verificable por máquina.
  3. Prueba de extremo a extremo por perfil. Para cada perfil declarado, un guion que entra como ese perfil y compara el conjunto de funcionalidades alcanzables contra la fila de la matriz: ni de menos ni de más. Es la prueba que atrapa las dos desincronizaciones típicas (el botón que sobra y la pantalla que falta).
  4. Caso manual. Lo que ninguna máquina juzga: si la agrupación se entiende, si la tarea se completa sin ayuda, si el texto está en el idioma del usuario. Se ejecuta con personas y se registra, como ya manda el peldaño 10.

4. Parte A — Calidad de código

El núcleo extiende el peldaño 9: no lo reemplaza ni lo contradice, le pone nombre, severidad y adaptador a cada cosa que ya se mide, y agrega lo que hoy falta, que es la interfaz vista como código.

idFamiliaEnunciadoVerificaSeveridad
CQ-01FormaHay un solo formateador, corre sin intervención y no admite discusión.CompuertaBLOQUEA
CQ-02FormaHay un solo linter por repositorio y sus reglas son las mismas para todo el mundo; se apaga una regla con motivo escrito, nunca en un archivo suelto.CompuertaBLOQUEA
CQ-03TamañoNingún archivo supera el límite declarado (arranca en 300 líneas) y ninguna función el suyo (arranca en 40).CompuertaBLOQUEA
CQ-04ComplejidadNinguna función supera el límite de caminos declarado.CompuertaBLOQUEA
CQ-05DuplicaciónNo entra duplicación nueva: el bloque copiado se extrae o se justifica.CompuertaBLOQUEA
CQ-06MuertosNo hay código muerto: funciones, variables, importaciones, ramas y dependencias sin uso.CompuertaBLOQUEA
CQ-07TiposSi el lenguaje permite tipos, el proyecto los usa en serio; el tipo "cualquiera" es una excepción declarada, no un hábito.CompuertaAVISA
CQ-08PruebasLa cobertura no baja: el número de hoy es el piso de mañana.CompuertaBLOQUEA
CQ-09PruebasCon usuarios reales, el puntaje de mutación se mide por bloque y cada mutante que sobrevive en código nuevo abre un pendiente.Compuerta + registroBLOQUEA
CQ-10DependenciasToda dependencia está declarada, se usa y no trae un árbol de terceros desproporcionado a lo que aporta.CompuertaAVISA
CQ-11SecretosNo hay credenciales, claves ni cadenas de conexión en el repositorio, ni en el historial nuevo.CompuertaBLOQUEA
CQ-12InterfazLa interfaz no decide: ninguna pantalla ni componente contiene reglas de negocio (qué se puede, cuánto sale, qué estado sigue). Vive en el dominio y la vista lo consulta.Revisión al cierre + caso manualBLOQUEA
CQ-13InterfazCada llamada al servidor pasa por un cliente único y tipado; ninguna pantalla arma su propia petición a mano.Compuerta (búsqueda)BLOQUEA
CQ-14InterfazHay un solo lugar donde vive el estado compartido; la duplicación de estado entre pantallas es un fallo, no un atajo.Revisión al cierreBLOQUEA
CQ-15InterfazTodo texto visible sale de un catálogo de traducciones; ninguna cadena de usuario queda escrita dentro del componente.Compuerta (búsqueda)BLOQUEA
CQ-16InterfazTodo elemento interactivo lleva identificador estable y rol, para que la prueba automática lo encuentre por nombre y no por posición.Compuerta (búsqueda)BLOQUEA
CQ-17InterfazTodos los colores, espaciados y tipografías salen de tokens; ningún valor mágico suelto en la hoja de estilos.Compuerta (búsqueda)BLOQUEA
CQ-18InterfazLa accesibilidad básica se verifica sola: contraste, etiquetas en los campos, foco visible, navegación por teclado en los flujos principales, imágenes con texto alternativo.CompuertaAVISA

Las reglas CQ-12 a CQ-18 son las que hacen que "calidad de código" signifique algo en el frente. Sin ellas, el proyecto puede tener mutación al noventa por ciento y una pantalla que calcula el total con su propia aritmética en un componente: el peor de los dos mundos, porque el cálculo duplicado pasa todas las pruebas del backend.

Severidades iniciales (D-048). Bloquean desde el día uno las catorce reglas que tienen verificador y que no dependen de un umbral que haya que discutir: CQ-01 a CQ-06, CQ-08 y CQ-11 a CQ-17. CQ-09 bloquea donde hay usuarios reales, que es donde se mide. Avisan tres, y sólo tres: CQ-07 (tipos), CQ-10 (dependencias) y CQ-18 (accesibilidad), porque son las que necesitan que el proyecto calibre primero. El formateador, el linter, el tamaño y la complejidad no se aflojan: el peldaño 9 ya los bloquea hoy, y esto lo extiende, no lo reemplaza; la deuda heredada se resuelve con una excepción declarada o con la línea base del trinquete, nunca bajando la severidad. Y CQ-12 y CQ-14 son las dos únicas reglas de esta tabla que bloquean con rojo humano y no de máquina: se verifican al cierre del pendiente y con el caso manual delante, igual que UX-22 y UX-27, no en cada commit. Si el proyecto no puede sostener ese cierre, la regla baja a AVISA por decisión registrada, no por olvido.

Adaptador por familia de frontend. Un ejemplo de cómo se instancia la capa 2 (los nombres son ilustrativos; el proyecto elige y lo escribe):

ConceptoAplicación de una sola página (React, Vue, Angular)Servidor con plantillasMobile nativoLínea de comandos
CQ-12 dominio en la vistaRegla de lint sobre tamaño y dependencias de componentes + revisiónRevisión del controladorRevisión del modelo de vistaRevisión de la capa de comandos
CQ-13 cliente únicoGeneración desde el contrato de la APIServicio único del servidorCliente generadoCliente único del SDK
CQ-15 textosCatálogo + regla que prohíbe literales visiblesCatálogo del motor de plantillasCatálogo de recursosCatálogo
CQ-16 identificadoresAtributos declarativos por elementoIdentificadores en el marcadoIdentificadores de accesibilidadSalida estable
CQ-17 tokensTokens en la hoja de estilos, sin valores sueltosIgualIgualNo aplica
CQ-18 accesibilidadAnalizador automático en la compuertaAnalizador sobre el HTML generadoAnalizador de accesibilidadNo aplica

Lo que cambia entre columnas es la herramienta y el umbral. Lo que no cambia es el enunciado. Eso es lo que hace la heurística agnóstica sin volverla decorativa.

5. Parte B — Usabilidad

Cinco familias. La primera y la segunda son las que el dueño pidió explícitamente; las otras tres existen porque sin ellas la agrupación y los perfiles se degradan igual, más lento.

B1 — Agrupación por convergencia funcional

La regla madre: una funcionalidad se agrupa por lo que la persona vino a hacer, no por el módulo del que salió. El código se organiza por entidades ("Factura", "Cliente", "Pago"); las personas no. Nadie entra al sistema a "gestionar entidades": entra a cobrar, a despachar, a cerrar el mes. Si el menú muestra las entidades, la persona hace de traductora. El menú es el trabajo.

idEnunciadoVerificaSeveridad
UX-01Cada grupo del menú se nombra con un trabajo del usuario (en su vocabulario, con el glosario del proyecto), nunca con un módulo técnico ni con una entidad de datos.Caso manual + revisión de la matrizAVISA
UX-02Cada funcionalidad tiene exactamente una casa canónica. Si sirve a dos grupos, se elige una casa y desde la otra se enlaza; no se duplica la entrada.Consulta a la matrizBLOQUEA
UX-03No hay huérfanas: toda funcionalidad declarada es alcanzable desde la pantalla de entrada en no más de tres pasos.Recorrido automático de rutasBLOQUEA
UX-04El tamaño de un grupo es razonable: menos de tres funcionalidades indica un grupo que no era grupo; más de siete indica un cajón.Consulta a la matrizAVISA
UX-05Todo grupo tiene una pantalla de entrada que dice qué se hace ahí y cuál es la acción principal. No hay grupos que se abren directo en una tabla vacía.Caso manualAVISA
UX-06Los flujos que la persona hace seguido viven juntos: si "cargar un pago" y "ver la cuenta del cliente" se usan en la misma sesión, comparten grupo.Caso manual (prueba de tarea)REGISTRA
UX-07La prueba del primer clic: el dueño, frente a una tarea concreta ("¿dónde cobrás un pago?"), nombra un lugar. Si nombra dos, hay duplicación; si no nombra ninguno, hay huérfana. Se corre al cierre de cada bloque.Caso manualAVISA

B2 — Perfiles y funcionalidades habilitadas por perfil

Acá está la pieza que más rinde, y la razón es de ingeniería, no de diseño: la habilitación se declara una vez, en una matriz, y todo lo demás se deriva de ella. Hoy el error clásico es escribir el permiso tres veces (en el menú, en el guard de la ruta y en el filtro de datos) y que las tres se separen. Con la matriz como único productor, el menú, el ruteo, los permisos del servidor y los guiones de prueba son consumidores, y la simetría productor/consumidor que el método ya exige se vuelve verificable sola.

La matriz tiene cuatro columnas y una fila por funcionalidad: funcionalidad, casa (el grupo de B1), perfiles que la tienen, ruta de entrada. Nada más.

idEnunciadoVerificaSeveridad
UX-08Toda funcionalidad declara en la matriz qué perfiles la tienen. Una funcionalidad sin perfil no existe: o se le asigna perfil o se borra.Consulta a la matrizBLOQUEA
UX-09Todo perfil declarado tiene al menos una funcionalidad y un punto de entrada propio. Un perfil vacío es un perfil que nadie usó al diseñar.Consulta a la matrizBLOQUEA
UX-10La navegación se genera desde la matriz. Un menú escrito a mano es un fallo, no un atajo.Compuerta (búsqueda)BLOQUEA
UX-11Ocultar no es proteger: toda ruta verifica el permiso del lado del servidor además de esconder la entrada. Escribir la dirección a mano no alcanza para entrar.Prueba de extremo a extremoBLOQUEA
UX-12Ni de menos ni de más: por cada perfil, el conjunto de funcionalidades alcanzables es exactamente el de su fila en la matriz.Prueba de extremo a extremo por perfilBLOQUEA
UX-13La negativa se explica: si una persona entra a una funcionalidad que no le corresponde, ve un mensaje que dice por qué y a quién pedirle acceso. Nunca una pantalla en blanco, nunca un botón gris sin razón.Caso manualAVISA
UX-14El mismo botón significa lo mismo para todos: si dos perfiles comparten etiqueta, comparten efecto. Si el efecto cambia según el perfil, la etiqueta cambia o la funcionalidad se separa en dos.Caso manualAVISA
UX-15Los datos también se filtran por perfil: quien ve la lista ve las filas que le corresponden, no la lista completa con las filas escondidas en el navegador.Prueba de extremo a extremo + revisión del servidorBLOQUEA
UX-16La matriz y el manual de usuario se actualizan en el mismo pendiente que la funcionalidad. Una funcionalidad nueva sin fila en la matriz no se cierra.Cierre de pendienteBLOQUEA

B3 — Estados, y qué ve la persona cuando algo no está

La mayoría de los reclamos de "no anda" son pantallas que no supieron decir "no hay nada", "está cargando" o "falló". Cuatro estados, siempre, en toda lista y toda pantalla de detalle.

idEnunciadoVerificaSeveridad
UX-17Toda lista tiene cuatro estados resueltos: con datos, vacía, cargando y con error. La vacía distingue "todavía no hay" de "tu búsqueda no encontró".Caso manual + revisiónAVISA
UX-18Mientras algo demora, se ve que está trabajando y se puede cancelar si es largo. Un botón que no responde nada es la queja número uno.Caso manualAVISA
UX-19El error dice qué pasó, qué se puede hacer y no borra lo cargado. Ni un código técnico solo, ni un "ocurrió un error".Caso manualAVISA

B4 — Acciones y errores

idEnunciadoVerificaSeveridad
UX-20Una pantalla tiene una acción principal evidente; el resto son secundarias y se ven como tales.Caso manualAVISA
UX-21Toda acción destructiva pide confirmación nombrando el objeto afectado, y cuando se puede se deshace en lugar de confirmar.Caso manualAVISA
UX-22Un formulario que falla conserva lo cargado y marca el campo con problema, en el lugar del campo.Caso manualBLOQUEA
UX-23Ninguna acción deja la pantalla sin salida: después de guardar, borrar o cancelar, la persona sabe dónde quedó y cómo seguir.Caso manualAVISA

B5 — Lenguaje y accesibilidad

idEnunciadoVerificaSeveridad
UX-24La interfaz habla el idioma del glosario del proyecto: el mismo objeto se llama igual en la pantalla, en el manual y en el correo. Un sinónimo es un defecto.Caso manual + revisiónAVISA
UX-25Todo se puede hacer sin mouse y con lector de pantalla en los flujos principales; el foco se ve siempre y no queda atrapado.Compuerta (CQ-18) + caso manualAVISA
UX-26Los estados no se comunican solo por color; toda imagen informativa tiene texto alternativo; los textos se leen a tamaño normal sin zoom.Compuerta (CQ-18)AVISA
UX-27Cada pendiente que toca una pantalla entrega la captura real del entorno de prueba, y el dueño la mira antes de cerrar. La captura no es opcional ni es un maqueta.Cierre de pendienteBLOQUEA

6. Dónde se engancha, y qué artefactos produce

El anexo no inventa peldaños nuevos: se cuelga de los que existen. Eso evita duplicar compuertas y evita el destino habitual de las listas de usabilidad, que es ser leídas una vez.

Dónde va (D-043). Es transversal a los cuatro tramos, con el peso principal en el Bucle de Construcción (peldaños 5 a 12), que es donde se decide y se construye. No es un peldaño propio: un peldaño numerado obligaría a renumerar la escalera, alteraría el conteo de pasos y sometería el anexo a la traducción obligatoria de los contratos a los ocho idiomas antes de que la construcción pueda pasar en verde, sin agregar ninguna compuerta que el bucle no tenga ya.

Cómo se engancha (D-044). Una fuente canónica, cinco anclas y dos entradas previas. El texto de las reglas vive solo acá y los prompts lo citan; nunca lo copian. Repetir las cuarenta y cinco reglas dentro de los ocho prompts del bucle las diluye (compiten con el trabajo propio de cada peldaño y el agente las obedece distinto cada vez), las deriva (dos copias del mismo texto se desincronizan solas, que es el antipatrón que persigue el peldaño 11) y no las vuelve más transversales: lo que vuelve transversal a una regla es que cada bloque pase por la misma compuerta, no que la regla esté escrita en todas partes.

MomentoQué se agregaPor qué ahí
Entrada previa 1 — definición del alcanceEl glosario del usuarioSin glosario, UX-01 y UX-24 no tienen contra qué comparar.
Entrada previa 2 — definición del alcanceLa lista de perfilesSin la lista, la matriz de B2 se inventa en el peldaño 5 y todo lo que se deriva de ella nace sin fundamento.
Ancla 1 — peldaño 5 (el plan)Todo pendiente que toca una pantalla declara tres cosas: a qué grupo de convergencia pertenece (B1), qué perfiles la tienen y qué criterios de aceptación son por perfil ("dado el perfil X, la persona puede hacer Y y no puede hacer Z"). Sin esa declaración el pendiente no pasa el peldaño.Acá nacen la agrupación y los perfiles: son decisiones de planificación, no de código. Es el ancla de mayor rendimiento y la que hoy no existe.
Ancla 2 — peldaño 8 (tests en rojo)La matriz se convierte en un test que primero se ve fallar: por cada perfil, lo alcanzable contra su fila (UX-11, UX-12, UX-15).Sin esto la matriz es un documento que nadie mira.
Ancla 3 — peldaño 9 (calidad)El catálogo CQ completo con su adaptador y sus umbrales declarados; docs/CODE_QUALITY.md reporta por regla, no por número único. Y la matriz como compuerta (UX-02, UX-03, UX-08, UX-09, UX-10, UX-16).Es el único lugar donde el texto entra literal como directiva, y es la compuerta que corre en cada bloque con trinquete.
Ancla 4 — peldaño 10 (casos manuales)Cada caso se ejecuta una vez por perfil afectado, derivado de la matriz y no escrito a mano. Un caso corrido con un solo perfil no cuenta como ejecutado.Los casos manuales son la única verificación humana del método; si no se abren por perfil, la mitad de B2 nunca se mira.
Ancla 5 — peldaño 12 (verificación y reporte honesto)El reporte dice qué se midió, qué quedó en avisa y qué regla está apagada, con su motivo, su autor y su fecha de revisión.Cero daño silencioso: un grupo apagado no puede leerse como cumplido.
Manual de usuarioSe organiza por los grupos de B1 y declara, por grupo, qué perfiles entran.El manual y el menú se nombran con las mismas palabras o el glosario se rompe.
Cierre de cada bloquePrueba del primer clic (UX-07), captura del entorno real (UX-27) y las dos pruebas de extremo a extremo de la matriz.Son las tres verificaciones que no se pueden automatizar.

Estado (D-049). Las cinco anclas están enganchadas: el prompt inicial de los peldaños 5, 8, 9, 10 y 12 cita este anexo en los ocho idiomas, con una sola redacción inglesa idéntica en todos y su traducción local al lado. El documento se publica en el sitio con el resto del método en los ocho idiomas, y sus dos prompts entraron en docs/html/api/prompts.json como contrato anexo-h: desde ahí build/prompts.mjs los compara byte a byte en los ocho o la construcción falla.

Los peldaños 6, 7 y 11 reciben a lo sumo una línea: el 6 ya registra umbrales y excepciones como decisiones (es el lugar natural de la excepción declarada), y el 11 es donde entra a los golpes el caso de la matriz escrita en cuatro lugares. No se les agrega texto propio para no diluirlos.

Tres artefactos, todos en docs/: CODE_QUALITY.md (extendido), USABILITY.md (nuevo, con el resultado por regla y las excepciones declaradas) y PROFILE_MATRIX.md (la matriz, que es a la vez documento y fuente del menú).

7. Configuración

Un solo archivo por proyecto declara capa 2 y capa 3. Ejemplo con la forma propuesta, no con valores definitivos:

{
  "version": 1,
  "frontend": "react-vite",
  "medido_por": {
    "formato": "prettier",
    "lint": "eslint",
    "tipos": "tsc",
    "complejidad": "eslint-complexity",
    "duplicacion": "jscpd",
    "muertos": "knip",
    "cobertura": "vitest-coverage",
    "mutacion": "stryker",
    "accesibilidad": "axe-core"
  },
  "umbrales": {
    "lineas_por_archivo": 300,
    "lineas_por_funcion": 40,
    "caminos_por_funcion": 10,
    "cobertura_minima": 0,
    "mutacion_objetivo": 0
  },
  "excepciones": [
    {
      "regla": "CQ-17",
      "motivo": "informe imprimible heredado, sin tokens",
      "autoriza": "dueño",
      "revisar": "2027-01-31"
    }
  ]
}

Los dos ceros son deliberados y son la parte que importa: la cobertura mínima la fija el trinquete con lo medido, y el objetivo de mutación lo fija el dueño cuando el proyecto tiene usuarios. Si están en cero y nadie los declaró, la compuerta lo reporta como umbral no declarado en vez de inventarlo.

8. Las dos piezas, en la forma que usa el método

Calidad de código.

Set up and maintain the code-quality gate for this project, configured for its frontend family. The core rules are the same in every project; what changes is how each one is measured and at which threshold. Install one formatter and one linter with a single shared configuration; enforce size limits per file and per function, complexity per function, duplication, dead code, declared-and-used dependencies, type checking where the language allows it, coverage with a ratchet, and secret scanning. Where the project has real users, add mutation testing scoped to the changed lines and record the score per block. Then extend the gate to the frontend itself: no business rule inside a screen, one typed client for every server call, one home for shared state, no user-visible string outside the translation catalogue, a stable identifier and role on every interactive element, styling only through tokens, and automatic basic accessibility checks. Every rule has a stable id, a severity (blocks, warns, records) and a named verifier. Thresholds and exceptions are declared by the owner in one configuration file; a rule switched off without a written exception is a gate failure, not a decision. Report the result per rule in docs/CODE_QUALITY.md, not as a single number.

Usabilidad.

Build the usability criteria for this project before writing the first screen, and enforce them where the method already has hooks. Group functionality by what the person came to do, never by the internal module or the data entity: every menu group is named with a user job in the project glossary, every functionality has exactly one canonical home, no functionality is orphaned, and every group is reachable in no more than three steps from the entry screen. Then declare accessibility in one matrix and derive everything from it: each functionality lists the profiles that have it, each functionality has at least one profile, each profile has at least one functionality and its own entry point, the navigation is generated from the matrix instead of written by hand, and every route checks the permission on the server because hiding an entry is not protecting it. Verify the matrix per profile with an end-to-end check that compares what is reachable with the matrix row: neither less nor more. Require the four states on every list (with data, empty, loading, error), a visible working indicator with the option to cancel long operations, an error message that says what happened and what to do without losing entered data, a primary action per screen, confirmation or undo for destructive actions, and a form that keeps what was typed. Run each manual test case once per affected profile, run the first-click check at the close of every block, and require a real screenshot of the test environment on every item that touches a screen. Record the result per rule, with owner-declared exceptions, in docs/USABILITY.md, and keep the matrix in docs/PROFILE_MATRIX.md as the single source of truth.

9. Lo que esta propuesta no hace

10. Las decisiones: qué quedó resuelto y qué falta

Resueltas

#DecisiónRegistro
1Transversal al Bucle de Construcción, no peldaño propio. No se renumera la escalera, no se altera el conteo de pasos y el anexo no hereda la obligación de traducir un contrato de peldaño.D-043
2Una fuente canónica con cinco anclas y dos entradas previas, en lugar de copiar las cuarenta y cinco reglas dentro de los ocho prompts del bucle.D-044
3Dos interruptores independientes (calidad y usabilidad), tres estados por regla (bloquea, avisa, apagada), adaptador por familia de frontend, umbrales y excepciones declarados por el dueño.D-045
4Disciplina del interruptor: vive en la configuración del proyecto y no en el prompt; apagar solo vale como decisión registrada con motivo, autor y fecha de revisión; el apagado es observable en el reporte; y el interruptor se prueba prendiendo y apagando.D-046
5Severidades iniciales, fijadas regla por regla: en calidad bloquean catorce (CQ-01 a CQ-06, CQ-08, CQ-11 a CQ-17), CQ-09 bloquea donde hay usuarios reales, y avisan tres (CQ-07, CQ-10, CQ-18). En usabilidad bloquean once (UX-02, UX-03, UX-08 a UX-12, UX-15, UX-16, UX-22, UX-27), UX-06 solo registra y el resto avisa. Ni "todo bloquea" —el proyecto no arranca— ni "todo avisa" —la heurística es un adorno—.D-048
6La accesibilidad arranca avisando y escala a bloqueante por declaración del dueño cuando el producto tiene usuarios finales fuera de la organización. El default no se inventa: la escalada se declara, con el mismo mecanismo que cualquier umbral (D-045).D-048

Cerrado en D-048, y las dos correcciones que arrastra

Las dos preguntas que trababan la escritura de los prompts ya están respondidas: la 1 quedó en la fila 5 y la 2 en la fila 6. Pero la recomendación que se aprobó tenía dos errores de hecho, y quedan escritos acá para que no vuelvan:

  1. El defecto del conteo. Donde este anexo decía "veintisiete reglas" el número correcto es cuarenta y cinco: 18 de calidad (CQ-01 a CQ-18) y 27 de usabilidad (UX-01 a UX-27). La cifra vieja venía de un borrador que solo contaba la mitad. Corregido en las secciones 6 y 9 y anotado en D-048; el texto de D-044 se conserva tal como se escribió, porque una decisión es un registro y no se reescribe.
  2. El formateador, el linter, el tamaño y la complejidad no se aflojan. Una versión anterior de esta recomendación los mandaba a "avisa" para no trabar proyectos con deuda heredada. No puede ser: el peldaño 9 ya los bloquea hoy, y esta extensión lo extiende, no lo reemplaza. La deuda heredada se resuelve con una excepción declarada —con motivo y fecha de revisión— o con la línea base del trinquete, no bajando la severidad de la regla.

Y una limitación declarada, porque es la única de su clase: CQ-12 y CQ-14 bloquean con rojo humano. Ninguna herramienta prueba que una pantalla no decide reglas de negocio. Se verifican al cierre del pendiente, con el caso manual delante y el mismo criterio que UX-22 y UX-27; si el proyecto no puede sostener ese cierre, bajan a AVISA por decisión registrada. Una regla que bloquea y que nadie verifica es peor que una regla que avisa.

Pendiente de calendario, no de decisión

La traducción. Hecha: el anexo existe en los ocho idiomas y sus dos prompts forman parte de la API de prompts, con el texto inglés idéntico byte a byte en las ocho versiones (lo exige D-043 y lo verifica build/prompts.mjs en cada construcción). El castellano sigue siendo el canónico: si alguna vez una traducción y el castellano discrepan, gana el castellano y la traducción se corrige en el mismo cambio.

11. Cómo se comprueba que la compuerta vigila

Una heurística que no cambia nada cuando se la prende o se la apaga no es una compuerta, es decoración. La prueba de aceptación de la implementación (PND-002) es un proyecto fixture con violaciones deliberadas de cada familia:

EscenarioResultado exigido
Calidad encendida, con violaciónRojo, nombrando la regla y el archivo donde está la violación.
Calidad apagada con registroVerde, y el reporte dice que está apagada, desde cuándo y quién lo autorizó.
Calidad apagada sin registroRojo. Apagar sin motivo escrito es un fallo, no una ausencia de regla.
Usabilidad encendida, con perfil que alcanza de másRojo en UX-12, con el perfil y la funcionalidad nombrados.
Usabilidad encendida, con funcionalidad sin fila en la matrizRojo en UX-08 al cerrar el pendiente (UX-16).
Ambos grupos apagadosVerde en ambos, con las dos líneas de apagado en el reporte.
Se planta una violación de una regla que avisaVerde, y se abre un pendiente que nombra la regla y el archivo: avisar no es aprobar.
Se planta una violación de una regla que bloqueaRojo, con regla, archivo y remedio nombrados. Y no hay tablero: el promedio no cierra bloques.
Tablero: se apaga una regla con registroEl cumplimiento puede subir, pero la cobertura de la compuerta baja y la cifra se publica con el asiento que lo explica. Con una sola cifra este escenario pasaría inadvertido; es la prueba de que las dos cifras existen por un motivo (D-047).
Tablero: dos corridas con reglamentos distintosLas dos cifras se muestran con su huella (versión del catálogo, reglas activas y apagadas, adaptador, versiones de herramientas) y no se grafican como una serie continua: son dos varas distintas y decirlo es parte del resultado.
Tablero: reglamento inválido (regla apagada sin registro)No emite cifras. La salida es rojo, no un tablero con un asterisco.
Tablero: cumplimiento alto con una regla que bloquea en rojoEl bloque no cierra. El tablero promedia; el verde lo decide cada regla, una por una.
Tablero: mejora el porcentaje por tocar solo lo automáticoEl porcentaje sube y la línea de verificación humana no se mueve; se reporta aparte y el reporte no suma las dos cosas en un número único.

Lo que se mira no es solo el color: se mira que las dos líneas de apagado existan en el reporte. Un resultado verde sin esa línea es el único fallo que esta prueba no puede detectar sola por color, y por eso se verifica leyendo la salida.

12. El tablero de cumplimiento (DECIDIDO: dos cifras, D-047)

Estado. Decidido el 2026-10-22 en D-047: el tablero va con dos cifras, con la huella del reglamento, con trinquete, con lo humano fuera del porcentaje y con el asiento obligatorio. No autoriza a cerrar bloques. Lo que sigue es la especificación que la implementación (PND-002) tiene que cumplir.

Qué es. Un derivado determinista del resultado por regla que la compuerta ya emitió. No mide nada nuevo ni juzga nada nuevo: cuenta. Si el tablero pudiera cambiar el veredicto de una regla habría dos fuentes de verdad para lo mismo, que es exactamente lo que el anexo combate en UX-10 (la navegación se deriva de la matriz) y en CQ-14 (un solo lugar para el estado).

Qué no es. No es un criterio de aceptación. Ninguna cifra autoriza a cerrar un bloque: el verde o el rojo lo decide cada regla que bloquea, una por una. El tablero describe la tendencia y señala qué mirar. Si empieza a usarse como umbral de cierre, dejó de servir, porque el camino más corto para subir un número es apagar reglas.

Dos cifras, nunca una.

CifraFórmulaQué mideCómo se mueve
Cumplimientoreglas que pasan ÷ reglas activasqué tan limpio está lo que se está mirandosube cuando se arregla
Cobertura de la compuertareglas activas ÷ reglas declaradas en el catálogocuánto del anexo está realmente mirandobaja cuando se apaga una regla

La razón de que sean dos: apagar una regla sube el cumplimiento y baja la cobertura. Con una sola cifra apagar es gratis y el tablero premia la ceguera. Con dos cifras que se mueven en direcciones opuestas, el atajo desaparece: para mostrar un tablero mejor hay que arreglar código, no apagar reglas. Y la cobertura no se puede subir sin medir.

La huella del reglamento. Cada registro guarda con qué vara se calculó: versión del catálogo, reglas activas y apagadas, adaptador de frontend y versiones de las herramientas. Sin eso, un 82 de ayer y un 91 de hoy no son la misma medida aunque se escriban igual: son dos reglamentos distintos y la serie es falsa. Dos cifras sin huella producen una ilusión de progreso, que es peor que no tener tablero. Si la huella cambia, el registro se marca como no comparable o el histórico se recalcula con la vara vigente; nunca se grafica junto sin decirlo.

Trinquete. El cumplimiento no baja de un bloque al siguiente sin una decisión registrada que lo explique. Es el mismo mecanismo que ya tiene la cobertura de pruebas en CQ-08: el número de hoy es el piso de mañana. Bajar no está prohibido; bajar sin registro, sí.

Lo que no entra en la cuenta. Lo que sólo puede juzgar una persona —la prueba del primer clic (UX-07), la prueba de tarea (UX-06), la captura (UX-27) y todos los casos manuales— se registra como pasado o fallado, por bloque, con nombre y fecha, y se reporta aparte como cobertura de verificación humana. No entra en el porcentaje de cumplimiento. Si se mezclan, el resultado es un número que es sesenta por ciento medición y cuarenta por ciento opinión, y nadie puede decir cuál es cuál. Por eso la sección 9 sigue valiendo: el tablero no inventa una nota de usabilidad, cuenta reglas.

Cómo se falsifica. Amplía la prueba de aceptación de la sección 11:

EscenarioResultado exigido
Se planta una violación de una regla que bloqueaEl cumplimiento baja en exactamente una regla sobre las activas, y aparece el rojo con la regla nombrada.
Se apaga una regla con registroEl cumplimiento puede subir; la cobertura baja en una regla sobre las declaradas; el reporte nombra la regla, el motivo y la fecha de revisión.
Se apaga sin registroRojo, y no se emite tablero: un reglamento inválido no produce cifras.
Mismo árbol y misma configuración, dos corridasLa misma cifra, idéntica.
Cambia la configuración entre dos bloquesLos dos registros quedan marcados como no comparables, o el histórico se recalcula con la vara vigente.
El tablero se usa como criterio de cierreUso indebido, no escenario válido: el verde lo decide la regla, no el promedio.

Dónde aparece. En el reporte honesto del peldaño 12 (ancla 5), y en este orden: primero el veredicto binario de la compuerta, después las dos cifras, después qué está apagado y hasta cuándo, después el movimiento contra el bloque anterior con su causa nombrada. Siempre con el asiento: bajó cuatro puntos: CQ-15, tres cadenas fuera del catálogo en la pantalla de cobro. Una cifra sin asiento es ruido; el asiento es lo que la vuelve accionable para un dueño que no lee código.

Riesgo declarado. El tablero lo va a leer el dueño, que no lee código, y por eso va a querer que suba. El número se convierte en el objetivo, y el objetivo desplaza al propósito. Las defensas son las de arriba, y son cinco: dos cifras que se contradicen al apagarse, la huella que impide comparar varas distintas, el trinquete que no deja bajar sin registro, lo humano fuera del porcentaje y el asiento obligatorio, con la compuerta que no se negocia por promedio. Si alguna de las cinco se cae, el tablero se apaga: un tablero mal usado hace más daño que no tenerlo.

13. Registro

Toda decisión de este anexo queda en docs/DECISIONES.md con fecha, autor, cita textual y archivos de impacto: D-043 (forma), D-044 (mecanismo), D-045 (interruptores), D-046 (disciplina del interruptor), D-047 (el tablero con dos cifras). La implementación y sus criterios de aceptación viven en PND-002.

No queda ninguna decisión abierta: la forma (D-043 y D-044), los interruptores (D-045 y D-046), el tablero (D-047) y las severidades iniciales con el peso de la accesibilidad (D-048) están decididas. El texto viaja en los ocho idiomas y forma parte de la API de prompts, que cierra el único punto que quedaba en el calendario.