Wiki 🔍 Search
Qiiub · Guía para el equipo de desarrollo

Cómo funcionan las reglas, el cascade y los guardrails

Qué se carga en la cabeza de Claude, cuándo se carga, y cómo CI mantiene todo honesto — para que nadie tenga que adivinar dónde vive una regla.

CLAUDE.md cascade .claude/rules/ cascade-guards.yml qiiub-doctor commit-msg hook CODEOWNERS ADRs T1–T6 smoke
🧠

La idea en una frase: las reglas no son un PDF que nadie lee — se cargan automáticamente en el contexto de Claude según dónde estés trabajando, y una capa de guardrails en CI verifica que esas reglas existan, sean válidas y no se erosionen. Reglas que se aplican solas + verificación que no depende de la memoria de nadie.

Parte 1 · El cascade

Qué se carga en el contexto, y en qué orden manda

Claude Code carga varias capas de instrucciones. Unas entran al arrancar la sesión; otras son perezosas (lazy) — solo entran cuando tocas un archivo que les corresponde. Cuando dos capas se contradicen, gana la más específica.

override total
MANDA SOBRE TODO

ADRs — docs/adr/

Las decisiones de arquitectura. Si un ADR dice X, se hace X — aunque CLAUDE.md o un ejemplo diga otra cosa. Toda decisión arquitectónica se escribe como ADR antes del código.
LAZY · subtree

Sub-CLAUDE.md en una carpeta

Un CLAUDE.md dentro de una subcarpeta. Carga solo cuando lees/editas un archivo en ese subárbol. Override de la raíz para esa área.
LAZY · path-glob

.claude/rules/*.md — reglas por dominio

Reglas con un paths: en el frontmatter. Cargan solo cuando tocas un archivo que matchea el globcsharp.md al abrir un .cs, frontend-ui.md al tocar apps/**. Es el modelo oficial de Anthropic (ADR-0098). Ver Parte 2.
explícito

Lookbook — docs/lookbook.md

El patrón canónico de código real. Override sobre la prosa cuando ambos aplican. Se consulta a propósito, no se auto-carga.
always-on
CARGA AL ARRANCAR

Root CLAUDE.md — universal (~207 líneas)

Lo que aplica a toda sesión: arquitectura, multi-tenancy, y las reglas load-bearing de seguridad (MerchantId-first, no-secrets, Security Checklist). El default universal cuando nada más específico aplica.
CARGA AL ARRANCARprioridad más baja

Level 0 — ~/.claude/CLAUDE.md (por-dev)

Config personal de cada desarrollador (locale, prefs). El proyecto siempre manda sobre esto. Nunca debe contener reglas que contradigan al repo — qiiub-doctor detecta esa deriva.
Precedencia: ADR sub-CLAUDE.md Lookbook root CLAUDE.md ~/.claude
🔒

La regla de oro de seguridad: como .claude/rules/ y los sub-CLAUDE.md son lazy, una regla que siempre debe aplicar — MerchantId-first, "nunca secretos en el código", el Security Checklist — se queda always-on en el root. Si la mueves a un archivo lazy, no estaría cargada hasta que alguien abra un archivo de ese tipo: un agujero silencioso. Esa es la política central del ADR-0098.

Parte 2 · Reglas por path (ADR-0098)

Cada sesión carga solo lo que le toca

El root CLAUDE.md se redujo de 464 → 207 líneas moviendo las reglas de dominio a .claude/rules/. Un backend dev ya no carga las reglas de UI (≈39% del root viejo) que nunca usa, y viceversa. Archivos más livianos = Claude respeta mejor las reglas que sí aplican.

⚙️ Sesión de backend
1Arrancas sesión → carga root CLAUDE.md (universal + seguridad)
2Abres src/QIIUB.Api/.../Endpoint.cs
3El path matchea src/**/* + **/*.cs
✓ Se carga csharp.md — FastEndpoints, EF Core, Dapper, Data Access, Testing.
✗ NO carga frontend-ui.md — no tocaste nada de UI.
🎨 Sesión de frontend
1Arrancas sesión → carga root CLAUDE.md (universal + seguridad)
2Abres apps/qiiub-portal/.../Page.tsx
3El path matchea apps/** + packages/qiiub-ui/**
✓ Se carga frontend-ui.md — reglas de UI, DataTable, i18n, Pre-Commit Checklist.
✗ NO carga csharp.md — no tocaste C#.
📐

Un archivo, dos subárboles hermanos. frontend-ui.md tiene paths: [apps/**, packages/qiiub-ui/**] — cubre las dos carpetas sin duplicar. Eso es lo que un sub-CLAUDE.md no puede hacer (está atado a su propia carpeta), y es la ventaja que probamos con el test T6c antes de confiar en ella.

Parte 3 · Los guardrails

La maquinaria que mantiene todo honesto

Las reglas no sirven si se erosionan en silencio. Estos chequeos corren automáticamente — en tu máquina, en cada commit y en cada PR — para que la deriva rebote sola, sin depender de que alguien se acuerde de verificar.

🩺

qiiub-doctor

scripts/qiiub-doctor.ps1
antes de cada sesión
  • ¿main local está fresco (<24h)?
  • ¿Cada CLAUDE.md tiene su header de versión?
  • Detecta deriva del Level 0 (~/.claude)
  • ¿La versión de Claude Code matchea el pin?
Si falla: resuélvelo antes de empezar a trabajar.
✍️

commit-msg hook

.husky/commit-msg
en cada commit
  • Prefijo conventional-commits (feat fix docs chore…)
  • Subject ≤ 50 caracteres
  • Sin atribución a Claude / sin robot emoji
Si falla: el commit se rechaza hasta que arregles el mensaje.
🛡️

Cascade Guards

.github/workflows/cascade-guards.yml
en cada PR
  • Las referencias a ADR existen y son citables
  • Paths gated → exigen review de CODEOWNER + ADR
  • Detecta dependencias nuevas (dual ecosystem)
  • Reporta archivos high-blast
Si falla: el PR no mergea sin el ADR o el review correcto.
📋

POS Spec Lint

scripts/pos-spec-lint.ps1
en PRs que tocan docs/design/pos
  • Contrato de spec (ADR-0087): frontmatter, enums, secciones
  • IDs únicos, covers: sin doble-claim, refs válidas
  • Tabla cross-cutting completa (MerchantId/RLS/offline…)
  • + drift de los README vs el frontmatter
Si falla: la spec no cumple el contrato → se arregla antes de merge.
🔬

Cascade Smoke Test

scripts/cascade-smoke-test.ps1
antes de subir el pin de Claude Code
  • Reproduce T1/T2/T4/T6 — que el cascade aún carga como esperamos
  • El validador real de que una versión nueva de Claude Code no rompió nada
Si falla: NO se sube .claude/EXPECTED_CC_VERSION.
👥

CODEOWNERS + branch protection

.github/CODEOWNERS
en cada PR
  • Todo PR exige review (* @jflores @mgandia)
  • Paths gated (CLAUDE.md, .claude/rules/, ADRs…) = high-blast
  • No te puedes auto-aprobar tu propio PR
  • Un push nuevo descarta el approve viejo (stale)
Si falla: el merge queda BLOCKED hasta el approve correcto.
Parte 4 · Cómo encaja todo

El ciclo de vida de un cambio

Dónde entra cada pieza, de principio a fin. Cada "gate" es un punto donde un guardrail verifica antes de dejar pasar.

Abrir sesión

Claude carga el cascade. Tú corres el doctor.

↳ qiiub-doctor
Escribir código

Las reglas del dominio cargan solas según el path que tocas.

↳ .claude/rules/
Commit

El hook valida el mensaje (prefijo + ≤50, sin atribución).

↳ commit-msg
Abrir PR

CI corre los guards + el lint; CODEOWNERS exige review.

↳ cascade-guards · lint
Merge

Solo con el review correcto y CI verde. Decisiones grandes = ADR.

↳ CODEOWNERS · ADR
⚖️

El principio detrás de todo: CI es el límite de confianza, no los pre-commit hooks. Un hook se puede saltar (git commit crudo); el merge no. Por eso las reglas que de verdad importan se verifican en el PR, donde nadie las puede bypassear.

Parte 5 · El respaldo empírico

No asumimos cómo carga Claude Code — lo probamos

Todo el diseño descansa en comportamientos de carga de Claude Code. En vez de confiar en la doc, los validamos con fixtures reales (knowledge-cascade-behavior.md). "Replay-then-trust": se prueba antes de depender de ello, y se re-prueba en cada versión nueva.

T1PASS
Sube por el árbol

El cascade carga cada CLAUDE.md desde el CWD hacia arriba.

T2PASS
Gana el más cercano

En conflicto, el sub-CLAUDE.md más específico override la raíz.

T3PASS
Techo de tamaño

Carga ≥30K tokens reales sin truncar (validado con relleno de alta entropía).

T4PASS
Lazy sub-load

El sub-CLAUDE.md entra al primer Read/Edit en su subárbol.

T5PASS
Edición mid-sesión

Editar un CLAUDE.md cargado inyecta un diff-note; Claude usa lo nuevo.

T6PASS
Path-scoping de rules

.claude/rules/ carga solo en el path que matchea (incl. 2 subárboles hermanos, T6c).