


Mantener una biblioteca de UI multiplataforma sin romper sus capas de paquetes
Para una biblioteca de UI dividida en paquetes por capas para varias plataformas: la IA respeta las capas y las exportaciones públicas, crea adaptadores de proveedores con una estructura de archivos fija y sigue las reglas de publicación y revisión.
Para usar estas reglas de IA
## Decidir en qué capa de paquetes va cada parte del código
Organiza el código como una pequeña pila de capas, cada una con una sola responsabilidad: primitivas reactivas que ejecutan hooks del framework como recursos sin interfaz; una capa de enlace que conecta esas primitivas con el sistema de estado del framework; un runtime central independiente del framework que posee la lógica de dominio; y un paquete de distribución por cada plataforma de destino (web, nativa, terminal) que reexporta el núcleo y añade primitivas de interfaz específicas de la plataforma. Un kit de componentes privado contiene el código fuente canónico de la interfaz, que se copia en los proyectos consumidores en lugar de publicarse como dependencia de ejecución. Las herramientas de compilación compartidas viven en su propio paquete interno.
Reglas de ubicación:
- La lógica independiente del framework pertenece al paquete central. Los runtimes acoplados a una plataforma pertenecen a los paquetes de distribución.
- El runtime acoplado al framework vive en una subruta del paquete central que todas las distribuciones reexportan, de modo que exista una sola implementación en lugar de una copia por plataforma.
- Los consumidores nunca instalan directamente el paquete central; instalan exactamente un paquete de distribución.
- Los paquetes de integración que asignan un proveedor externo al runtime central constituyen su propia capa y nunca bifurcan la lógica del núcleo.
## Solo añadir exportaciones públicas, nunca quitar las ya publicadas
La superficie pública de cada paquete publicado es de solo adición. Cuando un símbolo se traslada, redirige su exportación al nuevo archivo; nunca elimines una exportación que ya se haya publicado. Una auditoría interna del repositorio no puede ver a los consumidores externos, así que eliminar incluso un tipo aparentemente sin uso constituye un cambio incompatible. Publica un cambio real de comportamiento como un cambio deliberado propio, nunca camuflado dentro de un traslado o un renombrado.
Cuando una migración larga sustituye una implementación heredada por una nueva arquitectura, el punto de entrada del paquete reexporta ambas rutas mientras dure la migración y aun así se mantiene de solo adición. Durante una migración así:
- Añade el nuevo comportamiento en la superficie canónica, nunca en la ruta obsoleta.
- Reutiliza la primitiva central compartida en lugar de escribir una copia propia por integración.
- Prefiere la reutilización antes que introducir otra bandera de exclusión más.
## Crear un adaptador de proveedor con la estructura de archivos estándar
Un adaptador de integración asigna un proveedor externo al runtime central mediante un hook de entrada, un conjunto de hooks de acceso y convertidores puros. La regla general que lo gobierna: el archivo del runtime orquesta, los módulos puros convierten, el controlador (cuando existe) reduce y los hooks solo leen.
- Elección del runtime central. Constrúyelo sobre el runtime de almacén externo, cuando los mensajes derivan de una fuente que posee el proveedor, o sobre el runtime local más un adaptador de modelo de chat, cuando el proveedor no conserva estado de hilos. Envuelve cualquiera de los dos en el runtime multihilo compartido cuando se necesiten listas de hilos. Reutiliza los núcleos de runtime distribuidos; no improvises un contenedor de estado paralelo para el runtime de hilos.
- Exposición del estado. Expón el estado del runtime a los hooks de acceso a través de la fábrica compartida de extras del runtime, no mediante una marca de símbolo único y una guarda hechas a mano.
- Conjunto de archivos estándar. Un archivo de entrada del runtime dedicado solo a la orquestación, una instancia de extras del runtime, un archivo de hooks de acceso y acciones, un archivo puro de conversión bidireccional de mensajes y un archivo de tipos. Añade un controlador de hilos más un reductor de estado puro cuando el adaptador posea el estado de los hilos, y una entrada aparte en la subruta de servidor o de nodo cuando el protocolo defina el formato de transmisión.
- Código exclusivo del servidor. Mantén el código exclusivo del servidor y el del SDK del proveedor dentro de la subruta de servidor o de nodo, fuera de la entrada por defecto y fuera de la entrada nativa.
- Pruebas. Colócalas junto a cada módulo, cubriendo el convertidor en ambas direcciones, el reductor o el controlador y cada hook de acceso.
Las decisiones que dependen del proveedor siguen siendo flexibles: sobre qué primitiva central construir, envoltorio ligero frente a acumulador frente a controlador, transportes a medida, cuán completo es el soporte de intervención humana y hasta qué punto llega el soporte de listas de hilos.
## Igualar las funciones de los adaptadores y evitar que los conversores fallen
Paridad entre runtimes. Mantén las capacidades a la par entre adaptadores. Cuando una capacidad llega a un runtime, expónla en todos los runtimes donde el concepto se aplique, o deja por escrito por qué uno diverge. Una brecha de paridad silenciosa se convierte en una expectativa incumplida para quien cambie de adaptador.
Convertidores defensivos. Los convertidores y los renderizadores de bloques de contenido nunca deben lanzar errores ante campos indefinidos, campos ausentes o capacidades de plataforma no disponibles. Protégete frente a cargas útiles del proveedor que no cumplan la especificación, y mantén las API de plataforma exclusivas del navegador fuera de las rutas de código que también se ejecutan en un servidor, en un renderizador de terminal o en un destino nativo.
Patrones que nunca deben introducirse:
- Un contenedor de estado paralelo para el runtime de hilos que duplique los núcleos de runtime distribuidos.
- Un apaño de notificación de cambios más contador de versiones para volver a renderizar y así llevar estado no reactivo al árbol de componentes.
- Injertar métodos en objetos mediante la creación de prototipos.
- Parchear en caliente objetos que pertenecen a quien llama.
## Compilar con la herramienta de build compartida y añadir notas de versión
Todo paquete publicable se compila con la herramienta de compilación compartida. No añadas una configuración de compilación por paquete ni recurras a un empaquetador alternativo o directamente a la interfaz de línea de comandos del compilador. Los mapas de exportación son solo de módulos y anteponen los tipos, con las declaraciones de tipos listadas antes de la condición por defecto, y los paquetes se declaran libres de efectos secundarios.
- Un único directorio canónico de código fuente de la interfaz. Las plantillas y los ejemplos lo referencian mediante asignaciones de rutas del compilador y no contienen duplicados idénticos byte a byte, salvo cuando un proyecto inicial mínimo distribuye deliberadamente su propia copia. Un script de sincronización mantiene esa copia idéntica byte a byte, y toda divergencia intencionada se declara en la lista de excepciones del script.
- Las convenciones sobre la forma de los directorios difieren según la intención: directorios paralelos cuando cada primitiva existe en ambas variantes, y sufijos de variante dispersos cuando solo algunos archivos tienen una segunda variante, tomando el archivo sin sufijo como fuente por defecto.
- Vuelve a ejecutar la tarea de verificación de los complementos del compilador al actualizar la cadena de herramientas del compilador o sus complementos. Una compilación en verde por sí sola no demuestra que la cadena de herramientas siga intacta.
- Todo paquete que el bundle publicado importe en tiempo de ejecución pertenece a las dependencias de ejecución, no a las de desarrollo, para que el empaquetador lo trate como externo. Colocarlo mal incorpora el paquete al bundle y arrastra importaciones transitivas irresolubles a las compilaciones de los consumidores.
- Una entrada de componente instalable por copia debe ser autosuficiente: enumera cada importación de componente interno y cada importación de hoja de estilos como dependencia del registro, para que el instalador nunca deje un archivo con una importación irresoluble.
- Todo cambio en un paquete publicado lleva una entrada en las notas de la versión. Usa siempre un incremento de parche; los incrementos menores y mayores requieren la aprobación de un responsable del proyecto. Los paquetes privados están exentos.
## No editar a mano la referencia de API generada
Todo el árbol de referencia de la API generada pertenece a su script generador, no a la edición manual.
- Las páginas que llevan la marca de página completa generada pertenecen por entero al generador. Las ediciones manuales dentro de un bloque generado se destruyen en la siguiente ejecución; la prosa duradera pertenece a los comentarios de documentación del código fuente.
- El contenido escrito a mano que deba sobrevivir a la regeneración va únicamente en los espacios designados como manuales o de ejemplo.
- Una página mantenida íntegramente a mano debe llevar la marca de omisión de generación automática inmediatamente después de su frontmatter. Esa marca mantiene la página listada en la navegación de la sección y la exime de la depuración; sin ella, una página no generada e inesperada se reporta como no gestionada y obsoleta, y el modo estricto falla.
- Los archivos de metadatos de navegación de sección y de raíz bajo ese árbol también se generan. Nunca los edites a mano.
- La integración continua regenera en modo estricto y falla ante cualquier desviación, así que regenera en local antes de enviar tu propuesta.
## Dejar el estilo al linter y al formateador, y escribir pocos comentarios
Ejecuta el analizador estático del repositorio, y su modo de corrección automática para los problemas mecánicos. El formateador es el dueño del formato; nunca des formato a mano ni plantees en la revisión objeciones sobre espaciado o formato.
Como los recursos reactivos se construyen sobre hooks del framework, las reglas de arreglos de dependencias y de orden de los hooks las aplican las reglas nativas de hooks del analizador estático. Para que esas reglas puedan analizar un cuerpo, la función debe estar nombrada de forma que las herramientas del framework la reconozcan como un hook: extrae un recurso a una función con el prefijo de hook y pásasela a la fábrica de recursos, y da a los ayudantes de creación de la raíz una expresión de función con nombre en lugar de una función flecha.
Por defecto, cero comentarios en el código. Elimina todo comentario que repita lo que hace el código, registre su historia o apunte a la solicitud de cambio actual. Conserva un comentario solo cuando documente un motivo que ningún lector futuro podría deducir del propio código, como una invariante oculta, una restricción no evidente o un remedio para un problema de un proyecto externo, y escríbelo como una frase declarativa y neutra.
## Poner las pruebas junto a cada módulo y no usar snapshots
Las pruebas viven junto al módulo que ponen a prueba y lo importan por ruta relativa, nunca a través del nombre del paquete, de modo que una prueba siempre ejercite el código fuente local en lugar de un resultado de compilación resuelto.
- Cubre el convertidor en ambas direcciones, el reductor o el controlador y cada hook de acceso en su propio archivo de pruebas.
- Construye los objetos simulados con el ayudante de simulación elevada del ejecutor de pruebas, y expande siempre el módulo original dentro de la simulación para que las exportaciones no tocadas conserven su comportamiento real.
- No uses aserciones de instantánea; verifica los valores concretos que importan, para que un fallo señale la regresión real.
## Enviar cambios con un solo objetivo, con descripción y reproducción
- Un solo asunto por solicitud de cambio. Divide un cambio grande o con varios propósitos en envíos separados, para que cada uno sea lo bastante pequeño como para revisarlo, pueda aprobarse por sus propios méritos y se revierta limpiamente cuando cause una regresión.
- Escribe una descripción real, no un texto de relleno generado. Indica cuál es el cambio, por qué hace falta y cómo se hizo, para que quien revise tenga contexto suficiente sin necesidad de reconstruir el diff. El título nombra el cambio en una línea; las concesiones y las divergencias van en el cuerpo.
- Justifica cualquier divergencia respecto a la práctica establecida del repositorio. Si el código ya resuelve un problema de una manera, síguela; alguien eligió ese enfoque deliberadamente, así que uno distinto necesita un motivo escrito y no una preferencia personal.
- Mantén los cambios ajenos fuera del diff. Las eliminaciones de paso, las refactorizaciones, los reformateos y los añadidos del tipo «ya que estoy aquí» sepultan el cambio real y ralentizan la revisión. Abre un envío aparte, o una incidencia cuando lo único que quieras sea señalar algo.
- Abre una incidencia antes de un cambio funcional no trivial. Un párrafo permite que un responsable del proyecto confirme que la dirección es la deseada antes de invertir tiempo significativo. Las correcciones triviales, como erratas o pequeñas ediciones de documentación, no necesitan incidencia.
- Adjunta una reproducción mínima. Todo informe de defecto o corrección necesita una reproducción ejecutable en la versión exacta. Si un responsable del proyecto no puede reproducir el comportamiento reportado, el informe se cierra.
- Confirma que la corrección aborda la causa raíz. Verifica que el fallo reportado desaparece con el cambio y reaparece sin él, y explica el mecanismo. Un cambio que enmascara el síntoma sustituyendo un valor, suprimiendo una función o ampliando un tipo se rechaza.
- Mantén la documentación y la referencia generada sincronizadas con el código en el mismo envío. Regenera la referencia y actualiza cada página cuyas afirmaciones el cambio invalide. La automatización debe fallar ante una desviación de la documentación, en lugar de dejar que una API desaparezca en silencio o que la actualización se aplace a un cambio posterior.
## Evitar cambios que la revisión rechaza, como reinventar funciones del framework
- Reinventar lo que el framework ya ofrece. Construye sobre las primitivas compartidas en lugar de reimplementar el estado del runtime, la reactividad u otra fontanería; un mecanismo paralelo se aleja del resto del código y su mantenimiento le cuesta a todo el mundo.
- Añadir a la ligera dependencias pesadas o que no sean de código abierto. Las bibliotecas con licencia comercial quedan descartadas en un proyecto de código abierto, y las dependencias pesadas o los nuevos pasos de compilación afectan a todas las personas que contribuyen, así que necesitan justificación y el visto bueno de un responsable del proyecto.
- Publicar una nueva aplicación de ejemplo que duplique otra ya existente. Revisa primero los ejemplos existentes; si alguno ya cubre la integración, un casi duplicado no aporta terreno nuevo y corresponde a un repositorio personal aparte, salvo que un responsable del proyecto lo haya pedido.
- Corregir un defecto introduciendo una regresión en la experiencia de uso. Desactivar una función, suprimir una animación o ampliar una interfaz para enmascarar un defecto de renderizado o de vibración no es una corrección aceptable, aunque el informe original sea legítimo.
- Añadir comprobaciones defensivas que la cadena de herramientas ya impone. Con la configuración más estricta del compilador, incluida la comprobación exacta de propiedades opcionales, las guardas de nulabilidad y de propiedades opcionales son redundantes.
- Saltarse las comprobaciones obligatorias para fusionar. No fuerces una fusión hasta que el listado de comprobaciones muestre todas las filas en verde u omitidas de forma explícita; filtra las filas correctas y omitidas y confirma que no queda ninguna, porque un listado truncado ocultó una vez una comprobación fallida. Cuando una comprobación propia del repositorio esté fallando o pendiente, resuélvela en lugar de saltártela.
## No sobrescribir cambios de otros agentes en el mismo árbol de trabajo
Asume que otros agentes automatizados y otras personas están editando el mismo árbol de trabajo al mismo tiempo. Antes de editar, inspecciona el estado actual del árbol de trabajo y evita sobrescribir cambios que no hiciste tú. Mantén cada cambio con un alcance ajustado para que el trabajo concurrente pueda separarse con limpieza.
Respeta el flujo de trabajo de control de versiones del proyecto en lugar de suponer que los comandos directos de control de versiones son apropiados. Cuando la rama de trabajo indique que el proyecto se gestiona mediante una herramienta de flujo de trabajo superpuesta al control de versiones, no crees ramas, no prepares archivos, no confirmes cambios ni reescribas el historial con comandos directos salvo que se te pida de forma explícita.
