Todos usamos Claude Code, y todos somos productivos. El problema no aparece cuando codeás — aparece cuando seguís el trabajo de otro. Esta es una historia que ya vivimos, el método que la evita, y cómo se siente usarlo un día cualquiera.
Uscha · metodología spec-driven, tool-agnóstica · ← → para navegar
Cada uno configuró su Claude Code a su mejor criterio. Y el criterio de cada uno es bueno — pero es de cada uno.
Vive en el chat de cada sesión: qué se decidió, por qué, qué quedó afuera. El chat se compacta, se borra, se pierde.
CLAUDE.md distinto (o ninguno), prompts de memoria, skills diferentes. El mismo pedido da resultados distintos según quién lo haga.
"El agente dijo que está listo y los tests pasan." ¿Qué tests? ¿Asertan lo importante? Nadie lo mide — se confía en la narración.
Ninguna de estas cosas duele hoy. Duelen dentro de tres semanas, cuando otra persona hereda el trabajo.
Vale arma la feature de cupones con Claude Code, como siempre: directo al código, iterando en el chat. Queda bien. En el medio, Comercial le pide por Slack un detalle: un cupón vencido hace menos de 24 h se acepta igual (período de gracia). Ella se lo explica al agente en el chat, el agente lo implementa, tests verdes, merge.
¿Dónde quedó documentada la regla de gracia? En un Slack que va a scrollear al olvido y en un chat de Claude Code que se compacta. En el código quedó un expiredAt + 24h sin comentario. En ningún SPEC, en ningún test que la asertee explícitamente.
Le toca agregar reglas de vencimiento por categoría. Abre el código y encuentra el + 24h. Le pregunta a SU Claude Code — que tiene otro setup, otro CLAUDE.md, otra memoria — por qué está eso ahí.
El agente de Martín no miente: adivina con confianza — sin el contexto de Vale, el período de gracia ES indistinguible de un bug. Los tests pasan porque nunca pinnearon esa regla. El lunes siguiente, Comercial reporta que "se rompieron los cupones" en el peor momento posible.
La decisión (gracia de 24 h) nunca llegó a un archivo versionado. ¿Un comentario en el código? Explica, pero no protege: nada lo testea, no frena un merge, y el agente que "normaliza" lo borra junto con la línea.
El agente de Martín no se comporta como el de Vale: otro CLAUDE.md, otras skills, otra memoria. El comportamiento no era replicable.
"Tests verdes" sonó a evidencia, pero nadie midió si los tests asertaban lo importante. La regla crítica no tenía ni un test.
¿Y el code review? El reviewer tenía el mismo contexto que Martín: cero. El diff parecía un fix legítimo de off-by-one con tests verdes — y lo aprobó por la misma razón por la que el agente lo propuso. Faltaba contexto, no diligencia.
Una metodología spec-driven que arranca antes del spec, avanza solo con evidencia capturada, y para en un merge que aprueba un humano. La corremos todos igual, sobre los mismos archivos, con las mismas skills de Claude Code.
No es un proceso aparte del trabajo: es el mismo día, con tres momentos nuevos — dejarte interrogar antes, dejar que el loop mida durante, y leer el estado real al final.
La fricción está puesta donde es barata (media hora de preguntas a las 10:00) para evitar donde es cara (el lunes de Comercial reportando cupones rotos).
Antes de tocar código, el interrogatorio. El skill no acuerda con todo — pregunta hasta que la forma queda clara: contradicciones, términos difusos, modos de falla. Una pregunta a la vez.
La pregunta que en la historia real nadie hizo, acá la hace el método — y la respuesta no muere en un chat.
A medida que las decisiones se asientan, se escriben — no al final, no en el chat. El build lee archivos; el CI lee archivos; el próximo dev lee archivos.
SPEC.mdComportamiento observable, I/O, errores, la regla de gracia con su porqué, rollback.
docs/adr/*.mdUna decisión durable por archivo: qué se eligió, contra qué alternativa, por qué. El código enlaza con // ADR: <slug>.
ACCEPTANCE.mdLos criterios como checkboxes testeables — "cupón vencido hace <24h → se acepta". Esto alimenta el readiness.
CONTEXT.mdEl glosario del dominio: mata el lenguaje difuso antes de que llegue al código.
CONSTITUTION.mdLo que NUNCA es aceptable, gane el trade-off que gane. Una violación se registra como BLOCKER (flag-blocker) y frena todo hasta decisión humana.
RISKS · HANDOFFRiesgo residual y qué leer antes de codear — la carta al próximo dev, escrita cuando el contexto está fresco.
El orquestador toma la SPEC + ACCEPTANCE, construye, y corre un loop de QA que mide en vez de creer. Lo que BLOQUEA sale de artefactos reales parseados por qa_ledger.py — tests, coverage, linters, fact gates. Lo que el agente reporta de sí mismo se registra aparte, como narración — y un rojo medido siempre veta un verde narrado.
Coverage, tests y findings de linters parseados de los XML reales. Lo auto-reportado queda registrado aparte: narración, no dato.
gate-check (¿el cambio debilita tests/thresholds?) y demás gates se persisten con log-gate: uno rojo bloquea la convergencia.
El loop abre el PR, muestra el readiness (KPI 0-100) con su desglose, y para. Mergea una persona. Siempre.
La regla de gracia ahora tiene su criterio en ACCEPTANCE.md y su test que la aserta explícitamente. Ya no es un + 24h misterioso: es comportamiento especificado y pinneado.
Lo clave: el score no se negocia. Podés tener 90 de laburo hecho — si hay un test rojo, el techo es 35.
Esta es la respuesta a la falla 3 de la historia: "listo" era narración. En el método, lo narrado se guarda — pero nunca decide. Decide lo parseado de los artefactos: el XML de surefire, el reporte de JaCoCo, la estructura del diff, los bytes del golden.
Tres semanas después, Martín agarra cupones. Su agente — el mismo setup compartido, las mismas skills — lee los mismos archivos que escribió el método: SPEC, ADRs, ACCEPTANCE.
Doble defensa: la intención está escrita donde el agente la lee (archivos versionados), y aunque un agente intentara "arreglar" la regla, el test que la aserta se pone rojo y gate-check caza el intento de borrarlo o deshabilitarlo — un BLOCKER que la convergencia no deja pasar (debilitar los asserts queda flaggeado para revisión; --strict lo gatea).
Ejemplo de manual del método — una feature mínima, applyDiscount(monto, %), recorrida entera. La metodología no promete que no te desvíes: promete que cada desvío tenga un gate que lo cace.
Fijate el paso 7: el agente bajó un threshold para pasar — y el gate que lo cazó existe porque los agentes hacen exactamente eso. El método no asume buena conducta: la verifica.
Un gate que lee un HECHO (bytes, XML, estructura de diff) puede frenar el trabajo. Un gate que adivina sobre prosa solo puede susurrar — porque un gate con falsos positivos se apaga, y un gate muerto es peor que ninguno.
| Gate | Lee | |
|---|---|---|
| gate-check | estructura del diff: tests borrados/deshabilitados, thresholds bajados o eliminados | BLOQUEA |
| golden-diff | bytes vs .approved (migraciones — el único artefacto que el agente no escribe: un hook PreToolUse se lo bloquea) | BLOQUEA |
| simplicity-check | presupuesto del diff: tamaño, anidación, hunks (OVERBUILT = recortá) | BLOQUEA |
| spec-check estructural | ¿hay sección out-of-scope? ¿hay criterios de aceptación? (existe o no existe) | BLOQUEA |
| spec-check prosa | heurística: criterios vagos, sin métrica | ACONSEJA |
| readiness | KPI 0-100 del estado (con caps duros: tests rojos ≤35, BLOCKER/CRITICAL abierto ≤65) | REPORTA |
Y la que cierra el círculo de la historia de Vale y Martín: lo medido vence a lo narrado — un snapshot de tests rojo veta el "tests verdes" que reporte cualquier agente.
La pregunta de apertura de cualquier cambio: ¿qué puede romper esto, y cuánto cuesta la rotura? La respuesta dimensiona el aparato — no arrastramos toda la máquina detrás de un ajuste de config.
| Perfil | Ejemplo | Gates mínimos |
|---|---|---|
| A · Bajo | UI menor / config | build + test relevante — y nada más |
| B · Normal | feature local / bugfix | tests + estático + review |
| C · Crítico | pagos / seguridad | unit + integración + seguridad + rollback |
| D · Multi-sistema | API pública / eventos | contract tests + versionado |
| E · Legacy | refactor / migración | golden + no-regresión |
heurística de proceso — no mecanizada
La tabla la aplicamos NOSOTROS al clasificar el cambio (no hay un flag --profile que seleccione gates solo). La feature de cupones era B; si tocara el cobro, C — y el discovery lo pregunta.
/uscha-discovery (idea nueva) o /uscha-adr-refine (feature conocida). Dejate interrogar./uscha-devloop mide con el ledger; los fact gates se registran con log-gate.Cuando tocás código viejo que nadie entiende del todo, el riesgo no es romper lo que sabés que hace — es perder el comportamiento que nadie sabía que era intencional (la "gracia de 24h" de otro, de hace cinco años).
/uscha-characterize ejecuta el código ORIGINAL con corpus real y emite fixtures .received — comportamiento observado, no razonado. Y PARA.
Un humano revisa y los consagra como .approved. El agente no puede escribirlos: un hook PreToolUse le bloquea la escritura. Es el único artefacto fuera de su alcance — y esa es su razón de existir.
Cada pass corre golden-diff: byte a byte contra lo aprobado. DIVERGE = se frena. Sin fixtures = NOT-RUN, nunca "pasó".
El rigor escala con el blast radius. Un fix de UI corre build+test y nada más. La máquina completa es para lo que puede romper cosas caras — y ahí la ceremonia es más barata que el incidente de cupones.
Te frena 30 minutos al principio — donde la fricción es barata — para ahorrarte la falla cara: un build confiado de la forma equivocada. Lo que perdió Martín debuggeando el lunes fue MÁS que todo el discovery de Vale.
Funciona en solitario. Se rompe en el handoff — y acá nadie trabaja solo. El método no reemplaza tu criterio: lo hace legible para el que sigue. Tu yo de dentro de 3 meses también es "el que sigue".
Adoptar el método "porque se siente mejor" sería exactamente el vicio que el método combate. Criterios definidos ANTES de correrlo, medibles al cierre — y que también pueden dar que NO:
Al terminar, otra persona del equipo extiende la feature leyendo SOLO los archivos del repo. Si necesita preguntarle al autor, el método falló en su promesa central — y lo anotamos como hallazgo, no lo excusamos.
¿Algún gate frenó algo real que sin método hubiera pasado (un threshold bajado, un test debilitado, un criterio vago)? Si en todo el piloto ningún gate cazó nada, el aparato no se ganó su costo — también es un dato.
Anotamos cada falso positivo y cada paso que estorbó sin aportar. Un método que solo se elogia es un método que no se está probando. Con eso se ajustan presupuestos y umbrales.
Readiness del PR con su desglose (y qué techo lo capeó, si alguno) + churn aparte. No para premiar el número: para ver si el KPI cuenta la historia real del estado del trabajo.
si el piloto falla los criterios, se ajusta el método o se descarta — eso también es el método funcionando.
Cada uno sigue usando Claude Code — con toda su potencia. Lo que cambia es dónde vive la verdad: en archivos versionados que cualquier agente y cualquier persona pueden leer, con evidencia medida en vez de narrada, y con un humano dueño de cada merge.
Uscha · instanciado en Claude Code vía uscha-kit 1.50.0 · preguntas → ahora