Volver al portfolio

Proyecto personal / Validación de software y pipelines de build

Preflight

Preflight comprueba si una máquina y un cambio cumplen los requisitos del proyecto antes del commit o del build. Sirve a estudios de juegos y empresas de software en general: detecta SDK ausentes, archivos demasiado grandes y violaciones de políticas mediante reglas explícitas, con diagnósticos que indican qué corregir.

¿Por qué ejecutarlo antes de un commit?

Una textura fuente o un binario generado demasiado grande puede entrar en Git y descubrirse solo en CI. El stage pre-submit verifica archivos modificados antes del envío: el autor recibe ruta, límite, tamaño encontrado y una acción correctiva mientras aún puede ajustar el cambio. Un hook de commit y la CI pueden invocar la misma lógica; el equipo debe configurar ese hook.

Determinista significa que los mismos archivos, entorno inspeccionado, reglas, política y target producen el mismo veredicto y orden de hallazgos. La decisión procede de condiciones verificables, como comparar bytes con un límite, sin interpretación por IA. No garantiza un build exitoso ni software funcional: anticipa requisitos conocidos. Duraciones e identificadores de ejecución varían.

  • C#
  • .NET
  • JSON
  • SARIF
  • Windows
Diagnóstico ilustrativo con una regla de tamaño de archivo de la documentación pública. Es un ejemplo de lectura, no una captura de ejecución.
preflight run --stage pre-submit --changed-from origin/main --platform win64

core.presubmit.large-file   Failed
  at        Art/Characters/hero_diffuse.tga
  expected  <= 2,621,440 bytes
  actual    11,400,000 bytes
  fix       Retira el archivo del control de versiones o pide al responsable de la pipeline que revise el límite.

preflight explain core.presubmit.large-file --platform win64

El archivo contiene 11.400.000 bytes y supera el límite Win64 de 2.621.440 bytes. La regla compara su tamaño con maxBytes; no juzga el valor artístico de la textura ni la corrección del código. preflight explain permite comprobar por qué se aplica ese límite.

01 / Contexto

Feedback tardío, errores en cascada y scripts divergentes

En un estudio, el problema puede ser un asset fuera de presupuesto; en una empresa de software, un SDK ausente, una ruta prohibida o un artefacto de build enviado al repositorio. Son condiciones verificables antes de pasos costosos. Validar solo en CI retrasa el diagnóstico hasta ejecutar el job; mantener otro script local añade una fuente de divergencia.

Separé la verificación, compilada en C#, de la política JSON para que la lógica exista una vez y los requisitos varíen por proyecto. Los responsables de infraestructura definen reglas, límites y bloqueos y publican un paquete versionado. Los desarrolladores instalan ese paquete y ejecutan la herramienta sin implementar verificaciones. La CI sigue siendo el control del equipo y ejecuta la misma lógica.

Qué ocurre en una ejecución de pre-submit

  1. 01

    Resolución de la política

    preflight run --stage pre-submit --changed-from origin/main --platform win64 selecciona la pipeline declarada en el checkout y una versión instalada aceptada. El argumento de plataforma selecciona su capa de política.

  2. 02

    Selección de reglas y dependencias

    --changed-from origin/main define la referencia del diff Git; no es un filtro exclusivo de archivos en staging. El stage pre-submit selecciona reglas raíz y sus requisitos previos, aunque pertenezcan a otros stages.

  3. 03

    Ejecución e informe

    Las reglas se ejecutan por niveles del grafo con paralelismo limitado. El informe indica ubicación, esperado, encontrado y corrección. preflight explain core.presubmit.large-file --platform win64 muestra el origen del límite aplicado.

workspace
Verifica la máquina y el entorno de desarrollo.
pre-submit
Verifica los archivos modificados según la política del proyecto.
build-readiness
Verifica los requisitos previos de un build.

El comando evalúa archivos rastreados en el diff Git respecto a la referencia elegida. No hace commit ni instala automáticamente un hook.

02 / Diseño y arquitectura

Decisiones de arquitectura y sus consecuencias

Regla y política

Una implementación, límites distintos por proyecto

Una regla sabe cómo comprobar algo. Su política decide si se ejecuta, sus parámetros, gravedad y comportamiento de bloqueo. Dos proyectos usan el mismo assembly con límites de tamaño distintos, sin bifurcar el código. La lógica se prueba por separado y los requisitos pueden cambiar sin recompilar la herramienta.

Ejemplo de política JSON: una regla con un límite general y otro para Win64.
{
    "schemaVersion": 1,
    "pipeline": "projecta",
    "rules": {
        "core.presubmit.large-file": {
            "settings": {
                "maxBytes": 5242880
            }
        }
    },
    "targets": {
        "win64": {
            "rules": {
                "core.presubmit.large-file": {
                    "settings": {
                        "maxBytes": 2621440
                    }
                }
            }
        }
    }
}

Sin target explícito, maxBytes vale 5.242.880 (5 MiB). Con --platform win64, pasa a 2.621.440 (2,5 MiB). La implementación C# es la misma; cambia el requisito. El fragmento ilustra la selección de parámetros sin reproducir el manifiesto de distribución.

Grafo de ejecución

Dependencias ejecutadas por niveles del grafo

Las reglas declaran dependencias y se ejecutan por niveles topológicos. Las comprobaciones independientes comparten un nivel; los siguientes esperan sus requisitos. Si falla la comprobación de la toolchain, una sonda de compilación dependiente puede omitirse en lugar de producir otro fallo previsible.

La atribución de causa raíz recorre la cadena atravesando omisiones intermedias. El mensaje final apunta a la toolchain ausente, dando un problema que resolver en lugar de una lista de síntomas. La etapa selecciona las raíces del grafo sin descartar dependencias de otras etapas.

Elegí una barrera entre niveles para simplificar la propagación de fallos y la coordinación. Una regla lenta retrasa el siguiente nivel aunque parte de él pudiera empezar. Es un coste deliberado: la ejecución es más fácil de auditar y el informe se ordena por nivel e ID, sin depender de qué tarea termina primero.

Dos controles independientes

blocking y gating responden a preguntas diferentes

Una convención de nombres puede bloquear un submit sin volver inútil la compilación. Una sonda opcional puede ser un requisito técnico aunque su fallo no deba rechazar el envío. Un único booleano no expresa ambos casos. Preflight separa blocking, que afecta al resultado y al código de salida, de gating, que detiene reglas dependientes. La gravedad sigue siendo el nivel de comunicación.

Procedencia de la política

Origen y precedencia de los valores de política

Las políticas heredan parámetros, aplican destinos explícitos de plataforma/configuración y sellan claves contra cambios posteriores. Los sellos se acumulan en la cadena de herencia, impidiendo que un proyecto retire silenciosamente una restricción de la organización. Los overlays locales quedan fuera de CI.

El comando explain registra el origen de los valores efectivos: paquete, archivo, línea y valores reemplazados. Los ejes de destino deben indicarse explícitamente para coincidir con un bloque. Así, una configuración predeterminada no elige silenciosamente otra política de producción.

La precedencia debe ser visible porque un valor JSON no explica por sí solo la configuración efectiva. Sin procedencia, investigar diferencias entre una máquina y CI obligaría a reconstruir la herencia manualmente. preflight explain aporta esos datos desde la propia resolución.

Límite de los plugins

Un contrato común para reglas integradas y externas

Las reglas implementan IValidationRule mediante Preflight.Abstractions. El acceso a archivos, procesos, cambios y políticas llega por los servicios de RuleContext, permitiendo pruebas sin el workspace real. El assembly de reglas integradas no tiene una dependencia privilegiada de Core.

Los plugins se cargan en contextos de assembly separados y recolectables, compartiendo el contrato con el host. Las versiones de dependencias pueden coexistir; los IDs duplicados y contratos incompatibles se rechazan explícitamente. Es aislamiento de dependencias, no una sandbox de seguridad: los plugins siguen siendo código confiado por el responsable del pipeline.

Distribución

Reglas y política distribuidas como paquete versionado

Un paquete contiene política, assemblies de reglas y un manifiesto con SHA-256 por archivo y un rango de contrato compatible. El orden estable de las entradas y las fechas fijas hacen reproducibles sus bytes. La instalación verifica el paquete antes de confirmarlo en el almacén instalado.

El checkout declara un rango de versiones aceptadas; una máquina puede fijar una versión para volver atrás. Instalar un paquete no cambia ese pin. Preflight no busca actualizaciones por su cuenta: la distribución usa el canal de artefactos del estudio sin cambiar las reglas por sorpresa.

Resultados fiables

Estados de resultado con significados distintos

Passed, Warning, Failed, Errored, Skipped y NotApplicable tienen significados distintos. Una regla sin elementos aplicables no afirma éxito; un fallo de la regla se distingue de un defecto del workspace. Consola, JSON y SARIF presentan los mismos datos. Los códigos de salida diferencian un cambio bloqueado de una configuración inválida y un error interno.

El historial es NDJSON local append-only; las estadísticas de duración requieren suficientes observaciones. La herramienta puede medir un comando de build, pero medir su duración no demuestra que fue validado ni que el software funcione.

El determinismo se aplica al veredicto y al orden de hallazgos con entradas iguales, incluyendo entorno inspeccionado y versión de pipeline. La duración y el runId varían por diseño; comparar bytes exige controlar esos campos. La misma política en máquinas con SDK diferentes puede producir correctamente resultados distintos.

Caché incremental

Caché condicionada a la identidad de las entradas

La caché se activa explícitamente y solo admite reglas que proporcionan una huella de sus entradas. La clave incluye también la política efectiva, etapa, destino, generación del contrato e identidad del assembly. Cambiar un límite o recompilar un plugin invalida el resultado anterior. Los resultados en caché se identifican sin presentarlos como nuevas comprobaciones.

La decisión exige que el autor describa las entradas relevantes de su regla. Para una sonda incapaz de representar su entorno de forma fiable, repetir la ejecución es preferible a reutilizar evidencia incompleta. La caché está desactivada por defecto.

03 / Dentro del código

Fronteras entre contrato, ejecución, reglas e interfaz

Preflight.Abstractions

El vocabulario de los plugins: descriptores, resultados, contexto e interfaces de servicios. Depende de la biblioteca base, manteniendo ligero el contrato para reglas externas.

Preflight.Core

Resolución de políticas, grafos, ejecución, carga de plugins, caché e historial. Calcula los datos del informe sin depender de la CLI.

Preflight.Rules

Las verificaciones integradas usan el contrato público, como un plugin del equipo. Muestran la validación del workspace, cambios y requisitos previos del build sin incorporar las exigencias de cada proyecto en la herramienta.

Preflight.Cli

Comandos, parsing, empaquetado y presentación de resultados. La línea de comandos aloja el core; otra integración puede consumir sus datos sin extraer texto del terminal.

Cómo se verifica el comportamiento

El repositorio combina pruebas unitarias, contrato de plugins, salida exacta de consola y escenarios Gherkin que ejecutan el binario publicado. Las pruebas de límites impiden que las reglas integradas dependan de Core y que Core dependa de la CLI. El script verifica formato, compila con advertencias como errores, ejecuta las suites y recoge cobertura. Son comprobaciones de la herramienta, separadas de las reglas de validación definidas para cada proyecto de software o juego.

04 / Trabajo en curso

Implementación actual y límites del contrato

En desarrollo

Preflight es público bajo licencia MIT y sigue por debajo de 1.0. La implementación actual usa .NET 10 y se desarrolla en Windows. Reglas, políticas, paquetes e informes funcionan juntos; la API pública aún puede cambiar.

La dirección es fortalecer verificaciones y evidencias para pipelines de juegos y desarrollo de software en general. Las reglas específicas pertenecen al equipo que conoce los requisitos del proyecto. Compilación y pruebas permanecen en sus herramientas; una IDE o build farm podría alojar el mismo core. Esta página describe la CLI existente.

Explora el proyecto

El README documenta instalación, uso diario, creación de reglas, políticas y distribución de pipelines. El código muestra cómo esos contratos conectan con la ejecución y los informes.

Lee la documentación en GitHub

Contacto

Ciudad de Québec, QC, Canadá / Disponible para oportunidades

Estoy abierto a oportunidades en desarrollo de software, programación de herramientas y gameplay, así como a puestos de artista 3D junior. Si mi experiencia encaja con tu equipo, estaré encantado de conversar a través de mis perfiles sociales.