spec·loop 1 / ?
para el equipo · edición extendida · ~35 minutos

Cada uno usa el agente
a su manera. Y funciona…
hasta que tocás el código de otro.

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

01 la situación actual

Cinco devs, cinco métodos distintos.

Cada uno configuró su Claude Code a su mejor criterio. Y el criterio de cada uno es bueno — pero es de cada uno.

El contexto

Vive en el chat de cada sesión: qué se decidió, por qué, qué quedó afuera. El chat se compacta, se borra, se pierde.

El setup

CLAUDE.md distinto (o ninguno), prompts de memoria, skills diferentes. El mismo pedido da resultados distintos según quién lo haga.

La evidencia

"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.

02 una historia simulada — pero que ya viste pasar

Viernes: Vale shipea cupones.

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.

  claude — sesión de vale · viernes 17:40
> comercial pide: si el cupón venció hace menos de 24hs, aceptalo igual (gracia)
Entendido — agrego la ventana de gracia de 24 h en la validación de expiración…
✓ 14 tests passed · "listo, implementado y probado"
— merge. La razón del "bug raro" quedó acá, en este chat. Y este chat no lo va a leer nadie.

¿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.

03 tres semanas después

Martín hereda cupones.
Y hereda un misterio.

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í.

  claude — sesión de martín · otro setup, cero contexto de vale
> ¿por qué la validación de expiración suma 24hs? parece un bug
Coincido — parece un off-by-one en el manejo de fechas. La expiración debería ser
estricta. Lo corrijo y normalizo el manejo de timezones…
✗ regla de negocio eliminada ✓ 14 tests passed · ningún test asertaba la gracia

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.

04 el postmortem honesto

Nadie hizo nada mal.
Y todo salió mal.

falla 1

El "porqué" vivía en el chat

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.

falla 2

Setups distintos, resultados distintos

El agente de Martín no se comporta como el de Vale: otro CLAUDE.md, otras skills, otra memoria. El comportamiento no era replicable.

falla 3

"Listo" era narración

"Tests verdes" sonó a evidencia, pero nadie midió si los tests asertaban lo importante. La regla crítica no tenía ni un test.

falla 4

Nada frenó al segundo agente

¿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.

El problema no es la herramienta ni el dev. Es que el conocimiento vivía en lugares que se mueren — y no había ningún método compartido que lo obligara a vivir en el repo.
05 el método

Uscha: vos traés la idea,
el método construye el resto.

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.

CONSTITUTION — invariantes que ninguna estación puede violar idea01 discovery02 listo03 SPEC / ADR04 build05 verify06 evidencia07 gate humano08 loop interno · convergé, no persigas el cero loop externo · propuesta — el merge sigue siendo del humano
estación gate de evidencia del humano loop interno
06 la rosca de uso

Cómo se siente un día con el método.

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.

10:00idea 10:05 · ~30-40 min/uscha-discovery te grillacontradicciones · bordes 10:45SPEC + ADR al repocommiteados, no en el chat resto del día/uscha-devloop construyegates inline · log-gate al cerrarPR + readinessestado medido, no sensación humano mergea
tiempos ilustrativos de la historia de cupones — el discovery de una feature mediana toma media hora, no un sprint

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).

07 la misma historia, con método — acto 1

Replay: Vale arranca con /uscha-discovery.

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.

  claude — /uscha-discovery · viernes 10:00
discovery> ¿Qué pasa exactamente con un cupón vencido hace una hora? ¿Rechazo
duro, o hay tolerancia de negocio?
> buena pregunta… Comercial quiere 24hs de gracia. lo confirmo y te digo
discovery> Confirmado entonces: lo escribo en la SPEC como regla explícita con su
porqué, y como criterio de aceptación testeable en ACCEPTANCE.md.

La pregunta que en la historia real nadie hizo, acá la hace el método — y la respuesta no muere en un chat.

Un entrevistador complaciente hereda tus puntos ciegos y te los devuelve formateados como plan. La fricción es el entregable.regla operativa del discovery
08 lo que queda cuando la charla termina

La charla se cristaliza
en archivos del repo.

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.md

Comportamiento observable, I/O, errores, la regla de gracia con su porqué, rollback.

docs/adr/*.md

Una decisión durable por archivo: qué se eligió, contra qué alternativa, por qué. El código enlaza con // ADR: <slug>.

ACCEPTANCE.md

Los criterios como checkboxes testeables — "cupón vencido hace <24h → se acepta". Esto alimenta el readiness.

CONTEXT.md

El glosario del dominio: mata el lenguaje difuso antes de que llegue al código.

CONSTITUTION.md

Lo 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 · HANDOFF

Riesgo residual y qué leer antes de codear — la carta al próximo dev, escrita cuando el contexto está fresco.

La verdad vive en archivos versionados. El chat es donde se piensa; el repo es donde se recuerda.
09 la misma historia, con método — acto 2

Vale construye con /uscha-devloop:
evidencia, no narración.

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.

medido

Ledger

Coverage, tests y findings de linters parseados de los XML reales. Lo auto-reportado queda registrado aparte: narración, no dato.

medido

Fact gates

gate-check (¿el cambio debilita tests/thresholds?) y demás gates se persisten con log-gate: uno rojo bloquea la convergencia.

humano

Merge gate

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.

10 lo que ves al terminar — el kpi

Readiness: el estado medido,
no la sensación de "creo que está".

  salida del comando (abreviada) — números del ejemplo de cupones
$ python3 qa_ledger.py readiness
READINESS: 87.0/100 — RELEASE CANDIDATE
--- dimensions (weight | raw | contribution) ---
  adr           30 | 0.90 |  27.0  ← 9/10 criterios de ACCEPTANCE.md
  coverage      25 | 1.00 |  25.0  ← jacoco.xml, no palabra del agente
  static_gate   20 | 1.00 |  20.0  ← linters corridos y limpios (si nunca corren: 0.0)
  convergence   15 | 1.00 |  15.0  ← todas las tools + fact gates limpios
  integration   10 | 0.00 |   0.0  ← contract tests pendientes: se VE, no se esconde
--- churn (not readiness): max cycle 2, regressions 0
NOT READY <50 IN PROGRESS 50–79 RC 80–94 ≥95 87.0 techo 35: tests rojos techo 65: BLOCKER/CRITICAL abierto techo 75: escalación sin resolver
bandas y techos reales del engine — un techo no baja el trabajo hecho: le pone tope al número hasta que el hecho se resuelva

Lo clave: el score no se negocia. Podés tener 90 de laburo hecho — si hay un test rojo, el techo es 35.

11 por qué le podés creer al número

El ledger tiene dos pisos.

MEDIDO — puede bloquear snapshots (surefire/jacoco XML) · ingest-gate (linters) · log-gate (golden-diff, gate-check, pit-check, simplicity) NARRADO — solo aconseja log-step: lo que el agente cuenta de su propio pase (findings reportados/arreglados) — registro para la retrospectiva el rojo medido VETA
el contrato de dos pisos del qa_ledger — lo narrado se guarda; decide lo medido

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.

Una herramienta que no corrió jamás se inventa en verde. Ausente = sin evidencia, nunca "OK".
12 la misma historia, con método — acto 3

El handoff: Martín hereda
archivos, no misterios.

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.

  claude — sesión de martín · replay
> ¿por qué la validación de expiración suma 24hs? parece un bug
No es un bug: SPEC.md §expiración documenta la gracia de 24 h pedida por
Comercial (2026-06-12), y hay un criterio de aceptación que la pinnea.
Si querés cambiarla, es una enmienda a la SPEC — no un fix silencioso.
✓ la regla sobrevive · y si un agente borrara su test, gate-check lo marca BLOCKER

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).

13 no es que todo salga bien de una

En el ejemplo de manual, 6 de 10 pasos
son falla o refinamiento.

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.

1discovery 2⚠ spec vago→ testeable 3⚠ sin out-of-scope→ se agrega 4ADR redondeo 5build 6⚠ coverage mentíapit-check lo caza 7⚠ threshold bajadogate-check BLOCKER 8⚠ caso implícito→ enmienda a la SPEC 9⚠ OVERBUILTsimplicity: recortá 10ship avanza refina la SPEC (advisory o estructural) un gate te frena → arreglás y seguís ship

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.

14 la regla que ordena todo

Los hechos bloquean.
Las conjeturas solo aconsejan.

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.

GateLee
gate-checkestructura del diff: tests borrados/deshabilitados, thresholds bajados o eliminadosBLOQUEA
golden-diffbytes vs .approved (migraciones — el único artefacto que el agente no escribe: un hook PreToolUse se lo bloquea)BLOQUEA
simplicity-checkpresupuesto 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 prosaheurística: criterios vagos, sin métricaACONSEJA
readinessKPI 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.

15 antes de gastarle rigor a un cambio

El rigor escala con
lo que puede romper.

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.

PerfilEjemploGates mínimos
A · BajoUI menor / configbuild + test relevante — y nada más
B · Normalfeature local / bugfixtests + estático + review
C · Críticopagos / seguridadunit + integración + seguridad + rollback
D · Multi-sistemaAPI pública / eventoscontract tests + versionado
E · Legacyrefactor / migracióngolden + 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.

16 adopción honesta

Qué cambia en tu día
(y qué NO).

cambia — 4 hábitos
  • Antes de codear algo no-trivial: /uscha-discovery (idea nueva) o /uscha-adr-refine (feature conocida). Dejate interrogar.
  • Las decisiones van al repo en el momento: SPEC, ADR, ACCEPTANCE. No al final, no al chat.
  • El QA lo corre el loop y lo persiste: /uscha-devloop mide con el ledger; los fact gates se registran con log-gate.
  • El PR para en el merge. Mergea un humano leyendo el diff — nunca el agente.
NO cambia
  • Cambios triviales (one-liner, config): build + test y listo. El método NO se arrastra detrás de un fix de una línea.
  • Spikes y prototipos: sin SPEC. Anotás lo aprendido; se especifica solo lo que sobrevive.
  • Hotfix P0: primero arreglás. La SPEC/ADR retroactiva se debe dentro de las 24 h — válvula de escape diseñada, no improvisada.
  • Tu forma de pensar. El método no codea por vos: te obliga a decir qué querés ANTES, y a probar que salió DESPUÉS.
17 el caso especial que más nos duele

Legacy y migraciones:
el golden es el ancla.

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).

1 · capturar

/uscha-characterize ejecuta el código ORIGINAL con corpus real y emite fixtures .received — comportamiento observado, no razonado. Y PARA.

2 · humano aprueba

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.

3 · migrar con red

Cada pass corre golden-diff: byte a byte contra lo aprobado. DIVERGE = se frena. Sin fixtures = NOT-RUN, nunca "pasó".

Si el agente authoreara el golden, codificaría el mismo entendimiento parcial que perdió la lógica — y aprobaría contra su propio error.
18 lo que estás pensando

Las tres objeciones
(y las respuestas honestas).

"es más ceremonia"

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.

"me va a frenar"

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.

"mi forma funciona"

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".

El comportamiento se replica; la memoria se gana. Lo primero lo resuelve el setup compartido — lo segundo, los archivos en el repo.
19 arranque concreto

Cómo arrancamos esta semana.

  setup — una vez por máquina, 5 minutos
# 1. las skills del kit en el Claude Code de cada uno (o --target codex / both)
npx --yes @andresmassello/uscha@latest install --target claude
# 2. el repo queda methodology-ready de una: protocolo, invariantes,
# config, golden protegido (.gitattributes + hook) y statusline cableada
npx --yes @andresmassello/uscha@latest init
# 3. verificar
npx --yes @andresmassello/uscha@latest doctor --target claude
20 nos auto-aplicamos el método

El piloto también se mide
con hechos, no con sensaciones.

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:

criterio 1 · el test de handoff

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.

criterio 2 · gates que trabajaron

¿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.

criterio 3 · fricción improductiva

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.

criterio 4 · el estado final

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.

21 cierre

No es para que codees distinto.
Es para que el equipo recuerde.

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.

La herramienta ejecuta · el método gobierna · la evidencia decide · el humano aprueba.

Uscha · instanciado en Claude Code vía uscha-kit 1.50.0 · preguntas → ahora