Documentación / Calidad y gobierno

Contrato de calidad

Las reglas de calidad viven en un archivo versionado del repositorio, no en el prompt, y valen igual para personas y agentes.

El contrato de calidad es el archivo .ai/contract.json de tu proyecto. Define cuánto rigor exige el equipo: umbrales de medición, cobertura, complejidad, tamaño de los cambios, rutas protegidas y excepciones.

Lo aplican el gate del motor, los hooks de Git, la CI y los agentes. El resultado no depende de quién escriba el código: una persona, Yuli, Claude Code, Codex, Kiro o Antigravity.

Si el archivo no existe o no es válido, Yuli usa los valores por defecto (criticidad Negocio). Cada campo es opcional, así que un contrato parcial también funciona.

Dónde se edita

Abre el Centro de Gobierno (riel derecho → Más herramientas, o la paleta de comandos con Abrir el Centro de Gobierno) y entra en la pestaña Contrato.

Al guardar con Guardar y firmar, Yuli registra el cambio con tu git config user.name. Puedes ver todos los cambios en Historial del contrato.

Criticidad

La criticidad elige un perfil completo de umbrales. Hay cuatro niveles:

Valor en el archivo Etiqueta en Yuli Cuándo usarlo
low Baja Prototipos, herramientas internas, experimentos.
business Negocio Aplicaciones de negocio. Es el valor por defecto.
regulated Regulada Sistemas sujetos a auditoría o regulación.
safety Seguridad crítica Software donde un fallo tiene consecuencias graves.

Perfiles

Umbral Baja Negocio Regulada Seguridad crítica
Puntaje de aceptación 80 90 92 95
Rondas de medición 2 3 4 5
Cobertura mínima 50 % 70 % 80 % 90 %
Complejidad cognitiva máx. 20 15 15 10
Complejidad ciclomática máx. 15 10 10 8
Mutación mínima 0 % 0 % 60 % 75 %
Archivos por cambio 60 40 25 15
Líneas por cambio 2000 1000 600 400
Revisión independiente No No Sí Sí
Bloquear trampas en tests No Sí Sí Sí
Aplicación estricta No No Sí Sí

Puedes reemplazar un umbral concreto en gates. Solo cambia ese campo; el resto sigue saliendo del perfil. Bloquear trampas en tests y Aplicación estricta dependen solo de la criticidad y no se pueden reemplazar.

El puntaje de aceptación y las rondas del contrato reemplazan los ajustes locales de la fase de Medición.

Estructura del archivo

{
  "schemaVersion": 1,
  "criticality": "business",
  "gates": { "minCoverage": 75, "maxCyclomatic": null },
  "changeLimits": { "maxFiles": 40, "maxLines": 1000 },
  "protectedPaths": ["db/migrations/**"],
  "waivers": []
}
Campo Qué define
criticality low, business, regulated o safety.
gates acceptanceScore, maxMeasureRounds, minCoverage, maxCognitive, maxCyclomatic, requireIndependentReview, minMutationScore. null toma el valor del perfil.
changeLimits maxFiles y maxLines por cambio.
protectedPaths Globs extra, que se suman a los protegidos por defecto.
waivers Excepciones con vencimiento.
architecture Capas (layers con name, paths, mayDependOn) y forbidCycles.
slos Objetivos de servicio: latencyP95Ms, availability o errorRate.
licensePolicy Licencias permitidas (allow) y prohibidas (deny), por SPDX o por familia, como strong-copyleft.
reviewer Revisor independiente: requireOtherFamily, provider, model.
dataClassification Patrones de datos con su nivel: public, internal, confidential o restricted.
finops Presupuesto mensual por servicio y su responsable.

Límites de cambio

El tamaño de un cambio se mide con git diff --numstat. Los archivos de bloqueo (package-lock.json, yarn.lock, Cargo.lock, go.sum y similares) cuentan como archivos, pero sus líneas no.

Superar el límite bloquea con aplicación estricta (Regulada y Seguridad crítica). En los demás perfiles es un aviso.

Rutas protegidas

Un agente no puede editar estos archivos, aunque se lo pidan:

  • .ai/contract.json, .ai/quality.json y .ai/state/**
  • .claude/settings.json y .claude/settings.local.json
  • .githooks/**
  • .github/workflows/**, .gitlab-ci.yml y Jenkinsfile
  • CODEOWNERS y .github/CODEOWNERS

La comparación ignora mayúsculas. Agrega tus propias rutas en protectedPaths. Un cambio al contrato guardado desde Yuli queda en la auditoría y cuenta como aprobado.

Excepciones (waivers)

Una excepción permite saltar una regla de forma temporal y justificada.

Campo Contenido
id Identificador de la excepción.
rule Regla que se exceptúa: secrets, protectedPaths, testIntegrity, un tipo de trampa concreto o *.
path Glob al que aplica. Vacío significa cualquier ruta.
reason Motivo.
approvedBy Quién la aprobó.
expires Fecha de vencimiento, AAAA-MM-DD.
ticket Referencia opcional.

Una excepción vale hasta el día de expires, inclusive. Una fecha ausente o mal escrita cuenta como vencida. Al vencer, la regla vuelve a regir y el gate lo avisa.

En la interfaz cada excepción muestra su estado: Vigente, Vence pronto, Vencida o Fecha inválida.

testIntegrity exceptúa todas las detecciones de trampas en tests a la vez. Úsala con una ruta acotada y una fecha cercana.

Auditoría

Cada guardado agrega una línea a .ai/state/contract-audit.jsonl con la fecha, el autor, el hash SHA-256 y un resumen (por ejemplo, «criticality business→regulated; waivers +1»).

El autor es siempre una persona: el nombre indicado o tu git config user.name. «Yuli» y «Yuli Code» se rechazan como autores.

Siguiente paso