Integracion con Herramientas de Calidad

Por: Artiko
openspechuskybiomesonarqubeci-cdcalidad

Integracion con Herramientas de Calidad

Por que integrar

OpenSpec genera planes y la IA implementa codigo. Pero el codigo generado por IA necesita las mismas validaciones que el codigo humano. Husky, Biome y SonarQube son tus guardianes: atrapan problemas antes de que lleguen al repositorio.

La integracion funciona en dos niveles:

  1. En config.yaml: Para que los planes incluyan tareas de configuracion de herramientas
  2. En el proyecto: Para que el codigo generado por /opsx:apply pase las validaciones automaticamente

Husky + lint-staged

Setup

bun add -d husky lint-staged
bunx husky init

Configurar pre-commit

echo 'bunx lint-staged' > .husky/pre-commit

lint-staged en package.json

{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "biome check --write",
      "vitest related --run"
    ],
    "*.{json,md,yaml}": [
      "biome format --write"
    ]
  }
}

Este hook hace que cada commit ejecute:

  1. Biome para formateo y linting
  2. Vitest en modo related (solo tests afectados por los archivos cambiados)

Cuando /opsx:apply genera codigo y la IA intenta hacer commit, el hook se ejecuta automaticamente. Si el codigo no pasa Biome o los tests fallan, el commit se rechaza.

Reflejar en config.yaml

context: |
  ## CI local
  - Pre-commit: Husky + lint-staged
  - Al commitear se ejecuta: biome check + vitest related
  - El codigo DEBE pasar biome y tests antes de commitear
  - Si un test falla, corregir antes de continuar

Esto le dice a la IA que el codigo que genere sera validado por Husky. La IA ajustara su output para cumplir con Biome desde el inicio en vez de generar codigo que falle en el hook.

Biome

Setup

bun add -d @biomejs/biome
bunx biome init

Configuracion recomendada (biome.json)

{
  "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
  "organizeImports": { "enabled": true },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "security": {
        "noDangerouslySetInnerHTML": "error",
        "noGlobalEval": "error"
      },
      "suspicious": {
        "noExplicitAny": "error",
        "noConsoleLog": "warn"
      },
      "complexity": {
        "noExcessiveCognitiveComplexity": {
          "level": "error",
          "options": { "maxAllowedComplexity": 15 }
        }
      }
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  }
}

En config.yaml

context: |
  ## Linting
  - Biome para formateo y lint (reemplaza ESLint + Prettier)
  - Reglas activas: security, suspicious, complexity
  - noExplicitAny: error (no usar any)
  - Complejidad cognitiva maxima: 15
  - Line width: 100 caracteres

rules:
  tasks:
    - Si el cambio introduce archivos nuevos, verificar que pasan biome check
    - "No usar 'any' como tipo, definir tipos o interfaces explicitas"

Ahora la IA sabe que no debe generar any, debe mantener funciones simples y respetar el formato.

SonarQube

Contexto

SonarQube analiza el codigo en busca de bugs, vulnerabilidades, code smells y deuda tecnica. Normalmente corre en CI/CD, pero puedes correrlo localmente con SonarQube Community Edition o SonarCloud.

Setup con Docker (local)

docker run -d --name sonarqube \
  -p 9000:9000 \
  sonarqube:community

Scanner en el proyecto

bun add -d sonarqube-scanner
{
  "scripts": {
    "sonar": "sonar-scanner"
  }
}

sonar-project.properties

sonar.projectKey=mi-proyecto
sonar.sources=src
sonar.tests=src
sonar.test.inclusions=**/*.test.ts,**/*.spec.ts
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.qualitygate.wait=true

Quality Gate personalizado

En SonarQube, crea un Quality Gate con estas condiciones:

MetricaCondicionValor
Coverage>=80%
Duplicated Lines<=3%
Bugs=0
Vulnerabilities=0
Security Hotspots Reviewed=100%
Maintainability Rating<=A

En config.yaml

context: |
  ## Analisis estatico
  - SonarQube para analisis de codigo (bugs, vulnerabilidades, code smells)
  - Quality Gate: 80% coverage, 0 bugs, 0 vulnerabilities, rating A
  - El codigo debe pasar el Quality Gate antes de merge

rules:
  design:
    - No hardcodear credenciales o secretos
    - No usar algoritmos criptograficos debiles
    - No dejar recursos abiertos (conexiones, streams)
  tasks:
    - Si el cambio es significativo, incluir tarea de ejecutar analisis SonarQube
    - Resolver findings criticos antes de merge

Pipeline CI/CD completo

La integracion mas potente es combinar todo en un pipeline que corra automaticamente:

GitLab CI

stages:
  - quality
  - test
  - analyze

lint:
  stage: quality
  image: node:20-alpine
  script:
    - bun install
    - bunx biome check src/

test:
  stage: test
  image: node:20-alpine
  script:
    - bun install
    - bun run test:coverage
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

sonar:
  stage: analyze
  image: sonarsource/sonar-scanner-cli:latest
  script:
    - sonar-scanner
  needs: [test]

GitHub Actions

name: Quality
on: [push, pull_request]
jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bunx biome check src/
      - run: bun run test:coverage
      - uses: SonarSource/sonarqube-scan-action@v5
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Reflejar en config.yaml

context: |
  ## CI/CD
  - Pipeline: lint → test → sonar
  - Todo PR debe pasar: Biome lint, tests con coverage > 80%, SonarQube Quality Gate
  - No se puede mergear con tests fallando o coverage bajo

Patron: Validar specs contra tests

Una tecnica avanzada es usar los escenarios Gherkin de las delta specs como base para los tests:

## User Registration [ADDED]

### REQ-001: Valid registration
GIVEN a valid email and password >= 8 characters
WHEN the user submits the registration form
THEN the system creates an account and returns a JWT

### REQ-002: Duplicate email
GIVEN an email that already exists in the system
WHEN the user submits the registration form
THEN the system returns 409 Conflict

Estos escenarios se traducen directamente a tests:

describe("UserRegistration", () => {
  it("should create account and return JWT with valid data", async () => {
    // REQ-001
  });

  it("should return 409 when email already exists", async () => {
    // REQ-002
  });
});

Para que la IA haga esto automaticamente, agrega en rules:

rules:
  tasks:
    - Para cada escenario Gherkin en las delta specs, generar una tarea de test que lo implemente
    - Referenciar el REQ-ID en el nombre del test

Patron: pre-commit como safety net del apply

Cuando /opsx:apply genera codigo, Claude Code puede intentar correr los tests o hacer commit. Con Husky configurado, el flujo se convierte en:

/opsx:apply
  → IA genera codigo
  → IA corre tests (si task lo pide)
  → IA hace commit
  → Husky intercepta:
    → Biome check: formatea y valida
    → Vitest related: corre tests afectados
  → Si falla: IA recibe el error y corrige
  → Si pasa: commit exitoso

El pre-commit hook actua como safety net automatica. Incluso si la IA olvida correr tests, el hook los ejecuta.

Importante: Para que esto funcione, Claude Code debe tener permiso de ejecutar commits. Revisa tus permisos en la configuracion de Claude Code.

Checklist de integracion

Resumen


← Capitulo 12: Personalizacion Avanzada | Capitulo 14: Flujos y Patrones de Trabajo →