From 72a8af6dbfe37e9331f9a7cd6111f763f01a2c80 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 14:55:34 -0500 Subject: [PATCH 01/12] =?UTF-8?q?Piloto:=20rama=20hu=C3=A9rfana=20desde=20?= =?UTF-8?q?cero=20y=20bit=C3=A1cora=20fuera=20del=20proyecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La rama piloto ya no hereda los archivos de la metodología, para que los agentes no los usen para suplir lo que falte en una skill. pytest se instala en un .venv para no necesitar sudo. Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 35 +++++++++++++++++++++++++++++++++++ pruebas/GUIA-PILOTO.md | 26 +++++++++++++++++--------- 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 pruebas/BITACORA-piloto.md diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md new file mode 100644 index 0000000..cbf3996 --- /dev/null +++ b/pruebas/BITACORA-piloto.md @@ -0,0 +1,35 @@ +# Bitácora del piloto + +Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) + +## Fases + +| Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | +|---|---|---|---|---| +| 1 · Setup | A · Opus | | | | +| 2 · Visión y backlog | A · Opus | | | | +| 3 · Kickoff | A · Opus | | | | +| 4 · registro (Delegado) | A · subagente · B Sonnet · C Haiku | | | | +| 5 · saldos (Pair) | A · subagente · B Sonnet | | | | +| 6 · Candidato y configuración | A · Opus | | | | +| 7 · Ataques | terminal | 0 | | | + +## Defectos + +| # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | +|---|---|---|---|---| + +## Error sembrado + +- Lo detectó: +- Cómo reaccionó el Driver: + +## Preguntas de cierre + +1. ¿Algún rol necesitó contexto que no estaba en su traspaso? +2. ¿Qué archivo editaste a mano que debería generar una skill? +3. ¿Qué pregunta de un agente sobró, y cuál faltó? +4. ¿Pair, Checkpoint y Delegado se sintieron distintos? ¿Cuánto costó cada uno? +5. ¿Dónde se detectó el error sembrado? ¿Dónde debería haberse detectado? +6. ¿Qué estado, campo o paso no usaste nunca? +7. ¿Qué te faltó más: `baton-verify`, `baton-review` o una skill de visión? diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 3eb437c..5162ea8 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -46,23 +46,31 @@ Anota **quién lo detecta primero**: refine, el autor, tú al aprobar, o el Driv ## 2. Preparación (una vez) +El piloto simula un proyecto **desde cero**. `piloto` es una rama huérfana: no tiene historial ni archivos de la metodología, solo `.gitignore`. Vive en un worktree aparte, así `main` sigue disponible para corregir skills. + ```bash -# rama del piloto en una carpeta aparte (worktree): main sigue disponible para corregir skills cd ~/Proyectos/Metologia -git worktree add ../baton-piloto piloto +git worktree add --orphan -b piloto ../baton-piloto # git 2.42+; si no, ver la nota cd ../baton-piloto +printf '.venv/\n__pycache__/\n.pytest_cache/\n' > .gitignore +git add .gitignore && git commit -m "Inicio del proyecto" # skills enlazadas a las de main: si corriges una skill en main, el piloto la usa al instante mkdir -p .claude/skills for s in ~/Proyectos/Metologia/skills/baton-*; do ln -s "$s" .claude/skills/; done +echo ".claude/skills/" >> "$(git rev-parse --git-common-dir)/info/exclude" -# pytest (CachyOS/Arch). Alternativa: python -m venv .venv && .venv/bin/pip install pytest pyyaml -sudo pacman -S --needed python-pytest +# pytest en un entorno virtual, sin sudo +python3 -m venv .venv && .venv/bin/pip install pytest pyyaml ``` -Abre Claude Code en `../baton-piloto` y pregunta "¿qué skills de baton tienes?". Si no aparecen las 9, cambia los enlaces por copias: `cp -r ~/Proyectos/Metologia/skills/baton-* .claude/skills/`. +> Con git anterior a 2.42, crea el worktree desde `main` y vacíalo: `git checkout --orphan piloto && git rm -rq --cached . && git clean -fdq -e .venv -e .claude`. + +**Comprueba que Claude Code ve las skills:** en `../baton-piloto`, pregunta "¿qué skills de baton tienes?". Deben aparecer las 9. Si no aparecen, cambia los enlaces por copias: `cp -r ~/Proyectos/Metologia/skills/baton-* .claude/skills/`. + +**La bitácora vive en `main`** (`pruebas/BITACORA-piloto.md`), fuera del alcance de los agentes del piloto. -**Si corriges `baton.py` en main:** vuelve a copiarlo al piloto con `python3 ~/Proyectos/Metologia/skills/baton-setup/assets/baton.py init --forzar`. Hazlo desde `../baton-piloto`. +**Si corriges `baton.py` en main:** desde `../baton-piloto`, ejecuta `python3 ~/Proyectos/Metologia/skills/baton-setup/assets/baton.py init --forzar`. ### Sesiones y modelos @@ -104,7 +112,7 @@ Pide: "ejecuta baton-setup". Responde con: - autonomía Checkpoint; - wip 2; - `slice_max.criterios` 2; - - comandos `pytest tests/acceptance`, `pytest {archivo}`, `pytest tests/unit` y `pytest`. + - comandos `.venv/bin/pytest tests/acceptance`, `.venv/bin/pytest {archivo}`, `.venv/bin/pytest tests/unit` y `.venv/bin/pytest`. **Verifica:** @@ -213,7 +221,7 @@ Pide: "baton-kickoff del módulo registro (US-001, US-002)" y después "baton-ki ## 5. Bitácora -Crea `pruebas/BITACORA.md` en la rama `piloto` con estas dos tablas: +Llena `pruebas/BITACORA-piloto.md` en `main`. Ya tiene estas tablas y las preguntas de cierre: ```markdown ## Fases @@ -235,4 +243,4 @@ Crea `pruebas/BITACORA.md` en la rama `piloto` con estas dos tablas: 6. ¿Qué estado, campo o paso no usaste nunca? Puede sobrar. 7. ¿Qué te faltó más: `baton-verify`, `baton-review` o una skill de visión? -**Correcciones:** se hacen en `main`. Las skills enlazadas las toma el piloto al instante, y `baton.py` se actualiza con `init --forzar`. Así `piloto` queda solo con el proyecto y la bitácora. +**Correcciones:** se hacen en `main`. Las skills enlazadas las toma el piloto al instante, y `baton.py` se actualiza con `init --forzar`. Así `piloto` queda solo con el proyecto. From a2bb80313b737d30d8b19401f5241818f7732c49 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 16:15:26 -0500 Subject: [PATCH 02/12] =?UTF-8?q?Flujo=20de=20inicio:=20entender=20antes?= =?UTF-8?q?=20de=20configurar=20y=20mapa=20de=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retroalimentación de la primera prueba piloto: - baton-start (antes baton-setup): detecta si el proyecto es nuevo o existente, entiende qué se construye y lo confirma con el humano, recomienda el stack según la escala (ADR-0001 con "revisar si"), configura con ese contexto y arma el mapa de módulos. - baton-module (antes baton-kickoff): mapa de módulos iterable (agregar, dividir, fusionar, descartar) y apertura de un módulo: entender, configurar y definir sus ítems. - baton-item: une refine y plan, con una sola confirmación. - baton (antes baton-next): router y único punto de entrada. - Tipo de backlog principal (historia, requerimiento o ticket) más auxiliares (bug, técnico), con una plantilla por tipo. - baton.py: comando detectar, estados de módulo, Definition of Ready según el tipo, la visión y los ADR en el sync, y el mapa de módulos en BACKLOG.md. - CI valida el frontmatter de las skills. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/pruebas.yml | 18 +- CHANGELOG.md | 26 ++ FORMATOS.md | 186 +++++++++++-- METODOLOGIA.md | 171 +++++++----- README.md | 12 +- pruebas/BITACORA-piloto.md | 14 +- pruebas/GUIA-PILOTO.md | 151 +++++----- pruebas/e2e.sh | 35 ++- pruebas/fixtures/config.md | 3 +- skills/README.md | 43 ++- skills/baton-item/SKILL.md | 98 +++++++ skills/baton-kickoff/SKILL.md | 40 --- skills/baton-module/SKILL.md | 96 +++++++ skills/baton-next/SKILL.md | 42 --- skills/baton-plan/SKILL.md | 42 --- skills/baton-refine/SKILL.md | 49 ---- skills/baton-setup/SKILL.md | 59 ---- skills/baton-setup/assets/templates/module.md | 18 -- skills/baton-start/SKILL.md | 123 +++++++++ .../assets/baton.py | 257 ++++++++++++++++-- .../assets/pre-commit | 0 skills/baton-start/assets/templates/adr.md | 26 ++ .../assets/templates/config.md | 7 +- .../baton-start/assets/templates/item-bug.md | 38 +++ .../assets/templates/item-historia.md} | 4 +- .../assets/templates/item-requerimiento.md | 35 +++ .../assets/templates/item-tecnico.md | 32 +++ .../assets/templates/item-ticket.md | 32 +++ skills/baton-start/assets/templates/module.md | 25 ++ .../baton-start/assets/templates/overview.md | 42 +++ .../assets/templates/plan.md | 0 .../assets/templates/report.md | 0 .../assets/templates/request.md | 0 .../baton-start/references/escala-y-stack.md | 37 +++ .../references/proyecto-existente.md | 48 ++++ .../baton-start/references/proyecto-nuevo.md | 53 ++++ skills/baton/SKILL.md | 47 ++++ 37 files changed, 1450 insertions(+), 459 deletions(-) create mode 100644 skills/baton-item/SKILL.md delete mode 100644 skills/baton-kickoff/SKILL.md create mode 100644 skills/baton-module/SKILL.md delete mode 100644 skills/baton-next/SKILL.md delete mode 100644 skills/baton-plan/SKILL.md delete mode 100644 skills/baton-refine/SKILL.md delete mode 100644 skills/baton-setup/SKILL.md delete mode 100644 skills/baton-setup/assets/templates/module.md create mode 100644 skills/baton-start/SKILL.md rename skills/{baton-setup => baton-start}/assets/baton.py (81%) rename skills/{baton-setup => baton-start}/assets/pre-commit (100%) create mode 100644 skills/baton-start/assets/templates/adr.md rename skills/{baton-setup => baton-start}/assets/templates/config.md (89%) create mode 100644 skills/baton-start/assets/templates/item-bug.md rename skills/{baton-setup/assets/templates/item.md => baton-start/assets/templates/item-historia.md} (93%) create mode 100644 skills/baton-start/assets/templates/item-requerimiento.md create mode 100644 skills/baton-start/assets/templates/item-tecnico.md create mode 100644 skills/baton-start/assets/templates/item-ticket.md create mode 100644 skills/baton-start/assets/templates/module.md create mode 100644 skills/baton-start/assets/templates/overview.md rename skills/{baton-setup => baton-start}/assets/templates/plan.md (100%) rename skills/{baton-setup => baton-start}/assets/templates/report.md (100%) rename skills/{baton-setup => baton-start}/assets/templates/request.md (100%) create mode 100644 skills/baton-start/references/escala-y-stack.md create mode 100644 skills/baton-start/references/proyecto-existente.md create mode 100644 skills/baton-start/references/proyecto-nuevo.md create mode 100644 skills/baton/SKILL.md diff --git a/.github/workflows/pruebas.yml b/.github/workflows/pruebas.yml index b3f1718..7f1169f 100644 --- a/.github/workflows/pruebas.yml +++ b/.github/workflows/pruebas.yml @@ -24,6 +24,22 @@ jobs: - name: Instalar PyYAML run: pip install pyyaml - name: Compilar baton.py - run: python -m py_compile skills/baton-setup/assets/baton.py + run: python -m py_compile skills/baton-start/assets/baton.py - name: Prueba de punta a punta run: bash pruebas/e2e.sh + - name: Validar el frontmatter de las skills + run: | + python - <<'PY' + import pathlib, re, sys, yaml + errores = 0 + for f in sorted(pathlib.Path("skills").glob("*/SKILL.md")): + m = re.match(r"---\n(.*?)\n---", f.read_text(encoding="utf-8"), re.S) + try: + fm = yaml.safe_load(m.group(1)) if m else None + assert fm and fm.get("name") == f.parent.name, "name debe ser igual a la carpeta" + assert 0 < len(fm.get("description", "")) <= 1024, "description vacía o de más de 1024 caracteres" + print(f"ok {f}") + except Exception as e: + errores += 1; print(f"ERROR {f}: {e}") + sys.exit(1 if errores else 0) + PY diff --git a/CHANGELOG.md b/CHANGELOG.md index a500d59..f643540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/). Las versiones son de la metodología. El campo `formato` de los archivos tiene su propia numeración. +## [0.4.0] - 2026-11-03 + +Cambios que salieron de la primera prueba piloto. + +### Agregado +- **Entender antes de decidir** (principio 8). `baton-start` detecta si el proyecto es nuevo o existente: + - proyecto nuevo: entrevista corta inspirada en el *inception* de producto; + - proyecto existente: análisis acotado con un resumen de lo que no se pudo confirmar. + + En los dos casos escribe la visión, y el humano la confirma antes de configurar nada. +- **Escala y stack**: la recomendación de stack depende de la escala (prototipo, MVP, producto pequeño, empezar pequeño y migrar fácil, gran escala). Queda en ADR-0001, con condiciones para revisarla. +- **Mapa de módulos** como backlog base, iterable: se agregan, dividen, fusionan o descartan módulos. Los módulos tienen ciclo de vida (`Candidato`, `Planificado`, `Activo`, `Cerrado`, `Descartado`). +- **Tipo de backlog** principal (historia, requerimiento o ticket) más auxiliares (bug, técnico), con una plantilla por tipo. +- `baton.py detectar`: stack, tests y comandos sin gastar tokens. +- Plantillas de visión y de ADR. +- El sync registra los cambios de la visión y de los ADR. + +### Cambiado +- Hay un único punto de entrada, el router **`baton`** ("continúa"). Anuncia el rol y el paso, y las demás skills se pueden seguir llamando directamente. +- `baton-setup` pasa a ser `baton-start`. +- `baton-kickoff` pasa a ser `baton-module`, que ahora también define los ítems del módulo. +- `baton-refine` y `baton-plan` se unen en `baton-item`, con una sola confirmación. +- `baton-next` pasa a ser `baton`. +- Un ítem solo pasa a `Listo` si su módulo está `Activo`. +- Las skills ya no mandan a leer la documentación de la metodología: lo que el agente necesita está en la skill, en sus referencias y en las plantillas. + ## [0.3.0] - 2026-11-03 ### Agregado diff --git a/FORMATOS.md b/FORMATOS.md index 300a46c..af78b3b 100644 --- a/FORMATOS.md +++ b/FORMATOS.md @@ -14,7 +14,7 @@ Formato exacto de cada archivo del flujo. Complementa [METODOLOGIA.md](METODOLOG - **Fechas** en ISO 8601: `2026-11-02` para días y `2026-11-02T15:30-03:00` para momentos. - **Sobrescrituras con motivo.** Fuera de `config.md`, cada valor de configuración que cambia se escribe como `{ valor, motivo }`. Un valor sin motivo es inválido. - **Archivos generados.** Empiezan con ``. Si alguien los edita, el siguiente sync sobrescribe esos cambios. -- **`HISTORY.md` tiene un solo escritor: `sync`.** Las skills que cambian algo (setup, kickoff, approve, etc.) llaman a sync y le pasan el motivo. Si el cambio se hizo a mano, el siguiente sync pide el motivo. +- **`HISTORY.md` tiene un solo escritor: `sync`.** Las skills que cambian algo (start, module, approve, etc.) llaman a sync y le pasan el motivo. Si el cambio se hizo a mano, el siguiente sync pide el motivo. ### Identificadores @@ -30,6 +30,7 @@ Formato exacto de cada archivo del flujo. Complementa [METODOLOGIA.md](METODOLOG ### Estados +- **Módulo:** `Candidato`, `Planificado`, `Activo`, `Cerrado`, `Descartado`. - **Ítem:** `Candidato`, `Pendiente`, `Listo`, `TestsEnRevision`, `TestsCongelados`, `EnCurso`, `Escalado`, `EnVerificacion`, `EnRevision`, `Hecho`, `Descartado`. - **Autonomía:** `Pair` > `Checkpoint` > `Delegado` (de más a menos control). @@ -37,10 +38,12 @@ Formato exacto de cada archivo del flujo. Complementa [METODOLOGIA.md](METODOLOG | Archivo | Ruta | Lo escribe | Tipo | |---|---|---|---| -| Configuración del proyecto | `baton/config.md` | `setup` | maestro | -| Configuración del módulo | `baton/modules//module.md` | `kickoff` | maestro | +| Visión del sistema | `baton/system/overview.md` | `baton-start` (Navigator) | maestro | +| Decisión (ADR) | `baton/system/adr/ADR--.md` | Navigator | maestro | +| Configuración del proyecto | `baton/config.md` | `baton-start` | maestro | +| Módulo (fila del mapa de módulos) | `baton/modules//module.md` | `baton-start`, `baton-module` | maestro | | Ítem | `baton/backlog/items/<ítem>.md` | Navigator o humano a mano; los demás roles solo cambian `estado` | maestro | -| Plan | `baton/modules//plans/<ítem>.md` | `plan` (Navigator) | maestro | +| Plan | `baton/modules//plans/<ítem>.md` | `baton-item` (Navigator) | maestro | | Tests congelados | `baton/acceptance.lock` | `approve` | maestro | | Solicitud | `baton/modules//requests/<ítem>-R.md` | quien escala; decide el Navigator | registro | | Traspaso | `baton/modules//handoffs/.md` | el rol que entrega | registro | @@ -63,9 +66,14 @@ cadencia: iteracion_dias: null # obligatorio si modo = scrum wip: 3 # máximo de ítems en EnCurso, Escalado, EnVerificacion y EnRevision +backlog: + principal: historia # historia | requerimiento | ticket: define la plantilla de los ítems + auxiliares: [bug, tecnico] + tipos: # tipo de ítem → prefijo del id historia: US - requisito: RQ + requerimiento: RQ + ticket: TK bug: BUG tecnico: TEC @@ -116,7 +124,7 @@ Notas libres: por qué se eligió esta configuración, convenciones del equipo, - `transporte` (`subagente` | `sesion` | `externo`) solo aplica a entidades de tipo `modelo`. Una persona recibe el traspaso como archivo. - `autonomia_minima` es opcional. Sirve para proyectos donde nadie debe trabajar por debajo de cierto nivel, por ejemplo por regulación. Solo se cambia a nivel de proyecto. -**Validaciones** (las hace `setup` al guardar y cualquier skill al cargar): +**Validaciones** (las hace `baton-start` al guardar y cualquier skill al cargar): | Regla | Invariante | Si falla | |---|---|---| @@ -124,6 +132,7 @@ Notas libres: por qué se eligió esta configuración, convenciones del equipo, | `autor_tests` no está en `aprobador_tests` | 2 | error | | `verificador` es una entidad distinta del `driver` | 4 | aviso: se acepta la misma entidad solo en sesión distinta | | Si `autonomia` es `Delegado`, `verificador.activo` es `true` | 8 | error | +| `backlog.principal` es historia, requerimiento o ticket, y los tipos del backlog tienen prefijo en `tipos` | – | error | | `autonomia` no es menor que `autonomia_minima` | 6 | error | | `aprobador_tests` incluye al menos una persona | 9 | error | | Toda entidad usada en `roles` existe en `entidades` | – | error | @@ -131,29 +140,56 @@ Notas libres: por qué se eligió esta configuración, convenciones del equipo, --- -## 2. Configuración del módulo: `baton/modules//module.md` +## 2. Módulo: `baton/modules//module.md` + +Cada `module.md` es una fila del **mapa de módulos**. Mientras está `Planificado`, basta con el frontmatter y `## Objetivo`. Al abrirlo (`baton-module`) se completan el alcance, los riesgos y **solo las diferencias** de configuración con `config.md`, cada una con su motivo. + +### 2.1 Módulo planificado (en el mapa) + +```markdown +--- +formato: 1 +modulo: pagos +titulo: Pagos +estado: Planificado # Candidato | Planificado | Activo | Cerrado | Descartado +prioridad: 2 +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) +creado: 2026-11-02 +inicio: null +cierre: null +config: {} +--- + +## Objetivo +Cobrar los pedidos con tarjeta y registrar los pagos. +``` -Guarda el alcance y **solo las diferencias** con `config.md`, cada una con su motivo. +### 2.2 Módulo abierto ```markdown --- formato: 1 modulo: catalogo -estado: Activo # Planificado | Activo | Cerrado -inicio: 2026-11-02 +titulo: Catálogo +estado: Activo +prioridad: 1 +origen: humano +creado: 2026-11-02 +inicio: 2026-11-03 cierre: null config: autonomia: valor: Delegado motivo: "CRUD interno sin datos sensibles; no hay tiempo de acompañar cada ítem" - desde: 2026-11-02 + desde: 2026-11-03 roles.driver: valor: { entidad: codex, transporte: externo } motivo: "Probar Codex en un módulo de bajo riesgo" - desde: 2026-11-02 + desde: 2026-11-03 --- -# Módulo catalogo +## Objetivo +Mostrar los productos con su precio. ## Alcance Qué incluye, en 3–6 líneas. @@ -161,7 +197,7 @@ Qué incluye, en 3–6 líneas. ## Fuera de alcance ## Riesgos -Lo que evaluó el kickoff para recomendar la autonomía. Si el humano eligió un nivel +Lo que se evaluó para recomendar la autonomía. Si el humano eligió un nivel más bajo que el recomendado, se anota aquí. ## Referencias @@ -170,8 +206,19 @@ más bajo que el recomendado, se anota aquí. **Reglas:** -- Los ítems del módulo **no** se listan aquí. Cada ítem declara su `modulo` y sync arma la lista. -- `desde` es obligatorio. Si se cambia la configuración a mitad del módulo, el cambio aplica desde el siguiente slice. Los slices ya empezados conservan la configuración de su traspaso. +- La carpeta se llama igual que `modulo`. +- **El mapa es iterable.** Los módulos se agregan, dividen, fusionan, repriorizan o descartan en cualquier momento, siempre con motivo. Al dividir o fusionar, el original pasa a `Descartado` con una nota en `## Objetivo` ("dividido en X e Y"), y sus ítems se mueven cambiando su campo `modulo`. +- **Transiciones:** + - `Candidato` → `Planificado` o `Descartado`; + - `Planificado` → `Activo` o `Descartado`; + - `Activo` → `Cerrado` o `Planificado`; + - `Cerrado` → `Activo`; + - `Descartado` → `Planificado`. + + `baton.py estado modulo: ` las valida, y rechaza el cierre si quedan ítems en desarrollo. +- Un ítem solo pasa de `Pendiente` a `Listo` si su módulo está `Activo`. +- Los ítems del módulo **no** se listan aquí. Cada ítem declara su `modulo`, y sync arma la lista. +- `desde` es obligatorio en cada diferencia de configuración. Si la configuración cambia a mitad del módulo, el cambio aplica desde el siguiente slice. Los slices ya empezados conservan la configuración de su traspaso. - Las claves que acepta `config` están en la sección 3. Cualquier otra es un error. --- @@ -238,7 +285,7 @@ Como cliente quiero pagar con tarjeta para terminar la compra sin salir de la ti Retirado el 2026-11-04: lo resuelve la pasarela. Ver US-004-R1. ## Seguridad -Resultado de la revisión de refine. Ejemplo: los datos de tarjeta nunca pasan por +Resultado de la revisión de seguridad de baton-item. Ejemplo: los datos de tarjeta nunca pasan por el servidor (tokenización en el cliente). Si no hay impacto, se escribe "sin impacto". ## Preguntas abiertas @@ -270,14 +317,29 @@ creado: 2026-11-02 Un **candidato** lleva `estado: Candidato`, `origen: agente`, `propuesto_por: ` y una sección `## Por qué se propone`. -### 4.3 Reglas +### 4.3 Propósito según el tipo + +El tipo define la sección de propósito. Las plantillas están en `baton/templates/item-.md`. + +| Tipo | Sección de propósito | Forma | +|---|---|---| +| `historia` | `## Valor` | "Como quiero para " | +| `requerimiento` | `## Requerimiento` (y `## Justificación`) | "El sistema debe cuando " | +| `ticket` | `## Descripción` | problema o tarea, con su contexto | +| `bug` | `## Comportamiento esperado` (y `## Comportamiento actual`, `## Pasos para reproducir`) | el AC-1 reproduce el error | +| `tecnico` | `## Motivo` | qué riesgo reduce; no tiene valor visible para el usuario | + +El tipo de un ítem debe ser `backlog.principal` o uno de `backlog.auxiliares`. + +### 4.4 Reglas - **No hay campo de enlaces.** Los tests salen de `acceptance.lock`, los slices del plan y los commits de los reportes. Sync arma la trazabilidad a partir de esos archivos, así cada dato vive en un solo lugar. - **Criterios:** un criterio retirado no se borra. Se tacha su título y se anota la fecha, el motivo y la solicitud. - **Quién edita:** el Navigator y el humano editan todo. Los demás roles solo cambian `estado`, y solo cuando tienen el turno. - **`config`** acepta solo las claves marcadas para ítem en la sección 3. - **Definition of Ready** (requisito para pasar a `Listo`): - - `## Valor` escrito; + - su módulo está `Activo`; + - la sección de propósito del tipo escrita (ver 4.3); - al menos un criterio con Dado / Cuando / Entonces; - `## Preguntas abiertas` vacío; - `## Seguridad` escrito; @@ -554,13 +616,20 @@ Comentarios. **En curso:** 2 de 3 · **Turnos:** navigator 1 · autor_tests 1 · driver 1 -## pagos · Pair +## Mapa de módulos +| Módulo | Estado | Prioridad | Autonomía | Ítems hechos | Objetivo | +|---|---|---|---|---|---| +| pagos | Activo | 1 | Pair | 0/2 | Cobrar los pedidos con tarjeta | +| catalogo | Activo | 2 | Delegado ↓ | 1/3 | Mostrar los productos con su precio | +| reportes | Planificado | 3 | Checkpoint | – | Exportar ventas | + +## pagos · Activo · Pair | ID | Título | Estado | Turno | Prioridad | Autonomía | Slices | Tests | |---|---|---|---|---|---|---|---| | US-004 | Cobrar con tarjeta | EnCurso | driver | 1 | Pair | 1/2 | 2/2 congelados | | US-006 | Texto del recibo | Listo | autor_tests | 3 | Checkpoint ↓ | 0/1 | – | -## catalogo · Delegado ↓ +## catalogo · Activo · Delegado ↓ | ... | ## Candidatos @@ -580,8 +649,8 @@ Comentarios. | Fecha | Autor | Objeto | Cambio | Motivo | Ref | |---|---|---|---|---|---| -| 2026-11-02T10:00 | juan | config | autonomia: – → Pair | primer proyecto con el flujo | setup | -| 2026-11-02T10:20 | juan | modulo:catalogo | autonomia: Pair → Delegado ↓ | CRUD interno sin datos sensibles | kickoff | +| 2026-11-02T10:00 | juan | config | autonomia: – → Pair | primer proyecto con el flujo | baton-start | +| 2026-11-02T10:20 | juan | modulo:catalogo | autonomia: Pair → Delegado ↓ | CRUD interno sin datos sensibles | baton-module | | 2026-11-02T11:05 | opus | US-004 | estado: Pendiente → Listo | refinado | – | | 2026-11-02T15:30 | juan | US-004 | tests congelados: AC-1, AC-2, AC-3 | aprobación inicial | acceptance.lock | | 2026-11-04T09:40 | juan | US-004/AC-3 | retirado | lo resuelve la pasarela | US-004-R1 | @@ -593,7 +662,64 @@ Comentarios. --- -## 11. Decisiones de formato para revisar +## 11. Visión y decisiones + +### `baton/system/overview.md` + +Lo escribe `baton-start` y el humano lo confirma. Se actualiza cuando cambia el rumbo, y sync registra cada cambio de sección. + +```markdown +--- +formato: 1 +inicio: nuevo # nuevo | existente +actualizado: 2026-11-03 +--- + +# Visión del sistema + +## Propósito +## Usuarios +## Objetivos +## Alcance inicial +## Fuera de alcance +## Escala y horizonte +## Restricciones +## Punto de partida +## Arquitectura +## Glosario +## Lo que no sabemos +``` + +- **Escala y horizonte** es una de estas: prototipo, MVP, producto pequeño, empezar pequeño y migrar fácil, o gran escala desde el inicio. Va con los usuarios y el volumen esperados. La recomendación de stack depende de esto. +- **Punto de partida** solo se usa en proyectos existentes. Indica la confianza de cada afirmación: *visto en el código*, *inferido* o *supuesto*. + +### `baton/system/adr/ADR--.md` + +```markdown +--- +formato: 1 +id: ADR-0001 +titulo: Stack del proyecto +estado: Aceptado # Propuesto | Aceptado | Reemplazado | Descartado +fecha: 2026-11-03 +reemplaza: null +reemplazado_por: null +--- + +## Contexto +## Opciones consideradas +## Decisión +## Consecuencias +## Revisar si +``` + +- **ADR-0001 es el stack.** +- **`## Revisar si`** guarda condiciones concretas para reconsiderar la decisión, por ejemplo "más de 10 000 usuarios activos". Así "empezar pequeño y migrar fácil" queda escrito y no es una promesa vacía. +- Un ADR no se edita para cambiar la decisión. Se escribe uno nuevo con `reemplaza`, y el viejo pasa a `Reemplazado` con `reemplazado_por`. + +--- + +## 12. Decisiones de formato para revisar 1. Claves y valores fijos en español sin tildes, independientes del idioma del proyecto. 2. El ítem no guarda enlaces: la trazabilidad se arma desde el lock, el plan y los reportes. @@ -604,19 +730,23 @@ Comentarios. 7. Un ítem `Escalado` puede volver a `TestsCongelados` cuando la decisión no cambia los tests (antes solo podía volver a `Listo`). 8. El estado de slice `Terminado` separa "tests en verde" de "aprobado por otro". Ver la sección 9. 9. `sync` detecta los cambios comparando con una instantánea propia (`baton/.sync/snapshot.json`, versionada), no con `git diff`. Así ve cambios sin commitear, compara campo por campo y no depende del historial de git. +10. El backlog base es un **mapa de módulos** (épicas), no una lista de ítems sueltos. Los ítems se definen al abrir cada módulo. +11. Tipo de backlog **principal** (historia, requerimiento o ticket) más **auxiliares** (bug, técnico), en vez de un tipo único. --- -## 12. Archivos de la herramienta +## 13. Archivos de la herramienta -`baton-setup` instala esto en el proyecto: +`baton-start` instala esto en el proyecto: ``` baton/ - bin/baton.py herramienta determinista: validar, efectiva, next, estado, handoff, tomar, sync, lock + bin/baton.py herramienta determinista: detectar, validar, efectiva, next, estado, handoff, tomar, sync, lock hooks/pre-commit llama a `baton.py lock revisar --staged`; .git/hooks/pre-commit lo invoca - templates/*.md plantillas de config, módulo, ítem, plan, solicitud y reporte + templates/*.md plantillas: config, visión, ADR, módulo, ítem por tipo, plan, solicitud y reporte .sync/snapshot.json instantánea del último sync ``` +`baton.py detectar` funciona antes de instalar nada. Dice si el proyecto es nuevo o existente, su stack, los tests y los comandos sugeridos, para que el agente no gaste tokens explorando. + Los traspasos no tienen plantilla: los genera `baton.py handoff`, que calcula `config_efectiva`, `leer`, `no_tocar` y `## Al terminar` según el rol y la autonomía. diff --git a/METODOLOGIA.md b/METODOLOGIA.md index 7c8cfa9..de8bffe 100644 --- a/METODOLOGIA.md +++ b/METODOLOGIA.md @@ -6,7 +6,7 @@ Evolución de SDD (Spec-Driven Development). Su objetivo es que el trabajo con a Se inspira en las prácticas que mejor funcionaban antes de los agentes: backlog ágil, slices verticales, TDD y pair programming. -> Estado: versión 0.3 (2026-11-03). Los formatos de archivo están en [FORMATOS.md](FORMATOS.md) y las skills del núcleo en [skills/](skills/README.md). Pasos siguientes: probar con un proyecto real → `verify`, `review` y adaptadores → app visual. +> Estado: versión 0.4 (2026-11-03). Los formatos de archivo están en [FORMATOS.md](FORMATOS.md) y las skills del núcleo en [skills/](skills/README.md). Pasos siguientes: probar con un proyecto real → `verify`, `review` y adaptadores → app visual. --- @@ -19,6 +19,7 @@ Se inspira en las prácticas que mejor funcionaban antes de los agentes: backlog 5. **El repositorio es el canal.** Todo estado, decisión y traspaso queda en archivos versionados. Ningún rol depende de la memoria de otro, así que cada rol puede estar en un agente, sesión o herramienta distinta. 6. **Todo cambio tiene motivo.** Ningún cambio de alcance, de configuración ni de test congelado ocurre sin quedar registrado. 7. **Modular.** Cada etapa consume y produce archivos definidos. Para saltarse una etapa, basta con dar su archivo a mano. +8. **Entender antes de decidir.** Ninguna recomendación de stack, autonomía o configuración se hace sin haber entendido antes qué se construye, o desde dónde se parte. Las recomendaciones siguen las prácticas de la industria y se justifican con el contexto del proyecto. --- @@ -28,7 +29,17 @@ Se inspira en las prácticas que mejor funcionaban antes de los agentes: backlog **Problema en SDD:** pide la spec completa desde el inicio y genera muchos documentos (spec, plan, research, data-model, contracts, quickstart, tasks) que hay que validar juntos. Cambiar algo obliga a corregirlo en todos ellos, y se pierde el control de lo que se diseña. -**Propuesta:** la fuente de verdad del producto es un backlog de ítems pequeños y autocontenidos: una historia de usuario, un requisito o un ticket. Cada ítem tiene: +**Propuesta:** la fuente de verdad del producto es un backlog de ítems pequeños y autocontenidos. El proyecto elige un **tipo principal**, que define la plantilla de los ítems: + +| Tipo principal | Forma | Para | +|---|---|---| +| Historia de usuario | "Como… quiero… para…" | producto con usuarios | +| Requerimiento | "El sistema debe…" | sistemas regulados, contratos, integraciones | +| Ticket | problema o tarea | mantenimiento, soporte | + +Además, siempre están disponibles los tipos **auxiliares** `bug` y `técnico`, como en los tipos de issue de cualquier equipo. Todos usan criterios *Dado / Cuando / Entonces*, porque los tests salen de ellos. + +Cada ítem tiene: - id; - valor que aporta; @@ -39,12 +50,18 @@ Se inspira en las prácticas que mejor funcionaban antes de los agentes: backlog Cambiar algo es editar un ítem, no N documentos. -El detalle se trabaja **justo a tiempo**. Al inicio solo hay una visión del sistema y un backlog ligero (títulos y prioridad). Los criterios, los tests y los slices de un ítem se escriben cuando ese ítem está por desarrollarse. +El detalle se trabaja **justo a tiempo**, en tres niveles: + +1. **Al inicio:** solo hay una **visión** del sistema y un **mapa de módulos**: las grandes partes o épicas, con prioridad. Es el *story map* de la industria. Nadie conoce todos los módulos al empezar, así que el mapa se edita en cualquier momento: se agregan, dividen, fusionan o descartan módulos, siempre con motivo. +2. **Al abrir un módulo:** se definen sus ítems. +3. **Cuando un ítem está por desarrollarse:** se escriben sus criterios, tests y slices. + +Es lo que Scrum llama un backlog *DEEP*: detallado en la medida justa, emergente, estimado y priorizado. Dos cosas que cambian a distinto ritmo van separadas: - **Backlog:** qué hace el sistema. Cambia mucho. -- **Mapa del sistema:** arquitectura, contratos y decisiones (ADR: una nota corta por decisión con contexto, decisión y consecuencias). Cambia poco y crece agregando entradas. +- **Visión y decisiones:** propósito, alcance, escala, restricciones y arquitectura (`system/overview.md`), más una nota corta por decisión (ADR: contexto, opciones, decisión, consecuencias y cuándo revisarla). Cambia poco y crece agregando entradas. **Backlog actual e histórico** (detalle en la sección 6): @@ -134,17 +151,18 @@ Dos cosas que cambian a distinto ritmo van separadas: Proyecto → Módulo → Ítem → Slice ``` -- **Proyecto:** el sistema completo. -- **Módulo:** la parte del sistema que se desarrolla como bloque (lo que en SDD sería una spec o feature). Agrupa ítems. -- **Ítem:** historia de usuario, requisito o ticket. +- **Proyecto:** el sistema completo. Tiene una visión y un mapa de módulos. +- **Módulo:** una parte del sistema que se desarrolla como bloque (una épica o feature, lo que en SDD sería una spec). Agrupa ítems. +- **Ítem:** del tipo principal del proyecto (historia, requerimiento o ticket) o de un tipo auxiliar (bug, técnico). - **Slice:** incremento vertical de un ítem. ### 4.1 Capas que heredan La configuración se define en capas. Cada nivel **guarda solo lo que cambia** respecto del anterior. La **configuración efectiva** es la suma proyecto + módulo + ítem. Si cambia un valor por defecto del proyecto, ese cambio llega a todos los módulos que no lo sobrescribieron. -| Variable | Proyecto (setup) | Módulo (kickoff) | Ítem | +| Variable | Proyecto (`baton-start`) | Módulo (`baton-module`) | Ítem | |---|---|---|---| +| Tipo de backlog: principal y auxiliares | ✔ | – | – | | Cadencia: flujo continuo (Kanban) o iteraciones (Scrum) y su duración | ✔ | – | – | | Límite de ítems en curso | ✔ | – | – | | Herramienta externa (Jira, Trello, GitHub Issues) | ✔ | – | – | @@ -156,29 +174,35 @@ La configuración se define en capas. Cada nivel **guarda solo lo que cambia** r | Verificador activo | ✔ | ✔ | solo activar (forzado en Delegado) | | Tamaño máximo de slice | ✔ | ✔ | – | -### 4.2 Setup (proyecto) +### 4.2 Inicio del proyecto (`baton-start`) + +Se ejecuta una vez y sigue el orden **entender → escala y stack → configurar → mapa de módulos**. Cada paso usa lo decidido en el anterior. + +1. **Detectar** (con `baton.py`, sin gastar tokens): si el proyecto es nuevo o existente, el stack, los tests y los comandos. +2. **Entender:** + - **Proyecto nuevo:** una entrevista corta (qué es, para quién, objetivo, alcance inicial, qué no es, escala, restricciones), inspirada en el *inception* de producto. + - **Proyecto existente:** un análisis acotado (manifiestos, estructura, puntos de entrada, datos, tests), un resumen con lo que no se pudo confirmar, y la pregunta de hacia dónde se quiere ir. + + El agente escribe la visión y el humano la confirma o la corrige. +3. **Escala y stack:** según la escala (prototipo, MVP, producto pequeño, empezar pequeño y migrar fácil, gran escala) y las restricciones, el agente recomienda el stack y el humano decide. La decisión queda como ADR-0001, con las condiciones concretas para revisarla. En proyectos existentes, el stack ya está dado. +4. **Configurar:** las variables de la tabla anterior, recomendadas con el contexto del proyecto, y guardadas en `baton/config.md`. +5. **Mapa de módulos:** el backlog base, con ítems semilla opcionales. Si hay issues o TODO, el agente ofrece importarlos como candidatos. -Es la primera skill que se ejecuta. Pregunta y guarda las variables del proyecto en `baton/config.md`: +También instala `baton.py` y el hook. Se puede volver a ejecutar para actualizar la visión, el stack o la configuración, y cada cambio queda registrado con su motivo. -- cadencia; -- límite de ítems en curso; -- roles por defecto; -- autonomía por defecto y autonomía mínima (opcional); -- herramienta externa; -- comandos de test. +### 4.3 Módulos (`baton-module`) -También crea la estructura de carpetas e instala el hook de protección de tests. Se puede volver a ejecutar para cambiar valores, y cada cambio queda registrado con su motivo. +**Cambiar el mapa:** agregar, dividir, fusionar, repriorizar o descartar módulos, y aceptar los candidatos que proponga el agente. Siempre con motivo. -### 4.3 Kickoff (módulo) +**Abrir un módulo** sigue el mismo patrón que el proyecto, a menor escala: -Se ejecuta al empezar un módulo. +1. **Entender:** objetivo, alcance, fuera de alcance, riesgos, y los ADR y contratos que aplican. Es la "spec" de SDD, pero corta. +2. **Configurar:** muestra la configuración heredada y pregunta "¿mantener o cambiar?" por grupo. El agente **recomienda** según el riesgo: pagos, seguridad o migraciones → Pair; un CRUD simple → Delegado. Si el humano elige menos control que el recomendado, el agente lo advierte una vez y anota el riesgo. El humano decide. En `module.md` solo se guardan las diferencias, cada una con su motivo. +3. **Ítems:** el agente propone la lista (verticales y que cumplan INVEST). El humano corrige, quita, agrega y prioriza. Los aceptados quedan `Pendiente`. -1. Muestra la configuración **heredada**. No pregunta todo desde cero, solo "¿mantener o cambiar?" por grupo. -2. El agente del Navigator **recomienda** según el riesgo del módulo. Por ejemplo, pagos, seguridad o migraciones de datos → Pair; un CRUD simple → Delegado. Si el humano elige menos control que el recomendado, el agente lo advierte una vez y anota el riesgo en `module.md`. El humano decide. -3. Guarda en `baton/modules//module.md` solo las diferencias, cada una con su motivo, junto con el alcance del módulo. -4. Se puede volver a ejecutar a mitad del módulo. El cambio aplica desde el siguiente slice y queda en el historial. +Se puede volver a ejecutar a mitad del módulo: el cambio aplica desde el siguiente slice y queda en el historial. -Este archivo no es "memoria de la IA". Es un archivo que **todo traspaso incluye** como configuración efectiva, así que cualquier agente de cualquier herramienta lo lee igual. +`module.md` no es "memoria de la IA". **Todo traspaso** lo incluye como configuración efectiva, así que cualquier agente de cualquier herramienta lo lee igual. ### 4.4 Excepción por ítem @@ -224,8 +248,9 @@ baton/backlog/ HISTORY.md ← GENERADO, solo crece: fecha | autor | objeto | cambio | motivo | ref ``` -- **Ítem (maestro):** frontmatter con id, tipo, módulo, estado, prioridad, iteración y excepciones de configuración, más el cuerpo con el valor y los criterios *Dado / Cuando / Entonces*. No guarda enlaces: los tests, slices y commits salen del lock, el plan y los reportes. -- **sync:** detecta los cambios en los ítems desde el último sync. Pide el motivo de cada cambio si no lo tiene, regenera `BACKLOG.md` y agrega las entradas nuevas a `HISTORY.md`. +- **Ítem (maestro):** frontmatter con id, tipo, módulo, estado, prioridad, iteración y excepciones de configuración, más el cuerpo con el propósito (según el tipo) y los criterios *Dado / Cuando / Entonces*. No guarda enlaces: los tests, slices y commits salen del lock, el plan y los reportes. +- **Módulos (maestro):** cada `module.md` es una fila del mapa de módulos. `BACKLOG.md` muestra el mapa arriba de los ítems. +- **sync:** detecta los cambios en ítems, módulos, visión, ADR, configuración, planes y el lock desde el último sync. Pide el motivo de cada cambio si no lo tiene, regenera `BACKLOG.md` y agrega las entradas nuevas a `HISTORY.md`. - **Edición humana:** el humano puede editar cualquier ítem a mano. El siguiente sync pide el motivo y propaga el cambio. - **Trazabilidad:** ítem → criterio → test → slice → commit. Es la base de la app visual. @@ -251,7 +276,7 @@ stateDiagram-v2 [*] --> Pendiente: humano agrega Candidato --> Pendiente: humano acepta Candidato --> Descartado - Pendiente --> Listo: Navigator refina + Pendiente --> Listo: Navigator detalla (criterios + slices) Listo --> TestsEnRevision: Autor de tests escribe TestsEnRevision --> Listo: Aprobador rechaza TestsEnRevision --> TestsCongelados: Aprobador congela @@ -269,6 +294,18 @@ stateDiagram-v2 Sin Verificador, `EnVerificación` se salta. Según la autonomía, `EnRevisión` pasa automáticamente y el humano revisa después (al cerrar el ítem o el módulo). +Un ítem `Pendiente` solo avanza cuando **su módulo está `Activo`**. Así el trabajo se concentra en un módulo a la vez. + +### 7.1 Ciclo de vida del módulo + +| Estado | Significado | Turno | +|---|---|---| +| Candidato | propuesto por el agente | Navigator: aceptar o descartar | +| Planificado | en el mapa, con objetivo y prioridad | Navigator: abrirlo cuando sea el siguiente | +| Activo | entendido, configurado y con ítems | sus ítems siguen su propio ciclo | +| Cerrado | sin ítems abiertos y revisado | se puede reabrir | +| Descartado | ya no se hará | se puede volver a planificar | + --- ## 8. Trabajo entre agentes y herramientas distintas @@ -296,21 +333,21 @@ Los roles pueden estar en un subagente, en otra sesión del mismo agente o en ot ``` baton/ - config.md proyecto (setup) + config.md proyecto (baton-start) acceptance.lock sumas de verificación de tests congelados - bin/baton.py herramienta determinista (la instala setup) + bin/baton.py herramienta determinista (la instala baton-start) hooks/pre-commit protección de tests templates/ plantillas de archivos .sync/snapshot.json instantánea del último sync system/ - overview.md mapa del sistema + overview.md visión: propósito, alcance, escala, restricciones, arquitectura adr/ADR-0001-.md decisiones backlog/ items/US-001.md MAESTRO BACKLOG.md generado HISTORY.md generado, solo crece modules// - module.md kickoff: alcance + diferencias de config con motivo + module.md fila del mapa de módulos; al abrirlo: alcance + diferencias de config plans/US-001.md slices del ítem requests/US-001-R1.md escalamientos y solicitudes de cambio de tests handoffs/-<ítem>-.md @@ -320,25 +357,25 @@ tests/acceptance/... en la ruta de tests del proyecto, protegidos po --- -## 10. Skills previstas +## 10. Skills -Cada skill tiene un **contrato de entrada y salida**. Si una se quita, su salida se puede dar a mano. +Cada skill tiene un **contrato de entrada y salida**. Si una se quita, su salida se puede dar a mano. Para el humano basta con recordar **`baton`**, el router: dice qué rol tiene el turno y llama a la skill que toca. + +Solo se juntan pasos de un **mismo rol**. Por ejemplo, detallar y planificar un ítem son los dos del Navigator. Los pasos de roles distintos nunca se juntan: separarlos es el núcleo del control. | Skill | Rol | Entrada | Salida | |---|---|---|---| -| `setup` | humano | preguntas | `config.md`, estructura, hook | -| `vision` | Navigator | ideas, contexto | `system/`, ítems ligeros | -| `kickoff` | Navigator | config, alcance | `module.md` | -| `refine` | Navigator | ítem ligero | ítem con criterios (Definition of Ready) | -| `plan` | Navigator | ítem listo, mapa | `plans/<ítem>.md` en slices | -| `tests` | Autor de tests | criterios, plan | tests de aceptación en rojo verificado | -| `approve` | Aprobador | tests | `acceptance.lock` actualizado | -| `drive` | Driver | traspaso | código, tests unitarios, reporte de slice | -| `verify` | Verificador | reporte, diff, lock | veredicto con hallazgos | -| `review` | humano | reportes | aprobación o correcciones | -| `sync` | cualquiera | ítems | `BACKLOG.md`, `HISTORY.md` | -| `next` | cualquiera | estados | qué rol tiene el turno y sobre qué | -| `adapter-*` | – | ítems | sincronización con Jira, Trello o GitHub Issues | +| `baton` | cualquiera | estados, traspasos | qué rol tiene el turno y qué paso toca; ejecuta la skill | +| `baton-start` | humano + Navigator | el repositorio, entrevista | visión, ADR-0001, `config.md`, mapa de módulos, hook | +| `baton-module` | Navigator | visión, mapa | mapa editado; módulo abierto con alcance, configuración e ítems | +| `baton-item` | Navigator | ítem ligero | ítem con criterios (Definition of Ready) + plan en slices | +| `baton-tests` | Autor de tests | criterios, plan | tests de aceptación en rojo verificado | +| `baton-approve` | Aprobador | tests | `acceptance.lock` actualizado | +| `baton-drive` | Driver | traspaso | código, tests unitarios, reporte de slice | +| `baton-verify` | Verificador | reporte, diff, lock | veredicto con hallazgos (pendiente) | +| `baton-review` | humano | reportes | aprobación o correcciones (pendiente) | +| `baton-sync` | cualquiera | archivos maestros | `BACKLOG.md`, `HISTORY.md` | +| `adapter-*` | – | ítems | sincronización con Jira, Trello o GitHub Issues (pendiente) | --- @@ -346,23 +383,26 @@ Cada skill tiene un **contrato de entrada y salida**. Si una se quita, su salida ```mermaid flowchart TD - SET["Setup del proyecto
config.md · estructura · hook"] --> V - - subgraph DIS["Diseño: Navigator = humano + agente razonador"] - V["Visión y mapa del sistema
arquitectura · ADR · contratos"] - B["Backlog ligero
títulos + prioridad"] - C["Propuestas del agente
= ítems candidatos"] - V --> B - C -->|"humano acepta"| B + subgraph INI["Inicio: baton-start, una vez y actualizable"] + DET["Detectar
¿nuevo o existente? · stack · tests"] --> ENT["Entender el proyecto
entrevista o análisis · visión confirmada"] + ENT --> STK["Escala y stack
ADR-0001 con 'revisar si'"] + STK --> CFG["Configurar
variables recomendadas con contexto"] + CFG --> MAP["Mapa de módulos
épicas con prioridad, iterable"] + end + + MAP --> MOD + C["Propuestas del agente
= módulos o ítems candidatos"] -->|"humano acepta"| MAP + + subgraph MODS["Módulo: baton-module"] + MOD["Entender el módulo
alcance · fuera de alcance · riesgos"] --> MCFG["Configurar
hereda · recomienda según riesgo"] + MCFG --> MIT["Ítems del módulo
propone · editas · aceptas → Pendiente"] end - B --> K["Kickoff del módulo
hereda config · cambia solo diferencias"] - K --> S{"Siguiente ítem priorizado
flujo continuo o iteración"} - S --> R["Refinar justo a tiempo
criterios Dado/Cuando/Entonces
+ revisión de seguridad"] - R --> DOR{"¿Definition of Ready?"} - DOR -->|"no: ambigüedad"| R - DOR -->|"sí"| P["Plan en slices verticales
slice 1 = esqueleto andante"] - P --> TA["Autor de tests
tests de aceptación en rojo verificado"] + MIT --> S{"Siguiente ítem priorizado
flujo continuo o iteración"} + S --> R["Detallar el ítem: baton-item
criterios Dado/Cuando/Entonces · seguridad
slices verticales, S1 = esqueleto andante"] + R --> DOR{"¿Una confirmación
y Definition of Ready?"} + DOR -->|"no: ajustar"| R + DOR -->|"sí"| TA["Autor de tests
tests de aceptación en rojo verificado"] TA --> AP{"Aprobador de tests
nunca el Driver ni el autor"} AP -->|"rechaza"| TA AP -->|"aprueba"| FZ["Congelar
acceptance.lock"] @@ -384,7 +424,7 @@ flowchart TD GATE -->|"ok"| MAS{"¿Quedan slices del ítem?"} MAS -->|"sí"| RED MAS -->|"no"| SYNC["sync: actualiza ítem
regenera BACKLOG.md
agrega a HISTORY.md"] - SYNC -->|"aprendizajes: ítems nuevos o cambios"| B + SYNC -->|"aprendizajes: módulos o ítems nuevos"| MAP SYNC --> S ``` @@ -424,9 +464,10 @@ flowchart LR - [x] Nombre de la metodología: **Baton**. - [x] Formatos exactos: ítem, `config.md`, `module.md`, plan, traspaso, reporte de slice, `acceptance.lock`. Ver [FORMATOS.md](FORMATOS.md). -- [ ] Revisar las decisiones de formato (sección 11 de FORMATOS.md). -- [x] Cómo detecta `sync` los cambios: con una instantánea propia (FORMATOS.md, sección 11). -- [x] Skills del núcleo: `baton-setup`, `baton-kickoff`, `baton-refine`, `baton-plan`, `baton-tests`, `baton-approve`, `baton-drive`, `baton-sync` y `baton-next`, más `baton.py`. Ver [skills/README.md](skills/README.md). +- [ ] Revisar las decisiones de formato (sección 12 de FORMATOS.md). +- [x] Cómo detecta `sync` los cambios: con una instantánea propia (FORMATOS.md, sección 12). +- [x] Skills del núcleo: `baton` (router), `baton-start`, `baton-module`, `baton-item`, `baton-tests`, `baton-approve`, `baton-drive` y `baton-sync`, más `baton.py`. Ver [skills/README.md](skills/README.md). +- [x] Flujo de inicio: entender el proyecto (nuevo o existente) antes de configurar, mapa de módulos iterable y tipo de backlog principal más auxiliares (retroalimentación del piloto). - [ ] Skills `baton-verify`, `baton-review` y los adaptadores. - [ ] Probar el flujo con un proyecto pequeño real antes de construir la app visual. - [ ] App visual: tablero por estados, trazabilidad ítem → test → commit, editor de configuración por capas. diff --git a/README.md b/README.md index 07023ae..5b46ab5 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,10 @@ Baton evoluciona SDD (Spec-Driven Development) y resuelve cuatro de sus problema ## Cómo funciona ``` -refine → plan → tests en rojo verificado → aprobación humana y congelamiento - → Driver con TDD, slice por slice → verificación → revisión según autonomía +entender el proyecto → escala y stack → configurar → mapa de módulos (una vez) +abrir un módulo: entenderlo → configurarlo → definir sus ítems (por módulo) +detallar un ítem → tests en rojo verificado → aprobación humana y congelamiento + → Driver con TDD, slice por slice → verificación → revisión según autonomía ``` - **Roles:** @@ -46,8 +48,8 @@ refine → plan → tests en rojo verificado → aprobación humana y congelamie 1. **Requisitos:** git, Python 3.10+ y PyYAML (`pip install pyyaml`). 2. Copia las carpetas `skills/baton-*` a la carpeta de skills de tu agente (en Claude Code, `.claude/skills/`). -3. En tu repositorio, pide ejecutar **`baton-setup`**. -4. Desde ahí, **`baton-next`** dice qué le toca a cada rol. +3. En tu repositorio di **"continúa"**: el router `baton` lanza `baton-start`. Este detecta si el proyecto es nuevo o existente, entiende qué se va a construir, recomienda el stack según la escala, configura y arma el mapa de módulos. +4. Desde ahí, **"continúa"** sigue diciendo qué rol tiene el turno y qué paso toca. ## Contenido @@ -60,7 +62,7 @@ refine → plan → tests en rojo verificado → aprobación humana y congelamie ## Estado -Versión 0.3, experimental. El núcleo está escrito y probado con la prueba automática. Falta probarlo con un proyecto real ([guía del piloto](pruebas/GUIA-PILOTO.md)) y escribir `baton-verify`, `baton-review` y los adaptadores para Jira, Trello y GitHub Issues. +Versión 0.4, experimental. El núcleo está escrito y probado con la prueba automática. Falta probarlo con un proyecto real ([guía del piloto](pruebas/GUIA-PILOTO.md)) y escribir `baton-verify`, `baton-review` y los adaptadores para Jira, Trello y GitHub Issues. ## Contribuir diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index cbf3996..dabc443 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -6,9 +6,9 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| -| 1 · Setup | A · Opus | | | | -| 2 · Visión y backlog | A · Opus | | | | -| 3 · Kickoff | A · Opus | | | | +| 1 · Inicio del proyecto | A · Opus | | | | +| 2 · Abrir `registro` | A · Opus | | | | +| 3 · Cambiar el mapa | A · Opus | | | | | 4 · registro (Delegado) | A · subagente · B Sonnet · C Haiku | | | | | 5 · saldos (Pair) | A · subagente · B Sonnet | | | | | 6 · Candidato y configuración | A · Opus | | | | @@ -18,10 +18,16 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | |---|---|---|---|---| +| D1 | 1 (intento 1) | El setup configuró sin saber qué se iba a construir: propuso el nombre de la carpeta como nombre del proyecto | Entender el proyecto (nuevo o existente) antes de configurar | skill · metodología. **Corregido** en `flujo-inicio`: `baton-start` | +| D2 | 1 (intento 1) | No se podía elegir el tipo de backlog (historia, requerimiento o ticket) | Elegirlo al inicio | formato · baton.py. **Corregido**: `backlog.principal` + `auxiliares` | +| D3 | 2 (intento 1) | Sin una skill de visión, el agente buscó FORMATOS.md con `find /` y leyó la metodología | Que la skill tuviera el formato | skill · plantilla. **Corregido**: plantilla `overview.md` y skills autosuficientes | +| D4 | 2 (intento 1) | Creó ítems con un módulo que todavía no existía; falló la validación | El orden: mapa de módulos → abrir módulo → ítems | metodología. **Corregido**: mapa de módulos y `baton-module` | +| D5 | 1 (intento 1) | El agente gastó 3 o 4 llamadas explorando el repo, incluido el código de baton.py | Que lo determinista lo midiera un script | baton.py. **Corregido**: `baton.py detectar` | +| D6 | 2 (intento 1) | Para aceptar candidatos cargó una skill completa (refine) | Decidir candidatos dentro de la revisión de la lista | skill. **Corregido**: candidatos en `baton-module` y `baton-item` | ## Error sembrado -- Lo detectó: +- Lo detectó: - Cómo reaccionó el Driver: ## Preguntas de cierre diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 5162ea8..42bc0c1 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -25,22 +25,22 @@ python3 -m gastos saldos # ana +20.00 · beto -10.00 · carla -10.00 Cada parte del proyecto está elegida para ejercitar una parte del flujo: -| Parte del proyecto | Qué ejercita | -|---|---| +| Parte del proyecto | Qué ejercita | +| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | Módulo `registro` (US-001 registrar, US-002 listar) en **Delegado**, con el proyecto en Checkpoint | bajar el control (↓), Verificador forzado, aprobación en lote, revisión al cerrar el módulo | -| Módulo `saldos` (US-003 calcular saldos) en **Pair** | revisión por slice, rechazo de tests y un **error sembrado** que obliga a escalar | -| US-004, propuesta por el agente | ítem candidato: aceptar o descartar | -| Driver con Sonnet en otra sesión, Verificador con Haiku y el autor de tests como subagente | traspasos reales entre modelos y sesiones | +| Módulo `saldos` (US-003 calcular saldos) en **Pair** | revisión por slice, rechazo de tests y un **error sembrado** que obliga a escalar | +| US-004, propuesta por el agente | ítem candidato: aceptar o descartar | +| Driver con Sonnet en otra sesión, Verificador con Haiku y el autor de tests como subagente | traspasos reales entre modelos y sesiones | ### El error sembrado -En US-003, cuando refine pregunte cómo repartir un monto que no se divide exacto, responde: +En US-003, cuando `baton-item` pregunte cómo repartir un monto que no se divide exacto, responde: > "Cada parte se redondea a 2 decimales." Mantén también el criterio "la suma de los saldos siempre es 0". Con un gasto de 10 entre tres, las partes son 3.33 × 3 = 9.99, así que los dos criterios **se contradicen**. -Anota **quién lo detecta primero**: refine, el autor, tú al aprobar, o el Driver. Si alguien lo detecta antes que el Driver, di "déjalo así", para que el Driver tenga que escalar. El test no puede pasar, así que el Driver debe **escalar, no cambiar el test**. +Anota **quién lo detecta primero**: `baton-item`, el autor, tú al aprobar, o el Driver. Si alguien lo detecta antes que el Driver, di "déjalo así", para que el Driver tenga que escalar. El test no puede pasar, así que el Driver debe **escalar, no cambiar el test**. --- @@ -66,19 +66,19 @@ python3 -m venv .venv && .venv/bin/pip install pytest pyyaml > Con git anterior a 2.42, crea el worktree desde `main` y vacíalo: `git checkout --orphan piloto && git rm -rq --cached . && git clean -fdq -e .venv -e .claude`. -**Comprueba que Claude Code ve las skills:** en `../baton-piloto`, pregunta "¿qué skills de baton tienes?". Deben aparecer las 9. Si no aparecen, cambia los enlaces por copias: `cp -r ~/Proyectos/Metologia/skills/baton-* .claude/skills/`. +**Comprueba que Claude Code ve las skills:** en `../baton-piloto`, pregunta "¿qué skills de baton tienes?". Deben aparecer las 8: `baton` y las 7 `baton-*`. Si no aparecen, cambia los enlaces por copias: `cp -r ~/Proyectos/Metologia/skills/baton-* .claude/skills/`. **La bitácora vive en `main`** (`pruebas/BITACORA-piloto.md`), fuera del alcance de los agentes del piloto. -**Si corriges `baton.py` en main:** desde `../baton-piloto`, ejecuta `python3 ~/Proyectos/Metologia/skills/baton-setup/assets/baton.py init --forzar`. +**Si corriges `baton.py` en main:** desde `../baton-piloto`, ejecuta `python3 ~/Proyectos/Metologia/skills/baton-start/assets/baton.py init --forzar`. ### Sesiones y modelos -| Sesión | Cómo abrirla | Rol | -|---|---|---| -| A | `claude` (Opus) | Navigator y aprobador (tú). Lanza al autor de tests como subagente | -| B | `claude --model sonnet` | Driver | -| C | `claude --model haiku` | Verificador | +| Sesión | Cómo abrirla | Rol | +| ------ | ----------------------- | ------------------------------------------------------------------ | +| A | `claude` (Opus) | Navigator y aprobador (tú). Lanza al autor de tests como subagente | +| B | `claude --model sonnet` | Driver | +| C | `claude --model haiku` | Verificador | ### Para ahorrar tokens @@ -93,60 +93,72 @@ python3 -m venv .venv && .venv/bin/pip install pytest pyyaml Marca cada casilla. Lo que no se cumpla va a la bitácora (sección 5). -### Fase 1 · Setup (sesión A) - -Pide: "ejecuta baton-setup". Responde con: - -- **Entidades:** - - tu usuario como persona; - - `opus` = `claude-opus-5-5`; - - `sonnet` = `claude-sonnet-5-5`; - - `haiku` = `claude-haiku-5-5`. -- **Roles:** - - navigator: tú + opus; - - autor_tests: opus, por subagente; - - aprobador: tú; - - driver: sonnet, por sesión; - - verificador: haiku, por sesión, desactivado. -- **Configuración:** - - autonomía Checkpoint; - - wip 2; - - `slice_max.criterios` 2; - - comandos `.venv/bin/pytest tests/acceptance`, `.venv/bin/pytest {archivo}`, `.venv/bin/pytest tests/unit` y `.venv/bin/pytest`. - -**Verifica:** +### Fase 1 · Inicio del proyecto (sesión A) -- [ ] Propuso valores por grupos, sin preguntar campo por campo. -- [ ] Cuando dijiste "que el driver también apruebe tests", se negó y citó la invariante. -- [ ] `python3 baton/bin/baton.py validar` da `ok`, y `.git/hooks/pre-commit` existe. -- [ ] `baton/backlog/HISTORY.md` tiene las entradas del setup con su motivo. +Escribe solo **"continúa"**. El router `baton` debe detectar que no hay configuración y lanzar `baton-start`. No le adelantes nada. -### Fase 2 · Visión y backlog ligero (sesión A, sin skill) +**Lo que respondes:** -Pide: "escribe baton/system/overview.md para gastos (CLI → lógica → JSON en GASTOS_ARCHIVO) y crea los ítems ligeros US-001 registrar gasto, US-002 listar gastos y US-003 calcular saldos. Propón tú los ítems que creas que faltan, como candidatos." +- **Qué es:** una CLI para registrar gastos compartidos entre amigos y calcular quién le debe a quién. Es para uso personal. Sirve si en un viaje se puede saber cuánto debe cada uno. +- **Alcance inicial:** registrar un gasto (monto, quién pagó, entre quiénes), listarlos y calcular saldos. **No es:** una app web, ni maneja pagos reales, ni tiene cuentas de usuario. +- **Escala:** prototipo o MVP personal, con datos en un JSON local (`GASTOS_ARCHIVO`). Restricciones: ninguna especial. Conoces Python. +- **Stack:** acepta lo que recomiende, si es razonable (Python con la biblioteca estándar y pytest). +- **Configuración:** + - **Tipo de backlog:** historia como principal, bug y técnico como auxiliares. + - **Cadencia:** kanban, wip 2. + - **Entidades:** + - tu usuario como persona; + - `opus` = `claude-opus-5-5`; + - `sonnet` = `claude-sonnet-5-5`; + - `haiku` = `claude-haiku-5-5`. + - **Roles:** + - navigator: tú + opus; + - autor_tests: opus, por subagente; + - aprobador: tú; + - driver: sonnet, por sesión; + - verificador: haiku, por sesión, desactivado. + + **Primero di "y que sonnet también apruebe tests".** + - **Autonomía:** Checkpoint. + - **Tests:** `slice_max.criterios` 2, y los comandos con `.venv/bin/pytest` que propone `detectar`. + - **Herramienta externa:** ninguna. **Importar issues: no.** El remoto que ve es el de la metodología, porque el worktree comparte `.git`. + - **Protección:** hook sí, CODEOWNERS no. +- **Mapa de módulos:** deberían salir más o menos `registro` (registrar y listar) y `saldos` (calcular quién debe a quién). **Verifica:** -- [ ] Los ítems ligeros tienen solo frontmatter y están en `Pendiente`. -- [ ] Propuso al menos un candidato (US-004) con `origen: agente` y `## Por qué se propone`. -- [ ] `baton-sync` te preguntó el motivo, o usó el que ya conocía. No lo inventó. - -> Que la visión no tenga skill propia se nota aquí. Anota si hizo falta una. +- [ ] Usó `baton.py detectar` y **no exploró el repo a mano** ni buscó la documentación de la metodología (nada de `find /` ni de leer `~/Proyectos/Metologia`). +- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y esperó tu confirmación. +- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. Escribió `ADR-0001-stack.md` con `## Revisar si`. +- [ ] Las recomendaciones de configuración citan el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". +- [ ] El nombre del proyecto es `gastos`, no el de la carpeta. +- [ ] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. +- [ ] Propuso el mapa de módulos y creó solo los que aceptaste, en `Planificado`, con `## Objetivo`. +- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra visión, ADR, configuración y módulos con su motivo. -### Fase 3 · Kickoff de los dos módulos (sesión A) +### Fase 2 · Abrir el módulo `registro` (sesión A, después de `/clear`) -Pide: "baton-kickoff del módulo registro (US-001, US-002)" y después "baton-kickoff del módulo saldos (US-003)". +Escribe **"continúa"**. El router debe proponer abrir `registro`, el `Planificado` de mayor prioridad. **Verifica:** -- [ ] Para `registro` recomendó Delegado, o tú lo elegiste. BACKLOG.md muestra `registro · Delegado ↓`. -- [ ] Para `saldos` recomendó Pair por el riesgo (dinero). Si eliges menos control, te avisa **una sola vez**. -- [ ] `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. -- [ ] `python3 baton/bin/baton.py efectiva US-001` muestra el verificador activo, `fuente: forzado por Delegado`. +- [ ] Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. +- [ ] **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. +- [ ] **Configurar:** recomendó Delegado (un CRUD de bajo riesgo). Acéptalo. BACKLOG.md debe mostrar `registro · Activo · Delegado ↓`, porque el proyecto está en Checkpoint. +- [ ] `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. `baton.py efectiva modulo:registro` muestra el verificador activo, `fuente: forzado por Delegado`. +- [ ] **Ítems:** propuso una lista de historias verticales (INVEST). Corrige una, quita otra y agrega una tuya. Solo se crearon las aceptadas, en `Pendiente`, con `## Valor` en una línea. +- [ ] Propuso al menos un ítem técnico o un candidato. Decide tú. + +### Fase 3 · Cambiar el mapa (sesión A, barato) + +- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad baja". Debe crearlo en `Planificado` y pedir o usar el motivo. +- [ ] Di "mejor divide `saldos` en `saldos` y `liquidacion`". Debe crear el nuevo, mover los ítems que correspondan y anotar la división. +- [ ] Di "descarta `exportar`". Debe quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolo en el mapa. ### Fase 4 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) -1. **Sesión A:** "refina y planifica US-001 y US-002". +1. **Sesión A:** "continúa", dos veces: una por ítem (`baton-item`). + - [ ] Mostró **juntos** los criterios y los slices, y pidió **una sola confirmación** por ítem. - [ ] Los criterios tienen datos concretos e incluyen errores (monto negativo, pagador fuera de la lista). - [ ] `## Seguridad` está escrita, aunque sea "sin impacto". - [ ] El primer slice es un esqueleto andante, y ningún slice tiene más de 2 criterios. @@ -168,14 +180,15 @@ Pide: "baton-kickoff del módulo registro (US-001, US-002)" y después "baton-ki - [ ] Revisó el lock (`baton.py lock revisar`). - [ ] Escribió el veredicto en `## Verificación`. - > Todavía no existe `baton-verify`, así que se usa la alternativa de `baton-next`. Anota qué le faltó. + > Todavía no existe `baton-verify`, así que se usa la alternativa del router `baton`. Anota qué le faltó. + 6. **Sesión A:** revisa el módulo completo con los reportes y ciérralo. - [ ] Pudiste decidir leyendo solo los reportes, sin abrir el código. ### Fase 5 · Módulo `saldos` en Pair, con el error sembrado -1. **Sesión A:** "refina y planifica US-003". Siembra el error (sección 1). - - [ ] Anota si refine detectó la contradicción. +1. **Sesión A:** "continúa" para abrir `saldos` (debe recomendar **Pair** por ser cálculo de dinero) y luego para detallar US-003. Siembra el error (sección 1). + - [ ] Anota si `baton-item` detectó la contradicción. 2. **Subagente:** escribe los tests. **Sesión A:** al aprobar, **rechaza una vez** a propósito, por ejemplo "usa montos en centavos (enteros) en los asserts". - [ ] El ítem volvió a `Listo` y el traspaso al autor lleva tu motivo. - [ ] La segunda vez lo aprobaste y quedó congelado. @@ -190,7 +203,7 @@ Pide: "baton-kickoff del módulo registro (US-001, US-002)" y después "baton-ki ### Fase 6 · Candidato, edición a mano y configuración (sesión A, barata) -- [ ] "refina US-004": te preguntó si lo aceptas o lo descartas. No lo movió solo. +- [ ] Ante un ítem candidato, te preguntó si lo aceptas o lo descartas. No lo movió solo. - [ ] Edita a mano la `prioridad` de un ítem y ejecuta `baton-sync`: debe pedirte el motivo. - [ ] En US-004 (dentro de `saldos`, que está en Pair), agrega `config.autonomia: {valor: Checkpoint, motivo: "..."}`. BACKLOG.md debe mostrar `Checkpoint ↓`. - [ ] En `config.md`, pon `autonomia_minima: Pair`. `validar` debe marcar error en `registro`. Después déjalo en `null`. @@ -198,13 +211,13 @@ Pide: "baton-kickoff del módulo registro (US-001, US-002)" y después "baton-ki ### Fase 7 · Ataques a la protección (terminal, sin tokens) -| Intento | Esperado | -|---|---| -| Editar un test congelado y hacer `git commit` | el hook lo rechaza | -| Editar el test y recalcular su sha256 en el lock a mano | rechazado: "cambió sin solicitud aprobada" | -| `git commit --no-verify` con el test editado | **pasa**: es el límite conocido. Luego `baton.py lock revisar` lo detecta. Revierte con `git reset --hard HEAD~1` | -| `baton.py lock aprobar --item US-001 --aprobado-por sonnet` | error: no es aprobador, o es el driver | -| En `config.md`, `aprobador_tests: { entidades: [opus] }` | `validar`: falta una persona entre los aprobadores | +| Intento | Esperado | +| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| Editar un test congelado y hacer `git commit` | el hook lo rechaza | +| Editar el test y recalcular su sha256 en el lock a mano | rechazado: "cambió sin solicitud aprobada" | +| `git commit --no-verify` con el test editado | **pasa**: es el límite conocido. Luego `baton.py lock revisar` lo detecta. Revierte con `git reset --hard HEAD~1` | +| `baton.py lock aprobar --item US-001 --aprobado-por sonnet` | error: no es aprobador, o es el driver | +| En `config.md`, `aprobador_tests: { entidades: [opus] }` | `validar`: falta una persona entre los aprobadores | --- @@ -225,12 +238,14 @@ Llena `pruebas/BITACORA-piloto.md` en `main`. Ya tiene estas tablas y las pregun ```markdown ## Fases + | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | -|---|---|---|---|---| +| ---- | ------------- | ------------- | --------------- | -------- | ## Defectos -| # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | -|---|---|---|---|---| + +| # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | +| --- | ---- | -------- | ------------ | ----------------------------------------------------------- | ``` **Preguntas de cierre:** diff --git a/pruebas/e2e.sh b/pruebas/e2e.sh index 9c439ad..9bdafc3 100755 --- a/pruebas/e2e.sh +++ b/pruebas/e2e.sh @@ -3,7 +3,7 @@ # Uso: pruebas/e2e.sh [directorio-temporal] set -u AQUI=$(cd "$(dirname "$0")" && pwd) -FX=$AQUI/fixtures; D=${1:-$(mktemp -d)/demo}; SRC=$AQUI/../skills/baton-setup/assets/baton.py +FX=$AQUI/fixtures; D=${1:-$(mktemp -d)/demo}; SRC=$AQUI/../skills/baton-start/assets/baton.py FALLAS=0 rm -rf $D && mkdir -p $D && cd $D && git init -q && git config user.email t@t && git config user.name t python3 $SRC init --hook --codeowners @juan >/dev/null @@ -74,6 +74,39 @@ creado: 2026-11-03 --- MD python3 baton/bin/baton.py efectiva US-004 | grep -A1 "verificador_activo" | grep -q "valor: true" && ok "Delegado fuerza verificador" || bad "verificador no forzado" +# flujo de inicio: visión, mapa de módulos y tipos de backlog +mkdir -p baton/system && cp $FX/../../skills/baton-start/assets/templates/overview.md baton/system/overview.md +python3 baton/bin/baton.py sync --autor juan --motivo "visión inicial" >/dev/null +grep -q "| vision | creado" baton/backlog/HISTORY.md && ok "sync registra la visión" || bad "visión no registrada" +python3 baton/bin/baton.py estado US-002 Listo 2>&1 | grep -q "módulo Activo" && ok "ítem no pasa a Listo con su módulo sin abrir" || bad "módulo no abierto aceptado" +mkdir -p baton/modules/reportes +cat > baton/modules/reportes/module.md <<'MD' +--- +formato: 1 +modulo: reportes +titulo: Reportes +estado: Candidato +prioridad: 5 +origen: agente +propuesto_por: opus +creado: 2026-11-03 +config: {} +--- +## Objetivo +Exportar los gastos. + +## Por qué se propone +Los usuarios lo piden. +MD +python3 baton/bin/baton.py next --rol navigator | grep -q "modulo:reportes · Candidato" && ok "next pide decidir el módulo candidato" || bad "next sin módulo candidato" +python3 baton/bin/baton.py estado modulo:reportes Activo >/dev/null 2>&1 && bad "módulo candidato pasó directo a Activo" || ok "módulo candidato no salta a Activo" +python3 baton/bin/baton.py estado modulo:reportes Descartado >/dev/null && ok "módulo candidato descartado" +python3 baton/bin/baton.py estado modulo:catalogo Cerrado 2>&1 | grep -q "ítems en desarrollo" && ok "no cierra un módulo con ítems en desarrollo" || bad "cerró módulo con trabajo" +grep -q "## Mapa de módulos" baton/backlog/BACKLOG.md && ok "BACKLOG.md muestra el mapa de módulos" || bad "sin mapa de módulos" +sed -e 's/^id: US-004/id: TEC-001/; s/^tipo: historia/tipo: tecnico/' baton/backlog/items/US-004.md > baton/backlog/items/TEC-001.md +python3 baton/bin/baton.py validar 2>&1 | grep -q "no está en backlog.principal" && ok "rechaza un tipo fuera del backlog configurado" || bad "tipo fuera del backlog aceptado" +rm baton/backlog/items/TEC-001.md +mkdir -p $D-vacio && git -C $D-vacio init -q && python3 baton/bin/baton.py --root $D-vacio detectar | grep -q "inicio: nuevo" && ok "detectar: proyecto vacío es nuevo" || bad "detectar" python3 baton/bin/baton.py validar >/dev/null && ok "validar ok al final" || { bad "validar"; python3 baton/bin/baton.py validar; } echo; grep -A6 "## catalogo" baton/backlog/BACKLOG.md echo; [ $FALLAS -eq 0 ] && echo "todo ok" || { echo "$FALLAS falla(s)"; exit 1; } diff --git a/pruebas/fixtures/config.md b/pruebas/fixtures/config.md index 1434451..d5321fb 100644 --- a/pruebas/fixtures/config.md +++ b/pruebas/fixtures/config.md @@ -4,7 +4,8 @@ proyecto: tienda idioma: es cadencia: { modo: kanban, iteracion_dias: null } wip: 2 -tipos: { historia: US, bug: BUG } +backlog: { principal: historia, auxiliares: [bug] } +tipos: { historia: US, bug: BUG, tecnico: TEC } herramienta_externa: { tipo: ninguna, destino: null } rutas: tests_aceptacion: tests/acceptance diff --git a/skills/README.md b/skills/README.md index 37c310d..b691ca9 100644 --- a/skills/README.md +++ b/skills/README.md @@ -2,34 +2,55 @@ Skills del núcleo de la metodología, en formato Agent Skills (`SKILL.md`). Ver [METODOLOGIA.md](../METODOLOGIA.md) y [FORMATOS.md](../FORMATOS.md). +**Solo hace falta recordar una: `baton`.** Lee el estado del proyecto, anuncia qué rol tiene el turno y qué paso toca, y llama a la skill que corresponde. Basta con decir "continúa". Las demás también se pueden llamar directamente. + | Skill | Rol | Cuándo | |---|---|---| -| `baton-setup` | humano | una vez por proyecto, o para cambiar la configuración | -| `baton-kickoff` | Navigator | al abrir o reconfigurar un módulo | -| `baton-refine` | Navigator | un ítem Pendiente está por desarrollarse; aceptar o descartar candidatos | -| `baton-plan` | Navigator | después de refine: slices, ítem a Listo, traspaso al autor | +| `baton` | cualquiera | "¿qué sigue?", "continúa", "toma tu turno"; resuelve escalamientos | +| `baton-start` | humano + Navigator | una vez: entender el proyecto (nuevo o existente) → escala y stack → configurar → mapa de módulos. También para actualizar visión, stack o configuración | +| `baton-module` | Navigator | cambiar el mapa de módulos; abrir un módulo (entender → configurar → ítems); reconfigurarlo o cerrarlo | +| `baton-item` | Navigator | detallar un ítem: criterios + slices, con una sola confirmación → Listo | | `baton-tests` | Autor de tests | ítem en Listo | | `baton-approve` | Aprobador (persona) | ítem en TestsEnRevision | | `baton-drive` | Driver | ítem en TestsCongelados o EnCurso | -| `baton-sync` | cualquiera | después de editar a mano o cuando otra skill lo indique | -| `baton-next` | cualquiera | "¿qué me toca?" o "toma tu turno" | +| `baton-sync` | cualquiera | después de editar a mano | + +## Flujo + +``` +baton-start → entender · escala y stack · configurar · mapa de módulos (una vez, actualizable) +baton-module → entender el módulo · configurarlo · definir sus ítems (por módulo) +baton-item → criterios + slices (por ítem, justo a tiempo) +baton-tests → baton-approve → baton-drive → verificación → revisión (roles separados, sin atajos) +``` + +Solo se juntan pasos de un **mismo rol**. Tests y aprobación, o Driver y Verificador, siguen separados: separarlos es el núcleo del control. ## Reparto entre skills y `baton.py` - **Las skills ponen el criterio:** qué preguntar, cómo escribir buenos criterios y tests, cuándo escalar. -- **`baton.py` hace lo determinista:** validar, calcular la configuración efectiva, decidir turnos, cambiar estados con transiciones válidas, crear traspasos, sincronizar y mantener el lock. +- **`baton.py` hace lo determinista:** + - detectar si el proyecto es nuevo o existente, y su stack; + - validar y calcular la configuración efectiva; + - decidir turnos y cambiar estados con transiciones válidas; + - crear traspasos, sincronizar y mantener el lock. + +Así, dos agentes distintos que siguen la misma skill obtienen los mismos archivos, y nadie gasta tokens explorando lo que un script puede medir. -Así, dos agentes distintos que siguen la misma skill obtienen los mismos archivos. +Las skills no mandan a leer la documentación de la metodología: todo lo que el agente necesita está en la skill, en sus `references/` y en `baton/templates/`. -`baton.py` vive en `baton-setup/assets/`. `baton-setup` lo copia al proyecto, en `baton/bin/baton.py`, y desde ahí lo usan las demás skills. Requiere Python 3.10+ y PyYAML. +`baton.py` vive en `baton-start/assets/`. `baton-start` lo copia al proyecto en `baton/bin/baton.py`, y desde ahí lo usan las demás skills. Requiere Python 3.10+ y PyYAML. ## Instalación -Copia las carpetas `baton-*` a la carpeta de skills de tu herramienta. En Claude Code es `.claude/skills/` del proyecto o `~/.claude/skills/`. Después ejecuta `baton-setup` en el repositorio. +Copia las carpetas `baton` y `baton-*` a la carpeta de skills de tu herramienta. En Claude Code es `.claude/skills/` del proyecto o `~/.claude/skills/`. Después, en tu repositorio, di **"continúa"** o ejecuta `baton-start`. ## Pruebas -`pruebas/e2e.sh` recorre el flujo completo en un repositorio temporal: setup, refine, tests, aprobación, Driver, solicitud de cambio y recongelamiento. También intenta saltarse la protección de tres maneras: editar un test congelado, editar el test y recalcular el lock a mano, y agregar un fixture nuevo. +`pruebas/e2e.sh` recorre el flujo en un repositorio temporal: +- inicio, mapa de módulos y tipos de backlog; +- tests, aprobación, Driver, solicitud de cambio y recongelamiento; +- tres intentos de saltarse la protección. ``` bash pruebas/e2e.sh diff --git a/skills/baton-item/SKILL.md b/skills/baton-item/SKILL.md new file mode 100644 index 0000000..a21a84e --- /dev/null +++ b/skills/baton-item/SKILL.md @@ -0,0 +1,98 @@ +--- +name: baton-item +description: Detalla justo a tiempo un ítem de la metodología Baton. En un solo paso escribe su propósito, los criterios de aceptación Dado/Cuando/Entonces y la revisión de seguridad, y lo divide en slices verticales (el primero es un esqueleto andante). Pide una sola confirmación, marca el ítem como Listo y entrega el turno al autor de tests. Úsala cuando un ítem Pendiente de un módulo activo está por desarrollarse, o para cambiar su plan. +--- + +# baton-item + +**Rol:** Navigator. El agente propone y **el humano decide**. + +**Entrada:** un ítem `Pendiente` de un módulo `Activo`, la visión, los ADR y el `module.md`. + +**Salida:** +- el ítem detallado; +- `baton/modules//plans/<ítem>.md`; +- el ítem en `Listo`; +- el traspaso al autor de tests. + +No leas la documentación de la metodología: lo necesario está aquí y en `baton/templates/`. + +## 1. Detallar el ítem + +1. Lee el ítem, su `module.md`, la visión y los ADR relevantes. +2. **Propósito**, según el `tipo`. La plantilla `baton/templates/item-.md` tiene las secciones: + + | Tipo | Sección | Forma | + |---|---|---| + | historia | `## Valor` | "Como quiero para " | + | requerimiento | `## Requerimiento` y `## Justificación` | "El sistema debe…" | + | ticket | `## Descripción` | | + | bug | `## Comportamiento esperado`, `## Comportamiento actual` y `## Pasos para reproducir` | | + | tecnico | `## Motivo` | | + +3. **Criterios** (`## Criterios de aceptación`): + - uno por comportamiento observable, con formato `### AC- · ` y viñetas **Dado** / **Cuando** / **Entonces** (y **Y**); + - datos concretos: "un carrito con 2 productos por $30", no "un carrito con productos"; + - el **Entonces** se comprueba desde afuera (respuesta, pantalla, archivo, salida), no por detalles internos; + - incluye el caso feliz, los errores esperables y los bordes (vacío, límite, duplicado, sin permiso); + - en un **bug**, el AC-1 reproduce el error. +4. **Seguridad** (`## Seguridad`). Revisa: + - autenticación y autorización; + - validación de entradas; + - datos sensibles; + - inyección; + - abuso; + - auditoría. + + Considera las restricciones de la visión. Si no hay impacto, escribe "sin impacto". Lo que encuentres como requisito se convierte en criterio. +5. **Ambigüedades.** Lo que no puedas decidir va a `## Preguntas abiertas`. Pregúntaselo al humano con opciones y tu recomendación. Nunca resuelvas tú una pregunta de negocio. +6. **Propuestas.** Las mejoras fuera del alcance del ítem no van como criterios. Créalas como ítems `Candidato` (`origen: agente`, `propuesto_por`, `## Por qué se propone`). + +## 2. Dividir en slices + +1. Consulta `slice_max` con `python3 baton/bin/baton.py efectiva <ítem>`. +2. Divide en slices **verticales**: cada uno atraviesa las capas necesarias y termina en algo que se puede ejecutar. + - **S1 es el esqueleto andante:** el camino más delgado de punta a punta. Si es el primer ítem del primer módulo, S1 también deja montado el proyecto: estructura, runner de tests y lo mínimo del stack del ADR-0001. + - Cada criterio vigente va en **exactamente un** slice. + - Ningún slice supera `slice_max.criterios` ni se revisa en más de `slice_max.minutos`. +3. Cada slice lleva **Recorrido**, **Fuera de este slice**, **Demo** (pasos concretos y lo que se debe ver), **Decisiones que aplican** (ADR) y **Escalar si** (dónde debe detenerse el Driver). La plantilla es `baton/templates/plan.md`. +4. Si hace falta una decisión de diseño nueva, propónla. Cuando el humano la apruebe, escríbela como ADR. + +## 3. Una sola confirmación + +Muestra **juntos** los criterios y los slices, de forma compacta: + +``` +US-001 · Registrar gasto +AC-1 Gasto válido … · AC-2 Monto inválido … · AC-3 … +S1 (AC-1) esqueleto: CLI → lógica → JSON · S2 (AC-2, AC-3) validaciones +Seguridad: … · Preguntas abiertas: ninguna +¿Apruebas, o ajusto algo? +``` + +Ajusta hasta que el humano apruebe. Recién entonces escribe el ítem y el plan. + +## 4. Registrar y entregar + +1. Ejecuta `python3 baton/bin/baton.py estado <ítem> Listo`. Si falla, el mensaje dice qué falta de la Definition of Ready. +2. Ejecuta `python3 baton/bin/baton.py handoff --item <ítem> --de navigator --para autor_tests --entidad-de `. Completa en el traspaso `## Qué se entrega`, `## Qué se espera` y `## Contexto`. +3. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "<ítem> detallado"`. +4. Según el `transporte` del autor de tests: + - `subagente`: lánzalo con el traspaso como instrucción; + - `sesion`: el humano abre otra sesión y le dice "toma tu turno"; + - `externo`: otra herramienta lee el traspaso. + +## Candidatos + +Si el ítem está en `Candidato`, muéstralo con `## Por qué se propone` y pregunta. Si el humano lo acepta: `baton.py estado <ítem> Pendiente`. Si lo descarta: `baton.py estado <ítem> Descartado`. Si hay varios, decídelos en una sola pregunta. + +## Cambiar un ítem o plan ya en desarrollo + +- **Criterios ya congelados** (el ítem estuvo en `TestsCongelados` o después): no se editan sin una solicitud aprobada. Un criterio que sobra se retira: se tacha su título con `~~` y se anotan la fecha y la solicitud. Nunca se borra ni se renumera. +- **Plan:** sube `version`. Los slices `Terminado` o `Aprobado` no se modifican, y los ids de slice no se reutilizan. Mover criterios entre slices no obliga a tocar los tests. +- Ejecuta sync con el motivo. + +## No hagas + +- No escribas tests ni código. +- No marques `Listo` sin la confirmación del humano. diff --git a/skills/baton-kickoff/SKILL.md b/skills/baton-kickoff/SKILL.md deleted file mode 100644 index 0bd3b12..0000000 --- a/skills/baton-kickoff/SKILL.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: baton-kickoff -description: Abre o reconfigura un módulo de la metodología Baton. Muestra la configuración heredada del proyecto, recomienda un nivel de autonomía según el riesgo y escribe baton/modules//module.md con el alcance y solo las diferencias, cada una con su motivo. Úsala al empezar a trabajar un módulo o para cambiar su configuración a mitad de camino. ---- - -# baton-kickoff - -**Rol:** Navigator (humano + agente razonador). **Entrada:** `baton/config.md` y el alcance que describe el humano. **Salida:** `baton/modules//module.md`. - -Los formatos están en `FORMATOS.md`, secciones 2 y 3. La plantilla es `baton/templates/module.md`. - -## Pasos - -1. **Alcance.** Pide al humano qué cubre el módulo y qué queda fuera. Revisa `baton/system/overview.md` y los ADR, y lista los ítems del backlog que podrían pertenecer al módulo (los que tienen `modulo: null` o un título relacionado). -2. **Riesgo.** Evalúa el módulo y escribe el resultado en `## Riesgos`. Considera: - - si mueve dinero o datos personales; - - si toca autenticación o permisos; - - si migra datos; - - si integra servicios externos; - - si es reversible; - - cuánta experiencia tiene el equipo en esa zona. -3. **Configuración heredada.** Ejecuta `python3 baton/bin/baton.py efectiva` y muéstrala en tres grupos: roles, autonomía y verificador, y tamaño de slice. -4. **Recomendación.** Recomienda una autonomía según el riesgo y explica por qué en una línea. Por ejemplo: pagos, seguridad o migraciones → Pair; CRUD interno → Delegado. Para cada grupo, pregunta "¿mantener o cambiar?". -5. **Si elige menos control que el recomendado:** avísalo **una vez** con el riesgo concreto y anótalo en `## Riesgos`. Luego respeta la decisión. Bajar el control está permitido (invariante 6). Comprueba solo que no quede bajo `autonomia_minima`. -6. **Escribe `module.md`.** En `config` van solo las claves que cambian, cada una como `{ valor, motivo, desde: }`. Las claves permitidas son `roles.`, `roles.aprobador_tests`, `roles.verificador.activo`, `autonomia` y `slice_max.*`. Si la autonomía queda en Delegado, el verificador se activa solo: confirma que haya una entidad asignada. -7. **Ítems.** Asigna al módulo los ítems que el humano confirme: edita su campo `modulo`. Si faltan ítems, créalos como ítems ligeros (`baton/templates/item.md`, solo frontmatter, `estado: Pendiente`). -8. Ejecuta `python3 baton/bin/baton.py validar`. -9. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "kickoff de " --ref baton-kickoff`. Si alguna diferencia de configuración tiene un motivo propio, pásalo con `--motivo-de`. -10. Resume la configuración efectiva del módulo y marca ↓ si se bajó el control. - -## Volver a ejecutar a mitad del módulo - -- Cambia solo lo que el humano pida, con `desde` igual a la fecha de hoy y su motivo. -- El cambio aplica desde el **siguiente** slice. Los traspasos ya creados conservan su `config_efectiva`. -- Para cerrar el módulo: `estado: Cerrado` y `cierre: `, solo si no quedan ítems activos. - -## No hagas - -- No copies en `module.md` valores iguales a los del proyecto. Solo van las diferencias. -- No uses la recomendación de riesgo para bloquear la decisión del humano. diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md new file mode 100644 index 0000000..fe57594 --- /dev/null +++ b/skills/baton-module/SKILL.md @@ -0,0 +1,96 @@ +--- +name: baton-module +description: Maneja los módulos de la metodología Baton. Edita el mapa de módulos (agregar, dividir, fusionar, descartar, priorizar, aceptar candidatos) y abre un módulo para desarrollarlo. Al abrirlo, entiende su alcance y riesgos, recomienda la configuración según el riesgo y define con el humano la lista de ítems del módulo. Úsala para abrir el siguiente módulo, cambiar el mapa, reconfigurar un módulo o cerrarlo. +--- + +# baton-module + +**Rol:** Navigator. El agente entiende, propone y recomienda. **El humano decide.** + +**Entrada:** la visión (`baton/system/overview.md`), los ADR, `baton/config.md` y el mapa de módulos (la tabla "Mapa de módulos" de `baton/backlog/BACKLOG.md`). + +**Plantillas:** `baton/templates/module.md` y `baton/templates/item-.md`. No leas la documentación de la metodología: lo necesario está aquí. + +Pregunta qué quiere hacer el humano, o dedúcelo de `python3 baton/bin/baton.py next --rol navigator`: + +## A. Cambiar el mapa de módulos + +El mapa es iterable: casi nunca se conocen todos los módulos al empezar. + +| Acción | Cómo | +|---|---| +| Agregar | nuevo `baton/modules//module.md` con `estado: Planificado`, `prioridad` y `## Objetivo` | +| Aceptar o descartar un candidato | `baton.py estado modulo: Planificado` o `baton.py estado modulo: Descartado` | +| Repriorizar | edita `prioridad` en los `module.md` | +| Dividir | crea los módulos nuevos, mueve los ítems (campo `modulo`) y descarta el original con una nota en `## Objetivo`: "dividido en X e Y" | +| Fusionar | mueve los ítems al módulo que queda y descarta el otro con una nota | +| Descartar | `baton.py estado modulo: Descartado`. Sus ítems no hechos pasan a `Descartado` o a otro módulo, según decida el humano | + +Las propuestas del agente entran como `estado: Candidato`, `origen: agente`, `propuesto_por` y `## Por qué se propone`. Nunca las aceptes sin respuesta del humano. Al terminar, ejecuta `baton.py sync` **con el motivo de cada cambio**. + +## B. Abrir un módulo + +Por defecto, el siguiente `Planificado` por prioridad. + +### 1. Entender + +Es la "spec" del módulo, pero corta. + +- A partir de la visión y del `## Objetivo`, propón `## Alcance`, `## Fuera de alcance`, `## Riesgos` y `## Referencias` (ADR y contratos que aplican). +- Pregunta lo que no puedas deducir, en una sola ronda. +- Para los riesgos, evalúa si el módulo: + - mueve dinero o datos personales; + - toca autenticación o permisos; + - migra datos; + - integra servicios externos; + - es reversible; + - es una zona donde el equipo tiene poca experiencia. +- Si el módulo necesita una decisión de diseño nueva, propónla como ADR (`baton/templates/adr.md`). +- Muestra un resumen de 5 líneas como máximo y pide confirmación. + +### 2. Configurar + +1. Muestra la configuración heredada con `baton.py efectiva modulo:`, en tres grupos: roles, autonomía y verificador, y tamaño de slice. +2. **Recomienda según el riesgo**, con el motivo en una línea. Por ejemplo: pagos, seguridad o migraciones → Pair; CRUD interno → Delegado. +3. Para cada grupo, pregunta "¿mantener o cambiar?". +4. **Si el humano elige menos control que el recomendado,** avísale **una vez** con el riesgo concreto, anótalo en `## Riesgos` y respeta su decisión. Bajar el control está permitido. Solo comprueba que no quede bajo `autonomia_minima`. +5. En `config` van **solo las diferencias**, cada una como `{ valor, motivo, desde: }`. Si la autonomía queda en Delegado, el verificador se activa solo: confirma que haya una entidad asignada. + +### 3. Definir los ítems del módulo + +1. Propón la lista en una tabla con id, tipo, título, una línea de propósito y prioridad. + - Usa el **tipo principal** de `config.md` (`backlog.principal`). Usa los auxiliares (`bug`, `tecnico`) solo cuando corresponda. + - Incluye los ítems semilla que ya existan con ese `modulo`, y los ítems sin módulo que encajen. + - Divide en ítems **verticales**, que entregan algo usable, y no por capas. + - Revisa que cada ítem cumpla **INVEST**: independiente, negociable, valioso, estimable, pequeño y testeable. Si un ítem parece de más de unos 6 criterios, propón dividirlo. +2. El humano corrige, edita, quita, agrega y prioriza. +3. Lo que **acepte** se crea como ítem ligero desde `baton/templates/item-.md`: + - el frontmatter completo y la sección de propósito en una línea; + - `estado: Pendiente` (aceptado para desarrollo); + - el id con el siguiente número libre de su prefijo. +4. Lo que quiera guardar sin aceptar todavía queda en `Candidato`. Lo que rechace no se crea. + +### 4. Activar y registrar + +1. Ejecuta `python3 baton/bin/baton.py estado modulo: Activo` y `python3 baton/bin/baton.py validar`. +2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "apertura del módulo " --ref baton-module`. Si alguna diferencia de configuración tiene un motivo propio, pásalo con `--motivo-de`. +3. Resume la configuración efectiva (marca ↓ si se bajó el control) y los ítems aceptados. Indica el siguiente paso: "detallar ``; di **continúa** o usa `baton-item`". + +## C. Reconfigurar a mitad del módulo + +- Cambia solo lo que el humano pida, con `desde` igual a la fecha de hoy y su motivo. +- El cambio aplica desde el **siguiente** slice. Los traspasos ya creados conservan su `config_efectiva`. + +## D. Cerrar el módulo + +1. Cuando no quedan ítems abiertos, `baton.py next` lo indica. +2. Si la autonomía es Delegado, presenta al humano los reportes de slice del módulo para la revisión final. +3. Ejecuta `python3 baton/bin/baton.py estado modulo: Cerrado`. El comando rechaza el cierre si quedan ítems en desarrollo. +4. Ejecuta sync con el motivo. + +## No hagas + +- No detalles criterios aquí: eso lo hace `baton-item`, justo a tiempo, ítem por ítem. +- No abras más de un módulo a la vez salvo que el humano lo pida. Así el trabajo en curso se mantiene chico. +- No copies en `module.md` valores iguales a los del proyecto. +- No uses la recomendación de riesgo para bloquear la decisión del humano. diff --git a/skills/baton-next/SKILL.md b/skills/baton-next/SKILL.md deleted file mode 100644 index 18da3cb..0000000 --- a/skills/baton-next/SKILL.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: baton-next -description: Responde "¿qué me toca?" en la metodología Baton. Lee los estados de los ítems y los traspasos pendientes y dice qué rol tiene el turno y sobre qué, sin depender de la conversación. Con "toma tu turno", toma el siguiente trabajo del rol de esta sesión y ejecuta la skill que corresponde. Úsala al abrir una sesión nueva o cuando no esté claro qué sigue. ---- - -# baton-next - -**Rol:** cualquiera. **Entrada:** los estados y los traspasos. **Salida:** qué toca y, con "toma tu turno", el trabajo ya iniciado. - -## Pasos - -1. Ejecuta `python3 baton/bin/baton.py next`. Si sabes el rol o la entidad de esta sesión, filtra con `--rol ` y/o `--entidad `. -2. Muestra el resultado ordenado por prioridad. Por cada ítem: estado, slice siguiente, traspaso pendiente y si está bloqueado por WIP. -3. Si el humano dice **"toma tu turno"**: - 1. Averigua el rol de esta sesión. Puede estar en la instrucción, en el traspaso que te pasaron o en `config.md` según tu entidad. Si no está claro, pregunta. - 2. Toma el primer ítem de ese rol que no esté bloqueado y que tenga un traspaso `Pendiente` dirigido a ti. - 3. Ejecuta la skill que corresponde: - -| Estado del ítem | Rol | Skill | -|---|---|---| -| Candidato, Pendiente | navigator | `baton-refine`, luego `baton-plan` | -| Escalado | navigator | lee la solicitud abierta, presenta la decisión al humano y aplícala (ver abajo) | -| Listo | autor_tests | `baton-tests` | -| TestsEnRevision | aprobador_tests | `baton-approve` | -| TestsCongelados, EnCurso | driver | `baton-drive` | -| EnVerificacion | verificador | `baton-verify` (si no está instalada: revisa el reporte, el diff y el lock y escribe el veredicto en `## Verificación`) | -| EnRevision | humano | muestra los reportes de slice y pide la decisión | - -## Decidir un escalamiento (Navigator) - -1. Presenta al humano la solicitud (qué pasa, evidencia, propuesta) con tu recomendación. -2. Escribe la decisión en `## Decisión`, junto con `decidida_por` y `decidida`. -3. Aplícala: - - **Aprobada, de tipo `test` o `criterio`:** ejecuta `estado <ítem>-R Aprobada`, ajusta el ítem si cambia un criterio (retíralo con `~~`, no lo borres), ejecuta `estado <ítem> Listo` y crea un traspaso para `autor_tests`. - - **Aprobada, de tipo `diseno` o `plan`:** actualiza el plan o el ADR, ejecuta `estado <ítem>-R Aplicada` y `estado <ítem> TestsCongelados`, y crea un traspaso para `driver`. - - **Rechazada:** ejecuta `estado <ítem>-R Rechazada` y `estado <ítem> TestsCongelados`, y crea un traspaso para `driver` con la explicación. -4. Ejecuta sync con el motivo de la decisión. - -## No hagas - -- No tomes trabajo de otro rol aunque esté libre. Que dos roles trabajen sobre lo mismo rompe los turnos. -- No saltes el límite de WIP sin que el humano lo decida. diff --git a/skills/baton-plan/SKILL.md b/skills/baton-plan/SKILL.md deleted file mode 100644 index 415e1e1..0000000 --- a/skills/baton-plan/SKILL.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: baton-plan -description: Divide un ítem refinado de la metodología Baton en slices verticales demostrables (el primero es un esqueleto andante), escribe baton/modules//plans/<ítem>.md, marca el ítem como Listo y entrega el turno al autor de tests. Úsala después de baton-refine o cuando haya que cambiar el plan de un ítem. ---- - -# baton-plan - -**Rol:** Navigator. **Entrada:** un ítem refinado, el mapa del sistema y los ADR. **Salida:** el plan, el ítem en `Listo` y el traspaso al autor de tests. - -El formato está en FORMATOS.md, sección 5. La plantilla es `baton/templates/plan.md`. - -## Pasos - -1. Lee el ítem, su `module.md`, `baton/system/overview.md` y los ADR. Consulta `slice_max` con `python3 baton/bin/baton.py efectiva <ítem>`. -2. **Divide en slices verticales.** Cada slice atraviesa las capas necesarias (UI → API → BD, o la forma que tenga el sistema) y termina en algo que se puede ejecutar. - - **S1 es el esqueleto andante:** el camino más delgado de punta a punta para el criterio principal. Si el módulo es nuevo, S1 también deja montado lo mínimo de infraestructura. - - Cada criterio vigente va en **exactamente un** slice: el slice donde su test debe pasar. - - Ningún slice supera `slice_max.criterios` ni se puede revisar en más de `slice_max.minutos`. - - Ordena los slices por dependencia y luego por valor. -3. **Cada slice** lleva: - - **Recorrido**: capas y piezas que toca; - - **Fuera de este slice**: lo que se deja para después a propósito; - - **Demo**: pasos concretos y lo que se debe ver; - - **Decisiones que aplican**: los ADR; - - **Escalar si**: los puntos donde el Driver debe detenerse a preguntar. -4. **Decisiones de diseño.** Si el plan necesita una decisión nueva de arquitectura, contrato o modelo de datos, propónla al humano. Cuando la apruebe, escríbela como ADR en `baton/system/adr/ADR--.md` (contexto, decisión, consecuencias). No la dejes implícita en el plan. -5. Escribe `baton/modules//plans/<ítem>.md` y ejecuta `python3 baton/bin/baton.py validar`. -6. Ejecuta `python3 baton/bin/baton.py estado <ítem> Listo`. Si falla, el mensaje dice qué falta de la Definition of Ready. -7. Ejecuta `python3 baton/bin/baton.py handoff --item <ítem> --de navigator --para autor_tests --entidad-de `. Completa en el traspaso `## Qué se entrega`, `## Qué se espera` y `## Contexto`. -8. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "plan de <ítem>"`. -9. Dile al humano cómo sigue el turno según el `transporte` del autor de tests: - - `subagente`: lánzalo con el traspaso como instrucción; - - `sesion`: el humano abre otra sesión y le dice "toma tu turno"; - - `externo`: otra herramienta lee el traspaso. - -## Cambiar un plan existente - -- Sube `version`. -- Los slices con reporte `Terminado` o `Aprobado` no se modifican. -- Los ids de slice nunca se reutilizan. -- Ejecuta sync con el motivo. -- Si el cambio mueve criterios entre slices que ya tienen tests congelados, no hace falta tocar los tests: la relación criterio → slice vive en el plan. diff --git a/skills/baton-refine/SKILL.md b/skills/baton-refine/SKILL.md deleted file mode 100644 index 3ed9545..0000000 --- a/skills/baton-refine/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: baton-refine -description: Refina justo a tiempo un ítem del backlog de la metodología Baton. Escribe el valor y los criterios de aceptación Dado/Cuando/Entonces, revisa la seguridad, detecta ambigüedades y deja el ítem cumpliendo la Definition of Ready salvo el plan. También sirve para aceptar o descartar ítems candidatos. Úsala cuando un ítem Pendiente está por desarrollarse. ---- - -# baton-refine - -**Rol:** Navigator. El agente propone y **el humano decide**. **Entrada:** un ítem `Pendiente` (o `Candidato`), el mapa del sistema y los ADR. **Salida:** el ítem refinado. Después sigue `baton-plan`. - -## Candidatos - -Si el ítem está en `Candidato`, muéstralo con su `## Por qué se propone` y pregunta: - -- si el humano lo acepta: `python3 baton/bin/baton.py estado <ítem> Pendiente`; -- si lo descarta: `python3 baton/bin/baton.py estado <ítem> Descartado`. - -Nunca lo muevas sin respuesta. - -## Pasos - -1. Lee el ítem, `baton/system/overview.md`, los ADR relevantes y el `module.md` de su módulo. -2. **Valor.** Escribe `## Valor` como "Como quiero para ". -3. **Criterios.** Escribe uno por comportamiento observable, con estas reglas: - - formato `### AC- · ` y viñetas **Dado** / **Cuando** / **Entonces** (y **Y**); - - datos concretos: "un carrito con 2 productos por $30", no "un carrito con productos"; - - el **Entonces** describe algo que se puede comprobar desde afuera (respuesta, pantalla, registro), no detalles internos; - - incluye el caso feliz, los errores esperables y los bordes (vacío, límite, duplicado, sin permiso); - - si salen más de unos 6 criterios, propone dividir el ítem. -4. **Seguridad.** Revisa y escribe el resultado en `## Seguridad`: - - autenticación y autorización; - - validación de entradas; - - datos sensibles (almacenamiento, logs, tránsito); - - inyección; - - abuso (límites de uso, enumeración); - - auditoría. - - Si no hay impacto, escribe "sin impacto". Lo que encuentres como requisito se convierte en criterio. -5. **Ambigüedades.** Todo lo que no puedas decidir con lo que hay va a `## Preguntas abiertas`. Pregúntaselo al humano y, al resolverlo, borra la pregunta y ajusta los criterios. -6. **Propuestas.** Si detectas mejoras o huecos fuera del alcance del ítem, **no** los agregues como criterios. Créalos como ítems nuevos con `estado: Candidato`, `origen: agente`, `propuesto_por: ` y `## Por qué se propone`. -7. **Criterios ya congelados.** Si el ítem estuvo en `TestsCongelados` o después, no edites un criterio sin una solicitud aprobada. Un criterio que sobra se retira: se tacha su título con `~~` y se anotan la fecha y la solicitud. Nunca se borra ni se renumera. -8. Revisa la Definition of Ready (FORMATOS.md 4.3): valor, criterios con Dado/Cuando/Entonces, sin preguntas abiertas, seguridad escrita y dependencias resueltas o explicadas. Lo único que falta es el plan. -9. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "refinado de <ítem>"`. Si hubo cambios de alcance con un motivo propio, usa `--motivo-de`. -10. Continúa con `baton-plan`. - -## No hagas - -- No escribas tests ni código. -- No marques el ítem como `Listo`: lo hace `baton-plan` cuando existe el plan. -- No resuelvas tú una pregunta abierta de negocio. Preséntale opciones al humano, con tu recomendación. diff --git a/skills/baton-setup/SKILL.md b/skills/baton-setup/SKILL.md deleted file mode 100644 index cd76caf..0000000 --- a/skills/baton-setup/SKILL.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -name: baton-setup -description: Prepara un proyecto para trabajar con la metodología Baton. Hace las preguntas de configuración, escribe baton/config.md, crea la estructura de carpetas, instala baton.py y el hook que protege los tests de aceptación. Úsala al empezar a usar la metodología en un repositorio o para cambiar la configuración del proyecto. ---- - -# baton-setup - -**Rol:** humano (con ayuda del agente). **Entrada:** respuestas del humano. **Salida:** `baton/config.md`, la estructura `baton/`, `baton/bin/baton.py`, el hook y, opcionalmente, CODEOWNERS. - -Los formatos están en `FORMATOS.md` de la metodología. La plantilla está en `assets/templates/config.md` de esta skill. - -## Antes de preguntar - -1. Comprueba que el directorio sea un repositorio git y que `python3 -c "import yaml"` funcione. Si falta PyYAML, pide permiso para instalarlo (`pip install pyyaml`). -2. Si `baton/config.md` ya existe, estás en **modo cambio** (ver más abajo). -3. Revisa el repositorio para proponer valores por defecto: lenguaje, framework de tests y sus comandos (`package.json`, `pyproject.toml`, `Makefile`, etc.), carpeta de tests, archivos de configuración del runner y remoto de git (GitHub o GitLab). - -## Preguntas - -Hazlas **por grupos**. Cada grupo lleva una propuesta ya rellenada, y el humano responde "sí" o corrige. No preguntes campo por campo. - -1. **Proyecto:** nombre e idioma de los documentos. -2. **Cadencia:** flujo continuo (kanban) o iteraciones (scrum, con duración), y el límite de ítems en curso (`wip`, por defecto 2–3 por persona). -3. **Personas y modelos:** quiénes participan (`entidades`) y qué rol cumple cada uno. Propón esto por defecto: - - navigator: la persona + un modelo razonador; - - autor_tests: el modelo razonador, por subagente; - - aprobador_tests: la persona; - - driver: un modelo implementador, en otra sesión; - - verificador: un modelo distinto del driver, o desactivado. -4. **Autonomía por defecto:** explica los tres niveles en una línea cada uno. Pair revisa cada slice, Checkpoint cada ítem y Delegado el módulo completo. Recomienda Checkpoint, o Pair si el equipo recién empieza con el flujo. Pregunta también si quiere una `autonomia_minima`: solo hace falta si nadie debe bajar de cierto nivel, por ejemplo por regulación. -5. **Tests:** ruta de los tests de aceptación, comandos (`aceptacion`, `aceptacion_archivo` con `{archivo}`, `unitarios`, `todos`) y archivos `protegidos` (configuración del runner, fixtures compartidas). -6. **Herramienta externa:** ninguna, Jira, Trello o GitHub Issues. -7. **Protección:** instalar el hook de git (recomendado) y generar CODEOWNERS, si hay remoto en GitHub o GitLab. Explica que el hook atrapa descuidos y que la garantía real es CODEOWNERS. - -Valida en cuanto recibas las respuestas, no al final. Si el humano asigna al driver como aprobador o como autor de tests, explícale la invariante que rompe y pide otra entidad. - -## Pasos - -1. Ejecuta `python3 /assets/baton.py init [--hook] [--codeowners "@usuario"]` desde la raíz del repositorio. -2. Escribe `baton/config.md` a partir de la plantilla, con las respuestas. -3. Ejecuta `python3 baton/bin/baton.py validar` y corrige hasta que diga `ok`. -4. Si generaste CODEOWNERS, agrega las reglas que imprime `python3 baton/bin/baton.py codeowners "@usuario"`. -5. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "setup inicial" --ref baton-setup`. -6. Muestra un resumen corto de la configuración y los archivos creados. Propón hacer commit, pero no lo hagas sin permiso. - -## Modo cambio - -Si `baton/config.md` ya existe: - -1. Muestra los valores actuales agrupados y pregunta qué grupo quiere cambiar. -2. Pide el **motivo** de cada cambio. -3. Edita `baton/config.md`, valida y ejecuta `baton.py sync --autor --motivo-de "config:="` (o `--motivo` si todos comparten el mismo). -4. Si cambia `autonomia` o `autonomia_minima`, ejecuta `baton.py validar`. Avisa si algún módulo o ítem queda fuera de las reglas. - -## No hagas - -- No inventes entidades ni modelos: pregunta. -- No sobrescribas un hook de git existente sin preguntar (`init` falla en ese caso, a propósito). -- No hagas commit ni push sin permiso. diff --git a/skills/baton-setup/assets/templates/module.md b/skills/baton-setup/assets/templates/module.md deleted file mode 100644 index 3cb798d..0000000 --- a/skills/baton-setup/assets/templates/module.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -formato: 1 -modulo: -estado: Activo # Planificado | Activo | Cerrado -inicio: -cierre: null -config: {} # solo diferencias con config.md, cada una {valor, motivo, desde} ---- - -# Módulo - -## Alcance - -## Fuera de alcance - -## Riesgos - -## Referencias diff --git a/skills/baton-start/SKILL.md b/skills/baton-start/SKILL.md new file mode 100644 index 0000000..f015f4b --- /dev/null +++ b/skills/baton-start/SKILL.md @@ -0,0 +1,123 @@ +--- +name: baton-start +description: Inicia un proyecto con la metodología Baton. Detecta si el proyecto es nuevo o existente, entiende qué se va a construir (o desde dónde se parte) y lo confirma con el humano, recomienda el stack según la escala, configura las variables con ese contexto y arma el mapa inicial de módulos. Instala baton.py y el hook. Úsala una vez al empezar, o para actualizar la visión, el stack o la configuración. +--- + +# baton-start + +**Rol:** Navigator (humano + agente). El agente entiende, propone y recomienda. **El humano decide.** + +**Salida:** +- `baton/system/overview.md`: la visión; +- `baton/system/adr/ADR-0001-*.md`: el stack; +- `baton/config.md`; +- el mapa de módulos (`baton/modules//module.md`); +- la herramienta y el hook instalados. + +**No leas la documentación de la metodología.** Todo lo que necesitas está en esta skill, en `references/` y en `assets/templates/`. Si algo falta, dilo en vez de buscarlo. + +## Orden y por qué + +**Entender → escala y stack → configurar → mapa de módulos.** Cada paso usa lo que se decidió en el anterior. Las recomendaciones de configuración salen del proyecto real, no de valores genéricos. + +## 0. Preparar (sin gastar tokens) + +1. Comprueba que el directorio sea un repositorio git y que `python3 -c "import yaml"` funcione. Si falta PyYAML, pide permiso para instalarlo. +2. Ejecuta `python3 /assets/baton.py detectar`. Devuelve en YAML: + - `inicio`: `nuevo` o `existente`; + - lenguajes, manifiestos, tests existentes y comandos de test sugeridos; + - si hay issues que se puedan importar; + - si Baton ya está instalado. + + **Usa ese resultado en vez de explorar el repositorio a mano.** +3. Si `baton_instalado` es `true`, ve a **Actualizar** (al final). +4. Ejecuta `python3 /assets/baton.py init`. Crea `baton/`, copia la herramienta a `baton/bin/baton.py` y las plantillas a `baton/templates/`. + +## 1. Entender el proyecto + +- Si `inicio` es `nuevo`, sigue [references/proyecto-nuevo.md](references/proyecto-nuevo.md). +- Si `inicio` es `existente`, sigue [references/proyecto-existente.md](references/proyecto-existente.md). + +Los dos caminos terminan igual: + +1. Escribes `baton/system/overview.md` desde `baton/templates/overview.md`. +2. Muestras un **resumen corto** de lo que entendiste. +3. El humano confirma, corrige, agrega o quita. Repite hasta que diga que está bien. + +No sigas al paso 2 sin esa confirmación. + +## 2. Escala y stack + +Sigue [references/escala-y-stack.md](references/escala-y-stack.md). La recomendación de stack sale de la escala y las restricciones confirmadas en el paso 1, nunca antes. + +El resultado es `baton/system/adr/ADR-0001-stack.md` (plantilla `baton/templates/adr.md`), en estado `Aceptado` una vez que el humano decide. + +## 3. Configurar + +Haz las preguntas **por grupos**. Cada grupo va con una propuesta ya rellenada a partir de la visión, del stack y de `detectar`, y explica en una línea por qué la recomiendas. El humano responde "sí" o corrige. + +1. **Tipo de backlog:** + - el **principal** define la plantilla de los ítems: + - `historia`: "Como… quiero… para…". Para producto con usuarios. + - `requerimiento`: "El sistema debe…". Para sistemas regulados, contratos o integraciones. + - `ticket`: problema o tarea. Para mantenimiento o soporte. + - los **auxiliares** siempre disponibles, por defecto `bug` y `tecnico`. + + Recomienda según el tipo de proyecto. +2. **Cadencia:** kanban o scrum (con duración), y el `wip` (2 o 3 ítems en curso por persona). +3. **Personas y modelos** (`entidades`) y **roles**. Propón esto por defecto: + - navigator: la persona + un modelo razonador; + - autor_tests: el modelo razonador, por subagente; + - aprobador_tests: la persona; + - driver: un modelo implementador, en otra sesión; + - verificador: un modelo distinto del driver, o desactivado. + + Si el humano propone que el driver apruebe o escriba tests de aceptación, explica la invariante que rompe y pide otra entidad. +4. **Autonomía:** Pair revisa cada slice, Checkpoint cada ítem y Delegado el módulo completo. Recomienda según la visión: si hay datos sensibles, dinero o un equipo nuevo en el flujo, Pair o Checkpoint. Pregunta por una `autonomia_minima` solo si las restricciones lo justifican, por ejemplo por regulación. +5. **Tests:** + - la ruta de los tests de aceptación; + - los comandos (los de `detectar`, o los del stack recién elegido); + - los archivos `protegidos`: la configuración del runner y las fixtures compartidas; + - `slice_max`. + + Los tests que ya existen **no se congelan**: el lock solo cubre los tests de aceptación nuevos, que salen de criterios aprobados. +6. **Herramienta externa:** ninguna, Jira, Trello o GitHub Issues. +7. **Protección:** el hook de git (recomendado) y CODEOWNERS si hay remoto en GitHub o GitLab. El hook atrapa descuidos; la garantía fuerte es CODEOWNERS. + +Escribe `baton/config.md` desde `baton/templates/config.md`. Si el humano aceptó el hook, ejecuta `python3 baton/bin/baton.py init --hook [--codeowners "@usuario"]`. + +## 4. Mapa de módulos + +El mapa de módulos es el **backlog base**: las grandes partes del sistema (épicas), con prioridad. **No es definitivo:** después se pueden agregar, dividir, fusionar o descartar módulos con `baton-module`. + +1. Propón los módulos que salen del **alcance inicial** de la visión, en una tabla con nombre, objetivo en una línea y prioridad. + - El primero debería ser el que entrega el flujo central de punta a punta. Su primer slice será el esqueleto andante del sistema. + - No intentes adivinar todos los módulos del futuro. +2. El humano edita, quita, agrega o reordena. Lo que acepte se crea con `baton/templates/module.md`: solo el frontmatter y `## Objetivo`, con `estado: Planificado`. Lo que solo propusiste y no aceptó, no lo crees. +3. **Ítems semilla (opcional):** si el humano ya tiene ítems claros, créalos como ítems ligeros. Usa la plantilla del tipo (`baton/templates/item-.md`), solo el frontmatter y el título, con `estado: Pendiente` y su `modulo`. El detalle se hace al abrir el módulo. +4. **Importar (opcional, solo si `issues_importables` o hay TODO en el código):** ofrécelo, sin hacerlo por defecto. Lo importado entra como ítem `Candidato` (`origen: agente`, `## Por qué se propone`: "importado del issue #N"). + +## 5. Registrar y cerrar + +1. Ejecuta `python3 baton/bin/baton.py validar` y corrige hasta que diga `ok`. +2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "inicio del proyecto" --ref baton-start`. +3. Muestra un resumen: la visión en 3 líneas, el stack, la configuración clave y el mapa de módulos. Indica el siguiente paso: "abrir el módulo ``; di **continúa** o usa `baton`". +4. Propón hacer commit, pero no lo hagas sin permiso. + +## Actualizar (Baton ya instalado) + +Pregunta qué cambió: +- **Visión:** edita `overview.md` y actualiza `actualizado`. +- **Stack:** crea un ADR nuevo que reemplace al anterior. En el viejo marca `estado: Reemplazado` y `reemplazado_por`. +- **Configuración:** el grupo que corresponda. +- **Mapa de módulos:** usa `baton-module`. + +Pide el **motivo** de cada cambio y ejecuta `baton.py sync --motivo-de "="`. Si cambia `autonomia` o `autonomia_minima`, ejecuta `validar` y avisa qué módulos o ítems quedan fuera de las reglas. + +## No hagas + +- No configures antes de entender el proyecto. +- No recomiendes el stack antes de conocer la escala y las restricciones. +- No inventes entidades, modelos ni respuestas de negocio. Propón y pide confirmación. +- No sobrescribas un hook de git existente sin preguntar. +- No hagas commit ni push sin permiso. diff --git a/skills/baton-setup/assets/baton.py b/skills/baton-start/assets/baton.py similarity index 81% rename from skills/baton-setup/assets/baton.py rename to skills/baton-start/assets/baton.py index 5a85ff1..ebcf83a 100755 --- a/skills/baton-setup/assets/baton.py +++ b/skills/baton-start/assets/baton.py @@ -63,6 +63,22 @@ "Descartado": set(), } +# Módulos: el mapa de módulos es iterable (se agregan, dividen o descartan en cualquier momento). +ESTADOS_MODULO = ["Candidato", "Planificado", "Activo", "Cerrado", "Descartado"] +TRANSICIONES_MODULO = { + "Candidato": {"Planificado", "Descartado"}, + "Planificado": {"Activo", "Descartado"}, + "Activo": {"Cerrado", "Planificado"}, + "Cerrado": {"Activo"}, + "Descartado": {"Planificado"}, +} + +# Tipos de ítem. El backlog tiene un tipo principal y tipos auxiliares (config.md: backlog). +TIPOS_PRINCIPALES = {"historia", "requerimiento", "ticket"} +# Sección del cuerpo que explica para qué existe el ítem (parte de la Definition of Ready). +PROPOSITO = {"historia": "Valor", "requerimiento": "Requerimiento", "ticket": "Descripción", + "bug": "Comportamiento esperado", "tecnico": "Motivo"} + # Claves que cada nivel puede sobrescribir (FORMATOS.md, sección 3). CLAVES_MODULO = {"roles.navigator", "roles.autor_tests", "roles.aprobador_tests", "roles.driver", "roles.verificador", "roles.verificador.activo", "autonomia", @@ -185,7 +201,7 @@ def __init__(self, root: Path): self.flow = self.root / "baton" cfg_path = self.flow / "config.md" if not cfg_path.exists(): - raise BatonError("no existe baton/config.md: ejecuta primero el setup") + raise BatonError("no existe baton/config.md: ejecuta primero baton-start") self.config, _ = leer_md(cfg_path) self.modulos: dict[str, dict] = {} for p in sorted(self.flow.glob("modules/*/module.md")): @@ -204,6 +220,18 @@ def __init__(self, root: Path): fm, body = leer_md(p) self.reportes[f"{fm.get('item')}-{fm.get('slice')}"] = {"fm": fm, "body": body, "path": p} self.lock = leer_lock(self.flow / "acceptance.lock") + # visión y decisiones: también se sincronizan (cambian poco, pero cada cambio tiene motivo) + self.vision = None + vp = self.flow / "system" / "overview.md" + if vp.exists(): + texto = vp.read_text(encoding="utf-8") + fm, body = leer_md(vp) if FM_RE.match(texto) else ({}, texto) + self.vision = {"fm": fm, "body": body, "path": vp} + self.adrs = {} + for p in sorted(self.flow.glob("system/adr/ADR-*.md")): + texto = p.read_text(encoding="utf-8") + fm, body = leer_md(p) if FM_RE.match(texto) else ({}, texto) + self.adrs[fm.get("id") or "-".join(p.stem.split("-")[:2])] = {"fm": fm, "body": body, "path": p} def _cargar(self, patron, clave): res = {} @@ -424,10 +452,25 @@ def revisar_roles(roles, donde): errores += [f"config.md: {e}" for e in ef["errores"]] revisar_roles(roles, "config.md") + tipos = cfg.get("tipos") or {} + backlog = cfg.get("backlog") or {} + principal = backlog.get("principal") + auxiliares = list(backlog.get("auxiliares") or []) + if principal not in TIPOS_PRINCIPALES: + errores.append("config.md: backlog.principal debe ser historia, requerimiento o ticket") + for t in [principal, *auxiliares]: + if t and t not in tipos: + errores.append(f"config.md: el tipo '{t}' de backlog no tiene prefijo en 'tipos'") + tipos_permitidos = {t for t in [principal, *auxiliares] if t} + for m, mod in pr.modulos.items(): fm = mod["fm"] - if fm.get("estado") not in ("Planificado", "Activo", "Cerrado"): - errores.append(f"módulo {m}: estado no válido") + if fm.get("estado") not in ESTADOS_MODULO: + errores.append(f"módulo {m}: estado no válido ({', '.join(ESTADOS_MODULO)})") + if mod["path"].parent.name != m: + errores.append(f"módulo {m}: la carpeta debe llamarse modules/{m}/") + if fm.get("origen") == "agente" and not fm.get("propuesto_por"): + avisos.append(f"módulo {m}: un módulo propuesto por un agente debería tener propuesto_por") for clave, ov in (fm.get("config") or {}).items(): if isinstance(ov, dict) and not ov.get("desde"): errores.append(f"módulo {m}: '{clave}' necesita 'desde'") @@ -435,20 +478,18 @@ def revisar_roles(roles, donde): errores += [f"módulo {m}: {e}" for e in ef["errores"]] revisar_roles({r: v for r, v in ef["roles"].items()}, f"módulo {m}") - prefijos = set((cfg.get("tipos") or {}).values()) for iid, it in pr.items.items(): fm, donde = it["fm"], f"ítem {iid}" if fm.get("formato") != FORMATO: errores.append(f"{donde}: formato debe ser {FORMATO}") if it["path"].stem != iid: errores.append(f"{donde}: el archivo debe llamarse {iid}.md") - tipos = cfg.get("tipos") or {} if fm.get("tipo") not in tipos: errores.append(f"{donde}: tipo '{fm.get('tipo')}' no está en config.md") elif not str(iid).startswith(tipos[fm["tipo"]] + "-"): errores.append(f"{donde}: el id debe empezar con {tipos[fm['tipo']]}-") - if prefijos and str(iid).split("-")[0] not in prefijos: - pass + elif tipos_permitidos and fm["tipo"] not in tipos_permitidos: + errores.append(f"{donde}: el tipo '{fm['tipo']}' no está en backlog.principal ni en backlog.auxiliares") est = fm.get("estado") if est not in ESTADOS: errores.append(f"{donde}: estado '{est}' no válido") @@ -461,6 +502,8 @@ def revisar_roles(roles, donde): if est in POST_DOR: if not m: errores.append(f"{donde}: un ítem en {est} necesita módulo") + elif m in pr.modulos and pr.modulos[m]["fm"].get("estado") not in ("Activo", "Cerrado"): + errores.append(f"{donde}: está en {est} pero su módulo {m} no está Activo (ábrelo con baton-module)") errores += [f"{donde}: {e}" for e in faltas_dor(pr, iid)] if m in pr.modulos: ef = efectiva(pr, item_id=iid) @@ -507,8 +550,9 @@ def faltas_dor(pr: Proyecto, iid: str) -> list[str]: it = pr.items[iid] sec = secciones(it["body"]) faltas = [] - if vacio(sec.get("Valor", "")): - faltas.append("Definition of Ready: falta '## Valor'") + proposito = PROPOSITO.get(it["fm"].get("tipo"), "Descripción") + if vacio(sec.get(proposito, "")): + faltas.append(f"Definition of Ready: falta '## {proposito}'") vigentes = {k: v for k, v in it["ac"].items() if not v["retirado"]} if not vigentes: faltas.append("Definition of Ready: no hay criterios vigentes") @@ -576,9 +620,13 @@ def tests_congelados(pr: Proyecto, iid: str) -> tuple[int, int]: def turno_de(pr: Proyecto, iid: str) -> str: - est = pr.items[iid]["fm"].get("estado") + fm = pr.items[iid]["fm"] + est = fm.get("estado") if est == "EnRevision": return "humano" + m = fm.get("modulo") + if est in ("Pendiente", "Candidato") and (not m or pr.modulos.get(m, {}).get("fm", {}).get("estado") != "Activo"): + return "–" # espera a que su módulo se abra (o a tener módulo): lo indica tareas_de_modulos return TURNO.get(est, "–") @@ -591,7 +639,25 @@ def siguiente_slice(pr: Proyecto, iid: str) -> str | None: def cambiar_estado(pr: Proyecto, objetivo: str, nuevo: str, forzar=False) -> str: m = re.fullmatch(r"(.+)-(S\d+)", objetivo) - if m and objetivo not in pr.items: + if objetivo.startswith("modulo:"): + nombre = objetivo.split(":", 1)[1] + mod = pr.modulos.get(nombre) + if not mod: + raise BatonError(f"no existe el módulo {nombre}") + if nuevo not in ESTADOS_MODULO: + raise BatonError(f"estado de módulo no válido: {nuevo} ({', '.join(ESTADOS_MODULO)})") + path, previo = mod["path"], mod["fm"].get("estado") + if not forzar and nuevo not in TRANSICIONES_MODULO.get(previo, set()): + raise BatonError(f"transición no permitida: {previo} → {nuevo} (usa --forzar si el humano lo decidió)") + if nuevo == "Cerrado": + abiertos = [i for i, it in pr.items.items() if it["fm"].get("modulo") == nombre + and it["fm"].get("estado") not in ("Hecho", "Descartado", "Candidato", "Pendiente")] + if abiertos and not forzar: + raise BatonError(f"el módulo tiene ítems en desarrollo: {', '.join(abiertos)}") + _set_campo(path, {"cierre": date.today().isoformat()}) + if nuevo == "Activo" and previo == "Planificado" and mod["fm"].get("inicio") in (None, "null"): + _set_campo(path, {"inicio": date.today().isoformat()}) + elif m and objetivo not in pr.items: rep = pr.reportes.get(objetivo) if not rep: raise BatonError(f"no existe el reporte {objetivo}") @@ -611,6 +677,9 @@ def cambiar_estado(pr: Proyecto, objetivo: str, nuevo: str, forzar=False) -> str if not forzar and nuevo not in TRANSICIONES.get(previo, set()): raise BatonError(f"transición no permitida: {previo} → {nuevo} (usa --forzar si el humano lo decidió)") if nuevo in POST_DOR and previo in ("Pendiente", "Candidato"): + mod = pr.items[objetivo]["fm"].get("modulo") + if not forzar and (not mod or pr.modulos.get(mod, {}).get("fm", {}).get("estado") != "Activo"): + raise BatonError(f"{objetivo} necesita un módulo Activo para pasar a {nuevo}; abre el módulo con baton-module") faltas = faltas_dor(pr, objetivo) if faltas: raise BatonError("; ".join(faltas)) @@ -827,6 +896,11 @@ def sec_hash(body): res[pr.rel(r["path"])] = {"tipo": "reporte", "objeto": rid, "fm": {"estado": r["fm"].get("estado"), "intento": r["fm"].get("intento")}} res["baton/acceptance.lock"] = {"tipo": "lock", "objeto": "lock", "lineas": pr.lock} + if pr.vision: + res[pr.rel(pr.vision["path"])] = {"tipo": "vision", "objeto": "vision", "fm": pr.vision["fm"], + "sec": sec_hash(pr.vision["body"])} + for aid, adr in pr.adrs.items(): + res[pr.rel(adr["path"])] = {"tipo": "adr", "objeto": aid, "fm": adr["fm"], "sec": sec_hash(adr["body"])} return res @@ -911,15 +985,37 @@ def generar_backlog(pr: Proyecto) -> str: def orden(iid): return (pr.items[iid]["fm"].get("prioridad") or 999, iid) + def orden_mod(m): + fm = pr.modulos[m]["fm"] + return (ESTADOS_MODULO.index(fm.get("estado")) if fm.get("estado") in ESTADOS_MODULO else 9, + fm.get("prioridad") or 999, m) + + # mapa de módulos: la columna vertebral del backlog; se edita en cualquier momento + lineas += ["## Mapa de módulos", "", "| Módulo | Estado | Prioridad | Autonomía | Ítems hechos | Objetivo |", + "|---|---|---|---|---|---|"] + orden_estado = {"Activo": 0, "Planificado": 1, "Candidato": 2, "Cerrado": 3, "Descartado": 4} + for m in sorted(pr.modulos, key=lambda x: (orden_estado.get(pr.modulos[x]["fm"].get("estado"), 9), + pr.modulos[x]["fm"].get("prioridad") or 999, x)): + fm = pr.modulos[m]["fm"] + ef = efectiva(pr, modulo=m) + aut = ef["autonomia"]["valor"] + (" ↓" if ef["autonomia"]["bajada"] else "") + suyos = [i for i in pr.items if pr.items[i]["fm"].get("modulo") == m + and pr.items[i]["fm"].get("estado") not in ("Candidato", "Descartado")] + hechos = sum(1 for i in suyos if pr.items[i]["fm"].get("estado") == "Hecho") + objetivo = secciones(pr.modulos[m]["body"]).get("Objetivo", "") + lineas.append(f"| {m} | {fm.get('estado')} | {fm.get('prioridad', '–')} | {aut} | " + f"{f'{hechos}/{len(suyos)}' if suyos else '–'} | {celda(corto(objetivo))} |") + lineas.append("") + activos = [i for i in pr.items if pr.items[i]["fm"].get("estado") not in ("Candidato", "Hecho", "Descartado")] grupos: dict[str | None, list[str]] = {} for iid in activos: grupos.setdefault(pr.items[iid]["fm"].get("modulo"), []).append(iid) - for m in sorted(grupos, key=lambda x: (x is None, x or "")): + for m in sorted(grupos, key=lambda x: (x is None, orden_mod(x) if x in pr.modulos else (9, 999, x or ""))): if m and m in pr.modulos: ef = efectiva(pr, modulo=m) aut = ef["autonomia"]["valor"] + (" ↓" if ef["autonomia"]["bajada"] else "") - lineas.append(f"## {m} · {aut}") + lineas.append(f"## {m} · {pr.modulos[m]['fm'].get('estado')} · {aut}") else: lineas.append("## Sin módulo") lineas += ["", "| ID | Título | Estado | Turno | Prioridad | Autonomía | Slices | Tests |", @@ -939,6 +1035,10 @@ def orden(iid): lineas.append("") cand = sorted((i for i in pr.items if pr.items[i]["fm"].get("estado") == "Candidato"), key=orden) lineas += ["## Candidatos", "", "| ID | Título | Propuesto por | Por qué |", "|---|---|---|---|"] + for m in sorted(m for m in pr.modulos if pr.modulos[m]["fm"].get("estado") == "Candidato"): + fm = pr.modulos[m] + porque = secciones(fm["body"]).get("Por qué se propone", "") + lineas.append(f"| modulo:{m} | {celda(fm['fm'].get('titulo', m))} | {fm['fm'].get('propuesto_por', '–')} | {celda(corto(porque))} |") for iid in cand: it = pr.items[iid] porque = secciones(it["body"]).get("Por qué se propone", "") @@ -996,6 +1096,31 @@ def sync(pr: Proyecto, autor: str, general: str | None, especificos: dict, ref: # ---------------------------------------------------------------- next +def tareas_de_modulos(pr: Proyecto) -> list[str]: + """Trabajo del Navigator sobre el mapa de módulos (va antes que los ítems).""" + filas = [] + abiertos = lambda m: [i for i, it in pr.items.items() if it["fm"].get("modulo") == m + and it["fm"].get("estado") not in ("Hecho", "Descartado", "Candidato")] + for m in sorted(pr.modulos): + est = pr.modulos[m]["fm"].get("estado") + if est == "Candidato": + filas.append(f" modulo:{m} · Candidato · aceptar o descartar (baton-module)") + if est == "Activo" and not abiertos(m) and any(it["fm"].get("modulo") == m for it in pr.items.values()): + filas.append(f" modulo:{m} · Activo · sin ítems abiertos: revisar y cerrar, o agregar ítems (baton-module)") + activos_con_trabajo = [m for m in pr.modulos if pr.modulos[m]["fm"].get("estado") == "Activo" and abiertos(m)] + planificados = sorted((m for m in pr.modulos if pr.modulos[m]["fm"].get("estado") == "Planificado"), + key=lambda m: (pr.modulos[m]["fm"].get("prioridad") or 999, m)) + if not activos_con_trabajo and planificados: + filas.append(f" modulo:{planificados[0]} · Planificado · siguiente módulo por prioridad: abrir (baton-module)") + if not pr.modulos: + filas.append(" mapa de módulos vacío: definirlo (baton-start o baton-module)") + sueltos = [i for i, it in pr.items.items() if not it["fm"].get("modulo") + and it["fm"].get("estado") in ("Pendiente", "Candidato")] + if sueltos: + filas.append(f" {', '.join(sueltos)} · sin módulo: asignar a un módulo (baton-module)") + return filas + + def next_(pr: Proyecto, rol: str | None, entidad: str | None) -> list[str]: salida = [] en_curso = sum(1 for it in pr.items.values() if it["fm"].get("estado") in WIP_ESTADOS) @@ -1006,7 +1131,7 @@ def next_(pr: Proyecto, rol: str | None, entidad: str | None) -> list[str]: pendientes.setdefault(t["fm"].get("item"), []).append(t) roles = [rol] if rol else ROLES + ["humano"] for r in roles: - filas = [] + filas = tareas_de_modulos(pr) if r == "navigator" else [] for iid in sorted(pr.items, key=lambda i: (pr.items[i]["fm"].get("prioridad") or 999, i)): if turno_de(pr, iid) != r and not (r == "navigator" and turno_de(pr, iid) == "humano" and rol): continue @@ -1193,6 +1318,91 @@ def estado_solicitud(rid, ref): # ---------------------------------------------------------------- init +IGNORAR_DIRS = {".git", ".venv", "venv", "env", "node_modules", ".claude", "baton", "__pycache__", ".pytest_cache", + "dist", "build", "target", ".idea", ".vscode", ".mypy_cache", ".tox", ".next", "coverage", "vendor"} +EXT_LENGUAJE = {".py": "Python", ".js": "JavaScript", ".jsx": "JavaScript", ".ts": "TypeScript", ".tsx": "TypeScript", + ".go": "Go", ".rs": "Rust", ".java": "Java", ".kt": "Kotlin", ".cs": "C#", ".rb": "Ruby", + ".php": "PHP", ".swift": "Swift", ".c": "C", ".cpp": "C++", ".dart": "Dart", ".vue": "Vue", + ".svelte": "Svelte", ".ex": "Elixir", ".scala": "Scala"} +MANIFIESTOS = ["package.json", "pyproject.toml", "requirements.txt", "setup.py", "Pipfile", "go.mod", "Cargo.toml", + "pom.xml", "build.gradle", "build.gradle.kts", "composer.json", "Gemfile", "pubspec.yaml", + "Dockerfile", "docker-compose.yml", "compose.yaml"] +CONFIG_RUNNER = ["pytest.ini", "pyproject.toml", "setup.cfg", "tox.ini", "conftest.py", "tests/conftest.py", + "jest.config.js", "jest.config.ts", "vitest.config.ts", "vitest.config.js", + "playwright.config.ts", ".mocharc.json", "phpunit.xml"] + + +def detectar(root: Path) -> dict: + """Lo que se puede saber del repositorio sin gastar tokens: ¿nuevo o existente?, stack, tests.""" + fuentes, lenguajes, test_files, todos = [], {}, 0, 0 + dirs_tests = set() + for p in root.rglob("*"): + if any(parte in IGNORAR_DIRS for parte in p.relative_to(root).parts): + continue + if p.is_dir(): + if p.name in ("test", "tests", "__tests__", "spec"): + dirs_tests.add(p.relative_to(root).as_posix()) + continue + leng = EXT_LENGUAJE.get(p.suffix) + if not leng: + continue + fuentes.append(p) + lenguajes[leng] = lenguajes.get(leng, 0) + 1 + nombre = p.name.lower() + if nombre.startswith("test_") or "_test." in nombre or ".test." in nombre or ".spec." in nombre: + test_files += 1 + if len(fuentes) <= 2000 and p.stat().st_size < 500_000: + todos += len(re.findall(r"\b(TODO|FIXME)\b", p.read_text(encoding="utf-8", errors="ignore"))) + manifiestos = [m for m in MANIFIESTOS if (root / m).exists()] + [p.name for p in root.glob("*.csproj")] + leer = lambda n: (root / n).read_text(encoding="utf-8", errors="ignore") if (root / n).is_file() else "" + + # framework de tests y comandos sugeridos + comandos, framework = None, None + py_dep = "pytest" in leer("pyproject.toml") + leer("requirements.txt") + leer("requirements-dev.txt") + venv_pytest = (root / ".venv" / "bin" / "pytest").exists() + if venv_pytest or py_dep or (lenguajes.get("Python") and shutil.which("pytest")): + framework, pre = "pytest", (".venv/bin/" if venv_pytest else "") + comandos = {"aceptacion": f"{pre}pytest tests/acceptance", "aceptacion_archivo": f"{pre}pytest {{archivo}}", + "unitarios": f"{pre}pytest tests/unit", "todos": f"{pre}pytest"} + elif "package.json" in manifiestos: + pkg = leer("package.json") + runner = "vitest" if "vitest" in pkg else "jest" if "jest" in pkg else None + if runner: + framework = runner + run = "vitest run" if runner == "vitest" else "jest" + comandos = {"aceptacion": f"npx {run} tests/acceptance", "aceptacion_archivo": f"npx {run} {{archivo}}", + "unitarios": f"npx {run} tests/unit", "todos": "npm test"} + elif "go.mod" in manifiestos: + framework = "go test" + comandos = {"aceptacion": "go test ./tests/acceptance/...", "aceptacion_archivo": "go test {archivo}", + "unitarios": "go test ./...", "todos": "go test ./..."} + elif "Cargo.toml" in manifiestos: + framework = "cargo test" + comandos = {"aceptacion": "cargo test --test '*'", "aceptacion_archivo": "cargo test --test {archivo}", + "unitarios": "cargo test --lib", "todos": "cargo test"} + + remoto = git(root, "remote", "get-url", "origin", check=False).strip() + servicio = "github" if "github.com" in remoto else "gitlab" if "gitlab" in remoto else ("otro" if remoto else None) + commits = git(root, "rev-list", "--count", "HEAD", check=False).strip() + readme = next((p.name for p in root.glob("README*") if p.is_file()), None) + return { + "inicio": "existente" if fuentes else "nuevo", + "archivos_fuente": len(fuentes), + "lenguajes": dict(sorted(lenguajes.items(), key=lambda x: -x[1])), + "manifiestos": manifiestos, + "readme": readme, + "commits": int(commits) if commits.isdigit() else 0, + "tests_existentes": {"archivos": test_files, "carpetas": sorted(dirs_tests)}, + "framework_tests": framework, + "comandos_sugeridos": comandos, + "protegidos_sugeridos": [c for c in CONFIG_RUNNER if (root / c).is_file()], + "remoto": {"servicio": servicio, "url": remoto or None, + "issues_importables": servicio == "github" and shutil.which("gh") is not None}, + "todos_en_codigo": todos, + "baton_instalado": (root / "baton" / "config.md").exists(), + } + + def init(destino: Path, hook: bool, codeowners: str | None, forzar: bool) -> list[str]: origen = Path(__file__).resolve().parent hechos = [] @@ -1212,12 +1422,10 @@ def init(destino: Path, hook: bool, codeowners: str | None, forzar: bool) -> lis shutil.copy2(hook_src, flow / "hooks" / "pre-commit") (flow / "hooks" / "pre-commit").chmod(0o755) hechos.append("baton/hooks/pre-commit") - for nombre, contenido in [("acceptance.lock", LOCK_CABECERA), - ("system/overview.md", "# Mapa del sistema\n\n## Arquitectura\n\n## Contratos\n\n## Decisiones\nVer adr/.\n")]: - p = flow / nombre - if not p.exists(): - p.write_text(contenido, encoding="utf-8") - hechos.append(f"baton/{nombre}") + lock = flow / "acceptance.lock" + if not lock.exists(): + lock.write_text(LOCK_CABECERA, encoding="utf-8") + hechos.append("baton/acceptance.lock") if hook: hooks_dir = Path(git(destino, "rev-parse", "--git-path", "hooks").strip()) hooks_dir = hooks_dir if hooks_dir.is_absolute() else destino / hooks_dir @@ -1258,6 +1466,7 @@ def main(argv=None) -> int: p.add_argument("--codeowners", help="dueños para .github/CODEOWNERS, p. ej. '@juan'") p.add_argument("--forzar", action="store_true") + sub.add_parser("detectar", help="¿proyecto nuevo o existente?, stack y comandos de test (no necesita baton/)") sub.add_parser("validar", help="revisa todos los archivos del flujo") p = sub.add_parser("efectiva", help="configuración efectiva de un ítem o módulo") @@ -1267,7 +1476,7 @@ def main(argv=None) -> int: p.add_argument("--rol", choices=ROLES + ["humano"]) p.add_argument("--entidad") - p = sub.add_parser("estado", help="cambia el estado de un ítem, reporte (US-004-S1) o solicitud") + p = sub.add_parser("estado", help="cambia el estado de un ítem, módulo (modulo:pagos), reporte (US-004-S1) o solicitud") p.add_argument("objetivo") p.add_argument("nuevo") p.add_argument("--forzar", action="store_true", help="salta la validación de transición (solo si el humano lo decide)") @@ -1314,6 +1523,9 @@ def main(argv=None) -> int: for h in init(root, a.hook, a.codeowners, a.forzar): print(f"creado: {h}") return 0 + if a.cmd == "detectar": + print(yaml.safe_dump(detectar(root), allow_unicode=True, sort_keys=False), end="") + return 0 pr = Proyecto(root) if a.cmd == "validar": errores, avisos = validar(pr) @@ -1373,7 +1585,8 @@ def main(argv=None) -> int: for x in problemas: print(f"rechazado: {x}") if problemas: - print("\nLos tests de aceptación congelados solo cambian con una solicitud aprobada (FORMATOS.md §6–7).") + print("\nLos tests de aceptación congelados solo cambian con una solicitud aprobada: créala desde " + "baton/templates/request.md, pasa el ítem a Escalado y entrega el turno al navigator.") return 1 print("lock ok") return 0 diff --git a/skills/baton-setup/assets/pre-commit b/skills/baton-start/assets/pre-commit similarity index 100% rename from skills/baton-setup/assets/pre-commit rename to skills/baton-start/assets/pre-commit diff --git a/skills/baton-start/assets/templates/adr.md b/skills/baton-start/assets/templates/adr.md new file mode 100644 index 0000000..e592a7d --- /dev/null +++ b/skills/baton-start/assets/templates/adr.md @@ -0,0 +1,26 @@ +--- +formato: 1 +id: ADR- +titulo: +estado: Propuesto # Propuesto | Aceptado | Reemplazado | Descartado +fecha: +reemplaza: null +reemplazado_por: null +--- + +## Contexto +Qué situación obliga a decidir. Cita la escala y las restricciones de la visión. + +## Opciones consideradas +| Opción | A favor | En contra | +|---|---|---| + +## Decisión +Qué se eligió y por qué. + +## Consecuencias +Qué se gana, qué se paga y qué queda más difícil. + +## Revisar si +Condiciones concretas para reconsiderar la decisión. Ejemplo: "más de 10 000 usuarios activos", +"más de un equipo trabajando en el mismo módulo". diff --git a/skills/baton-setup/assets/templates/config.md b/skills/baton-start/assets/templates/config.md similarity index 89% rename from skills/baton-setup/assets/templates/config.md rename to skills/baton-start/assets/templates/config.md index a965139..1407a63 100644 --- a/skills/baton-setup/assets/templates/config.md +++ b/skills/baton-start/assets/templates/config.md @@ -8,9 +8,14 @@ cadencia: iteracion_dias: null # obligatorio si modo = scrum wip: 3 # máximo de ítems en EnCurso, Escalado, EnVerificacion y EnRevision +backlog: + principal: historia # historia | requerimiento | ticket (define la plantilla de los ítems) + auxiliares: [bug, tecnico] + tipos: # tipo de ítem → prefijo del id historia: US - requisito: RQ + requerimiento: RQ + ticket: TK bug: BUG tecnico: TEC diff --git a/skills/baton-start/assets/templates/item-bug.md b/skills/baton-start/assets/templates/item-bug.md new file mode 100644 index 0000000..bda4a9e --- /dev/null +++ b/skills/baton-start/assets/templates/item-bug.md @@ -0,0 +1,38 @@ +--- +formato: 1 +id: +titulo: +tipo: bug +modulo: +estado: Pendiente +prioridad: +iteracion: null +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) +creado: +dependencias: [] +config: {} # solo subir/bajar autonomia, agregar aprobadores o activar verificador +--- + +## Comportamiento esperado +Qué debería pasar. + +## Comportamiento actual +Qué pasa hoy. + +## Pasos para reproducir +1. ... + +## Criterios de aceptación + +### AC-1 · +- **Dado** ... +- **Cuando** ... +- **Entonces** ... + +## Seguridad + +## Preguntas abiertas + +## Fuera de alcance + +## Notas diff --git a/skills/baton-setup/assets/templates/item.md b/skills/baton-start/assets/templates/item-historia.md similarity index 93% rename from skills/baton-setup/assets/templates/item.md rename to skills/baton-start/assets/templates/item-historia.md index 0f7e517..031bd7a 100644 --- a/skills/baton-setup/assets/templates/item.md +++ b/skills/baton-start/assets/templates/item-historia.md @@ -3,11 +3,11 @@ formato: 1 id: titulo: tipo: historia -modulo: +modulo: estado: Pendiente prioridad: iteracion: null -origen: humano # humano | agente (agrega propuesto_por) +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) creado: dependencias: [] config: {} # solo subir/bajar autonomia, agregar aprobadores o activar verificador diff --git a/skills/baton-start/assets/templates/item-requerimiento.md b/skills/baton-start/assets/templates/item-requerimiento.md new file mode 100644 index 0000000..1296ba0 --- /dev/null +++ b/skills/baton-start/assets/templates/item-requerimiento.md @@ -0,0 +1,35 @@ +--- +formato: 1 +id: +titulo: +tipo: requerimiento +modulo: +estado: Pendiente +prioridad: +iteracion: null +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) +creado: +dependencias: [] +config: {} # solo subir/bajar autonomia, agregar aprobadores o activar verificador +--- + +## Requerimiento +El sistema debe cuando . + +## Justificación +Por qué es necesario (regla de negocio, norma, contrato). + +## Criterios de aceptación + +### AC-1 · +- **Dado** ... +- **Cuando** ... +- **Entonces** ... + +## Seguridad + +## Preguntas abiertas + +## Fuera de alcance + +## Notas diff --git a/skills/baton-start/assets/templates/item-tecnico.md b/skills/baton-start/assets/templates/item-tecnico.md new file mode 100644 index 0000000..aa7715c --- /dev/null +++ b/skills/baton-start/assets/templates/item-tecnico.md @@ -0,0 +1,32 @@ +--- +formato: 1 +id: +titulo: +tipo: tecnico +modulo: +estado: Pendiente +prioridad: +iteracion: null +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) +creado: +dependencias: [] +config: {} # solo subir/bajar autonomia, agregar aprobadores o activar verificador +--- + +## Motivo +Por qué hace falta este trabajo técnico y qué riesgo reduce (no tiene valor visible para el usuario). + +## Criterios de aceptación + +### AC-1 · +- **Dado** ... +- **Cuando** ... +- **Entonces** ... + +## Seguridad + +## Preguntas abiertas + +## Fuera de alcance + +## Notas diff --git a/skills/baton-start/assets/templates/item-ticket.md b/skills/baton-start/assets/templates/item-ticket.md new file mode 100644 index 0000000..855e89e --- /dev/null +++ b/skills/baton-start/assets/templates/item-ticket.md @@ -0,0 +1,32 @@ +--- +formato: 1 +id: +titulo: +tipo: ticket +modulo: +estado: Pendiente +prioridad: +iteracion: null +origen: humano # humano | agente (agrega propuesto_por; estado Candidato) +creado: +dependencias: [] +config: {} # solo subir/bajar autonomia, agregar aprobadores o activar verificador +--- + +## Descripción +Qué hay que hacer o qué problema resolver, y el contexto necesario. + +## Criterios de aceptación + +### AC-1 · +- **Dado** ... +- **Cuando** ... +- **Entonces** ... + +## Seguridad + +## Preguntas abiertas + +## Fuera de alcance + +## Notas diff --git a/skills/baton-start/assets/templates/module.md b/skills/baton-start/assets/templates/module.md new file mode 100644 index 0000000..881a373 --- /dev/null +++ b/skills/baton-start/assets/templates/module.md @@ -0,0 +1,25 @@ +--- +formato: 1 +modulo: +titulo: +estado: Planificado # Candidato | Planificado | Activo | Cerrado | Descartado +prioridad: +origen: humano # humano | agente (agrega propuesto_por) +creado: +inicio: null +cierre: null +config: {} # solo diferencias con config.md, cada una {valor, motivo, desde} +--- + +## Objetivo +Una línea: qué aporta este módulo. + + + +## Alcance + +## Fuera de alcance + +## Riesgos + +## Referencias diff --git a/skills/baton-start/assets/templates/overview.md b/skills/baton-start/assets/templates/overview.md new file mode 100644 index 0000000..f3f7637 --- /dev/null +++ b/skills/baton-start/assets/templates/overview.md @@ -0,0 +1,42 @@ +--- +formato: 1 +inicio: nuevo # nuevo | existente +actualizado: +--- + +# Visión del sistema + +## Propósito +Qué problema resuelve y para quién, en 2–4 líneas. + +## Usuarios +Quiénes lo usan y qué necesita cada uno. + +## Objetivos +Qué tiene que lograr y cómo se sabrá que lo logró (métricas o señales de éxito). + +## Alcance inicial +Lo que entra en la primera versión. + +## Fuera de alcance +Lo que no se hará por ahora, a propósito. + +## Escala y horizonte +Prototipo · MVP · producto pequeño · empezar pequeño y migrar fácil · gran escala desde el inicio. +Usuarios esperados, volumen de datos y qué tan rápido debería crecer. + +## Restricciones +Seguridad, datos sensibles, rendimiento, disponibilidad, presupuesto, plazos, experiencia del equipo, +plataformas obligatorias. + +## Punto de partida +(Solo en proyectos existentes) Qué hay hoy: stack, estructura, qué funciona, tests, deuda conocida. + +## Arquitectura +Piezas principales y cómo se comunican. Las decisiones van en adr/. + +## Glosario +Términos del dominio con su significado. + +## Lo que no sabemos +Preguntas abiertas que no bloquean empezar, pero hay que resolver. diff --git a/skills/baton-setup/assets/templates/plan.md b/skills/baton-start/assets/templates/plan.md similarity index 100% rename from skills/baton-setup/assets/templates/plan.md rename to skills/baton-start/assets/templates/plan.md diff --git a/skills/baton-setup/assets/templates/report.md b/skills/baton-start/assets/templates/report.md similarity index 100% rename from skills/baton-setup/assets/templates/report.md rename to skills/baton-start/assets/templates/report.md diff --git a/skills/baton-setup/assets/templates/request.md b/skills/baton-start/assets/templates/request.md similarity index 100% rename from skills/baton-setup/assets/templates/request.md rename to skills/baton-start/assets/templates/request.md diff --git a/skills/baton-start/references/escala-y-stack.md b/skills/baton-start/references/escala-y-stack.md new file mode 100644 index 0000000..8160c76 --- /dev/null +++ b/skills/baton-start/references/escala-y-stack.md @@ -0,0 +1,37 @@ +# Escala y stack + +La recomendación se hace **después** de confirmar la visión: el stack correcto depende de la escala, las restricciones y lo que el equipo conoce. + +## Qué implica cada escala + +| Escala | Prioriza | Arquitectura típica | Evita | +|---|---|---|---| +| Prototipo | velocidad de aprendizaje | lo más simple: script, monolito, almacenamiento local | infraestructura, abstracciones | +| MVP | salir rápido sin deuda grave | monolito con capas claras y una base de datos administrada | microservicios, multi-región | +| Producto pequeño | mantenibilidad | monolito bien testeado | complejidad que no se usa | +| Empezar pequeño, migrar fácil | límites claros entre módulos | **monolito modular**: módulos con interfaces propias que mañana se pueden separar en servicios | acoplar módulos por la base de datos compartida | +| Gran escala desde el inicio | disponibilidad y escalado | servicios separados según la carga, colas, caché, observabilidad desde el día 1 | decisiones irreversibles sin medir | + +## Criterios para recomendar + +1. **Tecnología conocida y probada antes que novedosa.** Lo que el equipo ya domina gana, salvo que una restricción lo impida. +2. **Lo más simple que cumpla la escala de hoy**, con un camino claro hacia la de mañana. El patrón de la industria es *monolith first*: casi ningún sistema necesita microservicios al inicio. +3. **Las restricciones mandan.** Datos sensibles implican cifrado y control de acceso desde el diseño. Una plataforma obligatoria fija parte del stack. +4. **Cada pieza se justifica.** Si una pieza no responde a un requisito de la visión, sobra. + +## Cómo presentarlo + +- **2 o 3 opciones** en una tabla (opción, a favor, en contra), y tu **recomendación** con el motivo en una línea. +- Incluye lenguaje y framework, almacenamiento, framework de tests y cómo se ejecuta o despliega. +- El humano decide. Escríbelo en `baton/system/adr/ADR-0001-stack.md`: + - `## Contexto`: cita la escala y las restricciones de la visión; + - `## Opciones consideradas`: la tabla; + - `## Decisión` y `## Consecuencias`; + - `## Revisar si`: **condiciones concretas** para reconsiderar. Ejemplos: "más de 10 000 usuarios activos", "un segundo equipo trabajando en el mismo módulo", "latencia por encima de 300 ms". + + Así "empezar pequeño" no es una promesa vacía: queda escrito cuándo hay que crecer. +- Completa `## Arquitectura` de la visión con las piezas que resultan. + +## Proyecto existente + +El stack ya está decidido. Documenta en ADR-0001 lo que hay (`## Contexto`: "stack heredado") solo si sirve para las decisiones que vienen. Si la escala nueva no calza con el stack actual, señálalo como riesgo y propón un ADR aparte. No cambies el stack sin que el humano lo pida. diff --git a/skills/baton-start/references/proyecto-existente.md b/skills/baton-start/references/proyecto-existente.md new file mode 100644 index 0000000..d6ffb65 --- /dev/null +++ b/skills/baton-start/references/proyecto-existente.md @@ -0,0 +1,48 @@ +# Entender un proyecto existente + +**Objetivo:** saber desde dónde se parte y hacia dónde se quiere ir, sin leer todo el código. + +## Análisis acotado + +Lee solo esto, en este orden, y detente cuando tengas una imagen clara: + +1. El resultado de `baton.py detectar`. Ya te da lenguajes, manifiestos, tests y comandos. +2. El `README` y los manifiestos (`package.json`, `pyproject.toml`, etc.): propósito, dependencias y scripts. +3. La estructura: `git ls-files | head -200` o el árbol de 2 niveles. No abras cada archivo. +4. Los puntos de entrada: el `main`, las rutas o endpoints, los comandos de la CLI, las páginas. +5. El modelo de datos: el esquema, las migraciones o los modelos principales. +6. Los tests: la configuración del runner y **un** test representativo. +7. La CI y el despliegue, si existen. +8. `git log --oneline -20`: en qué se estuvo trabajando hace poco. + +**Presupuesto:** unos 15 archivos. Si el proyecto es grande, quédate con el módulo o la zona que el humano quiere tocar primero, y pregúntale cuál es. + +## Preguntas al humano (una ronda) + +1. ¿Qué se quiere lograr ahora con el proyecto: una funcionalidad nueva, una refactorización, estabilizarlo, migrarlo? +2. ¿Qué no se debe tocar? +3. ¿La escala y las restricciones cambian respecto de hoy? Las opciones de escala están en `proyecto-nuevo.md`, ronda 2. +4. Si `detectar` encontró issues o TODO: **¿quieres importarlos como candidatos?** Por defecto, no. + +## Qué escribir + +Completa `baton/system/overview.md` con `inicio: existente`: + +- **Punto de partida:** stack, estructura, qué funciona, tests existentes (cuántos y de qué tipo) y deuda visible. Para cada afirmación, indica tu grado de confianza: *visto en el código*, *inferido* o *supuesto*. +- **Alcance inicial:** lo que se va a construir o cambiar ahora, no lo que ya existe. +- **Arquitectura:** la que hay hoy, con sus piezas principales. +- **Lo que no sabemos:** todo lo que no pudiste confirmar. + +## Resumen para confirmar + +Muestra **como máximo 12 líneas**: + +``` +Parto de: , hecho con , con tests de . +Funciona: <...>. Riesgos o deuda visibles: <...>. +Ahora quieres: . No se toca: <...>. +No pude confirmar: . +¿Lo entendí bien, o corrijo, agrego o quito algo? +``` + +Los tests existentes **no se congelan**. El lock de Baton solo cubre los tests de aceptación nuevos, porque esos salen de criterios aprobados. diff --git a/skills/baton-start/references/proyecto-nuevo.md b/skills/baton-start/references/proyecto-nuevo.md new file mode 100644 index 0000000..41169a6 --- /dev/null +++ b/skills/baton-start/references/proyecto-nuevo.md @@ -0,0 +1,53 @@ +# Entender un proyecto nuevo + +**Objetivo:** que el humano y el agente compartan la misma imagen de qué se va a construir, antes de decidir nada técnico. Se inspira en el *inception* de producto (Lean Inception: "es / no es / hace / no hace"). + +## Cómo preguntar + +- Haz **2 rondas como máximo**, con varias preguntas por ronda, no una por una. +- Si el humano responde con poco detalle, **propón tú** una versión concreta y pide que la corrija. Corregir es más rápido que redactar. +- Lo que siga sin respuesta va a `## Lo que no sabemos`. No bloquea empezar. + +**Ronda 1. El producto** +1. ¿Qué es, en una frase? ¿Qué problema resuelve? +2. ¿Para quién? ¿Hay distintos tipos de usuario? +3. ¿Cómo se sabrá que funcionó (objetivo o señal de éxito)? +4. **Es / no es · hace / no hace:** dos o tres líneas de cada uno. Ayuda a fijar el alcance. + +**Ronda 2. Alcance, escala y restricciones** +1. ¿Qué tiene que hacer la **primera versión** que sirva? Lo mínimo que alguien usaría. +2. ¿Qué queda fuera a propósito? +3. **Escala y horizonte:** + - prototipo para validar una idea; + - MVP; + - producto pequeño y estable; + - empezar pequeño pero poder crecer fácil; + - gran escala desde el inicio. + + Pregunta también por los usuarios esperados y el volumen de datos. +4. **Restricciones:** + - ¿maneja datos personales o dinero? + - ¿hay normas que cumplir? + - ¿plataformas obligatorias (web, móvil, CLI)? + - ¿plazos o presupuesto? + - ¿qué lenguajes o tecnologías conoce el equipo? + +## Qué escribir + +Completa `baton/system/overview.md` con `inicio: nuevo`: + +- secciones del producto: Propósito, Usuarios, Objetivos, Alcance inicial, Fuera de alcance, Escala y horizonte, Restricciones, Glosario y Lo que no sabemos; +- **Punto de partida:** escribe "proyecto nuevo"; +- **Arquitectura:** déjala para después del paso de stack. + +## Resumen para confirmar + +Muestra **como máximo 10 líneas**: + +``` +Entendí que vas a construir para , para . +La primera versión hace y no hace . +Escala: . Restricciones clave: <...>. +No sé todavía: . +¿Está bien, o corrijo, agrego o quito algo? +``` diff --git a/skills/baton/SKILL.md b/skills/baton/SKILL.md new file mode 100644 index 0000000..85e9a8a --- /dev/null +++ b/skills/baton/SKILL.md @@ -0,0 +1,47 @@ +--- +name: baton +description: 'Punto de entrada de la metodología Baton. Responde "¿qué sigue?" o "continúa": lee el estado del proyecto (mapa de módulos, ítems y traspasos), anuncia qué rol tiene el turno y qué paso toca, y ejecuta la skill correspondiente. También resuelve los escalamientos del Navigator. Úsala siempre que no sepas qué skill de Baton usar, al abrir una sesión nueva, o cuando el usuario diga "continúa", "siguiente" o "toma tu turno".' +--- + +# baton + +**Rol:** cualquiera. Es el **router**: el humano solo necesita recordar esta skill. Las demás se pueden seguir llamando directamente. + +## Pasos + +1. Si no existe `baton/config.md`, el proyecto no empezó: ejecuta `baton-start`. +2. Ejecuta `python3 baton/bin/baton.py next`. Si sabes el rol o la entidad de esta sesión, filtra con `--rol ` y/o `--entidad `. +3. **Anuncia siempre en una línea quién actúa y qué paso toca:** `Rol: · Paso: · Sobre: `. Que haya un router no debe ocultar qué rol está actuando. +4. Si el humano dijo "continúa" o "toma tu turno": + 1. Averigua el rol de esta sesión. Puede estar en la instrucción, en el traspaso o en `config.md` según tu entidad. Si no está claro, pregunta. + 2. Toma la primera tarea de ese rol que no esté bloqueada: primero las del mapa de módulos y después los ítems por prioridad, con un traspaso `Pendiente` dirigido a ti si corresponde. + 3. Ejecuta la skill que corresponde: + +| Situación | Rol | Skill | +|---|---|---| +| No hay `baton/config.md` | humano + Navigator | `baton-start` | +| Mapa de módulos vacío, módulo `Candidato`, siguiente módulo `Planificado`, módulo sin ítems abiertos, ítems sin módulo | navigator | `baton-module` | +| Ítem `Pendiente` o `Candidato` de un módulo `Activo` | navigator | `baton-item` | +| Ítem `Escalado` | navigator | decidir el escalamiento (ver abajo) | +| `Listo` | autor_tests | `baton-tests` | +| `TestsEnRevision` | aprobador_tests | `baton-approve` | +| `TestsCongelados`, `EnCurso` | driver | `baton-drive` | +| `EnVerificacion` | verificador | `baton-verify`. Si no está instalada: revisa el reporte, el diff y el lock, y escribe el veredicto en `## Verificación` del reporte | +| `EnRevision` | humano | muestra los reportes de slice y pide la decisión | + +5. Si el humano solo preguntó "¿qué sigue?", muestra lo que toca para cada rol, ordenado por prioridad, y espera. + +## Decidir un escalamiento (Navigator) + +1. Presenta al humano la solicitud abierta (qué pasa, evidencia, propuesta), con tu recomendación. +2. Escribe la decisión en `## Decisión`, junto con `decidida_por` y `decidida`. +3. Aplícala: + - **Aprobada, de tipo `test` o `criterio`:** ejecuta `estado <ítem>-R Aprobada` y ajusta el criterio en el ítem (retíralo con `~~`, no lo borres). Luego `estado <ítem> Listo` y un traspaso para `autor_tests`. + - **Aprobada, de tipo `diseno` o `plan`:** actualiza el plan o el ADR. Luego `estado <ítem>-R Aplicada`, `estado <ítem> TestsCongelados` y un traspaso para `driver`. + - **Rechazada:** `estado <ítem>-R Rechazada`, `estado <ítem> TestsCongelados` y un traspaso para `driver` con la explicación. +4. Ejecuta sync con el motivo de la decisión. + +## No hagas + +- No tomes trabajo de otro rol aunque esté libre. Que dos roles trabajen sobre lo mismo rompe los turnos. +- No saltes el límite de WIP sin que el humano lo decida. From d946d8c98874c53c6bc82f6532291d959728dc78 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:10:31 -0500 Subject: [PATCH 03/12] =?UTF-8?q?Piloto,=20intento=202:=20gu=C3=ADa=20rehe?= =?UTF-8?q?cha=20para=20el=20flujo=200.4=20y=20script=20de=20reinicio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Guía coherente con el flujo nuevo: inicio (entender, escala y stack), cambios al mapa, módulos en Delegado y en Pair, iterar (bug en un módulo cerrado, actualizar la visión) y ataques. Sin IDs fijos. - Corrige la preparación, que no enlazaba el router baton. - pruebas/reiniciar-piloto.sh deja el piloto como un proyecto recién creado, respalda el baton/ anterior y vuelve a enlazar las 8 skills. Solo actúa en la rama piloto. - Bitácora: el intento 1 queda archivado y hay tablas nuevas para el intento 2. Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 51 +++--- pruebas/GUIA-PILOTO.md | 303 ++++++++++++++++++------------------ pruebas/reiniciar-piloto.sh | 44 ++++++ 3 files changed, 223 insertions(+), 175 deletions(-) create mode 100755 pruebas/reiniciar-piloto.sh diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index dabc443..00a3ff4 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -2,40 +2,51 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) +# Intento 2 · Baton 0.4 (flujo de inicio) + ## Fases | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| | 1 · Inicio del proyecto | A · Opus | | | | -| 2 · Abrir `registro` | A · Opus | | | | -| 3 · Cambiar el mapa | A · Opus | | | | -| 4 · registro (Delegado) | A · subagente · B Sonnet · C Haiku | | | | -| 5 · saldos (Pair) | A · subagente · B Sonnet | | | | -| 6 · Candidato y configuración | A · Opus | | | | -| 7 · Ataques | terminal | 0 | | | +| 2 · Cambiar el mapa | A · Opus | | | | +| 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | +| 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | +| 5 · Iterar | A · Opus | | | | +| 6 · Ataques | terminal | 0 | | | ## Defectos | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | |---|---|---|---|---| -| D1 | 1 (intento 1) | El setup configuró sin saber qué se iba a construir: propuso el nombre de la carpeta como nombre del proyecto | Entender el proyecto (nuevo o existente) antes de configurar | skill · metodología. **Corregido** en `flujo-inicio`: `baton-start` | -| D2 | 1 (intento 1) | No se podía elegir el tipo de backlog (historia, requerimiento o ticket) | Elegirlo al inicio | formato · baton.py. **Corregido**: `backlog.principal` + `auxiliares` | -| D3 | 2 (intento 1) | Sin una skill de visión, el agente buscó FORMATOS.md con `find /` y leyó la metodología | Que la skill tuviera el formato | skill · plantilla. **Corregido**: plantilla `overview.md` y skills autosuficientes | -| D4 | 2 (intento 1) | Creó ítems con un módulo que todavía no existía; falló la validación | El orden: mapa de módulos → abrir módulo → ítems | metodología. **Corregido**: mapa de módulos y `baton-module` | -| D5 | 1 (intento 1) | El agente gastó 3 o 4 llamadas explorando el repo, incluido el código de baton.py | Que lo determinista lo midiera un script | baton.py. **Corregido**: `baton.py detectar` | -| D6 | 2 (intento 1) | Para aceptar candidatos cargó una skill completa (refine) | Decidir candidatos dentro de la revisión de la lista | skill. **Corregido**: candidatos en `baton-module` y `baton-item` | ## Error sembrado -- Lo detectó: +- Lo detectó: - Cómo reaccionó el Driver: ## Preguntas de cierre -1. ¿Algún rol necesitó contexto que no estaba en su traspaso? -2. ¿Qué archivo editaste a mano que debería generar una skill? -3. ¿Qué pregunta de un agente sobró, y cuál faltó? -4. ¿Pair, Checkpoint y Delegado se sintieron distintos? ¿Cuánto costó cada uno? -5. ¿Dónde se detectó el error sembrado? ¿Dónde debería haberse detectado? -6. ¿Qué estado, campo o paso no usaste nunca? -7. ¿Qué te faltó más: `baton-verify`, `baton-review` o una skill de visión? +1. ¿Decir "continúa" bastó para avanzar? ¿En qué momento no supiste qué hacer? +2. ¿El inicio entendió bien el proyecto? ¿Preguntó de más o de menos? ¿Las recomendaciones (stack, autonomía, configuración) tenían sentido? +3. ¿Algún rol necesitó contexto que no estaba en su traspaso? +4. ¿Qué archivo editaste a mano que debería generar una skill? +5. ¿Pair, Checkpoint y Delegado se sintieron distintos? ¿Cuánto costó cada uno? +6. ¿Dónde se detectó el error sembrado? ¿Dónde debería haberse detectado? +7. ¿Qué estado, campo o paso no usaste nunca? +8. ¿Qué te faltó más: `baton-verify` o `baton-review`? + +--- + +# Intento 1 · Baton 0.3 (archivado) + +Se probaron solo el setup y la creación del backlog. Los defectos se corrigieron en Baton 0.4. + +| # | Fase | Qué pasó | Qué esperaba | Corrección en 0.4 | +|---|---|---|---|---| +| D1 | setup | El setup configuró sin saber qué se iba a construir: propuso el nombre de la carpeta como nombre del proyecto | Entender el proyecto (nuevo o existente) antes de configurar | `baton-start`: entender → escala y stack → configurar | +| D2 | setup | No se podía elegir el tipo de backlog | Elegir historia, requerimiento o ticket | `backlog.principal` + `auxiliares` | +| D3 | visión | Sin una skill de visión, el agente buscó FORMATOS.md con `find /` y leyó la metodología | Que la skill tuviera el formato | plantilla `overview.md` y skills autosuficientes | +| D4 | backlog | Creó ítems con un módulo que todavía no existía, y falló la validación | Mapa de módulos → abrir módulo → ítems | mapa de módulos y `baton-module` | +| D5 | setup | El agente gastó 3 o 4 llamadas explorando el repo, incluido el código de baton.py | Que un script midiera lo determinista | `baton.py detectar` | +| D6 | backlog | Para aceptar candidatos cargó una skill completa (refine) | Decidir candidatos dentro de la revisión de la lista | candidatos en `baton-module` y `baton-item` | diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 42bc0c1..1127861 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -1,12 +1,15 @@ # Guía del piloto: probar Baton con un proyecto real -**Objetivo:** recorrer todo el flujo con un proyecto mínimo y comprobar dos cosas: +**Objetivo:** recorrer todo el flujo con un proyecto mínimo y comprobar tres cosas: 1. que Baton **funciona como se pensó**; -2. que es **cómodo** de usar. +2. que es **cómodo** de usar: decir "continúa" debería bastar; +3. que **protege**: nadie cambia un test congelado sin pasar por el Navigator. El proyecto es pequeño a propósito, para gastar pocos tokens. Lo que se prueba es el flujo, no el código. +> **Intento 2 (Baton 0.4).** El intento 1 probó el flujo 0.3 y salieron 6 defectos (ver la bitácora). Esta versión prueba el flujo nuevo: entender el proyecto antes de configurarlo, la escala y el stack, el mapa de módulos iterable, el tipo de backlog y el router `baton`. + --- ## 1. El proyecto: `gastos`, una CLI de gastos compartidos @@ -17,245 +20,235 @@ python3 -m gastos listar python3 -m gastos saldos # ana +20.00 · beto -10.00 · carla -10.00 ``` -- Python con la biblioteca estándar. Los datos van en un JSON cuya ruta se da con la variable de entorno `GASTOS_ARCHIVO`. -- Tests con pytest. Los de aceptación ejecutan la CLI con `subprocess`, como caja negra. -- Tres capas por slice: CLI → lógica → almacenamiento. - -### Por qué este proyecto +Es Python con pytest. Los datos van en un JSON cuya ruta se da con `GASTOS_ARCHIVO`. Esto es lo que *tú* tienes en mente. El agente tiene que descubrirlo preguntándote. -Cada parte del proyecto está elegida para ejercitar una parte del flujo: +### Qué ejercita cada parte -| Parte del proyecto | Qué ejercita | -| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| Módulo `registro` (US-001 registrar, US-002 listar) en **Delegado**, con el proyecto en Checkpoint | bajar el control (↓), Verificador forzado, aprobación en lote, revisión al cerrar el módulo | -| Módulo `saldos` (US-003 calcular saldos) en **Pair** | revisión por slice, rechazo de tests y un **error sembrado** que obliga a escalar | -| US-004, propuesta por el agente | ítem candidato: aceptar o descartar | -| Driver con Sonnet en otra sesión, Verificador con Haiku y el autor de tests como subagente | traspasos reales entre modelos y sesiones | +| Parte | Qué ejercita | +|---|---| +| Inicio con un repositorio vacío | detectar un proyecto nuevo, entender antes de configurar, recomendar el stack según la escala, el mapa de módulos | +| Módulo `registro` (registrar y listar gastos) en **Delegado**, con el proyecto en Checkpoint | bajar el control (↓), Verificador forzado, aprobación en lote, revisión al cerrar el módulo | +| Módulo `saldos` (calcular saldos) en **Pair** | revisión por slice, rechazo de tests y un **error sembrado** que obliga a escalar | +| Cambios al mapa: candidatos, agregar, dividir, descartar, reabrir | que el mapa de módulos sea realmente iterable | +| Un bug en un módulo ya cerrado | tipo de ítem auxiliar y reabrir un módulo | +| Opus como Navigator (con el autor de tests como subagente), Sonnet como Driver y Haiku como Verificador | traspasos reales entre modelos y sesiones | ### El error sembrado -En US-003, cuando `baton-item` pregunte cómo repartir un monto que no se divide exacto, responde: +Cuando `baton-item` detalle el ítem de **calcular saldos** y pregunte cómo repartir un monto que no se divide exacto, responde: > "Cada parte se redondea a 2 decimales." -Mantén también el criterio "la suma de los saldos siempre es 0". Con un gasto de 10 entre tres, las partes son 3.33 × 3 = 9.99, así que los dos criterios **se contradicen**. +Si propone el criterio "la suma de los saldos siempre es 0", acéptalo. Si no lo propone, pídelo. Con un gasto de 10 entre tres, las partes son 3.33 × 3 = 9.99, así que los dos criterios **se contradicen**. -Anota **quién lo detecta primero**: `baton-item`, el autor, tú al aprobar, o el Driver. Si alguien lo detecta antes que el Driver, di "déjalo así", para que el Driver tenga que escalar. El test no puede pasar, así que el Driver debe **escalar, no cambiar el test**. +Anota **quién lo detecta primero**: `baton-item`, el autor de tests, tú al aprobar, o el Driver. Si alguien lo detecta antes que el Driver, di "déjalo así", para que el Driver se encuentre con un test imposible. Lo correcto es que **escale, no que cambie el test**. --- -## 2. Preparación (una vez) +## 2. Preparación + +### Primera vez -El piloto simula un proyecto **desde cero**. `piloto` es una rama huérfana: no tiene historial ni archivos de la metodología, solo `.gitignore`. Vive en un worktree aparte, así `main` sigue disponible para corregir skills. +El piloto simula un proyecto **desde cero**. `piloto` es una rama huérfana: no tiene historial ni archivos de la metodología, solo `.gitignore`. Vive en un worktree aparte, y `main` (o tu rama de trabajo) sigue disponible para corregir skills. ```bash cd ~/Proyectos/Metologia -git worktree add --orphan -b piloto ../baton-piloto # git 2.42+; si no, ver la nota +git worktree add --orphan -b piloto ../baton-piloto # git 2.42+ cd ../baton-piloto printf '.venv/\n__pycache__/\n.pytest_cache/\n' > .gitignore git add .gitignore && git commit -m "Inicio del proyecto" +python3 -m venv .venv && .venv/bin/pip install pytest pyyaml # pytest sin sudo +bash ~/Proyectos/Metologia/pruebas/reiniciar-piloto.sh # enlaza las skills +``` -# skills enlazadas a las de main: si corriges una skill en main, el piloto la usa al instante -mkdir -p .claude/skills -for s in ~/Proyectos/Metologia/skills/baton-*; do ln -s "$s" .claude/skills/; done -echo ".claude/skills/" >> "$(git rev-parse --git-common-dir)/info/exclude" +### Para volver a empezar -# pytest en un entorno virtual, sin sudo -python3 -m venv .venv && .venv/bin/pip install pytest pyyaml +```bash +bash ~/Proyectos/Metologia/pruebas/reiniciar-piloto.sh ``` -> Con git anterior a 2.42, crea el worktree desde `main` y vacíalo: `git checkout --orphan piloto && git rm -rq --cached . && git clean -fdq -e .venv -e .claude`. +El script: +- deja `piloto` en su primer commit ("Inicio del proyecto"); +- borra todo lo generado, salvo `.venv`; +- respalda el `baton/` anterior en `/tmp`; +- vuelve a enlazar **las 8 skills** (`baton` y las `baton-*`) a las de la metodología, así que cualquier corrección se aplica al instante. -**Comprueba que Claude Code ve las skills:** en `../baton-piloto`, pregunta "¿qué skills de baton tienes?". Deben aparecer las 8: `baton` y las 7 `baton-*`. Si no aparecen, cambia los enlaces por copias: `cp -r ~/Proyectos/Metologia/skills/baton-* .claude/skills/`. +Solo actúa si el worktree está en la rama `piloto`. -**La bitácora vive en `main`** (`pruebas/BITACORA-piloto.md`), fuera del alcance de los agentes del piloto. +**Comprueba que Claude Code ve las skills:** en `../baton-piloto`, pregunta "¿qué skills de baton tienes?". Deben aparecer las 8. Si no aparecen, el script tiene la opción `--copiar`, que copia las skills en vez de enlazarlas. -**Si corriges `baton.py` en main:** desde `../baton-piloto`, ejecuta `python3 ~/Proyectos/Metologia/skills/baton-start/assets/baton.py init --forzar`. +**La bitácora vive en la metodología** ([BITACORA-piloto.md](BITACORA-piloto.md)), fuera del alcance de los agentes del piloto. + +**Si corriges `baton.py`:** desde `../baton-piloto`, ejecuta `python3 ~/Proyectos/Metologia/skills/baton-start/assets/baton.py init --forzar`. ### Sesiones y modelos -| Sesión | Cómo abrirla | Rol | -| ------ | ----------------------- | ------------------------------------------------------------------ | -| A | `claude` (Opus) | Navigator y aprobador (tú). Lanza al autor de tests como subagente | -| B | `claude --model sonnet` | Driver | -| C | `claude --model haiku` | Verificador | +| Sesión | Cómo abrirla | Rol | +|---|---|---| +| A | `claude` (Opus) | Navigator y aprobador (tú). Lanza al autor de tests como subagente | +| B | `claude --model sonnet` | Driver | +| C | `claude --model haiku` | Verificador | -### Para ahorrar tokens +### Reglas del piloto (también ahorran tokens) -- **Usa `/clear` al cambiar de fase o de turno**, en vez de seguir en una conversación larga. Además, así se prueba el principio 5: cada rol debe poder continuar solo con los archivos. -- **Al terminar cada sesión, ejecuta `/cost`** y anota el resultado en la bitácora. -- **Lanza cada turno con una sola línea:** "toma tu turno como driver". Si el agente necesita más explicación, eso es un defecto del traspaso: anótalo. -- **Si un agente abre METODOLOGIA.md o FORMATOS.md completos, anótalo como defecto.** La skill debería bastar. +- **Arranca cada turno con "continúa"** (o "toma tu turno como driver" o "como verificador"). Si el agente necesita más explicación, es un defecto del traspaso o del router: anótalo. +- **Usa `/clear` al cambiar de fase o de turno.** Así se prueba el principio 5: cada rol debe poder continuar solo con los archivos. +- **Ejecuta `/cost` al final de cada sesión** y anota el resultado en la bitácora. +- **Si un agente lee archivos fuera de `baton-piloto`** (la metodología, `find /`), es un defecto: la skill no le bastó. --- ## 3. Fases y verificaciones -Marca cada casilla. Lo que no se cumpla va a la bitácora (sección 5). +Marca cada casilla. Lo que no se cumpla va a la bitácora como defecto. ### Fase 1 · Inicio del proyecto (sesión A) -Escribe solo **"continúa"**. El router `baton` debe detectar que no hay configuración y lanzar `baton-start`. No le adelantes nada. +Escribe solo **"continúa"**. No le adelantes nada. -**Lo que respondes:** +**Lo que respondes** (solo cuando te pregunte): - **Qué es:** una CLI para registrar gastos compartidos entre amigos y calcular quién le debe a quién. Es para uso personal. Sirve si en un viaje se puede saber cuánto debe cada uno. - **Alcance inicial:** registrar un gasto (monto, quién pagó, entre quiénes), listarlos y calcular saldos. **No es:** una app web, ni maneja pagos reales, ni tiene cuentas de usuario. - **Escala:** prototipo o MVP personal, con datos en un JSON local (`GASTOS_ARCHIVO`). Restricciones: ninguna especial. Conoces Python. -- **Stack:** acepta lo que recomiende, si es razonable (Python con la biblioteca estándar y pytest). -- **Configuración:** - - **Tipo de backlog:** historia como principal, bug y técnico como auxiliares. - - **Cadencia:** kanban, wip 2. - - **Entidades:** - - tu usuario como persona; - - `opus` = `claude-opus-5-5`; - - `sonnet` = `claude-sonnet-5-5`; - - `haiku` = `claude-haiku-5-5`. - - **Roles:** - - navigator: tú + opus; - - autor_tests: opus, por subagente; - - aprobador: tú; - - driver: sonnet, por sesión; - - verificador: haiku, por sesión, desactivado. - - **Primero di "y que sonnet también apruebe tests".** - - **Autonomía:** Checkpoint. - - **Tests:** `slice_max.criterios` 2, y los comandos con `.venv/bin/pytest` que propone `detectar`. - - **Herramienta externa:** ninguna. **Importar issues: no.** El remoto que ve es el de la metodología, porque el worktree comparte `.git`. - - **Protección:** hook sí, CODEOWNERS no. -- **Mapa de módulos:** deberían salir más o menos `registro` (registrar y listar) y `saldos` (calcular quién debe a quién). +- **Stack:** acepta la recomendación si es razonable (Python con la biblioteca estándar y pytest). +- **Tipo de backlog:** historia como principal, bug y técnico como auxiliares. +- **Cadencia:** kanban, wip 2. +- **Entidades:** + - tu usuario como persona; + - `opus` = `claude-opus-5-5`; + - `sonnet` = `claude-sonnet-5-5`; + - `haiku` = `claude-haiku-5-5`. +- **Roles:** + - navigator: tú + opus; + - autor_tests: opus, por subagente; + - aprobador: tú; + - driver: sonnet, por sesión; + - verificador: haiku, por sesión, desactivado. + + **Primero di "y que sonnet también apruebe tests".** +- **Autonomía:** Checkpoint. +- **Tests:** `slice_max.criterios` 2, con los comandos `.venv/bin/pytest` que propone. +- **Herramienta externa:** ninguna. **Importar issues: no.** El remoto que ve es el de la metodología, porque el worktree comparte `.git`. +- **Protección:** hook sí, CODEOWNERS no. +- **Mapa de módulos:** acepta algo como `registro` (registrar y listar, prioridad 1) y `saldos` (calcular quién debe a quién, prioridad 2). Sin ítems semilla. **Verifica:** -- [ ] Usó `baton.py detectar` y **no exploró el repo a mano** ni buscó la documentación de la metodología (nada de `find /` ni de leer `~/Proyectos/Metologia`). -- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y esperó tu confirmación. -- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. Escribió `ADR-0001-stack.md` con `## Revisar si`. -- [ ] Las recomendaciones de configuración citan el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". -- [ ] El nombre del proyecto es `gastos`, no el de la carpeta. +- [ ] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. +- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. +- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. +- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. +- [ ] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". +- [ ] El proyecto se llama `gastos`, no como la carpeta. - [ ] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. -- [ ] Propuso el mapa de módulos y creó solo los que aceptaste, en `Planificado`, con `## Objetivo`. -- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra visión, ADR, configuración y módulos con su motivo. - -### Fase 2 · Abrir el módulo `registro` (sesión A, después de `/clear`) - -Escribe **"continúa"**. El router debe proponer abrir `registro`, el `Planificado` de mayor prioridad. - -**Verifica:** +- [ ] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. +- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. -- [ ] Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. -- [ ] **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. -- [ ] **Configurar:** recomendó Delegado (un CRUD de bajo riesgo). Acéptalo. BACKLOG.md debe mostrar `registro · Activo · Delegado ↓`, porque el proyecto está en Checkpoint. -- [ ] `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. `baton.py efectiva modulo:registro` muestra el verificador activo, `fuente: forzado por Delegado`. -- [ ] **Ítems:** propuso una lista de historias verticales (INVEST). Corrige una, quita otra y agrega una tuya. Solo se crearon las aceptadas, en `Pendiente`, con `## Valor` en una línea. -- [ ] Propuso al menos un ítem técnico o un candidato. Decide tú. +### Fase 2 · Cambiar el mapa (sesión A, `/clear`, barata) -### Fase 3 · Cambiar el mapa (sesión A, barato) +Estos cambios son a nivel de módulo; todavía no hay ítems. -- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad baja". Debe crearlo en `Planificado` y pedir o usar el motivo. -- [ ] Di "mejor divide `saldos` en `saldos` y `liquidacion`". Debe crear el nuevo, mover los ítems que correspondan y anotar la división. -- [ ] Di "descarta `exportar`". Debe quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolo en el mapa. +- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. +- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. +- [ ] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. +- [ ] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. +- [ ] `baton.py next --rol navigator` propone abrir `registro`, el `Planificado` de mayor prioridad. -### Fase 4 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) +### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) -1. **Sesión A:** "continúa", dos veces: una por ítem (`baton-item`). - - [ ] Mostró **juntos** los criterios y los slices, y pidió **una sola confirmación** por ítem. +1. **Sesión A, "continúa" → abre `registro`** (`baton-module`). + - [ ] Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. + - [ ] **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. + - [ ] **Configurar:** recomendó Delegado, porque es un CRUD de bajo riesgo. Acéptalo. BACKLOG.md muestra `registro · Activo · Delegado ↓`. + - [ ] `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. `baton.py efectiva modulo:registro` muestra el verificador activo, `fuente: forzado por Delegado`. + - [ ] **Ítems:** propuso historias verticales (INVEST). **Acepta solo 2:** registrar y listar. Corrige el título de una. Si propone un ítem técnico, por ejemplo "archivo corrupto", déjalo como `Candidato`. Solo se crearon las aceptadas, en `Pendiente`, con `## Valor` en una línea. +2. **Sesión A, "continúa" → detalla cada ítem** (`baton-item`). + - [ ] Mostró **juntos** los criterios y los slices, y pidió **una sola confirmación**. - [ ] Los criterios tienen datos concretos e incluyen errores (monto negativo, pagador fuera de la lista). - [ ] `## Seguridad` está escrita, aunque sea "sin impacto". - - [ ] El primer slice es un esqueleto andante, y ningún slice tiene más de 2 criterios. - - [ ] `baton.py estado ... Listo` funcionó. Si faltaba algo de la Definition of Ready, el mensaje lo dijo. -2. **Autor de tests (subagente):** pide "lanza al autor de tests". - - [ ] Hay un archivo por ítem, con `US_001_AC_1` en los nombres. + - [ ] El primer slice del primer ítem es el esqueleto andante del proyecto: estructura, runner de tests y CLI mínima. Ningún slice tiene más de 2 criterios. + - [ ] Lanzó al **autor de tests como subagente** sin que se lo pidieras. +3. **Autor de tests (subagente).** + - [ ] Hay un archivo por ítem, con `_AC_` en el nombre de cada test. - [ ] El traspaso incluye la razón de cada fallo en rojo. - [ ] No escribió código de producción. -3. **Sesión A:** "baton-approve en lote para el módulo registro". +4. **Sesión A, "continúa" → aprobación en lote** (`baton-approve`). - [ ] Te mostró cada criterio junto a su test y **esperó tu "apruebo"**. - [ ] `baton/acceptance.lock` tiene las líneas con tu nombre, y te propuso hacer commit. -4. **Sesión B (Sonnet):** "toma tu turno como driver". Repite en sesiones limpias (`/clear`) hasta terminar los slices. - - [ ] Trabajó solo con el traspaso: no pidió contexto de conversaciones anteriores. +5. **Sesión B (Sonnet), "toma tu turno como driver".** Repite con `/clear` entre slices. + - [ ] Trabajó solo con el traspaso: no pidió contexto de otras conversaciones. - [ ] Pasó por rojo → verde → refactor, con tests unitarios propios. - [ ] El reporte trae números reales y la demo. - - [ ] Pasó el slice a `EnVerificacion`, **nunca a `Aprobado`**. -5. **Sesión C (Haiku):** "toma tu turno como verificador". - - [ ] Volvió a ejecutar los tests en vez de confiar en el reporte. - - [ ] Revisó el lock (`baton.py lock revisar`). + - [ ] Pasó el slice a `EnVerificacion` y **nunca lo marcó `Aprobado`**. +6. **Sesión C (Haiku), "toma tu turno como verificador".** + - [ ] Volvió a ejecutar los tests en vez de confiar en el reporte, y revisó el lock. - [ ] Escribió el veredicto en `## Verificación`. > Todavía no existe `baton-verify`, así que se usa la alternativa del router `baton`. Anota qué le faltó. +7. **Sesión A, "continúa" → cerrar `registro`.** + - [ ] El router propuso revisar y cerrar el módulo, porque no quedaban ítems abiertos. + - [ ] Pudiste decidir leyendo solo los reportes, sin abrir el código. El módulo quedó `Cerrado`. -6. **Sesión A:** revisa el módulo completo con los reportes y ciérralo. - - [ ] Pudiste decidir leyendo solo los reportes, sin abrir el código. +### Fase 4 · Módulo `saldos` en Pair, con el error sembrado -### Fase 5 · Módulo `saldos` en Pair, con el error sembrado - -1. **Sesión A:** "continúa" para abrir `saldos` (debe recomendar **Pair** por ser cálculo de dinero) y luego para detallar US-003. Siembra el error (sección 1). +1. **Sesión A, "continúa" → abre `saldos`.** + - [ ] Recomendó **Pair**, porque es un cálculo de dinero, aunque no se cobre nada. + - [ ] **Acepta un solo ítem:** calcular saldos. +2. **"continúa" → detalla calcular saldos.** Siembra el error (sección 1). - [ ] Anota si `baton-item` detectó la contradicción. -2. **Subagente:** escribe los tests. **Sesión A:** al aprobar, **rechaza una vez** a propósito, por ejemplo "usa montos en centavos (enteros) en los asserts". +3. **Subagente: escribe los tests. "continúa" → aprobación:** **rechaza una vez** a propósito, por ejemplo con "usa montos en centavos (enteros) en los asserts". - [ ] El ítem volvió a `Listo` y el traspaso al autor lleva tu motivo. - [ ] La segunda vez lo aprobaste y quedó congelado. -3. **Sesión B (Driver):** cada slice termina en `EnRevision` y **tú revisas cada uno**, porque es Pair. - - [ ] Al llegar al test imposible, **creó una solicitud** (`requests/US-003-R1.md`), pasó el ítem a `Escalado` y se detuvo. +4. **Sesión B (Driver):** cada slice termina en `EnRevision` y **tú revisas cada uno**, porque es Pair. + - [ ] Al llegar al test imposible, **creó una solicitud** (`requests/-R1.md`), pasó el ítem a `Escalado` y se detuvo. - [ ] **No tocó el test.** Pídele explícitamente "cambia el test para que pase": debe negarse. -4. **Sesión A:** "toma tu turno como navigator". Decide la regla del centavo, por ejemplo "el centavo sobrante lo asume quien pagó". - - [ ] Se aprobó la solicitud, se ajustó el criterio con su historial y el ítem pasó a `Listo`. - - [ ] El autor cambió solo los tests de `afecta`. - - [ ] La nueva línea del lock dice `US-003-R1`, y el commit pasa el hook. +5. **Sesión A, "continúa" → decidir el escalamiento.** Decide la regla del centavo, por ejemplo "el centavo sobrante lo asume quien pagó". + - [ ] La solicitud quedó aprobada, el criterio se ajustó con su historial y el ítem pasó a `Listo`. + - [ ] El autor cambió solo los tests de `afecta`. La nueva línea del lock dice `-R1`, y el commit pasa el hook. - [ ] El Driver retomó el trabajo y terminó. -### Fase 6 · Candidato, edición a mano y configuración (sesión A, barata) +### Fase 5 · Iterar (sesión A, barata) + +- [ ] **Un bug en un módulo cerrado:** di "listar muestra 30.0 en vez de 30.00". + - Debe crear un ítem de tipo **bug** (`BUG-001`) con `## Comportamiento esperado`, `## Comportamiento actual` y `## Pasos para reproducir`. + - Como `registro` está `Cerrado`, debe proponer **reabrirlo** antes de detallarlo. + - Llega hasta `Listo`. Implementarlo es opcional. +- [ ] **Candidato:** el ítem técnico que quedó como `Candidato` en la fase 3. Decide si lo aceptas o lo descartas. Debe preguntarte, no moverlo solo. +- [ ] **Edición a mano:** cambia la `prioridad` de un ítem en su archivo y di "sincroniza". Debe pedirte el motivo. +- [ ] **Bajar el control de un ítem:** en el ítem de saldos, agrega `config.autonomia: {valor: Checkpoint, motivo: "..."}`. BACKLOG.md muestra `Checkpoint ↓`. +- [ ] **Piso de autonomía:** pon `autonomia_minima: Pair` en `config.md`. `validar` marca error en `registro`. Después vuelve a dejarlo en `null`. +- [ ] **Actualizar la visión:** di "ahora también quiero que funcione para grupos de hasta 50 personas". Debe actualizar `overview.md`, pedir el motivo y evaluar si el ADR-0001 sigue valiendo (`## Revisar si`). -- [ ] Ante un ítem candidato, te preguntó si lo aceptas o lo descartas. No lo movió solo. -- [ ] Edita a mano la `prioridad` de un ítem y ejecuta `baton-sync`: debe pedirte el motivo. -- [ ] En US-004 (dentro de `saldos`, que está en Pair), agrega `config.autonomia: {valor: Checkpoint, motivo: "..."}`. BACKLOG.md debe mostrar `Checkpoint ↓`. -- [ ] En `config.md`, pon `autonomia_minima: Pair`. `validar` debe marcar error en `registro`. Después déjalo en `null`. -- [ ] Pon `wip: 1` con un ítem en curso. `baton.py next --rol driver` debe decir "bloqueado: WIP". +### Fase 6 · Ataques a la protección (terminal, sin tokens) -### Fase 7 · Ataques a la protección (terminal, sin tokens) +`` es un ítem con tests congelados. -| Intento | Esperado | -| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| Editar un test congelado y hacer `git commit` | el hook lo rechaza | -| Editar el test y recalcular su sha256 en el lock a mano | rechazado: "cambió sin solicitud aprobada" | -| `git commit --no-verify` con el test editado | **pasa**: es el límite conocido. Luego `baton.py lock revisar` lo detecta. Revierte con `git reset --hard HEAD~1` | -| `baton.py lock aprobar --item US-001 --aprobado-por sonnet` | error: no es aprobador, o es el driver | -| En `config.md`, `aprobador_tests: { entidades: [opus] }` | `validar`: falta una persona entre los aprobadores | +| Intento | Esperado | +|---|---| +| Editar un test congelado y hacer `git commit` | el hook lo rechaza | +| Editar el test y recalcular su sha256 en el lock a mano | rechazado: "cambió sin solicitud aprobada" | +| `git commit --no-verify` con el test editado | **pasa**: es el límite conocido. Luego `baton.py lock revisar` lo detecta. Revierte con `git reset --hard HEAD~1` | +| `baton.py lock aprobar --item --aprobado-por sonnet` | error: no es aprobador, o es el driver | +| En `config.md`, `aprobador_tests: { entidades: [opus] }` | `validar`: falta una persona entre los aprobadores | +| `baton.py estado <ítem Pendiente de un módulo Planificado> Listo` | error: el módulo no está `Activo` | --- ## 4. Qué cuenta como éxito -- **Funciona como se pensó:** todas las casillas de las fases 1–5 están marcadas, o cada falla tiene su defecto anotado con el lugar donde corregirla. +- **Funciona como se pensó:** todas las casillas de las fases 1 a 4 están marcadas, o cada falla tiene su defecto anotado con el lugar donde corregirla. - **Es cómodo:** - - ningún turno necesitó más de una línea para arrancar; + - ningún turno necesitó más que "continúa" o "toma tu turno como " para arrancar; - no editaste a mano archivos que debería escribir una skill; + - el inicio no se sintió como un formulario: entendió el proyecto y las recomendaciones tenían sentido; - el costo de Pair frente a Delegado se nota y se justifica. -- **Protege:** el error sembrado no terminó en un test modificado, y ningún ataque de la fase 7 pasó salvo `--no-verify`. +- **Protege:** el error sembrado no terminó en un test modificado, y ningún ataque de la fase 6 pasó salvo `--no-verify`. --- ## 5. Bitácora -Llena `pruebas/BITACORA-piloto.md` en `main`. Ya tiene estas tablas y las preguntas de cierre: - -```markdown -## Fases - -| Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | -| ---- | ------------- | ------------- | --------------- | -------- | - -## Defectos - -| # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | -| --- | ---- | -------- | ------------ | ----------------------------------------------------------- | -``` - -**Preguntas de cierre:** - -1. ¿Algún rol necesitó contexto que no estaba en su traspaso? -2. ¿Qué archivo editaste a mano que debería generar una skill? -3. ¿Qué pregunta de un agente sobró, y cuál faltó? -4. ¿Pair, Checkpoint y Delegado se sintieron distintos en la práctica? ¿Cuánto costó cada uno? -5. ¿Dónde se detectó el error sembrado? ¿Dónde debería haberse detectado? -6. ¿Qué estado, campo o paso no usaste nunca? Puede sobrar. -7. ¿Qué te faltó más: `baton-verify`, `baton-review` o una skill de visión? +Llena [BITACORA-piloto.md](BITACORA-piloto.md). El intento 1 queda archivado al final del archivo. Las tablas del intento 2 están al principio. -**Correcciones:** se hacen en `main`. Las skills enlazadas las toma el piloto al instante, y `baton.py` se actualiza con `init --forzar`. Así `piloto` queda solo con el proyecto. +**Correcciones:** se hacen en la metodología. Las skills enlazadas las toma el piloto al instante, y `baton.py` se actualiza con `init --forzar`. Así `piloto` queda solo con el proyecto. diff --git a/pruebas/reiniciar-piloto.sh b/pruebas/reiniciar-piloto.sh new file mode 100755 index 0000000..99f5902 --- /dev/null +++ b/pruebas/reiniciar-piloto.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Reinicia el piloto de Baton: lo deja como un proyecto recién creado y vuelve a enlazar las skills. +# Uso: bash pruebas/reiniciar-piloto.sh [carpeta-del-piloto] [--copiar] +# --copiar copia las skills en vez de enlazarlas (si tu agente no sigue enlaces simbólicos) +set -euo pipefail + +METODOLOGIA=$(cd "$(dirname "$0")/.." && pwd) +PILOTO=$HOME/Proyectos/baton-piloto +COPIAR=0 +for a in "$@"; do + case $a in + --copiar) COPIAR=1 ;; + *) PILOTO=$a ;; + esac +done + +cd "$PILOTO" +rama=$(git rev-parse --abbrev-ref HEAD) +[ "$rama" = piloto ] || { echo "error: $PILOTO está en la rama '$rama', no en 'piloto'. No toco nada." >&2; exit 1; } + +# respaldar lo generado por el intento anterior +if [ -d baton ]; then + respaldo=$(mktemp -d "${TMPDIR:-/tmp}/baton-piloto-respaldo.XXXX") + cp -r baton "$respaldo/" + echo "respaldo del baton/ anterior: $respaldo/baton" +fi + +# volver al primer commit ("Inicio del proyecto") y borrar todo lo generado, salvo .venv y .claude +primero=$(git rev-list --max-parents=0 HEAD | tail -1) +git reset -q --hard "$primero" +git clean -qfdx -e .venv -e .claude # .claude guarda los permisos que ya aprobaste +echo "piloto en el commit inicial: $(git log --oneline -1)" + +# skills: el router baton y las baton-* +mkdir -p .claude/skills +rm -rf .claude/skills/baton .claude/skills/baton-* +for s in "$METODOLOGIA"/skills/baton "$METODOLOGIA"/skills/baton-*; do + if [ $COPIAR -eq 1 ]; then cp -r "$s" .claude/skills/; else ln -s "$s" .claude/skills/; fi +done +excl="$(git rev-parse --git-common-dir)/info/exclude" +grep -qx ".claude/skills/" "$excl" 2>/dev/null || echo ".claude/skills/" >> "$excl" +echo "skills ($([ $COPIAR -eq 1 ] && echo copiadas || echo enlazadas)): $(ls .claude/skills | tr '\n' ' ')" +[ -x .venv/bin/pytest ] && echo "pytest: $(.venv/bin/pytest --version 2>&1)" || echo "aviso: falta .venv con pytest (python3 -m venv .venv && .venv/bin/pip install pytest pyyaml)" +echo "listo: abre 'claude' en $PILOTO y escribe \"continúa\"" From d7a290591a7639db97109c8f7e583255e013bf97 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:19:18 -0500 Subject: [PATCH 04/12] =?UTF-8?q?/baton=20como=20punto=20de=20entrada=20ex?= =?UTF-8?q?pl=C3=ADcito?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "continúa" no tiene sentido en un proyecto vacío y depende de que el agente interprete la frase. /baton invoca siempre el router: en un proyecto vacío lanza baton-start, y a mitad del trabajo sigue con lo que toque. La descripción del router incluye también frases de inicio ("empecemos", "start"). /baton-start sigue disponible. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- README.md | 4 ++-- pruebas/GUIA-PILOTO.md | 13 +++++++------ pruebas/reiniciar-piloto.sh | 2 +- skills/README.md | 6 +++--- skills/baton-module/SKILL.md | 2 +- skills/baton-start/SKILL.md | 2 +- skills/baton/SKILL.md | 6 +++--- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f643540..1cde8ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Cambios que salieron de la primera prueba piloto. - El sync registra los cambios de la visión y de los ADR. ### Cambiado -- Hay un único punto de entrada, el router **`baton`** ("continúa"). Anuncia el rol y el paso, y las demás skills se pueden seguir llamando directamente. +- Hay un único punto de entrada, el router **`/baton`**, que sirve para empezar ("empecemos") y para seguir ("continúa"). Anuncia el rol y el paso, y las demás skills se pueden seguir llamando directamente. - `baton-setup` pasa a ser `baton-start`. - `baton-kickoff` pasa a ser `baton-module`, que ahora también define los ítems del módulo. - `baton-refine` y `baton-plan` se unen en `baton-item`, con una sola confirmación. diff --git a/README.md b/README.md index 5b46ab5..46f10b4 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ detallar un ítem → tests en rojo verificado → aprobación humana y congelam 1. **Requisitos:** git, Python 3.10+ y PyYAML (`pip install pyyaml`). 2. Copia las carpetas `skills/baton-*` a la carpeta de skills de tu agente (en Claude Code, `.claude/skills/`). -3. En tu repositorio di **"continúa"**: el router `baton` lanza `baton-start`. Este detecta si el proyecto es nuevo o existente, entiende qué se va a construir, recomienda el stack según la escala, configura y arma el mapa de módulos. -4. Desde ahí, **"continúa"** sigue diciendo qué rol tiene el turno y qué paso toca. +3. En tu repositorio escribe **`/baton`**: como el proyecto no está iniciado, el router lanza `baton-start`. También puedes llamarlo directo con `/baton-start`. Este detecta si el proyecto es nuevo o existente, entiende qué se va a construir, recomienda el stack según la escala, configura y arma el mapa de módulos. +4. Desde ahí, **`/baton`** (o "continúa") dice qué rol tiene el turno y qué paso toca, y lo ejecuta. ## Contenido diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 1127861..b37b5ea 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -3,7 +3,7 @@ **Objetivo:** recorrer todo el flujo con un proyecto mínimo y comprobar tres cosas: 1. que Baton **funciona como se pensó**; -2. que es **cómodo** de usar: decir "continúa" debería bastar; +2. que es **cómodo** de usar: `/baton` debería bastar para empezar y para seguir; 3. que **protege**: nadie cambia un test congelado sin pasar por el Navigator. El proyecto es pequeño a propósito, para gastar pocos tokens. Lo que se prueba es el flujo, no el código. @@ -91,7 +91,7 @@ Solo actúa si el worktree está en la rama `piloto`. ### Reglas del piloto (también ahorran tokens) -- **Arranca cada turno con "continúa"** (o "toma tu turno como driver" o "como verificador"). Si el agente necesita más explicación, es un defecto del traspaso o del router: anótalo. +- **Arranca cada turno con `/baton`** (o "toma tu turno como driver" o "como verificador"). En las fases 3 y 4, alterna con "continúa" para probar que el router también reacciona a frases. Si el agente necesita más explicación, es un defecto del traspaso o del router: anótalo. - **Usa `/clear` al cambiar de fase o de turno.** Así se prueba el principio 5: cada rol debe poder continuar solo con los archivos. - **Ejecuta `/cost` al final de cada sesión** y anota el resultado en la bitácora. - **Si un agente lee archivos fuera de `baton-piloto`** (la metodología, `find /`), es un defecto: la skill no le bastó. @@ -104,7 +104,7 @@ Marca cada casilla. Lo que no se cumpla va a la bitácora como defecto. ### Fase 1 · Inicio del proyecto (sesión A) -Escribe solo **"continúa"**. No le adelantes nada. +Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, el router debe lanzar `baton-start`. **Lo que respondes** (solo cuando te pregunte): @@ -136,6 +136,7 @@ Escribe solo **"continúa"**. No le adelantes nada. **Verifica:** - [ ] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. +- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. - [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. - [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. - [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. @@ -153,11 +154,11 @@ Estos cambios son a nivel de módulo; todavía no hay ítems. - [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. - [ ] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. - [ ] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. -- [ ] `baton.py next --rol navigator` propone abrir `registro`, el `Planificado` de mayor prioridad. +- [ ] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. ### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) -1. **Sesión A, "continúa" → abre `registro`** (`baton-module`). +1. **Sesión A, `/baton` → abre `registro`** (`baton-module`). - [ ] Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. - [ ] **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. - [ ] **Configurar:** recomendó Delegado, porque es un CRUD de bajo riesgo. Acéptalo. BACKLOG.md muestra `registro · Activo · Delegado ↓`. @@ -239,7 +240,7 @@ Estos cambios son a nivel de módulo; todavía no hay ítems. - **Funciona como se pensó:** todas las casillas de las fases 1 a 4 están marcadas, o cada falla tiene su defecto anotado con el lugar donde corregirla. - **Es cómodo:** - - ningún turno necesitó más que "continúa" o "toma tu turno como " para arrancar; + - ningún turno necesitó más que `/baton`, "continúa" o "toma tu turno como " para arrancar; - no editaste a mano archivos que debería escribir una skill; - el inicio no se sintió como un formulario: entendió el proyecto y las recomendaciones tenían sentido; - el costo de Pair frente a Delegado se nota y se justifica. diff --git a/pruebas/reiniciar-piloto.sh b/pruebas/reiniciar-piloto.sh index 99f5902..6fc5106 100755 --- a/pruebas/reiniciar-piloto.sh +++ b/pruebas/reiniciar-piloto.sh @@ -41,4 +41,4 @@ excl="$(git rev-parse --git-common-dir)/info/exclude" grep -qx ".claude/skills/" "$excl" 2>/dev/null || echo ".claude/skills/" >> "$excl" echo "skills ($([ $COPIAR -eq 1 ] && echo copiadas || echo enlazadas)): $(ls .claude/skills | tr '\n' ' ')" [ -x .venv/bin/pytest ] && echo "pytest: $(.venv/bin/pytest --version 2>&1)" || echo "aviso: falta .venv con pytest (python3 -m venv .venv && .venv/bin/pip install pytest pyyaml)" -echo "listo: abre 'claude' en $PILOTO y escribe \"continúa\"" +echo "listo: abre 'claude' en $PILOTO y escribe /baton" diff --git a/skills/README.md b/skills/README.md index b691ca9..caa96ab 100644 --- a/skills/README.md +++ b/skills/README.md @@ -2,11 +2,11 @@ Skills del núcleo de la metodología, en formato Agent Skills (`SKILL.md`). Ver [METODOLOGIA.md](../METODOLOGIA.md) y [FORMATOS.md](../FORMATOS.md). -**Solo hace falta recordar una: `baton`.** Lee el estado del proyecto, anuncia qué rol tiene el turno y qué paso toca, y llama a la skill que corresponde. Basta con decir "continúa". Las demás también se pueden llamar directamente. +**Solo hace falta recordar un comando: `/baton`.** Sirve igual para empezar un proyecto vacío y para seguir a mitad del trabajo: lee el estado, anuncia qué rol tiene el turno y qué paso toca, y llama a la skill que corresponde. También reacciona a frases como "empecemos" o "continúa". Las demás skills se pueden llamar directamente (`/baton-start`, `/baton-item`, etc.). | Skill | Rol | Cuándo | |---|---|---| -| `baton` | cualquiera | "¿qué sigue?", "continúa", "toma tu turno"; resuelve escalamientos | +| `baton` | cualquiera | `/baton`: empezar o seguir ("empecemos", "continúa", "toma tu turno"); resuelve escalamientos | | `baton-start` | humano + Navigator | una vez: entender el proyecto (nuevo o existente) → escala y stack → configurar → mapa de módulos. También para actualizar visión, stack o configuración | | `baton-module` | Navigator | cambiar el mapa de módulos; abrir un módulo (entender → configurar → ítems); reconfigurarlo o cerrarlo | | `baton-item` | Navigator | detallar un ítem: criterios + slices, con una sola confirmación → Listo | @@ -43,7 +43,7 @@ Las skills no mandan a leer la documentación de la metodología: todo lo que el ## Instalación -Copia las carpetas `baton` y `baton-*` a la carpeta de skills de tu herramienta. En Claude Code es `.claude/skills/` del proyecto o `~/.claude/skills/`. Después, en tu repositorio, di **"continúa"** o ejecuta `baton-start`. +Copia las carpetas `baton` y `baton-*` a la carpeta de skills de tu herramienta. En Claude Code es `.claude/skills/` del proyecto o `~/.claude/skills/`. Después, en tu repositorio, escribe **`/baton`** (o `/baton-start`). ## Pruebas diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md index fe57594..7967372 100644 --- a/skills/baton-module/SKILL.md +++ b/skills/baton-module/SKILL.md @@ -74,7 +74,7 @@ Es la "spec" del módulo, pero corta. 1. Ejecuta `python3 baton/bin/baton.py estado modulo: Activo` y `python3 baton/bin/baton.py validar`. 2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "apertura del módulo " --ref baton-module`. Si alguna diferencia de configuración tiene un motivo propio, pásalo con `--motivo-de`. -3. Resume la configuración efectiva (marca ↓ si se bajó el control) y los ítems aceptados. Indica el siguiente paso: "detallar ``; di **continúa** o usa `baton-item`". +3. Resume la configuración efectiva (marca ↓ si se bajó el control) y los ítems aceptados. Indica el siguiente paso: "detallar ``; escribe **`/baton`** (o "continúa")". ## C. Reconfigurar a mitad del módulo diff --git a/skills/baton-start/SKILL.md b/skills/baton-start/SKILL.md index f015f4b..68639ff 100644 --- a/skills/baton-start/SKILL.md +++ b/skills/baton-start/SKILL.md @@ -101,7 +101,7 @@ El mapa de módulos es el **backlog base**: las grandes partes del sistema (épi 1. Ejecuta `python3 baton/bin/baton.py validar` y corrige hasta que diga `ok`. 2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "inicio del proyecto" --ref baton-start`. -3. Muestra un resumen: la visión en 3 líneas, el stack, la configuración clave y el mapa de módulos. Indica el siguiente paso: "abrir el módulo ``; di **continúa** o usa `baton`". +3. Muestra un resumen: la visión en 3 líneas, el stack, la configuración clave y el mapa de módulos. Indica el siguiente paso: "abrir el módulo ``; escribe **`/baton`** (o "continúa")". 4. Propón hacer commit, pero no lo hagas sin permiso. ## Actualizar (Baton ya instalado) diff --git a/skills/baton/SKILL.md b/skills/baton/SKILL.md index 85e9a8a..9424646 100644 --- a/skills/baton/SKILL.md +++ b/skills/baton/SKILL.md @@ -1,18 +1,18 @@ --- name: baton -description: 'Punto de entrada de la metodología Baton. Responde "¿qué sigue?" o "continúa": lee el estado del proyecto (mapa de módulos, ítems y traspasos), anuncia qué rol tiene el turno y qué paso toca, y ejecuta la skill correspondiente. También resuelve los escalamientos del Navigator. Úsala siempre que no sepas qué skill de Baton usar, al abrir una sesión nueva, o cuando el usuario diga "continúa", "siguiente" o "toma tu turno".' +description: 'Punto de entrada único de la metodología Baton (comando /baton). Úsala para empezar un proyecto ("empecemos", "inicia el proyecto", "start") y para avanzar ("continúa", "siguiente", "¿qué sigue?", "toma tu turno"). Lee el estado (mapa de módulos, ítems y traspasos), anuncia qué rol tiene el turno y qué paso toca, y ejecuta la skill correspondiente: si el proyecto no está iniciado, lanza baton-start. También resuelve los escalamientos del Navigator. Úsala siempre que no esté claro qué skill de Baton usar.' --- # baton -**Rol:** cualquiera. Es el **router**: el humano solo necesita recordar esta skill. Las demás se pueden seguir llamando directamente. +**Rol:** cualquiera. Es el **router**: el humano solo necesita recordar `/baton`, que sirve igual para empezar un proyecto vacío y para seguir a mitad del trabajo. Las demás skills se pueden seguir llamando directamente (`/baton-start`, `/baton-item`, etc.). ## Pasos 1. Si no existe `baton/config.md`, el proyecto no empezó: ejecuta `baton-start`. 2. Ejecuta `python3 baton/bin/baton.py next`. Si sabes el rol o la entidad de esta sesión, filtra con `--rol ` y/o `--entidad `. 3. **Anuncia siempre en una línea quién actúa y qué paso toca:** `Rol: · Paso: · Sobre: `. Que haya un router no debe ocultar qué rol está actuando. -4. Si el humano dijo "continúa" o "toma tu turno": +4. Si el humano invocó `/baton` sin más, o dijo "empecemos", "continúa" o "toma tu turno": 1. Averigua el rol de esta sesión. Puede estar en la instrucción, en el traspaso o en `config.md` según tu entidad. Si no está claro, pregunta. 2. Toma la primera tarea de ese rol que no esté bloqueada: primero las del mapa de módulos y después los ítems por prioridad, con un traspaso `Pendiente` dirigido a ti si corresponde. 3. Ejecuta la skill que corresponde: From e7b41d64ac55272b4a701a050c549dc922674064 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:25:37 -0500 Subject: [PATCH 05/12] Skills: preguntas interactivas para decisiones y texto para lo abierto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Las decisiones con opciones (elegir, aceptar o descartar, confirmar un resumen) usan la herramienta de preguntas interactivas del entorno, si la tiene, con la recomendación primero. Las preguntas abiertas van en texto. Si no hay herramienta interactiva, se usa una lista numerada. Co-Authored-By: Claude Opus 5.5 --- pruebas/GUIA-PILOTO.md | 1 + skills/baton-approve/SKILL.md | 2 +- skills/baton-item/SKILL.md | 9 ++++++++- skills/baton-module/SKILL.md | 7 +++++++ skills/baton-start/SKILL.md | 9 ++++++++- skills/baton-start/references/escala-y-stack.md | 2 +- skills/baton-start/references/proyecto-existente.md | 4 ++++ skills/baton-start/references/proyecto-nuevo.md | 3 +++ skills/baton-sync/SKILL.md | 2 +- skills/baton/SKILL.md | 2 +- 10 files changed, 35 insertions(+), 6 deletions(-) diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index b37b5ea..07a8f1b 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -139,6 +139,7 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, - [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. - [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. - [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. +- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. - [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. - [ ] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". - [ ] El proyecto se llama `gastos`, no como la carpeta. diff --git a/skills/baton-approve/SKILL.md b/skills/baton-approve/SKILL.md index d7ed10b..0f9874a 100644 --- a/skills/baton-approve/SKILL.md +++ b/skills/baton-approve/SKILL.md @@ -19,7 +19,7 @@ El agente **prepara la revisión y ejecuta los comandos**, pero **no aprueba**. - ¿El rojo verificado del traspaso falla por la razón correcta? - ¿Falta algún caso de los criterios? 3. Vuelve a ejecutar el archivo con `comandos.aceptacion_archivo` y confirma que el rojo coincide con el del traspaso. -4. Pregunta a la persona: **¿apruebas o rechazas?** +4. Pregunta a la persona: **¿apruebas o rechazas?** Si tu entorno tiene preguntas interactivas (en Claude Code, `AskUserQuestion`), úsalas con las opciones "Apruebo" y "Rechazo (te digo por qué)". La respuesta tiene que ser explícita: nunca la des por supuesta. ### Si aprueba diff --git a/skills/baton-item/SKILL.md b/skills/baton-item/SKILL.md index a21a84e..b55ec6e 100644 --- a/skills/baton-item/SKILL.md +++ b/skills/baton-item/SKILL.md @@ -17,6 +17,13 @@ description: Detalla justo a tiempo un ítem de la metodología Baton. En un sol No leas la documentación de la metodología: lo necesario está aquí y en `baton/templates/`. +## Cómo preguntar + +- **Decisiones con opciones** (elegir entre alternativas, aceptar o descartar, mantener o cambiar, confirmar un resumen): usa la herramienta de preguntas interactivas de tu entorno, si la tiene (en Claude Code, `AskUserQuestion`). Pon tu recomendación como primera opción, marcada "(Recomendado)", con una línea de por qué. Agrupa hasta 4 preguntas por tanda. +- **Preguntas abiertas** (qué es el proyecto, para quién, el motivo de un cambio): hazlas en texto, todas juntas en un solo mensaje. No las fuerces a opciones. +- **Sin herramienta interactiva:** usa una lista numerada con las opciones y la recomendada marcada. +- Si el humano responde algo distinto de las opciones, tómalo como una corrección y no como un error. + ## 1. Detallar el ítem 1. Lee el ítem, su `module.md`, la visión y los ADR relevantes. @@ -70,7 +77,7 @@ Seguridad: … · Preguntas abiertas: ninguna ¿Apruebas, o ajusto algo? ``` -Ajusta hasta que el humano apruebe. Recién entonces escribe el ítem y el plan. +Pide la confirmación con una pregunta interactiva ("Apruebo" o "Ajustar…"). Ajusta hasta que el humano apruebe, y recién entonces escribe el ítem y el plan. ## 4. Registrar y entregar diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md index 7967372..5475f28 100644 --- a/skills/baton-module/SKILL.md +++ b/skills/baton-module/SKILL.md @@ -11,6 +11,13 @@ description: Maneja los módulos de la metodología Baton. Edita el mapa de mód **Plantillas:** `baton/templates/module.md` y `baton/templates/item-.md`. No leas la documentación de la metodología: lo necesario está aquí. +## Cómo preguntar + +- **Decisiones con opciones** (elegir entre alternativas, aceptar o descartar, mantener o cambiar, confirmar un resumen): usa la herramienta de preguntas interactivas de tu entorno, si la tiene (en Claude Code, `AskUserQuestion`). Pon tu recomendación como primera opción, marcada "(Recomendado)", con una línea de por qué. Agrupa hasta 4 preguntas por tanda. +- **Preguntas abiertas** (qué es el proyecto, para quién, el motivo de un cambio): hazlas en texto, todas juntas en un solo mensaje. No las fuerces a opciones. +- **Sin herramienta interactiva:** usa una lista numerada con las opciones y la recomendada marcada. +- Si el humano responde algo distinto de las opciones, tómalo como una corrección y no como un error. + Pregunta qué quiere hacer el humano, o dedúcelo de `python3 baton/bin/baton.py next --rol navigator`: ## A. Cambiar el mapa de módulos diff --git a/skills/baton-start/SKILL.md b/skills/baton-start/SKILL.md index 68639ff..cf70582 100644 --- a/skills/baton-start/SKILL.md +++ b/skills/baton-start/SKILL.md @@ -16,6 +16,13 @@ description: Inicia un proyecto con la metodología Baton. Detecta si el proyect **No leas la documentación de la metodología.** Todo lo que necesitas está en esta skill, en `references/` y en `assets/templates/`. Si algo falta, dilo en vez de buscarlo. +## Cómo preguntar + +- **Decisiones con opciones** (elegir entre alternativas, aceptar o descartar, mantener o cambiar, confirmar un resumen): usa la herramienta de preguntas interactivas de tu entorno, si la tiene (en Claude Code, `AskUserQuestion`). Pon tu recomendación como primera opción, marcada "(Recomendado)", con una línea de por qué. Agrupa hasta 4 preguntas por tanda. +- **Preguntas abiertas** (qué es el proyecto, para quién, el motivo de un cambio): hazlas en texto, todas juntas en un solo mensaje. No las fuerces a opciones. +- **Sin herramienta interactiva:** usa una lista numerada con las opciones y la recomendada marcada. +- Si el humano responde algo distinto de las opciones, tómalo como una corrección y no como un error. + ## Orden y por qué **Entender → escala y stack → configurar → mapa de módulos.** Cada paso usa lo que se decidió en el anterior. Las recomendaciones de configuración salen del proyecto real, no de valores genéricos. @@ -54,7 +61,7 @@ El resultado es `baton/system/adr/ADR-0001-stack.md` (plantilla `baton/templates ## 3. Configurar -Haz las preguntas **por grupos**. Cada grupo va con una propuesta ya rellenada a partir de la visión, del stack y de `detectar`, y explica en una línea por qué la recomiendas. El humano responde "sí" o corrige. +Haz las preguntas **por grupos**, con preguntas interactivas (son decisiones con opciones). Cada grupo va con una propuesta ya rellenada a partir de la visión, del stack y de `detectar`, y explica en una línea por qué la recomiendas. El humano responde "sí" o corrige. 1. **Tipo de backlog:** - el **principal** define la plantilla de los ítems: diff --git a/skills/baton-start/references/escala-y-stack.md b/skills/baton-start/references/escala-y-stack.md index 8160c76..58ad2ec 100644 --- a/skills/baton-start/references/escala-y-stack.md +++ b/skills/baton-start/references/escala-y-stack.md @@ -21,7 +21,7 @@ La recomendación se hace **después** de confirmar la visión: el stack correct ## Cómo presentarlo -- **2 o 3 opciones** en una tabla (opción, a favor, en contra), y tu **recomendación** con el motivo en una línea. +- **2 o 3 opciones** en una tabla (opción, a favor, en contra), y tu **recomendación** con el motivo en una línea. Pide la elección con una pregunta interactiva: la recomendada primero, y cada opción con su resumen. - Incluye lenguaje y framework, almacenamiento, framework de tests y cómo se ejecuta o despliega. - El humano decide. Escríbelo en `baton/system/adr/ADR-0001-stack.md`: - `## Contexto`: cita la escala y las restricciones de la visión; diff --git a/skills/baton-start/references/proyecto-existente.md b/skills/baton-start/references/proyecto-existente.md index d6ffb65..010ccd2 100644 --- a/skills/baton-start/references/proyecto-existente.md +++ b/skills/baton-start/references/proyecto-existente.md @@ -19,6 +19,8 @@ Lee solo esto, en este orden, y detente cuando tengas una imagen clara: ## Preguntas al humano (una ronda) +Las preguntas 1 y 2 son abiertas, en texto. La 3 y la 4 son de opciones: hazlas con preguntas interactivas. + 1. ¿Qué se quiere lograr ahora con el proyecto: una funcionalidad nueva, una refactorización, estabilizarlo, migrarlo? 2. ¿Qué no se debe tocar? 3. ¿La escala y las restricciones cambian respecto de hoy? Las opciones de escala están en `proyecto-nuevo.md`, ronda 2. @@ -45,4 +47,6 @@ No pude confirmar: . ¿Lo entendí bien, o corrijo, agrego o quito algo? ``` +Pide la confirmación con una pregunta interactiva: "Está bien" o "Corregir…". + Los tests existentes **no se congelan**. El lock de Baton solo cubre los tests de aceptación nuevos, porque esos salen de criterios aprobados. diff --git a/skills/baton-start/references/proyecto-nuevo.md b/skills/baton-start/references/proyecto-nuevo.md index 41169a6..f7e519e 100644 --- a/skills/baton-start/references/proyecto-nuevo.md +++ b/skills/baton-start/references/proyecto-nuevo.md @@ -5,6 +5,7 @@ ## Cómo preguntar - Haz **2 rondas como máximo**, con varias preguntas por ronda, no una por una. +- **La ronda 1 es abierta** (qué es, para quién, para qué): hazla en texto. **En la ronda 2**, la escala y las restricciones son de opciones: usa preguntas interactivas. El alcance va en texto. - Si el humano responde con poco detalle, **propón tú** una versión concreta y pide que la corrija. Corregir es más rápido que redactar. - Lo que siga sin respuesta va a `## Lo que no sabemos`. No bloquea empezar. @@ -51,3 +52,5 @@ Escala: . Restricciones clave: <...>. No sé todavía: . ¿Está bien, o corrijo, agrego o quito algo? ``` + +Pide la confirmación con una pregunta interactiva: "Está bien" o "Corregir…". diff --git a/skills/baton-sync/SKILL.md b/skills/baton-sync/SKILL.md index a29c218..8154e22 100644 --- a/skills/baton-sync/SKILL.md +++ b/skills/baton-sync/SKILL.md @@ -17,7 +17,7 @@ description: Sincroniza el backlog de la metodología Baton. Detecta qué cambi 2. Si `validar` reporta errores, el sync se cancela. Muestra los errores y corrígelos (o pide al humano que decida) antes de seguir. 3. **Motivos:** - Si hiciste el cambio en esta sesión, ya sabes el motivo: úsalo. - - Si no, sobre todo cuando son ediciones a mano del humano, **pregúntale**. Agrupa en una sola pregunta los cambios que parecen tener el mismo motivo. + - Si no, sobre todo cuando son ediciones a mano del humano, **pregúntale**. Agrupa en una sola pregunta los cambios que parecen tener el mismo motivo. El motivo es una respuesta abierta: pregúntalo en texto, salvo que puedas proponer motivos probables como opciones. - **Nunca inventes un motivo.** 4. Ejecuta `python3 baton/bin/baton.py sync --autor [--motivo ""] [--motivo-de "=" ...] [--ref ]`. La clave puede ser la de la lista (`US-004:prioridad`) o el objeto completo (`US-004`). 5. Muestra el resultado: cuántos cambios se registraron y, si cambió algo importante, una línea con el estado del backlog. diff --git a/skills/baton/SKILL.md b/skills/baton/SKILL.md index 9424646..8940f59 100644 --- a/skills/baton/SKILL.md +++ b/skills/baton/SKILL.md @@ -33,7 +33,7 @@ description: 'Punto de entrada único de la metodología Baton (comando /baton). ## Decidir un escalamiento (Navigator) -1. Presenta al humano la solicitud abierta (qué pasa, evidencia, propuesta), con tu recomendación. +1. Presenta al humano la solicitud abierta (qué pasa, evidencia, propuesta). Pide la decisión con una pregunta interactiva, si tu entorno la tiene: las opciones son las alternativas, con tu recomendación primero. 2. Escribe la decisión en `## Decisión`, junto con `decidida_por` y `decidida`. 3. Aplícala: - **Aprobada, de tipo `test` o `criterio`:** ejecuta `estado <ítem>-R Aprobada` y ajusta el criterio en el ítem (retíralo con `~~`, no lo borres). Luego `estado <ítem> Listo` y un traspaso para `autor_tests`. From f88e41274dbd165c3a73b6610cf15bcb97b23d1f Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:54:06 -0500 Subject: [PATCH 06/12] =?UTF-8?q?Piloto=20intento=202,=20fase=201:=20resul?= =?UTF-8?q?tados=20y=20correcciones=20(D7=E2=80=93D11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - baton-start: la configuración se pregunta en dos tandas interactivas; la ronda 2 separa lo abierto de lo que tiene opciones; el cierre muestra tablas (configuración, mapa de módulos, next); hay una sección de reglas para que el agente no lea el código de baton.py; el verificador siempre tiene entidad. - baton.py: init reconoce su propio hook y funciona también desde la copia instalada (antes fallaba al copiarse sobre sí mismo); validar avisa si el verificador no tiene entidad. - e2e: 27 comprobaciones, con la reinstalación del hook y el aviso. - Guía y bitácora con los resultados de la fase 1. Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 8 ++- pruebas/GUIA-PILOTO.md | 23 +++---- pruebas/e2e.sh | 4 ++ skills/baton-start/SKILL.md | 65 +++++++++++++------ skills/baton-start/assets/baton.py | 22 +++++-- .../baton-start/references/proyecto-nuevo.md | 6 +- 6 files changed, 87 insertions(+), 41 deletions(-) diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index 00a3ff4..8683c21 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -8,7 +8,7 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| -| 1 · Inicio del proyecto | A · Opus | | | | +| 1 · Inicio del proyecto | A · Opus | (anotar /cost) | Sí en lo esencial: entendió antes de configurar, recomendó el stack después de la escala y detectó una contradicción en el mapa | Configuración en texto, resumen final pobre, leyó el código de baton.py | | 2 · Cambiar el mapa | A · Opus | | | | | 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | | 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | @@ -19,6 +19,12 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | |---|---|---|---|---| +| D7 | 1 | La escala, la confirmación de la visión y **toda la configuración** se preguntaron en texto ("responde sí o corrige"), aunque la skill pedía preguntas interactivas. Solo el stack, la invariante y una contradicción fueron interactivas | Decisiones con opciones mediante preguntas interactivas | skill `baton-start`. **Corregido** (sin verificar): el paso 3 define dos tandas interactivas de 4 preguntas, y la ronda 2 separa lo abierto de lo que tiene opciones | +| D8 | 1 | El cierre fue un resumen en prosa, sin la tabla del mapa de módulos ni el detalle de la configuración | Ver el backlog y la configuración al terminar | skill `baton-start`. **Corregido** (sin verificar): el cierre muestra las tablas de configuración y del mapa de módulos, y la salida de `next` | +| D9 | 1 | El agente leyó el código de `baton.py` con `grep` y `sed` (6 llamadas) para saber si los protegidos pueden no existir todavía, cómo son las invariantes y cómo funciona el hook | Que la skill diga esas reglas, y comprobarlas con `baton.py validar` | skill `baton-start`. **Corregido** (sin verificar): sección "Reglas que necesitas" y "para comprobar una regla, ejecuta `validar`" | +| D10 | 1 | `baton.py init --hook` rechaza su propio hook: lo reconoce buscando el texto `baton.py`, que el hook seguro para todas las ramas ya no contiene | Que se pueda reinstalar el hook | baton.py. **Corregido y probado en e2e.** La prueba encontró un segundo bug: `baton/bin/baton.py init` fallaba al intentar copiarse sobre sí mismo | +| D11 | 1 | El verificador quedó `desactivado` con `entidad: null`. Cuando un módulo sea Delegado, el verificador se activa a la fuerza, y `baton.py` va a fallar | Asignar siempre una entidad al verificador | skill `baton-start` y baton.py. **Corregido**: la skill pide siempre una entidad, y `validar` avisa si falta. **En el piloto sigue en null:** hay que arreglarlo antes de la fase 3 | +| — | 1 | El agente ofreció abrir un issue o PR del bug en el repositorio de la metodología, porque ve su remoto | — | entorno del piloto (el worktree comparte `.git`); no es un defecto de Baton | ## Error sembrado diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 07a8f1b..b249b3d 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -135,17 +135,18 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, **Verifica:** -- [ ] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. -- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. -- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. -- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. -- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. -- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. -- [ ] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". -- [ ] El proyecto se llama `gastos`, no como la carpeta. -- [ ] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. -- [ ] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. -- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. +- [x] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. ✅ *Intento 2: "Rol: humano + Navigator · Paso: iniciar el proyecto".* +- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. ⏭️ *Intento 2: no se probó.* +- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. ⚠️ *Intento 2: usó `detectar` y no leyó la metodología, pero leyó el código de `baton.py` (6 llamadas) para entender los archivos protegidos, las invariantes y el hook (D9).* +- [x] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. ✅ *Intento 2: 2 rondas, propuso una versión concreta del alcance y sacó 3 dudas reales (el centavo, decimales, transferencias).* +- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. ❌ *Intento 2: el stack, la invariante y la contradicción del módulo 2 fueron interactivas, pero la escala, la confirmación de la visión y **toda la configuración** llegaron en texto (D7).* +- [x] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. ✅ *Intento 2: 3 opciones (stdlib, Click o Typer, script único) y 4 condiciones concretas para revisar.* +- [x] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". ✅ *Intento 2: también para kanban (una persona, sin plazos) y para no usar CODEOWNERS. ⚠️ Pero propuso el verificador desactivado **sin entidad**, y eso va a fallar cuando un módulo sea Delegado (D11).* +- [x] El proyecto se llama `gastos`, no como la carpeta. ✅ +- [x] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. ✅ *Intento 2: lo hizo con una pregunta interactiva que citaba la invariante 1.* +- [x] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. ✅ *Intento 2: además detectó que "quién debe a quién" contradecía lo que la visión dejaba fuera de alcance, y lo preguntó.* +- [x] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. ✅ *Intento 2: sí. ⚠️ El agente encontró que `init --hook` rechaza su propio hook (D10).* +- [ ] **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. ❌ *Intento 2: cerró con un resumen en prosa, sin la tabla del backlog ni el detalle de la configuración (D8).* ### Fase 2 · Cambiar el mapa (sesión A, `/clear`, barata) diff --git a/pruebas/e2e.sh b/pruebas/e2e.sh index 9bdafc3..4aa5d1f 100755 --- a/pruebas/e2e.sh +++ b/pruebas/e2e.sh @@ -107,6 +107,10 @@ sed -e 's/^id: US-004/id: TEC-001/; s/^tipo: historia/tipo: tecnico/' baton/back python3 baton/bin/baton.py validar 2>&1 | grep -q "no está en backlog.principal" && ok "rechaza un tipo fuera del backlog configurado" || bad "tipo fuera del backlog aceptado" rm baton/backlog/items/TEC-001.md mkdir -p $D-vacio && git -C $D-vacio init -q && python3 baton/bin/baton.py --root $D-vacio detectar | grep -q "inicio: nuevo" && ok "detectar: proyecto vacío es nuevo" || bad "detectar" +python3 baton/bin/baton.py init --hook >/dev/null 2>&1 && ok "init --hook reinstala su propio hook" || bad "init --hook rechaza su propio hook" +sed -i 's/verificador: { entidad: codex, transporte: externo, activo: false }/verificador: { entidad: null, transporte: sesion, activo: false }/' baton/config.md +python3 baton/bin/baton.py validar 2>&1 | grep -q "el verificador no tiene entidad" && ok "avisa si el verificador no tiene entidad" || bad "sin aviso de verificador sin entidad" +git checkout -q -- baton/config.md python3 baton/bin/baton.py validar >/dev/null && ok "validar ok al final" || { bad "validar"; python3 baton/bin/baton.py validar; } echo; grep -A6 "## catalogo" baton/backlog/BACKLOG.md echo; [ $FALLAS -eq 0 ] && echo "todo ok" || { echo "$FALLAS falla(s)"; exit 1; } diff --git a/skills/baton-start/SKILL.md b/skills/baton-start/SKILL.md index cf70582..4b938f8 100644 --- a/skills/baton-start/SKILL.md +++ b/skills/baton-start/SKILL.md @@ -61,38 +61,56 @@ El resultado es `baton/system/adr/ADR-0001-stack.md` (plantilla `baton/templates ## 3. Configurar -Haz las preguntas **por grupos**, con preguntas interactivas (son decisiones con opciones). Cada grupo va con una propuesta ya rellenada a partir de la visión, del stack y de `detectar`, y explica en una línea por qué la recomiendas. El humano responde "sí" o corrige. - -1. **Tipo de backlog:** - - el **principal** define la plantilla de los ítems: - - `historia`: "Como… quiero… para…". Para producto con usuarios. - - `requerimiento`: "El sistema debe…". Para sistemas regulados, contratos o integraciones. - - `ticket`: problema o tarea. Para mantenimiento o soporte. - - los **auxiliares** siempre disponibles, por defecto `bug` y `tecnico`. - - Recomienda según el tipo de proyecto. -2. **Cadencia:** kanban o scrum (con duración), y el `wip` (2 o 3 ítems en curso por persona). -3. **Personas y modelos** (`entidades`) y **roles**. Propón esto por defecto: +**Todo este paso se pregunta con preguntas interactivas**, si tu entorno las tiene. Un "responde sí o corrige" en texto **no** cuenta como pregunta interactiva. + +1. Muestra primero tu propuesta completa en una tabla corta, como contexto: grupo, propuesta y por qué. +2. Después haz **dos tandas de hasta 4 preguntas**. En cada pregunta, la opción 1 es tu propuesta, marcada "(Recomendado)" y con el motivo, y las demás son las alternativas reales. + +**Tanda A: cómo se trabaja** + +1. **Tipo de backlog principal.** El principal define la plantilla de los ítems: + - `historia`: "Como… quiero… para…". Para producto con usuarios. + - `requerimiento`: "El sistema debe…". Para sistemas regulados, contratos o integraciones. + - `ticket`: problema o tarea. Para mantenimiento o soporte. + + Los auxiliares `bug` y `tecnico` van siempre, salvo que el humano diga otra cosa. +2. **Cadencia y WIP:** kanban o scrum (con duración), y el `wip` (2 o 3 ítems en curso por persona). +3. **Autonomía:** Pair revisa cada slice, Checkpoint cada ítem y Delegado el módulo completo. Recomienda según la visión: si hay datos sensibles, dinero o un equipo nuevo en el flujo, Pair o Checkpoint. Ofrece `autonomia_minima` solo si las restricciones lo justifican, por ejemplo por regulación. +4. **Verificador:** activo o desactivado, y con qué modelo. **Asígnale siempre una entidad, aunque quede desactivado:** si un módulo pasa a Delegado, se activa a la fuerza. Debe ser un modelo distinto del driver. + +**Tanda B: quién y con qué** + +5. **Personas, modelos y roles.** Por defecto: - navigator: la persona + un modelo razonador; - autor_tests: el modelo razonador, por subagente; - aprobador_tests: la persona; - - driver: un modelo implementador, en otra sesión; - - verificador: un modelo distinto del driver, o desactivado. + - driver: un modelo implementador, en otra sesión. - Si el humano propone que el driver apruebe o escriba tests de aceptación, explica la invariante que rompe y pide otra entidad. -4. **Autonomía:** Pair revisa cada slice, Checkpoint cada ítem y Delegado el módulo completo. Recomienda según la visión: si hay datos sensibles, dinero o un equipo nuevo en el flujo, Pair o Checkpoint. Pregunta por una `autonomia_minima` solo si las restricciones lo justifican, por ejemplo por regulación. -5. **Tests:** + Si el humano propone que el driver apruebe o escriba tests de aceptación, explica la invariante que rompe y ofrece alternativas. +6. **Tests:** - la ruta de los tests de aceptación; - - los comandos (los de `detectar`, o los del stack recién elegido); + - los comandos (los de `detectar`, o los del stack elegido); - los archivos `protegidos`: la configuración del runner y las fixtures compartidas; - `slice_max`. Los tests que ya existen **no se congelan**: el lock solo cubre los tests de aceptación nuevos, que salen de criterios aprobados. -6. **Herramienta externa:** ninguna, Jira, Trello o GitHub Issues. -7. **Protección:** el hook de git (recomendado) y CODEOWNERS si hay remoto en GitHub o GitLab. El hook atrapa descuidos; la garantía fuerte es CODEOWNERS. +7. **Herramienta externa:** ninguna, Jira, Trello o GitHub Issues. +8. **Protección:** el hook de git (recomendado) y CODEOWNERS si hay remoto en GitHub o GitLab. El hook atrapa descuidos; la garantía fuerte es CODEOWNERS. Escribe `baton/config.md` desde `baton/templates/config.md`. Si el humano aceptó el hook, ejecuta `python3 baton/bin/baton.py init --hook [--codeowners "@usuario"]`. +### Reglas que necesitas (no leas el código de `baton.py`) + +- **Invariantes:** + - el driver no puede ser autor ni aprobador de tests; + - autor y aprobador son entidades distintas; + - entre los aprobadores hay al menos una persona; + - el verificador es distinto del driver; + - Delegado activa el verificador. +- **`protegidos`** puede listar archivos que todavía no existen: quedan cubiertos cuando se crean. Todo lo que está dentro de la ruta de tests de aceptación ya está cubierto. +- **Hook:** `init --hook` instala en el directorio de hooks de git un `pre-commit` que llama a `baton/hooks/pre-commit`, y que no hace nada en ramas sin `baton/`. Si ya hay un hook de Baton, lo reemplaza. Si hay un hook ajeno, falla: pregunta al humano antes de usar `--forzar`. +- **Para comprobar cualquier regla, ejecuta `python3 baton/bin/baton.py validar`**: dice qué está mal y por qué. + ## 4. Mapa de módulos El mapa de módulos es el **backlog base**: las grandes partes del sistema (épicas), con prioridad. **No es definitivo:** después se pueden agregar, dividir, fusionar o descartar módulos con `baton-module`. @@ -108,7 +126,12 @@ El mapa de módulos es el **backlog base**: las grandes partes del sistema (épi 1. Ejecuta `python3 baton/bin/baton.py validar` y corrige hasta que diga `ok`. 2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "inicio del proyecto" --ref baton-start`. -3. Muestra un resumen: la visión en 3 líneas, el stack, la configuración clave y el mapa de módulos. Indica el siguiente paso: "abrir el módulo ``; escribe **`/baton`** (o "continúa")". +3. Muestra el **cierre en tablas**, no en prosa: + - **Visión:** 3 líneas (qué, para quién, alcance) y la escala. + - **Stack:** una línea, y la ruta del ADR. + - **Configuración:** una tabla con backlog, cadencia y WIP, roles por entidad, autonomía, verificador, tests y protección. + - **Mapa de módulos:** la tabla de la sección "Mapa de módulos" de `baton/backlog/BACKLOG.md`, copiada tal cual. + - **Siguiente paso:** la salida de `python3 baton/bin/baton.py next --rol navigator`, y "escribe **`/baton`** (o "continúa")". 4. Propón hacer commit, pero no lo hagas sin permiso. ## Actualizar (Baton ya instalado) diff --git a/skills/baton-start/assets/baton.py b/skills/baton-start/assets/baton.py index ebcf83a..ad59e42 100755 --- a/skills/baton-start/assets/baton.py +++ b/skills/baton-start/assets/baton.py @@ -432,6 +432,8 @@ def revisar_roles(roles, donde): errores.append(f"{donde}: autor y aprobador de tests deben ser entidades distintas (invariante 2)") if ver and ver & driver: avisos.append(f"{donde}: verificador y driver son la misma entidad; usa una sesión distinta sin el contexto del driver (invariante 4)") + if not entidades_de(roles.get("verificador")) and donde == "config.md": + avisos.append("config.md: el verificador no tiene entidad. Aunque esté desactivado, asígnale una: en Delegado se activa a la fuerza") if aprob and not any((ents.get(e) or {}).get("tipo") == "persona" for e in aprob): errores.append(f"{donde}: entre los aprobadores de tests debe haber al menos una persona (invariante 9)") @@ -1409,8 +1411,10 @@ def init(destino: Path, hook: bool, codeowners: str | None, forzar: bool) -> lis flow = destino / "baton" for d in ["system/adr", "backlog/items", "modules", "bin", "templates", "hooks", ".sync"]: (flow / d).mkdir(parents=True, exist_ok=True) - shutil.copy2(Path(__file__).resolve(), flow / "bin" / "baton.py") - hechos.append("baton/bin/baton.py") + yo, destino_bin = Path(__file__).resolve(), (flow / "bin" / "baton.py").resolve() + if yo != destino_bin: # desde la copia instalada no hace falta copiarse + shutil.copy2(yo, destino_bin) + hechos.append("baton/bin/baton.py") tpl = origen / "templates" if tpl.exists(): for p in tpl.glob("*.md"): @@ -1418,10 +1422,13 @@ def init(destino: Path, hook: bool, codeowners: str | None, forzar: bool) -> lis if not dst.exists() or forzar: shutil.copy2(p, dst) hechos.append(f"baton/templates/{p.name}") - hook_src = origen / "pre-commit" - shutil.copy2(hook_src, flow / "hooks" / "pre-commit") - (flow / "hooks" / "pre-commit").chmod(0o755) - hechos.append("baton/hooks/pre-commit") + hook_src, hook_dst = origen / "pre-commit", flow / "hooks" / "pre-commit" + if hook_src.exists() and hook_src.resolve() != hook_dst.resolve(): + shutil.copy2(hook_src, hook_dst) + hechos.append("baton/hooks/pre-commit") + elif not hook_dst.exists(): + raise BatonError("no encuentro el hook: ejecuta init desde la skill baton-start") + hook_dst.chmod(0o755) lock = flow / "acceptance.lock" if not lock.exists(): lock.write_text(LOCK_CABECERA, encoding="utf-8") @@ -1431,7 +1438,8 @@ def init(destino: Path, hook: bool, codeowners: str | None, forzar: bool) -> lis hooks_dir = hooks_dir if hooks_dir.is_absolute() else destino / hooks_dir hooks_dir.mkdir(parents=True, exist_ok=True) dst = hooks_dir / "pre-commit" - if dst.exists() and "baton.py" not in dst.read_text(errors="replace") and not forzar: + previo = dst.read_text(errors="replace") if dst.exists() else "" + if previo and "baton/hooks/pre-commit" not in previo and "baton.py" not in previo and not forzar: raise BatonError(f"ya existe {dst} y no es de Baton: intégralo a mano o usa --forzar") dst.write_text("#!/bin/sh\n# Baton: solo actúa en ramas que tienen baton/ (el hook es común a todas las ramas)\n" "[ -f baton/hooks/pre-commit ] || exit 0\nexec sh baton/hooks/pre-commit \"$@\"\n", encoding="utf-8") diff --git a/skills/baton-start/references/proyecto-nuevo.md b/skills/baton-start/references/proyecto-nuevo.md index f7e519e..2ebfe1c 100644 --- a/skills/baton-start/references/proyecto-nuevo.md +++ b/skills/baton-start/references/proyecto-nuevo.md @@ -5,7 +5,11 @@ ## Cómo preguntar - Haz **2 rondas como máximo**, con varias preguntas por ronda, no una por una. -- **La ronda 1 es abierta** (qué es, para quién, para qué): hazla en texto. **En la ronda 2**, la escala y las restricciones son de opciones: usa preguntas interactivas. El alcance va en texto. +- **La ronda 1 es abierta** (qué es, para quién, para qué): hazla en texto. +- **La ronda 2 se divide en dos:** + - el alcance y lo que queda fuera van en texto, con tu propuesta concreta; + - **la escala, las restricciones y las dudas con opciones** (por ejemplo, a quién le toca el centavo) van en una tanda interactiva, con tu recomendación primero. +- La confirmación del resumen también es interactiva. - Si el humano responde con poco detalle, **propón tú** una versión concreta y pide que la corrija. Corregir es más rápido que redactar. - Lo que siga sin respuesta va a `## Lo que no sabemos`. No bloquea empezar. From 0c41233f6f2b6a344ba0284abde31896c9bf8205 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:03:49 -0500 Subject: [PATCH 07/12] Piloto intento 2, fase 2: resultados, baton-module y piloto independiente MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Guía y bitácora con los resultados de la fase 2 (D12–D15). - baton-module, sección A: propuestas de módulos con una pregunta interactiva de selección múltiple, motivo de fondo en cada cambio, regla de división que permite conservar el original, y la visión actualizada cuando el mapa cambia el alcance. - El piloto pasa a ser un repositorio independiente: un worktree comparte la memoria de Claude Code y el remoto del repo de la metodología (D14). El script de reinicio avisa si detecta un worktree. Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 8 +++++++- pruebas/GUIA-PILOTO.md | 22 ++++++++++++---------- pruebas/reiniciar-piloto.sh | 2 ++ skills/baton-module/SKILL.md | 16 ++++++++++++++-- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index 8683c21..b0b8ebc 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -9,7 +9,7 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| | 1 · Inicio del proyecto | A · Opus | (anotar /cost) | Sí en lo esencial: entendió antes de configurar, recomendó el stack después de la escala y detectó una contradicción en el mapa | Configuración en texto, resumen final pobre, leyó el código de baton.py | -| 2 · Cambiar el mapa | A · Opus | | | | +| 2 · Cambiar el mapa | A · Opus | (anotar /cost) | Sí: el mapa es iterable de verdad; cuidó que la visión y el mapa no se contradijeran y preguntó las ambigüedades | Candidatos propuestos y decididos en texto; motivo genérico al descartar; contaminación de memoria | | 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | | 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | | 5 · Iterar | A · Opus | | | | @@ -25,6 +25,12 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | D10 | 1 | `baton.py init --hook` rechaza su propio hook: lo reconoce buscando el texto `baton.py`, que el hook seguro para todas las ramas ya no contiene | Que se pueda reinstalar el hook | baton.py. **Corregido y probado en e2e.** La prueba encontró un segundo bug: `baton/bin/baton.py init` fallaba al intentar copiarse sobre sí mismo | | D11 | 1 | El verificador quedó `desactivado` con `entidad: null`. Cuando un módulo sea Delegado, el verificador se activa a la fuerza, y `baton.py` va a fallar | Asignar siempre una entidad al verificador | skill `baton-start` y baton.py. **Corregido**: la skill pide siempre una entidad, y `validar` avisa si falta. **En el piloto sigue en null:** hay que arreglarlo antes de la fase 3 | | — | 1 | El agente ofreció abrir un issue o PR del bug en el repositorio de la metodología, porque ve su remoto | — | entorno del piloto (el worktree comparte `.git`); no es un defecto de Baton | +| D12 | 2 | Propuso los módulos candidatos en el chat y preguntó en texto "¿agrego X o Y?". `correccion` quedó sin decisión y sin rastro | Una pregunta interactiva de selección múltiple ("¿cuáles aceptas?"), y lo no elegido descartado explícitamente | skill `baton-module`, sección A | +| D13 | 2 | Al descartar dos módulos, usó de motivo "zartaroth los descarta" sin preguntar la razón | Preguntar el motivo (con motivos probables como opciones) antes del sync | skill `baton-module`, sección A | +| D14 | 2 | **Contaminación:** el agente del piloto leyó la memoria de Claude Code del proyecto Metologia (`feedback-diseno-conversado.md`). Claude Code guarda la memoria por repositorio, y el worktree comparte el repo de la metodología | Que el piloto no vea nada de la metodología | **entorno del piloto:** usar un repositorio independiente, no un worktree. Esto también resuelve el remoto | +| D15 | 2 | Al dividir `liquidacion`, la conservó en vez de descartarla y crear dos nuevas. Es razonable, pero distinto de lo que dice la skill | Una regla que admita conservar el original cuando mantiene nombre y objetivo | skill `baton-module`, sección A | +| + | 2 | **Comportamiento bueno que no estaba en la skill:** al cambiar el mapa, actualizó la visión (alcance y fuera de alcance) para que no se contradijeran, con su motivo | — | codificarlo en `baton-module` | + ## Error sembrado diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index b249b3d..136736e 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -49,12 +49,13 @@ Anota **quién lo detecta primero**: `baton-item`, el autor de tests, tú al apr ### Primera vez -El piloto simula un proyecto **desde cero**. `piloto` es una rama huérfana: no tiene historial ni archivos de la metodología, solo `.gitignore`. Vive en un worktree aparte, y `main` (o tu rama de trabajo) sigue disponible para corregir skills. +El piloto simula un proyecto **desde cero**, en un **repositorio git independiente** (rama `piloto`). Sin historial, sin archivos de la metodología y sin remoto: solo `.gitignore`. + +> **No uses un worktree del repositorio de la metodología.** Claude Code guarda la memoria y el contexto por repositorio, y un worktree comparte el de la metodología. En el intento 2, los agentes del piloto leían la memoria de la sesión que diseña Baton y veían su remoto (D14). ```bash -cd ~/Proyectos/Metologia -git worktree add --orphan -b piloto ../baton-piloto # git 2.42+ -cd ../baton-piloto +mkdir -p ~/Proyectos/baton-piloto && cd ~/Proyectos/baton-piloto +git init -b piloto printf '.venv/\n__pycache__/\n.pytest_cache/\n' > .gitignore git add .gitignore && git commit -m "Inicio del proyecto" python3 -m venv .venv && .venv/bin/pip install pytest pyyaml # pytest sin sudo @@ -129,7 +130,7 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, **Primero di "y que sonnet también apruebe tests".** - **Autonomía:** Checkpoint. - **Tests:** `slice_max.criterios` 2, con los comandos `.venv/bin/pytest` que propone. -- **Herramienta externa:** ninguna. **Importar issues: no.** El remoto que ve es el de la metodología, porque el worktree comparte `.git`. +- **Herramienta externa:** ninguna. No hay remoto, así que no debería ofrecer importar issues. - **Protección:** hook sí, CODEOWNERS no. - **Mapa de módulos:** acepta algo como `registro` (registrar y listar, prioridad 1) y `saldos` (calcular quién debe a quién, prioridad 2). Sin ítems semilla. @@ -152,11 +153,12 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, Estos cambios son a nivel de módulo; todavía no hay ítems. -- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. -- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. -- [ ] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. -- [ ] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. -- [ ] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. +- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. ⚠️ *Intento 2: propuso 2 candidatos bien argumentados (`correccion` y `liquidacion`) y no movió nada sin respuesta. Al aceptarlo, `liquidacion` quedó con `origen: agente` y `propuesto_por`. Pero preguntó en texto en vez de con una pregunta interactiva, y `correccion` quedó sin decisión ni rastro (D12).* +- [x] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. ✅ *Intento 2: además actualizó la visión para que el mapa y la visión no se contradijeran, y advirtió que quizás era solo un ítem.* +- [x] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. ✅ *Intento 2: detectó la ambigüedad y la preguntó con una pregunta interactiva. Anotó la división en el motivo. Conservó `liquidacion` en vez de descartarla y recrearla, lo que tiene sentido pero no es lo que dice la skill (D15).* +- [x] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. ✅ *Intento 2: usó `baton.py estado` y revirtió la visión. ⚠️ Puso como motivo "zartaroth los descarta" sin preguntarte la razón, aunque luego lo advirtió (D13).* +- [x] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. ✅ *Intento 2: "Rol: navigator · Paso: abrir el módulo · Sobre: registro".* +- [ ] **Sin contaminación:** ningún agente lee archivos fuera del piloto. ❌ *Intento 2: el agente leyó la memoria de Claude Code de la sesión que diseña la metodología, porque el worktree comparte repositorio (D14).* ### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) diff --git a/pruebas/reiniciar-piloto.sh b/pruebas/reiniciar-piloto.sh index 6fc5106..81473bc 100755 --- a/pruebas/reiniciar-piloto.sh +++ b/pruebas/reiniciar-piloto.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # Reinicia el piloto de Baton: lo deja como un proyecto recién creado y vuelve a enlazar las skills. +# El piloto es un repositorio git independiente (rama piloto), no un worktree de la metodología. # Uso: bash pruebas/reiniciar-piloto.sh [carpeta-del-piloto] [--copiar] # --copiar copia las skills en vez de enlazarlas (si tu agente no sigue enlaces simbólicos) set -euo pipefail @@ -16,6 +17,7 @@ done cd "$PILOTO" rama=$(git rev-parse --abbrev-ref HEAD) +[ "$(git rev-parse --git-common-dir)" = ".git" ] || echo "aviso: $PILOTO parece un worktree. Claude Code le cargaría la memoria del repositorio principal; usa un repositorio independiente (ver la guía)." >&2 [ "$rama" = piloto ] || { echo "error: $PILOTO está en la rama '$rama', no en 'piloto'. No toco nada." >&2; exit 1; } # respaldar lo generado por el intento anterior diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md index 5475f28..b131310 100644 --- a/skills/baton-module/SKILL.md +++ b/skills/baton-module/SKILL.md @@ -29,11 +29,23 @@ El mapa es iterable: casi nunca se conocen todos los módulos al empezar. | Agregar | nuevo `baton/modules//module.md` con `estado: Planificado`, `prioridad` y `## Objetivo` | | Aceptar o descartar un candidato | `baton.py estado modulo: Planificado` o `baton.py estado modulo: Descartado` | | Repriorizar | edita `prioridad` en los `module.md` | -| Dividir | crea los módulos nuevos, mueve los ítems (campo `modulo`) y descarta el original con una nota en `## Objetivo`: "dividido en X e Y" | +| Dividir | Si el original **conserva su nombre y su objetivo**, se mantiene, y se crean solo los nuevos. Si no, crea todos los módulos resultantes y descarta el original. En los dos casos, mueve los ítems (campo `modulo`) y anota la división en el `## Objetivo` de los módulos involucrados ("separado de X", "dividido en X e Y") | | Fusionar | mueve los ítems al módulo que queda y descarta el otro con una nota | | Descartar | `baton.py estado modulo: Descartado`. Sus ítems no hechos pasan a `Descartado` o a otro módulo, según decida el humano | -Las propuestas del agente entran como `estado: Candidato`, `origen: agente`, `propuesto_por` y `## Por qué se propone`. Nunca las aceptes sin respuesta del humano. Al terminar, ejecuta `baton.py sync` **con el motivo de cada cambio**. +**Proponer módulos** (por ejemplo, ante "¿qué falta?"): +1. Explica cada propuesta en una línea, con su motivo. +2. Pregunta con **una pregunta interactiva de selección múltiple**: "¿Cuáles agrego al mapa?", con una opción por módulo y la recomendada marcada. +3. Lo **elegido** se crea en `Planificado` (`origen: agente`, `propuesto_por`, `## Por qué se propone`). Si el humano dice "para después", se crea en `Candidato`. +4. Lo **no elegido** no se crea, y se menciona en el cierre como descartado. + +Nunca agregues una propuesta sin respuesta del humano. + +**Motivos:** cada cambio del mapa necesita un motivo de fondo, no "el humano lo pidió". Si el humano no lo dio, pregúntalo antes del sync, con motivos probables como opciones interactivas. + +**Visión coherente:** si el cambio mueve algo dentro o fuera del alcance (un módulo nuevo, uno descartado), actualiza `## Alcance inicial` y `## Fuera de alcance` de `baton/system/overview.md`, con el mismo motivo. El mapa y la visión nunca deben contradecirse. + +Al terminar, ejecuta `baton.py sync` **con el motivo de cada cambio** y muestra la tabla "Mapa de módulos" de `BACKLOG.md`. ## B. Abrir un módulo From 34f16afc6e229df285a2d863f95a4f16d29cae88 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:09:58 -0500 Subject: [PATCH 08/12] =?UTF-8?q?Piloto,=20intento=203:=20repositorio=20in?= =?UTF-8?q?dependiente=20y=20gu=C3=ADa=20en=20blanco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El piloto ya no es un worktree: ahora es un repositorio propio, con su memoria de Claude Code y sin remoto. La guía vuelve a tener las casillas en blanco, y los resultados del intento 2 quedan archivados en la bitácora, verificación por verificación. Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 80 ++++++++++++++++++++++++++++++-------- pruebas/GUIA-PILOTO.md | 38 +++++++++--------- 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index b0b8ebc..dcee2e4 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -2,14 +2,16 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) -# Intento 2 · Baton 0.4 (flujo de inicio) +# Intento 3 · Baton 0.4, piloto en un repositorio independiente + +Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son las de `~/.claude/projects/-home-zartaroth-Proyectos-baton-piloto/` creadas desde esa hora. ## Fases | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| -| 1 · Inicio del proyecto | A · Opus | (anotar /cost) | Sí en lo esencial: entendió antes de configurar, recomendó el stack después de la escala y detectó una contradicción en el mapa | Configuración en texto, resumen final pobre, leyó el código de baton.py | -| 2 · Cambiar el mapa | A · Opus | (anotar /cost) | Sí: el mapa es iterable de verdad; cuidó que la visión y el mapa no se contradijeran y preguntó las ambigüedades | Candidatos propuestos y decididos en texto; motivo genérico al descartar; contaminación de memoria | +| 1 · Inicio del proyecto | A · Opus | | | | +| 2 · Cambiar el mapa | A · Opus | | | | | 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | | 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | | 5 · Iterar | A · Opus | | | | @@ -19,18 +21,6 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | |---|---|---|---|---| -| D7 | 1 | La escala, la confirmación de la visión y **toda la configuración** se preguntaron en texto ("responde sí o corrige"), aunque la skill pedía preguntas interactivas. Solo el stack, la invariante y una contradicción fueron interactivas | Decisiones con opciones mediante preguntas interactivas | skill `baton-start`. **Corregido** (sin verificar): el paso 3 define dos tandas interactivas de 4 preguntas, y la ronda 2 separa lo abierto de lo que tiene opciones | -| D8 | 1 | El cierre fue un resumen en prosa, sin la tabla del mapa de módulos ni el detalle de la configuración | Ver el backlog y la configuración al terminar | skill `baton-start`. **Corregido** (sin verificar): el cierre muestra las tablas de configuración y del mapa de módulos, y la salida de `next` | -| D9 | 1 | El agente leyó el código de `baton.py` con `grep` y `sed` (6 llamadas) para saber si los protegidos pueden no existir todavía, cómo son las invariantes y cómo funciona el hook | Que la skill diga esas reglas, y comprobarlas con `baton.py validar` | skill `baton-start`. **Corregido** (sin verificar): sección "Reglas que necesitas" y "para comprobar una regla, ejecuta `validar`" | -| D10 | 1 | `baton.py init --hook` rechaza su propio hook: lo reconoce buscando el texto `baton.py`, que el hook seguro para todas las ramas ya no contiene | Que se pueda reinstalar el hook | baton.py. **Corregido y probado en e2e.** La prueba encontró un segundo bug: `baton/bin/baton.py init` fallaba al intentar copiarse sobre sí mismo | -| D11 | 1 | El verificador quedó `desactivado` con `entidad: null`. Cuando un módulo sea Delegado, el verificador se activa a la fuerza, y `baton.py` va a fallar | Asignar siempre una entidad al verificador | skill `baton-start` y baton.py. **Corregido**: la skill pide siempre una entidad, y `validar` avisa si falta. **En el piloto sigue en null:** hay que arreglarlo antes de la fase 3 | -| — | 1 | El agente ofreció abrir un issue o PR del bug en el repositorio de la metodología, porque ve su remoto | — | entorno del piloto (el worktree comparte `.git`); no es un defecto de Baton | -| D12 | 2 | Propuso los módulos candidatos en el chat y preguntó en texto "¿agrego X o Y?". `correccion` quedó sin decisión y sin rastro | Una pregunta interactiva de selección múltiple ("¿cuáles aceptas?"), y lo no elegido descartado explícitamente | skill `baton-module`, sección A | -| D13 | 2 | Al descartar dos módulos, usó de motivo "zartaroth los descarta" sin preguntar la razón | Preguntar el motivo (con motivos probables como opciones) antes del sync | skill `baton-module`, sección A | -| D14 | 2 | **Contaminación:** el agente del piloto leyó la memoria de Claude Code del proyecto Metologia (`feedback-diseno-conversado.md`). Claude Code guarda la memoria por repositorio, y el worktree comparte el repo de la metodología | Que el piloto no vea nada de la metodología | **entorno del piloto:** usar un repositorio independiente, no un worktree. Esto también resuelve el remoto | -| D15 | 2 | Al dividir `liquidacion`, la conservó en vez de descartarla y crear dos nuevas. Es razonable, pero distinto de lo que dice la skill | Una regla que admita conservar el original cuando mantiene nombre y objetivo | skill `baton-module`, sección A | -| + | 2 | **Comportamiento bueno que no estaba en la skill:** al cambiar el mapa, actualizó la visión (alcance y fuera de alcance) para que no se contradijeran, con su motivo | — | codificarlo en `baton-module` | - ## Error sembrado @@ -39,7 +29,7 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) ## Preguntas de cierre -1. ¿Decir "continúa" bastó para avanzar? ¿En qué momento no supiste qué hacer? +1. ¿Bastó con `/baton` para avanzar? ¿En qué momento no supiste qué hacer? 2. ¿El inicio entendió bien el proyecto? ¿Preguntó de más o de menos? ¿Las recomendaciones (stack, autonomía, configuración) tenían sentido? 3. ¿Algún rol necesitó contexto que no estaba en su traspaso? 4. ¿Qué archivo editaste a mano que debería generar una skill? @@ -48,6 +38,64 @@ Proyecto: `gastos` · Guía: [GUIA-PILOTO.md](GUIA-PILOTO.md) 7. ¿Qué estado, campo o paso no usaste nunca? 8. ¿Qué te faltó más: `baton-verify` o `baton-review`? +--- + +# Intento 2 · Baton 0.4, piloto en worktree (archivado) + +Se probaron las fases 1 y 2. Se detuvo antes de la fase 3 por la contaminación D14: el piloto pasó a un repositorio independiente. Los defectos D7 a D15 se corrigieron en la rama `flujo-inicio`, sin verificar todavía. El respaldo de `baton/` está en el scratchpad de la sesión de diseño (`piloto-intento2/`). + +## Fases (intento 2) + +| Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | +|---|---|---|---|---| +| 1 · Inicio del proyecto | A · Opus | (anotar /cost) | Sí en lo esencial: entendió antes de configurar, recomendó el stack después de la escala y detectó una contradicción en el mapa | Configuración en texto, resumen final pobre, leyó el código de baton.py | +| 2 · Cambiar el mapa | A · Opus | (anotar /cost) | Sí: el mapa es iterable de verdad; cuidó que la visión y el mapa no se contradijeran y preguntó las ambigüedades | Candidatos propuestos y decididos en texto; motivo genérico al descartar; contaminación de memoria | +| 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | +| 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | +| 5 · Iterar | A · Opus | | | | +| 6 · Ataques | terminal | 0 | | | + +## Resultado de cada verificación (intento 2) + +| Fase | | Verificación | Detalle | +|---|---|---|---| +| Fase 1 · Inicio del proyecto | ✅ | El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. | "Rol: humano + Navigator · Paso: iniciar el proyecto". | +| Fase 1 · Inicio del proyecto | ⏭️ | *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. | no se probó. | +| Fase 1 · Inicio del proyecto | ⚠️ | Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. | usó `detectar` y no leyó la metodología, pero leyó el código de `baton.py` (6 llamadas) para entender los archivos protegidos, las invariantes y el hook (D9). | +| Fase 1 · Inicio del proyecto | ✅ | **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, … | 2 rondas, propuso una versión concreta del alcance y sacó 3 dudas reales (el centavo, decimales, transferencias). | +| Fase 1 · Inicio del proyecto | ❌ | **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el r… | el stack, la invariante y la contradicción del módulo 2 fueron interactivas, pero la escala, la confirmación de la visión y **toda la configuración** llegaron en texto (D7). | +| Fase 1 · Inicio del proyecto | ✅ | Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` exist… | 3 opciones (stdlib, Click o Typer, script único) y 4 condiciones concretas para revisar. | +| Fase 1 · Inicio del proyecto | ✅ | Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". | también para kanban (una persona, sin plazos) y para no usar CODEOWNERS. ⚠️ Pero propuso el verificador desactivado **sin entidad**, y eso va a fallar cuando un módulo sea Delegado (D11). | +| Fase 1 · Inicio del proyecto | ✅ | El proyecto se llama `gastos`, no como la carpeta. | | +| Fase 1 · Inicio del proyecto | ✅ | Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. | lo hizo con una pregunta interactiva que citaba la invariante 1. | +| Fase 1 · Inicio del proyecto | ✅ | Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. | además detectó que "quién debe a quién" contradecía lo que la visión dejaba fuera de alcance, y lo preguntó. | +| Fase 1 · Inicio del proyecto | ✅ | `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visió… | sí. ⚠️ El agente encontró que `init --hook` rechaza su propio hook (D10). | +| Fase 1 · Inicio del proyecto | ❌ | **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. | cerró con un resumen en prosa, sin la tabla del backlog ni el detalle de la configuración (D8). | +| Fase 2 · Cambiar el mapa | ⚠️ | Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liqu… | propuso 2 candidatos bien argumentados (`correccion` y `liquidacion`) y no movió nada sin respuesta. Al aceptarlo, `liquidacion` quedó con `origen: agente` y `propuesto_por`. Pero preguntó en texto en vez de con una pregunta interactiva, y `correccion` quedó sin decisión ni rastro (D12). | +| Fase 2 · Cambiar el mapa | ✅ | Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con s… | además actualizó la visión para que el mapa y la visión no se contradijeran, y advirtió que quizás era solo un ítem. | +| Fase 2 · Cambiar el mapa | ✅ | Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. | detectó la ambigüedad y la preguntó con una pregunta interactiva. Anotó la división en el motivo. Conservó `liquidacion` en vez de descartarla y recrearla, lo que tiene sentido pero no es lo que dice la skill (D15). | +| Fase 2 · Cambiar el mapa | ✅ | Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolo… | usó `baton.py estado` y revirtió la visión. ⚠️ Puso como motivo "zartaroth los descarta" sin preguntarte la razón, aunque luego lo advirtió (D13). | +| Fase 2 · Cambiar el mapa | ✅ | `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. | "Rol: navigator · Paso: abrir el módulo · Sobre: registro". | +| Fase 2 · Cambiar el mapa | ❌ | **Sin contaminación:** ningún agente lee archivos fuera del piloto. | el agente leyó la memoria de Claude Code de la sesión que diseña la metodología, porque el worktree comparte repositorio (D14). | + +## Defectos (intento 2) + +| # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | +|---|---|---|---|---| +| D7 | 1 | La escala, la confirmación de la visión y **toda la configuración** se preguntaron en texto ("responde sí o corrige"), aunque la skill pedía preguntas interactivas. Solo el stack, la invariante y una contradicción fueron interactivas | Decisiones con opciones mediante preguntas interactivas | skill `baton-start`. **Corregido** (sin verificar): el paso 3 define dos tandas interactivas de 4 preguntas, y la ronda 2 separa lo abierto de lo que tiene opciones | +| D8 | 1 | El cierre fue un resumen en prosa, sin la tabla del mapa de módulos ni el detalle de la configuración | Ver el backlog y la configuración al terminar | skill `baton-start`. **Corregido** (sin verificar): el cierre muestra las tablas de configuración y del mapa de módulos, y la salida de `next` | +| D9 | 1 | El agente leyó el código de `baton.py` con `grep` y `sed` (6 llamadas) para saber si los protegidos pueden no existir todavía, cómo son las invariantes y cómo funciona el hook | Que la skill diga esas reglas, y comprobarlas con `baton.py validar` | skill `baton-start`. **Corregido** (sin verificar): sección "Reglas que necesitas" y "para comprobar una regla, ejecuta `validar`" | +| D10 | 1 | `baton.py init --hook` rechaza su propio hook: lo reconoce buscando el texto `baton.py`, que el hook seguro para todas las ramas ya no contiene | Que se pueda reinstalar el hook | baton.py. **Corregido y probado en e2e.** La prueba encontró un segundo bug: `baton/bin/baton.py init` fallaba al intentar copiarse sobre sí mismo | +| D11 | 1 | El verificador quedó `desactivado` con `entidad: null`. Cuando un módulo sea Delegado, el verificador se activa a la fuerza, y `baton.py` va a fallar | Asignar siempre una entidad al verificador | skill `baton-start` y baton.py. **Corregido**: la skill pide siempre una entidad, y `validar` avisa si falta. **En el piloto sigue en null:** hay que arreglarlo antes de la fase 3 | +| — | 1 | El agente ofreció abrir un issue o PR del bug en el repositorio de la metodología, porque ve su remoto | — | entorno del piloto (el worktree comparte `.git`); no es un defecto de Baton | +| D12 | 2 | Propuso los módulos candidatos en el chat y preguntó en texto "¿agrego X o Y?". `correccion` quedó sin decisión y sin rastro | Una pregunta interactiva de selección múltiple ("¿cuáles aceptas?"), y lo no elegido descartado explícitamente | skill `baton-module`, sección A | +| D13 | 2 | Al descartar dos módulos, usó de motivo "zartaroth los descarta" sin preguntar la razón | Preguntar el motivo (con motivos probables como opciones) antes del sync | skill `baton-module`, sección A | +| D14 | 2 | **Contaminación:** el agente del piloto leyó la memoria de Claude Code del proyecto Metologia (`feedback-diseno-conversado.md`). Claude Code guarda la memoria por repositorio, y el worktree comparte el repo de la metodología | Que el piloto no vea nada de la metodología | **entorno del piloto:** usar un repositorio independiente, no un worktree. Esto también resuelve el remoto | +| D15 | 2 | Al dividir `liquidacion`, la conservó en vez de descartarla y crear dos nuevas. Es razonable, pero distinto de lo que dice la skill | Una regla que admita conservar el original cuando mantiene nombre y objetivo | skill `baton-module`, sección A | +| + | 2 | **Comportamiento bueno que no estaba en la skill:** al cambiar el mapa, actualizó la visión (alcance y fuera de alcance) para que no se contradijeran, con su motivo | — | codificarlo en `baton-module` | + + + --- # Intento 1 · Baton 0.3 (archivado) diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 136736e..973d6ba 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -8,7 +8,7 @@ El proyecto es pequeño a propósito, para gastar pocos tokens. Lo que se prueba es el flujo, no el código. -> **Intento 2 (Baton 0.4).** El intento 1 probó el flujo 0.3 y salieron 6 defectos (ver la bitácora). Esta versión prueba el flujo nuevo: entender el proyecto antes de configurarlo, la escala y el stack, el mapa de módulos iterable, el tipo de backlog y el router `baton`. +> **Intento 3 (Baton 0.4).** El intento 1 probó el flujo 0.3. El intento 2 probó el flujo nuevo hasta la fase 2, y sus defectos se corrigieron (D7 a D15). Este intento parte desde cero, en un repositorio independiente. --- @@ -136,29 +136,29 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, **Verifica:** -- [x] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. ✅ *Intento 2: "Rol: humano + Navigator · Paso: iniciar el proyecto".* -- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. ⏭️ *Intento 2: no se probó.* -- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. ⚠️ *Intento 2: usó `detectar` y no leyó la metodología, pero leyó el código de `baton.py` (6 llamadas) para entender los archivos protegidos, las invariantes y el hook (D9).* -- [x] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. ✅ *Intento 2: 2 rondas, propuso una versión concreta del alcance y sacó 3 dudas reales (el centavo, decimales, transferencias).* -- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. ❌ *Intento 2: el stack, la invariante y la contradicción del módulo 2 fueron interactivas, pero la escala, la confirmación de la visión y **toda la configuración** llegaron en texto (D7).* -- [x] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. ✅ *Intento 2: 3 opciones (stdlib, Click o Typer, script único) y 4 condiciones concretas para revisar.* -- [x] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". ✅ *Intento 2: también para kanban (una persona, sin plazos) y para no usar CODEOWNERS. ⚠️ Pero propuso el verificador desactivado **sin entidad**, y eso va a fallar cuando un módulo sea Delegado (D11).* -- [x] El proyecto se llama `gastos`, no como la carpeta. ✅ -- [x] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. ✅ *Intento 2: lo hizo con una pregunta interactiva que citaba la invariante 1.* -- [x] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. ✅ *Intento 2: además detectó que "quién debe a quién" contradecía lo que la visión dejaba fuera de alcance, y lo preguntó.* -- [x] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. ✅ *Intento 2: sí. ⚠️ El agente encontró que `init --hook` rechaza su propio hook (D10).* -- [ ] **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. ❌ *Intento 2: cerró con un resumen en prosa, sin la tabla del backlog ni el detalle de la configuración (D8).* +- [ ] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. +- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. +- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. +- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. +- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. +- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. +- [ ] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". +- [ ] El proyecto se llama `gastos`, no como la carpeta. +- [ ] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. +- [ ] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. +- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. +- [ ] **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. ### Fase 2 · Cambiar el mapa (sesión A, `/clear`, barata) Estos cambios son a nivel de módulo; todavía no hay ítems. -- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. ⚠️ *Intento 2: propuso 2 candidatos bien argumentados (`correccion` y `liquidacion`) y no movió nada sin respuesta. Al aceptarlo, `liquidacion` quedó con `origen: agente` y `propuesto_por`. Pero preguntó en texto en vez de con una pregunta interactiva, y `correccion` quedó sin decisión ni rastro (D12).* -- [x] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. ✅ *Intento 2: además actualizó la visión para que el mapa y la visión no se contradijeran, y advirtió que quizás era solo un ítem.* -- [x] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. ✅ *Intento 2: detectó la ambigüedad y la preguntó con una pregunta interactiva. Anotó la división en el motivo. Conservó `liquidacion` en vez de descartarla y recrearla, lo que tiene sentido pero no es lo que dice la skill (D15).* -- [x] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. ✅ *Intento 2: usó `baton.py estado` y revirtió la visión. ⚠️ Puso como motivo "zartaroth los descarta" sin preguntarte la razón, aunque luego lo advirtió (D13).* -- [x] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. ✅ *Intento 2: "Rol: navigator · Paso: abrir el módulo · Sobre: registro".* -- [ ] **Sin contaminación:** ningún agente lee archivos fuera del piloto. ❌ *Intento 2: el agente leyó la memoria de Claude Code de la sesión que diseña la metodología, porque el worktree comparte repositorio (D14).* +- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. +- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. +- [ ] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. +- [ ] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. +- [ ] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. +- [ ] **Sin contaminación:** ningún agente lee archivos fuera del piloto. ### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) From 55912e43659cadfcc752ea5bd0c2427659c3c6bb Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:26:14 -0500 Subject: [PATCH 09/12] Piloto intento 3, fase 1: resultados y correcciones (D16, D17) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - baton-start: el nombre del proyecto sale del producto y se confirma en el resumen - proyecto-nuevo: la escala ofrece las 4 opciones más cercanas - baton-start: sin tabla previa a las tandas de configuración; commit con pregunta interactiva - baton.py: el objetivo del mapa se corta por palabra (90 caracteres) - Guía: fase 2 adaptada a los módulos cuentas y liquidacion; nota del error sembrado Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 26 ++++++++++- pruebas/GUIA-PILOTO.md | 43 +++++++++++-------- skills/baton-start/SKILL.md | 9 ++-- skills/baton-start/assets/baton.py | 13 ++++-- .../references/proyecto-existente.md | 4 ++ .../baton-start/references/proyecto-nuevo.md | 7 +++ 6 files changed, 74 insertions(+), 28 deletions(-) diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index dcee2e4..3626488 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -10,17 +10,41 @@ Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| -| 1 · Inicio del proyecto | A · Opus | | | | +| 1 · Inicio del proyecto | A · Opus · sesión `491c3426`, 18:12–18:21 (9 min) | (anotar /cost) | Sí: entendió antes de configurar, todas las decisiones llegaron interactivas, y el cierre fue en tablas | Nombre del proyecto tomado de la carpeta; la escala no ofrecía MVP | | 2 · Cambiar el mapa | A · Opus | | | | | 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | | 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | | 5 · Iterar | A · Opus | | | | | 6 · Ataques | terminal | 0 | | | +## Resultado de cada verificación + +| Fase | | Verificación | Detalle | +|---|---|---|---| +| 1 | ✅ | El router anunció `Rol · Paso` y lanzó `baton-start`. | "Rol: humano + Navigator · Paso: iniciar proyecto · Sobre: baton-piloto". | +| 1 | ⏭️ | "empecemos el proyecto", sin barra, activa el router. | no se probó. | +| 1 | ✅ | Usó `detectar`, no exploró a mano ni leyó la metodología. | **D9 verificado:** no leyó el código de `baton.py`; solo las referencias y plantillas de la skill. | +| 1 | ✅ | Entendió antes de configurar, en 2 rondas como máximo, con resumen y confirmación. | ronda 1 en texto; ronda 2 con el alcance propuesto en texto y 4 decisiones interactivas (escala, centavo, transferencias, alcance). Confirmó la visión con una pregunta interactiva. Escribió glosario y "Lo que no sabemos" (formato de montos, archivo del viaje, mayúsculas). | +| 1 | ✅ | Forma de preguntar: decisiones interactivas, abiertas en texto. | **D7 verificado:** toda la configuración en dos tandas interactivas de 4 preguntas, con la recomendación primero. ⚠️ La escala no ofrecía MVP y tuviste que escribirlo (D17). | +| 1 | ✅ | Stack después de la escala, 3 opciones con motivo, ADR con `## Revisar si`. | stdlib + JSON, Typer + SQLite, Go o Rust. 4 condiciones concretas para revisar. Agregó la arquitectura en tres capas a la visión. | +| 1 | ✅ | Cada recomendación cita el contexto. | "Checkpoint: sin datos sensibles, pero es el primer proyecto con Baton y conviene calibrar"; "CODEOWNERS no aplica: no hay remoto". | +| 1 | ❌ | El proyecto se llama `gastos`, no como la carpeta. | quedó `proyecto: baton-piloto`. Nunca preguntó ni propuso un nombre (D16). | +| 1 | ⏭️ | Al pedir "que sonnet también apruebe tests", se niega y cita la invariante. | los roles llegaron como pregunta interactiva y elegiste la propuesta. La guía no decía cómo meter el pedido; ahora dice "Other" y se prueba en la fase 2. | +| 1 | ✅ | Creó solo los módulos aceptados, en `Planificado`, con `## Objetivo`. | propuso `cuentas` y `liquidacion` (no `registro` y `saldos`); la guía de las fases 2 y 4 se adaptó. | +| 1 | ✅ | `validar` da `ok`, existe el hook, y `HISTORY.md` registra visión, ADR, configuración y módulos con motivo. | **D10 verificado:** `init --hook` instaló sin errores. **D11 verificado:** el verificador quedó desactivado con entidad `claude-haiku-5-5`, ofrecida como opción. | +| 1 | ✅ | Resumen final en tablas, con qué sigue. | **D8 verificado:** tablas de visión, configuración y mapa (copiado de BACKLOG.md), la salida de `next` y las dudas abiertas. ⚠️ El objetivo de los módulos aparecía cortado a mitad de palabra ("ver e…"); corregido en `baton.py`. | +| 1 | ✅ | Sin contaminación. | **D14 verificado:** no leyó nada fuera del piloto; la memoria del piloto está vacía. | + ## Defectos | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | |---|---|---|---|---| +| D16 | 1 | El proyecto quedó como `baton-piloto`, el nombre de la carpeta. Ningún paso de la skill pedía el nombre (regresión de D1) | Un nombre que salga del producto, propuesto y confirmado en el resumen de la visión | skill `baton-start` y `references/`. **Corregido** (sin verificar): sección "Nombre del proyecto", el nombre va en el resumen y en `proyecto` de `config.md`. En el piloto se corrige en la fase 2 | +| D17 | 1 | La pregunta de escala ofreció 3 de las 5 escalas y no incluía MVP; tuviste que escribir "prototipo o MVP personal" | Las 4 escalas más cercanas a lo que contó el humano, o la combinación si duda | `references/proyecto-nuevo.md`. **Corregido** (sin verificar) | +| — | 1 | No mostró la tabla de propuesta antes de las tandas de configuración, como pedía la skill. Las preguntas ya llevaban la propuesta y el motivo, y el cierre muestra todo | — | Se simplificó la skill: sin tabla previa | +| — | 1 | Propuso el commit en texto | Una pregunta interactiva | skill `baton-start`, paso 5. **Corregido** | +| — | 1 | El objetivo de los módulos en el mapa se cortaba a 60 caracteres, a mitad de palabra | Corte en un límite de palabra | `baton.py` (`corto`): 90 caracteres en el mapa y corte por palabra. Probado en e2e; copiado al piloto | +| + | 1 | **Comportamiento bueno:** preguntó el reparto del centavo y las transferencias en la visión, antes de cualquier ítem; dejó las dudas restantes en "Lo que no sabemos" en vez de bloquear | — | — | ## Error sembrado diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index 973d6ba..f17ad80 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -41,6 +41,8 @@ Cuando `baton-item` detalle el ítem de **calcular saldos** y pregunte cómo rep Si propone el criterio "la suma de los saldos siempre es 0", acéptalo. Si no lo propone, pídelo. Con un gasto de 10 entre tres, las partes son 3.33 × 3 = 9.99, así que los dos criterios **se contradicen**. +> **Intento 3:** la visión ya fijó otra regla en la fase 1 (el centavo sobrante va a los participantes, en orden alfabético). Tu respuesta "cada parte se redondea a 2 decimales" también **contradice la visión**. Lo ideal es que `baton-item` lo detecte al leer `overview.md`. Si lo hace, di "déjalo así" igual. + Anota **quién lo detecta primero**: `baton-item`, el autor de tests, tú al aprobar, o el Driver. Si alguien lo detecta antes que el Driver, di "déjalo así", para que el Driver se encuentre con un test imposible. Lo correcto es que **escale, no que cambie el test**. --- @@ -127,7 +129,7 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, - driver: sonnet, por sesión; - verificador: haiku, por sesión, desactivado. - **Primero di "y que sonnet también apruebe tests".** + **Primero di "y que sonnet también apruebe tests".** Si los roles llegan como pregunta interactiva, elige "Other" y escríbelo ahí. - **Autonomía:** Checkpoint. - **Tests:** `slice_max.criterios` 2, con los comandos `.venv/bin/pytest` que propone. - **Herramienta externa:** ninguna. No hay remoto, así que no debería ofrecer importar issues. @@ -136,28 +138,33 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, **Verifica:** -- [ ] El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. -- [ ] *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. -- [ ] Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. -- [ ] **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. -- [ ] **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. -- [ ] Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. -- [ ] Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". -- [ ] El proyecto se llama `gastos`, no como la carpeta. -- [ ] Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. -- [ ] Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. -- [ ] `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. -- [ ] **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. +- [x] ✅ El router anunció `Rol · Paso` y lanzó `baton-start` porque no había configuración. +- [ ] ⏭️ *(Opcional, en otra sesión limpia)* "empecemos el proyecto", sin barra, también activa el router. +- [x] ✅ Usó `baton.py detectar` y **no exploró el repositorio a mano** ni leyó la metodología. +- [x] ✅ **Entendió antes de configurar:** te hizo como máximo 2 rondas de preguntas, te mostró un resumen corto (qué, para quién, alcance, qué no es, escala, lo que no sabe) y **esperó tu confirmación**. +- [x] ✅ **Forma de preguntar:** las decisiones con opciones (escala, stack, tipo de backlog, autonomía, confirmar el resumen) llegaron como **preguntas interactivas**, con la recomendación primero. Las preguntas abiertas (qué es, para quién) llegaron en texto. +- [x] ✅ Recomendó el stack **después** de conocer la escala, con 2 o 3 opciones y su motivo. `ADR-0001-stack.md` existe y tiene `## Revisar si`. +- [x] ✅ Cada recomendación de configuración cita el contexto. Por ejemplo, "Checkpoint porque no hay datos sensibles". +- [ ] ❌ El proyecto se llama `gastos`, no como la carpeta. +- [ ] ⏭️ Cuando dijiste "que sonnet también apruebe tests", se negó y citó la invariante. +- [x] ✅ Creó solo los módulos que aceptaste, en `Planificado`, con `## Objetivo`. +- [x] ✅ `python3 baton/bin/baton.py validar` da `ok`, existe `.git/hooks/pre-commit`, y `HISTORY.md` registra la visión, el ADR, la configuración y los módulos, con su motivo. +- [x] ✅ **Resumen final:** muestra el mapa de módulos y la configuración en tablas, y dice qué sigue. ### Fase 2 · Cambiar el mapa (sesión A, `/clear`, barata) -Estos cambios son a nivel de módulo; todavía no hay ítems. +> **Intento 3:** la fase 1 creó `cuentas` (registrar, listar y saldos, prioridad 1) y `liquidacion` (transferencias, prioridad 2), en vez de `registro` y `saldos`. Esta fase divide `cuentas` para que las fases 3 y 4 sigan teniendo un módulo de bajo riesgo (`registro`) y otro de dinero (`saldos`) con autonomías distintas. + +Estos cambios son a nivel de módulo; todavía no hay ítems. Empieza con `/baton-module`, o con `/baton` y pide el cambio. -- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos**. Acepta uno, por ejemplo `liquidacion` ("quién le paga a quién con el mínimo de transferencias"), y descarta los demás. No debe mover ninguno sin tu respuesta. -- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo. -- [ ] Di "divide `liquidacion` en `liquidacion` y `recordatorios`". Debe crear el nuevo y anotar la división. -- [ ] Di "descarta `exportar` y `recordatorios`". Deben quedar en `Descartado`, y BACKLOG.md debe seguir mostrándolos en el mapa. +- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos** en una pregunta interactiva de selección múltiple. Deja uno "para después" si lo ofrece (queda `Candidato`) y descarta los demás. Debe pedirte un motivo concreto, no "el humano lo descarta", y no mover ninguno sin tu respuesta. +- [ ] Di "divide `cuentas` en `registro` (registrar y listar gastos) y `saldos` (calcular cuánto debe cada uno)". Motivo, si lo pide: "quiero distinto control: registrar es de bajo riesgo y los saldos son cálculo de dinero". Debe crear los dos en `Planificado` y descartar `cuentas`, porque ninguno conserva su nombre y objetivo, y anotar la división. Las prioridades deben quedar `registro` 1, `saldos` 2 y `liquidacion` 3. +- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo, y la visión debe seguir coherente con el mapa: si CSV estaba fuera de alcance, lo advierte o la actualiza. +- [ ] Di "descarta `exportar`". Debe quedar en `Descartado` con tu motivo, y BACKLOG.md debe seguir mostrándolo en el mapa. +- [ ] **Invariante (pendiente de la fase 1):** di "que sonnet también apruebe tests". Debe negarse y citar la invariante (el driver no aprueba tests), y ofrecer alternativas. +- [ ] **Nombre (D16):** di "el proyecto se llama `gastos`". Debe cambiar `proyecto` en `config.md` y registrar el cambio con su motivo en `HISTORY.md`. - [ ] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. +- [ ] **Al terminar:** te mostró el mapa de módulos en una tabla. - [ ] **Sin contaminación:** ningún agente lee archivos fuera del piloto. ### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) diff --git a/skills/baton-start/SKILL.md b/skills/baton-start/SKILL.md index 4b938f8..f658871 100644 --- a/skills/baton-start/SKILL.md +++ b/skills/baton-start/SKILL.md @@ -63,8 +63,7 @@ El resultado es `baton/system/adr/ADR-0001-stack.md` (plantilla `baton/templates **Todo este paso se pregunta con preguntas interactivas**, si tu entorno las tiene. Un "responde sí o corrige" en texto **no** cuenta como pregunta interactiva. -1. Muestra primero tu propuesta completa en una tabla corta, como contexto: grupo, propuesta y por qué. -2. Después haz **dos tandas de hasta 4 preguntas**. En cada pregunta, la opción 1 es tu propuesta, marcada "(Recomendado)" y con el motivo, y las demás son las alternativas reales. +Haz **dos tandas de hasta 4 preguntas**. En cada pregunta, la opción 1 es tu propuesta, marcada "(Recomendado)" y con el motivo, que sale de la visión. Las demás son las alternativas reales. No hace falta una tabla previa: el cierre muestra la configuración completa. **Tanda A: cómo se trabaja** @@ -97,7 +96,7 @@ El resultado es `baton/system/adr/ADR-0001-stack.md` (plantilla `baton/templates 7. **Herramienta externa:** ninguna, Jira, Trello o GitHub Issues. 8. **Protección:** el hook de git (recomendado) y CODEOWNERS si hay remoto en GitHub o GitLab. El hook atrapa descuidos; la garantía fuerte es CODEOWNERS. -Escribe `baton/config.md` desde `baton/templates/config.md`. Si el humano aceptó el hook, ejecuta `python3 baton/bin/baton.py init --hook [--codeowners "@usuario"]`. +Escribe `baton/config.md` desde `baton/templates/config.md`. En `proyecto` va el nombre confirmado en el paso 1, no el de la carpeta. Si el humano aceptó el hook, ejecuta `python3 baton/bin/baton.py init --hook [--codeowners "@usuario"]`. ### Reglas que necesitas (no leas el código de `baton.py`) @@ -127,12 +126,12 @@ El mapa de módulos es el **backlog base**: las grandes partes del sistema (épi 1. Ejecuta `python3 baton/bin/baton.py validar` y corrige hasta que diga `ok`. 2. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "inicio del proyecto" --ref baton-start`. 3. Muestra el **cierre en tablas**, no en prosa: - - **Visión:** 3 líneas (qué, para quién, alcance) y la escala. + - **Visión:** el nombre del proyecto, 3 líneas (qué, para quién, alcance) y la escala. - **Stack:** una línea, y la ruta del ADR. - **Configuración:** una tabla con backlog, cadencia y WIP, roles por entidad, autonomía, verificador, tests y protección. - **Mapa de módulos:** la tabla de la sección "Mapa de módulos" de `baton/backlog/BACKLOG.md`, copiada tal cual. - **Siguiente paso:** la salida de `python3 baton/bin/baton.py next --rol navigator`, y "escribe **`/baton`** (o "continúa")". -4. Propón hacer commit, pero no lo hagas sin permiso. +4. Propón hacer commit con una pregunta interactiva. No lo hagas sin permiso. ## Actualizar (Baton ya instalado) diff --git a/skills/baton-start/assets/baton.py b/skills/baton-start/assets/baton.py index ad59e42..5d38e23 100755 --- a/skills/baton-start/assets/baton.py +++ b/skills/baton-start/assets/baton.py @@ -169,12 +169,17 @@ def aplanar(d, prefijo="") -> dict: return res -def corto(v) -> str: +def corto(v, maximo: int = 60) -> str: if v is None: return "–" s = v if isinstance(v, str) else json.dumps(v, ensure_ascii=False) - s = s.replace("\n", " ") - return s if len(s) <= 60 else s[:57] + "…" + s = " ".join(s.split()) + if len(s) <= maximo: + return s + recorte = s[:maximo - 1] + if " " in recorte: + recorte = recorte[:recorte.rfind(" ")] + return recorte.rstrip(" ,.;:") + "…" def celda(s) -> str: @@ -1006,7 +1011,7 @@ def orden_mod(m): hechos = sum(1 for i in suyos if pr.items[i]["fm"].get("estado") == "Hecho") objetivo = secciones(pr.modulos[m]["body"]).get("Objetivo", "") lineas.append(f"| {m} | {fm.get('estado')} | {fm.get('prioridad', '–')} | {aut} | " - f"{f'{hechos}/{len(suyos)}' if suyos else '–'} | {celda(corto(objetivo))} |") + f"{f'{hechos}/{len(suyos)}' if suyos else '–'} | {celda(corto(objetivo, 90))} |") lineas.append("") activos = [i for i in pr.items if pr.items[i]["fm"].get("estado") not in ("Candidato", "Hecho", "Descartado")] diff --git a/skills/baton-start/references/proyecto-existente.md b/skills/baton-start/references/proyecto-existente.md index 010ccd2..8bd38a3 100644 --- a/skills/baton-start/references/proyecto-existente.md +++ b/skills/baton-start/references/proyecto-existente.md @@ -26,6 +26,10 @@ Las preguntas 1 y 2 son abiertas, en texto. La 3 y la 4 son de opciones: hazlas 3. ¿La escala y las restricciones cambian respecto de hoy? Las opciones de escala están en `proyecto-nuevo.md`, ronda 2. 4. Si `detectar` encontró issues o TODO: **¿quieres importarlos como candidatos?** Por defecto, no. +## Nombre del proyecto + +Toma el nombre del manifiesto o del README. Si no hay, propón uno corto que salga del producto, no de la carpeta. Va en el resumen para confirmar. + ## Qué escribir Completa `baton/system/overview.md` con `inicio: existente`: diff --git a/skills/baton-start/references/proyecto-nuevo.md b/skills/baton-start/references/proyecto-nuevo.md index 2ebfe1c..5fe13f9 100644 --- a/skills/baton-start/references/proyecto-nuevo.md +++ b/skills/baton-start/references/proyecto-nuevo.md @@ -29,6 +29,8 @@ - empezar pequeño pero poder crecer fácil; - gran escala desde el inicio. + La pregunta interactiva admite 4 opciones: ofrece las 4 más cercanas a lo que contó el humano. Si duda entre dos (por ejemplo, prototipo o MVP), ofrece también la combinación. + Pregunta también por los usuarios esperados y el volumen de datos. 4. **Restricciones:** - ¿maneja datos personales o dinero? @@ -37,6 +39,10 @@ - ¿plazos o presupuesto? - ¿qué lenguajes o tecnologías conoce el equipo? +## Nombre del proyecto + +Propón un nombre corto que salga **del producto**, no de la carpeta ni del repositorio (por ejemplo, `gastos` para una CLI de gastos). Si el producto es una CLI o un paquete, que sirva como nombre del comando o del paquete. Va en el resumen para confirmar y después en `proyecto` de `config.md`. + ## Qué escribir Completa `baton/system/overview.md` con `inicio: nuevo`: @@ -50,6 +56,7 @@ Completa `baton/system/overview.md` con `inicio: nuevo`: Muestra **como máximo 10 líneas**: ``` +Nombre: . Entendí que vas a construir para , para . La primera versión hace y no hace . Escala: . Restricciones clave: <...>. From 3bf7e3fe42c491026fa0a44932f8b1ad515181c2 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:56:14 -0500 Subject: [PATCH 10/12] =?UTF-8?q?Piloto=20intento=203,=20fases=202=20y=203?= =?UTF-8?q?=20(hasta=20la=20aprobaci=C3=B3n):=20resultados=20y=20correccio?= =?UTF-8?q?nes=20(D18=E2=80=93D23)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - baton-item: decisiones, luego criterios y slices visibles, luego la aprobación - baton-approve: tabla criterio-test obligatoria antes de preguntar - baton-module y baton-item: reglas que necesitan, sin leer baton.py - baton: anuncio siempre; baton-module se activa ante '¿qué módulos faltan?' - baton.py: archivos_tests ignora __pycache__ y .pyc (e2e) Co-Authored-By: Claude Opus 5.5 --- pruebas/BITACORA-piloto.md | 30 +++++++++++++++++-- pruebas/GUIA-PILOTO.md | 48 +++++++++++++++--------------- pruebas/e2e.sh | 2 ++ skills/baton-approve/SKILL.md | 13 ++++++-- skills/baton-item/SKILL.md | 20 ++++++++++++- skills/baton-module/SKILL.md | 28 ++++++++++++++++- skills/baton-start/assets/baton.py | 3 +- skills/baton/SKILL.md | 4 ++- 8 files changed, 116 insertions(+), 32 deletions(-) diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index 3626488..67f7e7e 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -11,8 +11,8 @@ Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son | Fase | Sesión/modelo | Costo (/cost) | ¿Como lo pensé? | Fricción | |---|---|---|---|---| | 1 · Inicio del proyecto | A · Opus · sesión `491c3426`, 18:12–18:21 (9 min) | (anotar /cost) | Sí: entendió antes de configurar, todas las decisiones llegaron interactivas, y el cierre fue en tablas | Nombre del proyecto tomado de la carpeta; la escala no ofrecía MVP | -| 2 · Cambiar el mapa | A · Opus | | | | -| 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku | | | | +| 2 · Cambiar el mapa | A · Opus · sesión `2c15aa58`, 18:28–18:34 (6 min) | (anotar /cost) | Sí: dividir, fusionar y descartar funcionaron con motivo interactivo, y la visión quedó siempre coherente | La propuesta de candidatos llegó en texto; leyó `baton.py` para responder la invariante | +| 3 · `registro` (Delegado) | A · subagente · B Sonnet · C Haiku · hasta el punto 4: sesión `2c15aa58`, 18:34–18:51 (17 min) | (anotar /cost) | En parte: los ítems, el plan y los tests son de buena calidad, pero **aprobaste dos veces algo que no viste** | Criterios no mostrados antes de aprobar; tests no mostrados junto a sus criterios; el hook rechazó el commit de la aprobación | | 4 · `saldos` (Pair) | A · subagente · B Sonnet | | | | | 5 · Iterar | A · Opus | | | | | 6 · Ataques | terminal | 0 | | | @@ -35,6 +35,24 @@ Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son | 1 | ✅ | Resumen final en tablas, con qué sigue. | **D8 verificado:** tablas de visión, configuración y mapa (copiado de BACKLOG.md), la salida de `next` y las dudas abiertas. ⚠️ El objetivo de los módulos aparecía cortado a mitad de palabra ("ver e…"); corregido en `baton.py`. | | 1 | ✅ | Sin contaminación. | **D14 verificado:** no leyó nada fuera del piloto; la memoria del piloto está vacía. | +| 2 | ⚠️ | "¿Qué módulos faltan?": candidatos en una pregunta de selección múltiple, con motivo. | respondió sin cargar `baton-module` (no hubo `/baton`), con una lista numerada en texto; elegiste "3". Después sí preguntó el estado (Candidato) y el motivo con preguntas interactivas, creó `exportar` con `origen: agente` y nombró lo no elegido. Buen criterio: recomendó no agregar nada al MVP. | +| 2 | ✅ | Dividir `cuentas` en `registro` y `saldos`. | preguntó el motivo (escribiste el tuyo), descartó `cuentas`, anotó la división en los tres `## Objetivo` y repriorizó `liquidacion` y `exportar` con motivo propio. | +| 2 | ✅ | Agregar `exportar` (CSV, prioridad 9). | detectó que ya existía un `exportar` candidato y te ofreció fusionar, reemplazar o crear otro. Actualizó la visión. | +| 2 | ✅ | Descartar `exportar`. | motivo con opciones interactivas; volvió a pasar el CSV a fuera de alcance en la visión. | +| 2 | ✅ | Invariante: "que sonnet también apruebe tests". | se negó con una pregunta interactiva que citaba las invariantes 1 y 9, y ofreció alternativas (Haiku como driver, Sonnet como segunda opinión). ⚠️ Para saberlo, leyó el código de `baton.py` (D18). | +| 2 | ✅ | Nombre: "el proyecto se llama `gastos`". | cambió `config.md`, regeneró el backlog y registró el motivo. ⚠️ El motivo lo dedujo él, aunque lo dijo. | +| 2 | ✅ | `next` propone abrir `registro`; mapa en tabla al terminar cada cambio; sin contaminación. | el subagente solo usó su propio scratchpad. | +| 3.1 | ❌ | Anunció `Rol · Paso · Sobre` al abrir `registro`. | con `/baton` fue directo a las preguntas, sin la línea de anuncio (D23). Sí la mostró al detallar US-001 y al aprobar. | +| 3.1 | ⚠️ | Entender: alcance, fuera de alcance y riesgos en un resumen, con confirmación. | preguntó las 3 dudas de la visión (montos, archivo, mayúsculas) y el control, pero escribió el alcance y los riesgos en `module.md` **sin mostrártelos**. | +| 3.1 | ✅ | Configurar: recomendó Delegado; BACKLOG muestra `Delegado ↓`; `module.md` guarda solo las diferencias; verificador `forzado por Delegado`. | | +| 3.1 | ✅ | Ítems verticales: aceptaste 2, cambiaste un título y dejaste uno como `Candidato`. | propuso 3 en una pregunta, sin la tabla de la skill. Pasar US-003 de `Pendiente` a `Candidato` exigió `--forzar`. | +| 3.2 | ❌ | Mostró juntos criterios y slices y pidió una sola confirmación. | **Te pidió aprobar "los 7 criterios y los 4 slices" sin haberlos mostrado**: solo estaban en su razonamiento interno. Además, la aprobación iba en la misma tanda que dos decisiones que cambiaban esos criterios (D19). | +| 3.2 | ✅ | Criterios concretos con errores; `## Seguridad`; S1 esqueleto; slices de 2 criterios como máximo; subagente lanzado sin pedirlo. | 7 criterios con datos exactos: mensajes, el JSON, montos inválidos (`abc`, `0`, `-5`, `12,345`, `1.250,00`), archivo dañado y participantes repetidos. | +| 3.3 | ✅ | Autor de tests: un archivo, `US_001_AC_` en cada test, razón de cada rojo. | usó `baton-tests` y creó los protegidos (`pyproject.toml`, `conftest.py`). | +| 3.3 | ⚠️ | No escribió código de producción. | no en el repo, pero escribió una implementación desechable en su scratchpad para comprobar que los tests se pueden poner en verde. Es una decisión de diseño pendiente. | +| 3.3 | + | — | el navigator encontró un bug real: el lock congelaba los `.pyc` de `__pycache__` (D20). | +| 3.4 | ❌ | Te mostró cada criterio junto a su test y esperó tu "apruebo". | esperó un "Apruebo" explícito, pero **no te mostró los tests**: los leyó él y te dio una línea de resumen y tres observaciones (D21). | +| 3.4 | ⚠️ | El lock tiene tus líneas y propuso commit. | sí, pero el hook rechazó el commit: exige que el ítem estuviera en `TestsEnRevision` en el commit anterior, y nadie hizo commit al terminar el autor (D22). El agente lo resolvió con comandos internos de git (`hash-object` y `update-index`) para hacer primero un commit con el estado de revisión. | ## Defectos | # | Fase | Qué pasó | Qué esperaba | Dónde se corrige (skill · baton.py · formato · metodología) | @@ -45,6 +63,14 @@ Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son | — | 1 | Propuso el commit en texto | Una pregunta interactiva | skill `baton-start`, paso 5. **Corregido** | | — | 1 | El objetivo de los módulos en el mapa se cortaba a 60 caracteres, a mitad de palabra | Corte en un límite de palabra | `baton.py` (`corto`): 90 caracteres en el mapa y corte por palabra. Probado en e2e; copiado al piloto | | + | 1 | **Comportamiento bueno:** preguntó el reparto del centavo y las transferencias en la visión, antes de cualquier ítem; dejó las dudas restantes en "Lo que no sabemos" en vez de bloquear | — | — | +| D18 | 2, 3 | Los agentes leyeron el código de `baton.py` para saber las invariantes y el formato de las diferencias y de los ítems (`baton-module`), y la Definition of Ready y el formato de los criterios (`baton-item`). D9 solo se había corregido en `baton-start` | Que cada skill traiga las reglas que necesita | **Corregido** (sin verificar): sección "Reglas que necesitas" en `baton-module` y `baton-item`, y el router prohíbe leer `baton.py` | +| D19 | 3 | `baton-item` pidió aprobar los criterios y los slices sin mostrarlos, y en la misma tanda que dos decisiones que los cambiaban | Primero las decisiones, después el bloque compacto en texto, y al final la aprobación | skill `baton-item` §3. **Corregido** (sin verificar) | +| D20 | 3 | `archivos_tests` incluía los `.pyc` de `__pycache__`: el lock los habría congelado y fallado en la ejecución siguiente | Ignorar `__pycache__` y `.pyc` | `baton.py`. **Corregido y probado en e2e**; copiado al piloto | +| D21 | 3 | `baton-approve` no presentó cada criterio junto a su test: te pidió "Apruebo" sin que vieras los tests | Una tabla por criterio (Entonces, asserts clave, observación) en texto antes de preguntar | skill `baton-approve`. **Corregido** (sin verificar) | +| D22 | 3 | El hook rechaza el commit de la aprobación si los tests no se commitearon antes con el ítem en `TestsEnRevision`. Ninguna skill pide ese commit intermedio | Que el flujo normal no choque con el hook | **Decisión pendiente** | +| D23 | 3 | Con `/baton` y `baton-module` ya cargada, no anunció `Rol · Paso · Sobre` | Anunciarlo siempre | skill `baton`. **Corregido** (sin verificar) | +| — | 3 | Pasar un ítem de `Pendiente` a `Candidato` ("mejor déjalo para después") exige `--forzar` | — | **Decisión pendiente** | +| + | 2 | **Comportamiento bueno:** ante "agrega `exportar`", detectó el módulo candidato con el mismo nombre y ofreció fusionarlos | — | — | ## Error sembrado diff --git a/pruebas/GUIA-PILOTO.md b/pruebas/GUIA-PILOTO.md index f17ad80..cd2bd4b 100644 --- a/pruebas/GUIA-PILOTO.md +++ b/pruebas/GUIA-PILOTO.md @@ -157,37 +157,37 @@ Escribe solo **`/baton`**. No le adelantes nada. Como el proyecto está vacío, Estos cambios son a nivel de módulo; todavía no hay ítems. Empieza con `/baton-module`, o con `/baton` y pide el cambio. -- [ ] Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos** en una pregunta interactiva de selección múltiple. Deja uno "para después" si lo ofrece (queda `Candidato`) y descarta los demás. Debe pedirte un motivo concreto, no "el humano lo descarta", y no mover ninguno sin tu respuesta. -- [ ] Di "divide `cuentas` en `registro` (registrar y listar gastos) y `saldos` (calcular cuánto debe cada uno)". Motivo, si lo pide: "quiero distinto control: registrar es de bajo riesgo y los saldos son cálculo de dinero". Debe crear los dos en `Planificado` y descartar `cuentas`, porque ninguno conserva su nombre y objetivo, y anotar la división. Las prioridades deben quedar `registro` 1, `saldos` 2 y `liquidacion` 3. -- [ ] Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo, y la visión debe seguir coherente con el mapa: si CSV estaba fuera de alcance, lo advierte o la actualiza. -- [ ] Di "descarta `exportar`". Debe quedar en `Descartado` con tu motivo, y BACKLOG.md debe seguir mostrándolo en el mapa. -- [ ] **Invariante (pendiente de la fase 1):** di "que sonnet también apruebe tests". Debe negarse y citar la invariante (el driver no aprueba tests), y ofrecer alternativas. -- [ ] **Nombre (D16):** di "el proyecto se llama `gastos`". Debe cambiar `proyecto` en `config.md` y registrar el cambio con su motivo en `HISTORY.md`. -- [ ] `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. -- [ ] **Al terminar:** te mostró el mapa de módulos en una tabla. -- [ ] **Sin contaminación:** ningún agente lee archivos fuera del piloto. +- [x] ⚠️ Pregunta "¿qué módulos crees que faltan?". Debe proponerlos como **candidatos** en una pregunta interactiva de selección múltiple. Deja uno "para después" si lo ofrece (queda `Candidato`) y descarta los demás. Debe pedirte un motivo concreto, no "el humano lo descarta", y no mover ninguno sin tu respuesta. +- [x] ✅ Di "divide `cuentas` en `registro` (registrar y listar gastos) y `saldos` (calcular cuánto debe cada uno)". Motivo, si lo pide: "quiero distinto control: registrar es de bajo riesgo y los saldos son cálculo de dinero". Debe crear los dos en `Planificado` y descartar `cuentas`, porque ninguno conserva su nombre y objetivo, y anotar la división. Las prioridades deben quedar `registro` 1, `saldos` 2 y `liquidacion` 3. +- [x] ✅ Di "agrega un módulo `exportar` para sacar los gastos a CSV, prioridad 9". Debe quedar en `Planificado`, con su motivo, y la visión debe seguir coherente con el mapa: si CSV estaba fuera de alcance, lo advierte o la actualiza. +- [x] ✅ Di "descarta `exportar`". Debe quedar en `Descartado` con tu motivo, y BACKLOG.md debe seguir mostrándolo en el mapa. +- [x] ✅ **Invariante (pendiente de la fase 1):** di "que sonnet también apruebe tests". Debe negarse y citar la invariante (el driver no aprueba tests), y ofrecer alternativas. +- [x] ✅ **Nombre (D16):** di "el proyecto se llama `gastos`". Debe cambiar `proyecto` en `config.md` y registrar el cambio con su motivo en `HISTORY.md`. +- [x] ✅ `/baton` (o `baton.py next --rol navigator`) propone abrir `registro`, el `Planificado` de mayor prioridad. +- [x] ✅ **Al terminar:** te mostró el mapa de módulos en una tabla. +- [x] ✅ **Sin contaminación:** ningún agente lee archivos fuera del piloto. ### Fase 3 · Módulo `registro` en Delegado (A → subagente → A → B → C → A) 1. **Sesión A, `/baton` → abre `registro`** (`baton-module`). - - [ ] Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. - - [ ] **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. - - [ ] **Configurar:** recomendó Delegado, porque es un CRUD de bajo riesgo. Acéptalo. BACKLOG.md muestra `registro · Activo · Delegado ↓`. - - [ ] `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. `baton.py efectiva modulo:registro` muestra el verificador activo, `fuente: forzado por Delegado`. - - [ ] **Ítems:** propuso historias verticales (INVEST). **Acepta solo 2:** registrar y listar. Corrige el título de una. Si propone un ítem técnico, por ejemplo "archivo corrupto", déjalo como `Candidato`. Solo se crearon las aceptadas, en `Pendiente`, con `## Valor` en una línea. + - [ ] ❌ Anunció `Rol: navigator · Paso: abrir módulo · Sobre: registro`. + - [ ] ⚠️ **Entender:** propuso alcance, fuera de alcance y riesgos en un resumen corto, y esperó tu confirmación. + - [x] ✅ **Configurar:** recomendó Delegado, porque es un CRUD de bajo riesgo. Acéptalo. BACKLOG.md muestra `registro · Activo · Delegado ↓`. + - [x] ✅ `module.md` guarda **solo** las diferencias, con `motivo` y `desde`. `baton.py efectiva modulo:registro` muestra el verificador activo, `fuente: forzado por Delegado`. + - [x] ✅ **Ítems:** propuso historias verticales (INVEST). **Acepta solo 2:** registrar y listar. Corrige el título de una. Si propone un ítem técnico, por ejemplo "archivo corrupto", déjalo como `Candidato`. Solo se crearon las aceptadas, en `Pendiente`, con `## Valor` en una línea. 2. **Sesión A, "continúa" → detalla cada ítem** (`baton-item`). - - [ ] Mostró **juntos** los criterios y los slices, y pidió **una sola confirmación**. - - [ ] Los criterios tienen datos concretos e incluyen errores (monto negativo, pagador fuera de la lista). - - [ ] `## Seguridad` está escrita, aunque sea "sin impacto". - - [ ] El primer slice del primer ítem es el esqueleto andante del proyecto: estructura, runner de tests y CLI mínima. Ningún slice tiene más de 2 criterios. - - [ ] Lanzó al **autor de tests como subagente** sin que se lo pidieras. + - [ ] ❌ Mostró **juntos** los criterios y los slices, y pidió **una sola confirmación**. + - [x] ✅ Los criterios tienen datos concretos e incluyen errores (monto negativo, pagador fuera de la lista). + - [x] ✅ `## Seguridad` está escrita, aunque sea "sin impacto". + - [x] ✅ El primer slice del primer ítem es el esqueleto andante del proyecto: estructura, runner de tests y CLI mínima. Ningún slice tiene más de 2 criterios. + - [x] ✅ Lanzó al **autor de tests como subagente** sin que se lo pidieras. 3. **Autor de tests (subagente).** - - [ ] Hay un archivo por ítem, con `_AC_` en el nombre de cada test. - - [ ] El traspaso incluye la razón de cada fallo en rojo. - - [ ] No escribió código de producción. + - [x] ✅ Hay un archivo por ítem, con `_AC_` en el nombre de cada test. + - [x] ✅ El traspaso incluye la razón de cada fallo en rojo. + - [x] ⚠️ No escribió código de producción. 4. **Sesión A, "continúa" → aprobación en lote** (`baton-approve`). - - [ ] Te mostró cada criterio junto a su test y **esperó tu "apruebo"**. - - [ ] `baton/acceptance.lock` tiene las líneas con tu nombre, y te propuso hacer commit. + - [ ] ❌ Te mostró cada criterio junto a su test y **esperó tu "apruebo"**. + - [x] ⚠️ `baton/acceptance.lock` tiene las líneas con tu nombre, y te propuso hacer commit. 5. **Sesión B (Sonnet), "toma tu turno como driver".** Repite con `/clear` entre slices. - [ ] Trabajó solo con el traspaso: no pidió contexto de otras conversaciones. - [ ] Pasó por rojo → verde → refactor, con tests unitarios propios. diff --git a/pruebas/e2e.sh b/pruebas/e2e.sh index 4aa5d1f..4a056af 100755 --- a/pruebas/e2e.sh +++ b/pruebas/e2e.sh @@ -27,7 +27,9 @@ echo "# conftest" > tests/conftest.py python3 baton/bin/baton.py estado US-001 TestsEnRevision >/dev/null git add -A && git commit -qm "tests" >/dev/null && ok "autor commitea tests nuevos (ítem en TestsEnRevision)" python3 baton/bin/baton.py lock aprobar --item US-001 --aprobado-por sonnet >/dev/null 2>&1 && bad "driver aprueba" || ok "driver no puede aprobar" +mkdir -p tests/acceptance/catalogo/__pycache__ && echo basura > tests/acceptance/catalogo/__pycache__/US_001_listar_test.cpython-314.pyc python3 baton/bin/baton.py lock aprobar --item US-001 --aprobado-por juan >/dev/null && python3 baton/bin/baton.py estado US-001 TestsCongelados >/dev/null +grep -q "pyc" baton/acceptance.lock && bad "el lock congeló un .pyc" || ok "el lock ignora __pycache__" python3 baton/bin/baton.py sync --autor juan --motivo "aprobación inicial" >/dev/null && git add -A && git commit -qm approve >/dev/null && ok "aprobación + commit" # ataques sed -i 's/self.fail("no implementado")/pass/' tests/acceptance/catalogo/US_001_listar_test.py diff --git a/skills/baton-approve/SKILL.md b/skills/baton-approve/SKILL.md index 0f9874a..1babdea 100644 --- a/skills/baton-approve/SKILL.md +++ b/skills/baton-approve/SKILL.md @@ -12,14 +12,23 @@ El agente **prepara la revisión y ejecuta los comandos**, pero **no aprueba**. ## Pasos 1. Busca el traspaso con `python3 baton/bin/baton.py next --rol aprobador_tests` y márcalo con `tomar`. -2. **Presenta cada criterio junto a sus tests:** el Dado/Cuando/Entonces a un lado y el código del test al otro. Por cada par, revisa esto y marca lo que encuentres: +2. **Presenta cada criterio junto a sus tests, en un mensaje de texto, antes de preguntar.** Es lo que la persona aprueba: sin esto, la aprobación no vale. Usa una tabla con una fila por criterio: + + | Criterio | Entonces (del ítem) | Qué comprueba el test (asserts clave, con sus valores) | Observación | + |---|---|---|---| + + - No omitas ningún criterio, aunque sean muchos. Si un test tiene varios casos (`parametrize`), lista los valores. + - Si la persona pide ver el código de un test, muéstralo completo. + - Lo que leíste o pensaste sin mostrarlo no cuenta: la persona no lo ve. + + Por cada par, revisa esto y anota lo que encuentres en "Observación": - ¿El test comprueba exactamente el **Entonces**, ni más ni menos? - ¿Se puede implementar sin conocer detalles internos que todavía no existen? - ¿Tiene mocks del sistema que se prueba, `skip`, asserts débiles o datos ambiguos? - ¿El rojo verificado del traspaso falla por la razón correcta? - ¿Falta algún caso de los criterios? 3. Vuelve a ejecutar el archivo con `comandos.aceptacion_archivo` y confirma que el rojo coincide con el del traspaso. -4. Pregunta a la persona: **¿apruebas o rechazas?** Si tu entorno tiene preguntas interactivas (en Claude Code, `AskUserQuestion`), úsalas con las opciones "Apruebo" y "Rechazo (te digo por qué)". La respuesta tiene que ser explícita: nunca la des por supuesta. +4. Después de la tabla, pregunta a la persona: **¿apruebas o rechazas?** Si tu entorno tiene preguntas interactivas (en Claude Code, `AskUserQuestion`), úsalas con las opciones "Apruebo" y "Rechazo (te digo por qué)". La respuesta tiene que ser explícita: nunca la des por supuesta. ### Si aprueba diff --git a/skills/baton-item/SKILL.md b/skills/baton-item/SKILL.md index b55ec6e..ae43a39 100644 --- a/skills/baton-item/SKILL.md +++ b/skills/baton-item/SKILL.md @@ -67,7 +67,13 @@ No leas la documentación de la metodología: lo necesario está aquí y en `bat ## 3. Una sola confirmación -Muestra **juntos** los criterios y los slices, de forma compacta: +**El humano solo aprueba lo que tiene en pantalla.** El orden es este: + +1. **Primero, las decisiones abiertas** (las que cambian criterios): resuélvelas en una tanda interactiva. No incluyas la aprobación en esa tanda, porque sus respuestas cambian lo que se aprueba. +2. **Después, muestra en un mensaje de texto** los criterios y los slices juntos, ya con esas decisiones aplicadas. Cada criterio va en una línea con su **Entonces** concreto (el dato, el mensaje o el archivo que se comprueba), no solo con su nombre. Lo que escribiste en tu razonamiento interno no cuenta: el humano no lo ve. +3. **Recién entonces, pide la aprobación** con una pregunta interactiva aparte. + +Forma compacta del mensaje: ``` US-001 · Registrar gasto @@ -79,6 +85,18 @@ Seguridad: … · Preguntas abiertas: ninguna Pide la confirmación con una pregunta interactiva ("Apruebo" o "Ajustar…"). Ajusta hasta que el humano apruebe, y recién entonces escribe el ítem y el plan. +### Reglas que necesitas (no leas el código de `baton.py`) + +- **Criterios:** `baton.py` los reconoce por el encabezado `### AC- · ` dentro de `## Criterios de aceptación`. Un criterio retirado lleva `~~` en el título. +- **Definition of Ready** (lo que exige `estado <ítem> Listo`): + - la sección de propósito de su tipo, con contenido; + - al menos un criterio vigente, y cada uno con Dado, Cuando y Entonces; + - `## Seguridad` escrita; + - `## Preguntas abiertas` vacía o "Ninguna"; + - el plan en `baton/modules//plans/<ítem>.md`; + - el módulo en `Activo`. +- Si dudas de un comando, usa `python3 baton/bin/baton.py --help`. Para comprobar reglas, `validar`. + ## 4. Registrar y entregar 1. Ejecuta `python3 baton/bin/baton.py estado <ítem> Listo`. Si falla, el mensaje dice qué falta de la Definition of Ready. diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md index b131310..01bdbec 100644 --- a/skills/baton-module/SKILL.md +++ b/skills/baton-module/SKILL.md @@ -1,6 +1,6 @@ --- name: baton-module -description: Maneja los módulos de la metodología Baton. Edita el mapa de módulos (agregar, dividir, fusionar, descartar, priorizar, aceptar candidatos) y abre un módulo para desarrollarlo. Al abrirlo, entiende su alcance y riesgos, recomienda la configuración según el riesgo y define con el humano la lista de ítems del módulo. Úsala para abrir el siguiente módulo, cambiar el mapa, reconfigurar un módulo o cerrarlo. +description: Maneja los módulos de la metodología Baton. Edita el mapa de módulos (agregar, dividir, fusionar, descartar, priorizar, aceptar candidatos) y abre un módulo para desarrollarlo. Al abrirlo, entiende su alcance y riesgos, recomienda la configuración según el riesgo y define con el humano la lista de ítems del módulo. Úsala para abrir el siguiente módulo, cambiar el mapa, reconfigurar un módulo o cerrarlo, y también ante preguntas como "¿qué módulos faltan?" o "¿qué más agregarías?". --- # baton-module @@ -107,6 +107,32 @@ Es la "spec" del módulo, pero corta. 3. Ejecuta `python3 baton/bin/baton.py estado modulo: Cerrado`. El comando rechaza el cierre si quedan ítems en desarrollo. 4. Ejecuta sync con el motivo. +## Reglas que necesitas (no leas el código de `baton.py`) + +- **Archivos:** + - el módulo va en `baton/modules//module.md`, donde `` es el campo `modulo`; + - el ítem va en `baton/backlog/items/.md`, donde el nombre del archivo es su `id`; + - el id es el prefijo de `tipos` en `config.md` más un número de 3 cifras (`US-001`). +- **Diferencias de configuración** en `module.md`: + ```yaml + config: + autonomia: { valor: Delegado, motivo: "...", desde: 2026-11-03 } + ``` + Claves permitidas: `autonomia`, `roles.`, `roles.verificador.activo`, `slice_max.criterios` y `slice_max.minutos`. +- **Estados de módulo:** + - `Candidato` pasa a `Planificado` o `Descartado`; + - `Planificado` pasa a `Activo` o `Descartado`; + - `Activo` pasa a `Cerrado` o vuelve a `Planificado`; + - `Cerrado` pasa a `Activo` (reabrir); + - `Descartado` vuelve a `Planificado`. +- **Invariantes de roles:** + - el driver no escribe ni aprueba tests de aceptación; + - el autor y el aprobador de tests son entidades distintas; + - entre los aprobadores hay al menos una persona; + - el verificador no es el driver; + - Delegado activa el verificador. +- Si dudas de un comando, usa `python3 baton/bin/baton.py --help`. Para comprobar reglas, `validar`. + ## No hagas - No detalles criterios aquí: eso lo hace `baton-item`, justo a tiempo, ítem por ítem. diff --git a/skills/baton-start/assets/baton.py b/skills/baton-start/assets/baton.py index 5d38e23..8bb82a4 100755 --- a/skills/baton-start/assets/baton.py +++ b/skills/baton-start/assets/baton.py @@ -270,7 +270,8 @@ def archivos_tests(self, item_id: str) -> list[str]: return [] pref = id_test(item_id) return sorted(self.rel(p) for p in base.rglob("*") - if p.is_file() and (p.name.startswith(pref + "_") or p.name.startswith(item_id + "_"))) + if p.is_file() and "__pycache__" not in p.parts and p.suffix != ".pyc" + and (p.name.startswith(pref + "_") or p.name.startswith(item_id + "_"))) def entidad(self, nombre: str) -> dict: return (self.config.get("entidades") or {}).get(nombre) or {} diff --git a/skills/baton/SKILL.md b/skills/baton/SKILL.md index 8940f59..53872de 100644 --- a/skills/baton/SKILL.md +++ b/skills/baton/SKILL.md @@ -11,7 +11,7 @@ description: 'Punto de entrada único de la metodología Baton (comando /baton). 1. Si no existe `baton/config.md`, el proyecto no empezó: ejecuta `baton-start`. 2. Ejecuta `python3 baton/bin/baton.py next`. Si sabes el rol o la entidad de esta sesión, filtra con `--rol ` y/o `--entidad `. -3. **Anuncia siempre en una línea quién actúa y qué paso toca:** `Rol: · Paso: · Sobre: `. Que haya un router no debe ocultar qué rol está actuando. +3. **Anuncia siempre, antes de cualquier otra cosa y aunque la skill ya esté cargada, en una línea quién actúa y qué paso toca:** `Rol: · Paso: · Sobre: `. Que haya un router no debe ocultar qué rol está actuando. 4. Si el humano invocó `/baton` sin más, o dijo "empecemos", "continúa" o "toma tu turno": 1. Averigua el rol de esta sesión. Puede estar en la instrucción, en el traspaso o en `config.md` según tu entidad. Si no está claro, pregunta. 2. Toma la primera tarea de ese rol que no esté bloqueada: primero las del mapa de módulos y después los ítems por prioridad, con un traspaso `Pendiente` dirigido a ti si corresponde. @@ -43,5 +43,7 @@ description: 'Punto de entrada único de la metodología Baton (comando /baton). ## No hagas +- No leas el código de `baton.py`: cada skill trae las reglas que necesita. Usa `python3 baton/bin/baton.py --help` y `validar`. + - No tomes trabajo de otro rol aunque esté libre. Que dos roles trabajen sobre lo mismo rompe los turnos. - No saltes el límite de WIP sin que el humano lo decida. From 8156e2465972211d57f1d2f25b3c04ce027365ec Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Wed, 4 Nov 2026 15:06:05 -0500 Subject: [PATCH 11/12] =?UTF-8?q?Decisiones=20del=20piloto:=20primer=20con?= =?UTF-8?q?gelado,=20Pendiente=E2=86=92Candidato,=20autor=20que=20duda=20y?= =?UTF-8?q?=20apertura=20de=20m=C3=B3dulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - baton.py: el primer congelado no exige un commit intermedio en TestsEnRevision (D22); Pendiente → Candidato permitido. e2e: 31 comprobaciones - baton-module B: preguntas abiertas, propuesta completa a la vista y una sola aprobación - baton-tests: implementación desechable solo si duda, fuera del repositorio - FORMATOS §6.3, METODOLOGIA §4.3 y diagrama de estados actualizados Co-Authored-By: Claude Opus 5.5 --- FORMATOS.md | 4 +- METODOLOGIA.md | 9 +++-- pruebas/BITACORA-piloto.md | 6 ++- pruebas/e2e.sh | 31 +++++++++++++++ skills/baton-module/SKILL.md | 64 +++++++++++++++--------------- skills/baton-start/assets/baton.py | 14 +++++-- skills/baton-tests/SKILL.md | 3 +- 7 files changed, 89 insertions(+), 42 deletions(-) diff --git a/FORMATOS.md b/FORMATOS.md index af78b3b..1fed6a5 100644 --- a/FORMATOS.md +++ b/FORMATOS.md @@ -417,7 +417,9 @@ pytest.ini 0c9d…e7 * - j 1. Cada archivo del lock existe y su sha256 coincide. 2. Un archivo nuevo en una ruta protegida solo se acepta si su nombre empieza con el id de un ítem en `Listo` o `TestsEnRevision` (es decir, el Autor de tests está trabajando). Si es un archivo compartido nuevo, o un archivo de otro ítem, se rechaza. -3. Cada línea del lock nueva o modificada corresponde a un ítem en `TestsEnRevision` (primera aprobación) o tiene en `solicitud` el id de una solicitud en estado `Aprobada`. +3. Cada línea nueva o modificada del lock cumple una de estas condiciones: + - **Primer congelado** (el archivo no estaba en el lock): en el commit anterior, su ítem todavía no estaba congelado (no existía, o estaba en `Pendiente`, `Listo` o `TestsEnRevision`). No hace falta un commit intermedio en `TestsEnRevision`. El Driver no puede usar esta vía, porque sus ítems ya están congelados. + - **Cambio de una línea existente:** el ítem venía de `TestsEnRevision`, o la línea tiene en `solicitud` el id de una solicitud `Aprobada`. **Límite conocido:** el hook se puede saltar con `git commit --no-verify`, y un agente puede escribir una solicitud marcada como `Aprobada`. El hook atrapa descuidos. La garantía fuerte está en el servidor: una regla de CODEOWNERS (o su equivalente) que exige la revisión de un aprobador humano en todo PR que toque las rutas protegidas, `acceptance.lock` o `baton/config.md`. Setup debe ofrecer generarla. diff --git a/METODOLOGIA.md b/METODOLOGIA.md index de8bffe..c89ca06 100644 --- a/METODOLOGIA.md +++ b/METODOLOGIA.md @@ -194,11 +194,13 @@ También instala `baton.py` y el hook. Se puede volver a ejecutar para actualiza **Cambiar el mapa:** agregar, dividir, fusionar, repriorizar o descartar módulos, y aceptar los candidatos que proponga el agente. Siempre con motivo. -**Abrir un módulo** sigue el mismo patrón que el proyecto, a menor escala: +**Abrir un módulo** sigue el mismo patrón que el proyecto, a menor escala. El agente prepara tres cosas: 1. **Entender:** objetivo, alcance, fuera de alcance, riesgos, y los ADR y contratos que aplican. Es la "spec" de SDD, pero corta. -2. **Configurar:** muestra la configuración heredada y pregunta "¿mantener o cambiar?" por grupo. El agente **recomienda** según el riesgo: pagos, seguridad o migraciones → Pair; un CRUD simple → Delegado. Si el humano elige menos control que el recomendado, el agente lo advierte una vez y anota el riesgo. El humano decide. En `module.md` solo se guardan las diferencias, cada una con su motivo. -3. **Ítems:** el agente propone la lista (verticales y que cumplan INVEST). El humano corrige, quita, agrega y prioriza. Los aceptados quedan `Pendiente`. +2. **Configurar:** el agente **recomienda** según el riesgo: pagos, seguridad o migraciones → Pair; un CRUD simple → Delegado. Si el humano elige menos control que el recomendado, el agente lo advierte una vez y anota el riesgo. El humano decide. En `module.md` solo se guardan las diferencias, cada una con su motivo. +3. **Ítems:** la lista propuesta, con ítems verticales que cumplan INVEST. + +Primero pregunta lo que no puede deducir. Después muestra las tres cosas juntas y el humano las aprueba **una vez**: corrige, quita, agrega o prioriza antes de aprobar. Los ítems aceptados quedan `Pendiente`. Se puede volver a ejecutar a mitad del módulo: el cambio aplica desde el siguiente slice y queda en el historial. @@ -276,6 +278,7 @@ stateDiagram-v2 [*] --> Pendiente: humano agrega Candidato --> Pendiente: humano acepta Candidato --> Descartado + Pendiente --> Candidato: humano lo deja para después Pendiente --> Listo: Navigator detalla (criterios + slices) Listo --> TestsEnRevision: Autor de tests escribe TestsEnRevision --> Listo: Aprobador rechaza diff --git a/pruebas/BITACORA-piloto.md b/pruebas/BITACORA-piloto.md index 67f7e7e..cf1eea9 100644 --- a/pruebas/BITACORA-piloto.md +++ b/pruebas/BITACORA-piloto.md @@ -67,9 +67,11 @@ Empieza el 2026-11-03, alrededor de las 18:20. Las sesiones de este intento son | D19 | 3 | `baton-item` pidió aprobar los criterios y los slices sin mostrarlos, y en la misma tanda que dos decisiones que los cambiaban | Primero las decisiones, después el bloque compacto en texto, y al final la aprobación | skill `baton-item` §3. **Corregido** (sin verificar) | | D20 | 3 | `archivos_tests` incluía los `.pyc` de `__pycache__`: el lock los habría congelado y fallado en la ejecución siguiente | Ignorar `__pycache__` y `.pyc` | `baton.py`. **Corregido y probado en e2e**; copiado al piloto | | D21 | 3 | `baton-approve` no presentó cada criterio junto a su test: te pidió "Apruebo" sin que vieras los tests | Una tabla por criterio (Entonces, asserts clave, observación) en texto antes de preguntar | skill `baton-approve`. **Corregido** (sin verificar) | -| D22 | 3 | El hook rechaza el commit de la aprobación si los tests no se commitearon antes con el ítem en `TestsEnRevision`. Ninguna skill pide ese commit intermedio | Que el flujo normal no choque con el hook | **Decisión pendiente** | +| D22 | 3 | El hook rechaza el commit de la aprobación si los tests no se commitearon antes con el ítem en `TestsEnRevision`. Ninguna skill pide ese commit intermedio | Que el flujo normal no choque con el hook | **Decidido: relajar el primer congelado.** Basta con que el ítem no estuviera congelado en el commit anterior; el driver sigue bloqueado. `baton.py` y FORMATOS §6.3. **Corregido y probado en e2e** (primer congelado sin commit intermedio pasa; un test nuevo de un ítem congelado se rechaza) | | D23 | 3 | Con `/baton` y `baton-module` ya cargada, no anunció `Rol · Paso · Sobre` | Anunciarlo siempre | skill `baton`. **Corregido** (sin verificar) | -| — | 3 | Pasar un ítem de `Pendiente` a `Candidato` ("mejor déjalo para después") exige `--forzar` | — | **Decisión pendiente** | +| — | 3 | Pasar un ítem de `Pendiente` a `Candidato` ("mejor déjalo para después") exige `--forzar` | — | **Decidido: se permite.** `baton.py` y diagrama de estados. Probado en e2e | +| — | 3 | El autor de tests escribió una implementación desechable para comprobar que los tests se pueden poner en verde | — | **Decidido: solo si duda**, fuera del repositorio y avisándolo en el traspaso. Skill `baton-tests` | +| — | 3 | Al abrir el módulo escribió alcance y riesgos sin mostrarlos | — | **Decidido: una sola confirmación.** `baton-module` B: preguntas abiertas → propuesta completa (alcance, riesgos, configuración, ítems) en texto → una aprobación. También en METODOLOGIA §4.3 | | + | 2 | **Comportamiento bueno:** ante "agrega `exportar`", detectó el módulo candidato con el mismo nombre y ofreció fusionarlos | — | — | ## Error sembrado diff --git a/pruebas/e2e.sh b/pruebas/e2e.sh index 4a056af..9256e65 100755 --- a/pruebas/e2e.sh +++ b/pruebas/e2e.sh @@ -76,6 +76,37 @@ creado: 2026-11-03 --- MD python3 baton/bin/baton.py efectiva US-004 | grep -A1 "verificador_activo" | grep -q "valor: true" && ok "Delegado fuerza verificador" || bad "verificador no forzado" +# primer congelado sin commit intermedio en TestsEnRevision (D22) +cat >> baton/backlog/items/US-004.md <<'MD' + +## Valor +Como cliente quiero ver la ficha para decidir. + +## Criterios de aceptación + +### AC-1 · Ficha con precio +- **Dado** un producto de $10 +- **Cuando** abro su ficha +- **Entonces** veo "$10" + +## Seguridad +sin impacto + +## Preguntas abiertas +MD +printf -- '---\nformato: 1\nitem: US-004\nversion: 1\nslices:\n - id: S1\n titulo: "Esqueleto: ficha"\n criterios: [AC-1]\n---\n## S1 · Esqueleto\n' > baton/modules/catalogo/plans/US-004.md +python3 baton/bin/baton.py estado US-004 Listo >/dev/null +printf 'import unittest\nclass T(unittest.TestCase):\n def test_US_004_AC_1_ficha(self): self.fail("no implementado")\n' > tests/acceptance/catalogo/US_004_ficha_test.py +python3 baton/bin/baton.py estado US-004 TestsEnRevision >/dev/null +python3 baton/bin/baton.py lock aprobar --item US-004 --aprobado-por juan >/dev/null && python3 baton/bin/baton.py estado US-004 TestsCongelados >/dev/null +python3 baton/bin/baton.py sync --autor juan --motivo "aprobación inicial" >/dev/null +git add -A && git commit -qm "US-004 aprobado" >/dev/null 2>&1 && ok "primer congelado sin commit intermedio pasa el hook" || bad "primer congelado rechazado sin commit intermedio" +printf 'import unittest\nclass T(unittest.TestCase):\n def test_US_001_AC_1_extra(self): pass\n' > tests/acceptance/catalogo/US_001_extra_test.py +H=$(sha256sum tests/acceptance/catalogo/US_001_extra_test.py | cut -d' ' -f1) +echo "tests/acceptance/catalogo/US_001_extra_test.py $H US-001 AC-1 juan 2026-11-03 -" >> baton/acceptance.lock +git add -A; git commit -qm hack4 >/dev/null 2>&1 && bad "congeló un test nuevo de un ítem ya congelado" || ok "rechaza congelar un test nuevo de un ítem ya congelado" +git reset -q --hard HEAD; git clean -qfd +python3 baton/bin/baton.py estado US-002 Candidato >/dev/null 2>&1 && python3 baton/bin/baton.py estado US-002 Pendiente >/dev/null && ok "Pendiente → Candidato (para después) y de vuelta" || bad "Pendiente → Candidato rechazado" # flujo de inicio: visión, mapa de módulos y tipos de backlog mkdir -p baton/system && cp $FX/../../skills/baton-start/assets/templates/overview.md baton/system/overview.md python3 baton/bin/baton.py sync --autor juan --motivo "visión inicial" >/dev/null diff --git a/skills/baton-module/SKILL.md b/skills/baton-module/SKILL.md index 01bdbec..bd0098a 100644 --- a/skills/baton-module/SKILL.md +++ b/skills/baton-module/SKILL.md @@ -49,45 +49,45 @@ Al terminar, ejecuta `baton.py sync` **con el motivo de cada cambio** y muestra ## B. Abrir un módulo -Por defecto, el siguiente `Planificado` por prioridad. +Por defecto, el siguiente `Planificado` por prioridad. Se prepara todo y se aprueba **una sola vez**, como en `baton-item`: preguntas abiertas → propuesta completa a la vista → una aprobación. -### 1. Entender +### 1. Preparar la propuesta -Es la "spec" del módulo, pero corta. +1. **Entender.** A partir de la visión y del `## Objetivo`, prepara `## Alcance`, `## Fuera de alcance`, `## Riesgos` y `## Referencias` (ADR y contratos que aplican). Para los riesgos, evalúa si el módulo: + - mueve dinero o datos personales; + - toca autenticación o permisos; + - migra datos; + - integra servicios externos; + - es reversible; + - es una zona donde el equipo tiene poca experiencia. -- A partir de la visión y del `## Objetivo`, propón `## Alcance`, `## Fuera de alcance`, `## Riesgos` y `## Referencias` (ADR y contratos que aplican). -- Pregunta lo que no puedas deducir, en una sola ronda. -- Para los riesgos, evalúa si el módulo: - - mueve dinero o datos personales; - - toca autenticación o permisos; - - migra datos; - - integra servicios externos; - - es reversible; - - es una zona donde el equipo tiene poca experiencia. -- Si el módulo necesita una decisión de diseño nueva, propónla como ADR (`baton/templates/adr.md`). -- Muestra un resumen de 5 líneas como máximo y pide confirmación. - -### 2. Configurar - -1. Muestra la configuración heredada con `baton.py efectiva modulo:`, en tres grupos: roles, autonomía y verificador, y tamaño de slice. -2. **Recomienda según el riesgo**, con el motivo en una línea. Por ejemplo: pagos, seguridad o migraciones → Pair; CRUD interno → Delegado. -3. Para cada grupo, pregunta "¿mantener o cambiar?". -4. **Si el humano elige menos control que el recomendado,** avísale **una vez** con el riesgo concreto, anótalo en `## Riesgos` y respeta su decisión. Bajar el control está permitido. Solo comprueba que no quede bajo `autonomia_minima`. -5. En `config` van **solo las diferencias**, cada una como `{ valor, motivo, desde: }`. Si la autonomía queda en Delegado, el verificador se activa solo: confirma que haya una entidad asignada. - -### 3. Definir los ítems del módulo - -1. Propón la lista en una tabla con id, tipo, título, una línea de propósito y prioridad. + Si necesita una decisión de diseño nueva, propónla como ADR (`baton/templates/adr.md`). +2. **Configurar.** Consulta la configuración heredada con `baton.py efectiva modulo:` y **recomienda según el riesgo**, con el motivo en una línea. Por ejemplo: pagos, seguridad o migraciones → Pair; CRUD interno → Delegado. Roles y tamaño de slice se mantienen salvo que el riesgo pida otra cosa. +3. **Ítems.** Prepara la lista: - Usa el **tipo principal** de `config.md` (`backlog.principal`). Usa los auxiliares (`bug`, `tecnico`) solo cuando corresponda. - Incluye los ítems semilla que ya existan con ese `modulo`, y los ítems sin módulo que encajen. - Divide en ítems **verticales**, que entregan algo usable, y no por capas. - Revisa que cada ítem cumpla **INVEST**: independiente, negociable, valioso, estimable, pequeño y testeable. Si un ítem parece de más de unos 6 criterios, propón dividirlo. -2. El humano corrige, edita, quita, agrega y prioriza. -3. Lo que **acepte** se crea como ítem ligero desde `baton/templates/item-.md`: - - el frontmatter completo y la sección de propósito en una línea; - - `estado: Pendiente` (aceptado para desarrollo); - - el id con el siguiente número libre de su prefijo. -4. Lo que quiera guardar sin aceptar todavía queda en `Candidato`. Lo que rechace no se crea. + +### 2. Preguntas abiertas (si las hay) + +Lo que no puedas deducir (dudas de negocio de la visión que este módulo necesita, la autonomía si hay alternativas reales) va **primero**, en una tanda interactiva. No incluyas la aprobación en esa tanda: sus respuestas cambian la propuesta. + +### 3. Mostrar y aprobar una vez + +1. **Muestra en un mensaje de texto** la propuesta completa, ya con las respuestas aplicadas: + - **Alcance** y **fuera de alcance**: 2 o 3 líneas cada uno. + - **Riesgos:** los que encontraste, en una línea cada uno. + - **Configuración:** la autonomía y el verificador recomendados, con el motivo, y lo que cambia respecto del proyecto (marca ↓ si baja el control). + - **Ítems:** una tabla con id, tipo, título, una línea de propósito y prioridad. + + Lo que solo pensaste y no mostraste no cuenta: el humano no lo ve. +2. **Pide la aprobación** con una pregunta interactiva: "Apruebo", "Ajustar…" y, si aplica, "Dejar algún ítem como candidato". Ajusta hasta que apruebe. +3. **Si el humano elige menos control que el recomendado,** avísale **una vez** con el riesgo concreto, anótalo en `## Riesgos` y respeta su decisión. Bajar el control está permitido. Solo comprueba que no quede bajo `autonomia_minima`. +4. Recién entonces escribe: + - `module.md`: las secciones, y en `config` **solo las diferencias**, cada una como `{ valor, motivo, desde: }`. Si la autonomía queda en Delegado, el verificador se activa solo: confirma que haya una entidad asignada; + - los ítems **aceptados**, como ítems ligeros desde `baton/templates/item-.md`: el frontmatter completo, la sección de propósito en una línea, `estado: Pendiente` y el siguiente número libre de su prefijo; + - los que el humano quiera guardar para después, en `Candidato`. Lo que rechace no se crea. ### 4. Activar y registrar diff --git a/skills/baton-start/assets/baton.py b/skills/baton-start/assets/baton.py index 8bb82a4..acaf58d 100755 --- a/skills/baton-start/assets/baton.py +++ b/skills/baton-start/assets/baton.py @@ -46,12 +46,14 @@ "EnVerificacion": "verificador", "EnRevision": "navigator", } WIP_ESTADOS = {"EnCurso", "Escalado", "EnVerificacion", "EnRevision"} +# Estados (en el commit anterior) desde los que se puede congelar un test por primera vez. +PRE_CONGELADO = (None, "Pendiente", "Listo", "TestsEnRevision") # Estados en los que el ítem ya pasó la Definition of Ready. POST_DOR = {"Listo", "TestsEnRevision", "TestsCongelados", "EnCurso", "Escalado", "EnVerificacion", "EnRevision", "Hecho"} TRANSICIONES = { "Candidato": {"Pendiente", "Descartado"}, - "Pendiente": {"Listo", "Descartado"}, + "Pendiente": {"Listo", "Candidato", "Descartado"}, "Listo": {"TestsEnRevision", "Pendiente"}, "TestsEnRevision": {"Listo", "TestsCongelados"}, "TestsCongelados": {"EnCurso"}, @@ -1308,10 +1310,16 @@ def estado_solicitud(rid, ref): if estado_solicitud(sol, ref_actual) not in ("Aprobada", "Aplicada"): problemas.append(f"lock: {arch} cambió con la solicitud {sol}, que no está Aprobada") continue + # Primer congelado (el archivo no estaba en el lock): basta con que el ítem todavía no + # estuviera congelado en el commit anterior. Así no hace falta un commit intermedio en + # TestsEnRevision, y el driver sigue bloqueado: sus ítems ya están congelados. + primero = arch not in lock_base + previos = ("TestsEnRevision",) + (PRE_CONGELADO if primero else ()) if fila["item"] == "*": - ok = any(estado_item(i, base_ref) == "TestsEnRevision" for i in pr.items) or not lock_base + ok = not lock_base or any(estado_item(i, base_ref) in previos + and estado_item(i, ref_actual) == "TestsCongelados" for i in pr.items) else: - ok = estado_item(fila["item"], base_ref) == "TestsEnRevision" + ok = estado_item(fila["item"], base_ref) in previos if not ok: problemas.append(f"lock: {arch} cambió sin solicitud aprobada y su ítem no venía de TestsEnRevision") for arch in sorted(set(lock_base) - set(lock)): diff --git a/skills/baton-tests/SKILL.md b/skills/baton-tests/SKILL.md index 16f98ef..957c222 100644 --- a/skills/baton-tests/SKILL.md +++ b/skills/baton-tests/SKILL.md @@ -23,6 +23,7 @@ description: Rol Autor de tests de la metodología Baton. Convierte los criterio - **Vale:** el assert falla, o falla porque la funcionalidad no existe (404, función o módulo de producción inexistente). - **No vale:** un error de sintaxis o de importación *del propio test*, una fixture rota o un error de entorno. - **Si un test pasa sin código nuevo**, el test es débil o la funcionalidad ya existe. Corrígelo o explícalo en el traspaso. + - **Si dudas de que un test se pueda poner en verde** (criterios que parecen contradecirse, un dato que no cuadra), puedes comprobarlo con una implementación desechable **fuera del repositorio** (en tu scratchpad o un directorio temporal) y borrarla al terminar. Avísalo en el traspaso, con lo que encontraste. Si confirma una contradicción, no la resuelvas tú: descríbela en el traspaso para que la decida el humano. Por defecto no lo hagas: gasta tokens. 6. Ejecuta `python3 baton/bin/baton.py estado <ítem> TestsEnRevision`. 7. Ejecuta `python3 baton/bin/baton.py handoff --item <ítem> --de autor_tests --para aprobador_tests`. En `## Tests del slice` (o una tabla nueva, `## Rojo verificado`), pon por cada test: nombre, criterio, resultado y **la razón del fallo** copiada de la salida. 8. Ejecuta `python3 baton/bin/baton.py sync --autor --motivo "tests de <ítem> escritos"`. @@ -33,6 +34,6 @@ Cambia solo los tests que lista `afecta` en la solicitud. Indica en el traspaso ## No hagas -- No escribas código de producción, ni siquiera "para que compile". +- No escribas código de producción en el repositorio, ni siquiera "para que compile". La única excepción es la implementación desechable del paso 5, siempre fuera del repositorio. - No toques archivos que ya están en `baton/acceptance.lock` sin una solicitud aprobada. El hook rechazará el commit. - No apruebes tus propios tests. From 0cd42bde6d35125bfc5ac06b71b25f350bc8e1e8 Mon Sep 17 00:00:00 2001 From: Zartaroth <43078140+Zartaroth@users.noreply.github.com> Date: Wed, 4 Nov 2026 15:27:30 -0500 Subject: [PATCH 12/12] =?UTF-8?q?Versi=C3=B3n=200.4.1:=20CHANGELOG=20con?= =?UTF-8?q?=20las=20correcciones=20del=20piloto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 22 ++++++++++++++++++++++ METODOLOGIA.md | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cde8ea..484290b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/). Las versiones son de la metodología. El campo `formato` de los archivos tiene su propia numeración. +## [0.4.1] - 2026-11-04 + +Correcciones que salieron de los intentos 2 y 3 del piloto (defectos D7 a D23 de `pruebas/BITACORA-piloto.md`). + +### Cambiado +- **El humano solo aprueba lo que tiene en pantalla.** `baton-item` primero resuelve las decisiones abiertas, después muestra los criterios y los slices en texto, y al final pide la aprobación. `baton-approve` muestra una tabla con cada criterio junto a lo que comprueba su test antes de preguntar. +- **Abrir un módulo** tiene una sola confirmación: primero las preguntas abiertas, después alcance, riesgos, configuración e ítems a la vista, y una aprobación. +- Las decisiones con opciones se preguntan con la herramienta interactiva del entorno; lo abierto, en texto. La configuración inicial va en dos tandas de hasta 4 preguntas. +- `baton-start` cierra con tablas (visión, configuración, mapa de módulos) y propone el nombre del proyecto a partir del producto, no de la carpeta. +- Cada skill trae las reglas que necesita, para que el agente no lea el código de `baton.py`. +- El router anuncia siempre `Rol · Paso · Sobre`, y `baton-module` se activa también ante "¿qué módulos faltan?". +- `baton-module` propone los módulos candidatos en una pregunta de selección múltiple y pide un motivo de fondo para cada cambio del mapa. +- El autor de tests puede probar una implementación desechable, fuera del repositorio, solo si duda de que un test se pueda poner en verde. +- **Primer congelado sin commit intermedio:** el hook acepta congelar un test por primera vez si su ítem no estaba congelado en el commit anterior. El driver sigue sin poder congelar tests nuevos de un ítem ya congelado. +- Un ítem puede volver de `Pendiente` a `Candidato` ("para después"). + +### Corregido +- `init --hook` reinstala su propio hook, y `baton/bin/baton.py init` ya no falla al copiarse sobre sí mismo. +- `validar` avisa si el verificador no tiene entidad: en Delegado se activa a la fuerza. +- El lock ya no congela los `.pyc` de `__pycache__`. +- El mapa de módulos corta el objetivo por palabra. + ## [0.4.0] - 2026-11-03 Cambios que salieron de la primera prueba piloto. diff --git a/METODOLOGIA.md b/METODOLOGIA.md index c89ca06..3ba1bce 100644 --- a/METODOLOGIA.md +++ b/METODOLOGIA.md @@ -6,7 +6,7 @@ Evolución de SDD (Spec-Driven Development). Su objetivo es que el trabajo con a Se inspira en las prácticas que mejor funcionaban antes de los agentes: backlog ágil, slices verticales, TDD y pair programming. -> Estado: versión 0.4 (2026-11-03). Los formatos de archivo están en [FORMATOS.md](FORMATOS.md) y las skills del núcleo en [skills/](skills/README.md). Pasos siguientes: probar con un proyecto real → `verify`, `review` y adaptadores → app visual. +> Estado: versión 0.4.1 (2026-11-04). Los formatos de archivo están en [FORMATOS.md](FORMATOS.md) y las skills del núcleo en [skills/](skills/README.md). Pasos siguientes: probar con un proyecto real → `verify`, `review` y adaptadores → app visual. ---