@ingeniomaps/cauce 0.68.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/README.md +13 -6
  3. package/automatization/AGENTS.md +1 -1
  4. package/automatization/runners/antigravity/rules/cauce.md +1 -1
  5. package/automatization/runners/claude/CLAUDE.md +1 -1
  6. package/automatization/runners/codex/AGENTS.md +1 -1
  7. package/automatization/runners/gemini/GEMINI.md +1 -1
  8. package/automatization/shared/skills/autobuild/SKILL.md +1 -1
  9. package/automatization/workflows/autobuild.js +44 -8
  10. package/engine/cli/archive.js +87 -0
  11. package/engine/cli/args.js +7 -2
  12. package/engine/cli/catalog.js +9 -1
  13. package/engine/cli/claims.js +125 -0
  14. package/engine/cli/ops.js +17 -4
  15. package/engine/cli/planning.js +158 -102
  16. package/engine/cli/worktree.js +89 -0
  17. package/engine/core/ownership.js +16 -5
  18. package/engine/core/repos.js +67 -0
  19. package/engine/hooks/files.js +3 -2
  20. package/engine/planning/adoption.js +1 -1
  21. package/engine/planning/claims.js +153 -0
  22. package/engine/planning/contracts.js +43 -202
  23. package/engine/planning/parser.js +89 -33
  24. package/engine/planning/recurring.js +148 -0
  25. package/engine/planning/state.js +39 -6
  26. package/engine/planning/structure.js +220 -0
  27. package/package.json +1 -1
  28. package/template/.gitattributes +19 -0
  29. package/template/AGENTS.md +54 -5
  30. package/template/Makefile +4 -1
  31. package/template/automatization/AGENTS.md +1 -1
  32. package/template/gitignore +9 -0
  33. package/template/planning/BACKLOG.md +5 -0
  34. package/template/planning/FLOW.md +3 -1
  35. package/template/planning/PROTOCOL.md +25 -8
  36. package/template/planning/README.md +4 -3
  37. package/template/planning/RECURRING.md +77 -0
  38. package/template/planning/adr/system/OPS-001-planificacion-como-fuente-de-verdad.md +3 -2
  39. package/template/planning/business-rules/system/BR-OPS-001-una-sola-tarea-activa.md +7 -4
  40. package/template/planning/business-rules/system/BR-OPS-005-una-tarea-un-runner.md +44 -0
  41. package/template/planning/claims/README.md +70 -0
  42. package/template/planning/delivery/README.md +1 -0
  43. package/template/planning/delivery/multi-repo.md +11 -0
  44. package/template/planning/delivery/teamwork.md +162 -0
  45. package/template/planning/done/README.md +41 -0
  46. package/template/planning/wip/README.md +49 -0
  47. package/template/planning/DONE.md +0 -13
  48. package/template/planning/WIP.md +0 -22
@@ -150,9 +150,12 @@ que hacía falta, apagala después, y que la razón quede escrita donde alguien
150
150
  Antes de abrir un archivo de `planning/`, preguntarle al CLI: es determinista, no gasta contexto y no
151
151
  muta nada.
152
152
 
153
- - `node tools/ops.js context planning` — gate, mutex de WIP y la tarea que corresponde ahora, con su
154
- aceptación y sus criterios. Es la entrada correcta para empezar a trabajar.
153
+ - `node tools/ops.js context planning [--hito <slug>]` — gate, mutex de WIP y la tarea que corresponde
154
+ ahora, con su aceptación y sus criterios. Es la entrada correcta para empezar a trabajar. Con `--hito`
155
+ la cola se acota a ese hito, que es como un equipo se reparte trabajo sin coordinarse.
155
156
  - `node tools/ops.js tree planning` — panorama de roadmap, backlog, WIP, inbox y done.
157
+ - `node tools/ops.js recurring planning [--promote <qué>]` — qué trabajo recurrente venció y con
158
+ qué línea se promueve. Emite esa línea; escribirla en `BACKLOG.md` es de una persona.
156
159
  - `node tools/ops.js check planning` — validación de contratos y trazabilidad.
157
160
  - `node tools/ops.js evidence planning [--task <slug>]` — contrasta la evidencia de una entrada de DONE
158
161
  contra lo que no escribió su autor: si el artefacto que `tests:` nombra existe en las raíces de
@@ -161,8 +164,49 @@ muta nada.
161
164
  nombrada haya corrido —eso depende del runner, y varios no la nombran al pasar— ni reemplaza a leer
162
165
  su fuente, que es lo que R9 pide.
163
166
 
164
- Los cuatro aceptan `--json`. Leer `BACKLOG.md`, `WIP.md` o `HUMAN_ACTIONS.md` completos sólo cuando haga
165
- falta editarlos o cuando el CLI no responda la pregunta.
167
+ Los cinco aceptan `--json`. Leer `BACKLOG.md`, tu `wip/<runner>.md`, `HUMAN_ACTIONS.md` o `RECURRING.md`
168
+ completos sólo cuando haga falta editarlos o cuando el CLI no responda la pregunta.
169
+
170
+ ## Cómo tomar trabajo
171
+
172
+ Con equipo, la tarea que `context` devuelve puede estar libre o ya ser tuya, y la salida lo dice. Libre
173
+ se toma antes de empezar:
174
+
175
+ - `node tools/ops.js claim planning <tarea>` — la reserva a tu nombre y escribe `planning/claims/<tarea>.md`.
176
+ - `node tools/ops.js release planning <tarea>` — la devuelve a la cola.
177
+
178
+ Una tarea que declara `(depende: slug)` no se ofrece ni se puede tomar hasta que eso esté en DONE, y
179
+ `context` la muestra con una línea `WAIT`. No hay que adelantarse: lo que sigue es trabajo de quien tiene
180
+ la tarea de la que depende.
181
+
182
+ Tomar no es promover: la tarea ya estaba aprobada en `BACKLOG.md` y esto sólo dice quién la hace, así que
183
+ entra en la autonomía del runner. Lo que no entra es tocar el reclamo de otro — ni tomarlo, ni soltarlo—,
184
+ y `context` directamente no ofrece una tarea reclamada.
185
+
186
+ El reclamo hay que **commitearlo y empujarlo**: sin eso el otro runner lee lo que hay en su copia y la
187
+ reserva no existe para nadie más.
188
+
189
+ ## Con qué runner arrancás
190
+
191
+ Antes de pedir trabajo hay que saber quién lo tiene. Dos sesiones en la misma máquina resuelven la misma
192
+ identidad de git, así que lo que las distingue es el `CAUCE_RUNNER` de cada una.
193
+
194
+ `node tools/ops.js runners planning [--json]` dice qué runners tienen una tarea abierta, cuál, desde
195
+ cuándo y si su rama avanzó. Según lo que devuelva:
196
+
197
+ - **Ninguno** — arrancá con un id propio y no preguntes nada. No hay trabajo que retomar.
198
+ - **Uno o más** — **preguntale a la persona** cuál retoma o si arranca uno nuevo, nombrando la tarea de
199
+ cada uno, desde cuándo y si avanzó. Retomar el id de un agente que sigue corriendo le saca la tarea, y
200
+ arrancar uno nuevo cuando había trabajo a medias lo deja huérfano: las dos rompen algo, y por eso la
201
+ elección no es tuya.
202
+
203
+ Elegido el id, **exportalo vos** y usalo en cada `ops` de la sesión. **Nunca le pidas a una persona que
204
+ escriba una variable de entorno**: no es el idioma en el que trabaja, y el runner es cómo el toolkit
205
+ distingue dos sesiones, no una decisión de producto. Lo suyo es elegir; la mecánica es tuya.
206
+
207
+ - `node tools/ops.js worktree planning <tarea>` — prepara el árbol de trabajo de esa tarea y te devuelve
208
+ la ruta con el `export CAUCE_RUNNER` hecho. No clona nada: `git worktree` comparte el mismo `.git`, y
209
+ cada árbol queda fijado a su rama, así que ningún agente hace `checkout` sobre el trabajo de otro.
166
210
 
167
211
  ## Autonomía
168
212
 
@@ -178,6 +222,11 @@ Nunca amplía el alcance, promueve sus propias ideas, reescribe el proceso duran
178
222
  `git add .`/`git add -A`, reescribe historia con `--force` o `--amend`, ni afirma éxito sin evidencia
179
223
  real. Tampoco publica: sin autorización no hay `push`.
180
224
 
225
+ Una recurrencia vencida tampoco la promueve, y ésta es la que más se parece a una excepción: la
226
+ aceptación ya está escrita, la fecha la calculó el CLI y `context` la nombra sola. Nada de eso es la
227
+ aprobación que pide BR-OPS-002 — `context` la nombra para que la vea una persona, y quien la pega en
228
+ `BACKLOG.md` es esa persona.
229
+
181
230
  Publicar es lo único de todo eso que este proyecto puede habilitar, y `runner.allowPush` en
182
231
  `ops.config.json` es la autorización que R10 pide. Reescribir historia publicada no entra en el trato:
183
232
  un `push --force` se frena con la llave prendida o apagada.
@@ -193,5 +242,5 @@ publicación tampoco se decide ahí: la decide `allowPush`.
193
242
  3. QA valida el comportamiento por el camino real, no por un atajo interno.
194
243
  4. La deuda residual va a `planning/INBOX.md`.
195
244
  5. El cambio se commitea en el repo del servicio —uno por naturaleza del diff, y una tarea suele
196
- tener una sola— y el hash real queda en `DONE.md`.
245
+ tener una sola— y el hash real queda en la evidencia de la tarea, `planning/done/<slug>.md`.
197
246
  6. `node tools/ops.js check planning` queda verde.
package/template/Makefile CHANGED
@@ -1,6 +1,6 @@
1
1
  .DEFAULT_GOAL := help
2
2
 
3
- .PHONY: help check tree context upgrade destroy automation-check
3
+ .PHONY: help check tree context recurring upgrade destroy automation-check
4
4
  .PHONY: integration-check integration-sync require-key integration-promote
5
5
  .PHONY: require-agent agent-learn agent-propose agent-evaluate require-flow flow-list flow-check flow-show
6
6
  .PHONY: install-claude install-codex install-gemini install-antigravity
@@ -23,6 +23,9 @@ tree: ## Muestra roadmap, backlog, WIP y Done
23
23
  context: ## Muestra el contexto mínimo de la tarea vigente
24
24
  @node tools/ops.js context planning
25
25
 
26
+ recurring: ## Muestra qué trabajo recurrente vence y con qué línea se promueve
27
+ @node tools/ops.js recurring planning
28
+
26
29
  # `init` fija la versión exacta del motor, así que `npm update` no la mueve: hay que pedir @latest.
27
30
  # Sin este primer paso `upgrade` compara contra el motor instalado y contesta «al día» para siempre.
28
31
  destroy: ## Muestra qué se pierde al borrar esta instancia (borrar exige --force a mano)
@@ -62,6 +62,6 @@ cambia instalación o materialización, valida `ops init` en un directorio tempo
62
62
 
63
63
  ## Límites
64
64
 
65
- No edites `planning/BACKLOG.md`, `WIP.md` o `DONE.md` desde hooks o instaladores. No hagas que `ops init` active
65
+ No edites `planning/BACKLOG.md`, `planning/wip/` ni `planning/done/` desde hooks o instaladores. No hagas que `ops init` active
66
66
  un runner silenciosamente. No agregues lógica de negocio, nombres de servicios de un proyecto, tokens, rutas
67
67
  personales ni modelos concretos a esta capa reusable.
@@ -9,5 +9,14 @@ node_modules/
9
9
  # máquina. Committearlo sería historia que nadie lee y un conflicto por commit.
10
10
  planning/.verify-log
11
11
 
12
+ # El plan de cada runner. Es de la máquina que lo corre —existe para recuperar una ejecución
13
+ # interrumpida, y nadie más puede retomarla— y cambia en cada paso, así que compartirlo es un conflicto
14
+ # por commit a cambio de nada. Lo que el equipo sí necesita saber vive en `planning/claims/`.
15
+ #
16
+ # Se excluyen los planes y no el directorio: git no puede volver a incluir un archivo cuyo directorio
17
+ # está excluido, y el README de ahí adentro sí tiene que viajar.
18
+ planning/wip/*.md
19
+ !planning/wip/README.md
20
+
12
21
  *.tgz
13
22
  .DS_Store
@@ -5,6 +5,10 @@ Solo contiene trabajo aprobado y listo. Las ideas viven en `INBOX.md`.
5
5
  La aceptación se escribe en la línea o se hereda del criterio que la tarea cita. El lane y el cast son
6
6
  opcionales: sin ellos la tarea está sin clasificar, que es el estado que dispara al clasificador.
7
7
 
8
+ `(depende: slug)` declara qué tiene que estar en DONE antes de que esta tarea se pueda tomar. El orden de
9
+ la lista alcanzaba cuando trabajaba un runner; con dos, el segundo toma la que sigue mientras el primero
10
+ construye aquella de la que depende.
11
+
8
12
  Pasando de nueve tareas un hito, o de cinco criterios heredados una tarea, `check` pide decidir (R17):
9
13
  o se parte, o lleva `(sin partir: <razón>)` en su línea.
10
14
 
@@ -14,4 +18,5 @@ o se parte, o lleva `(sin partir: <razón>)` en su línea.
14
18
  - [ ] **slug-de-tarea** [full] — Resultado a construir. _Aceptación: conducta observable._ (service: ruta) (cast: quien-entrega → quien-revisa)
15
19
  - [ ] **otro-slug** [lite] — Resultado a construir. (→ C1) (epic: 001) (service: ruta) (cast: quien-entrega → quien-revisa, otro-revisor)
16
20
  - [ ] **sin-clasificar** — Resultado a construir. _Aceptación: conducta observable._ (service: ruta)
21
+ - [ ] **la-que-sigue** [lite] — Resultado a construir. _Aceptación: conducta observable._ (service: ruta) (depende: slug-de-tarea)
17
22
  -->
@@ -5,7 +5,7 @@ INBOX ──promoción humana──▶ roadmap ──historias listas──▶ B
5
5
  ▲ │
6
6
  │ Pick/Plan
7
7
  │ ▼
8
- │ done/ ◀── archive ◀── DONE ◀── Verify/QA ◀────────── WIP
8
+ │ done/<tarea>.md ◀── evidencia ◀── Verify/QA ◀───── WIP
9
9
  │ │
10
10
  └───────────── deuda adyacente ─────────────────────────────┤
11
11
  │
@@ -15,6 +15,8 @@ INBOX ──promoción humana──▶ roadmap ──historias listas──▶ B
15
15
 
16
16
  ## Preparar
17
17
 
18
+ 0. Si `ops recurring planning` nombra una recurrencia vencida, decidir si esta vuelta se promueve —el
19
+ comando emite su línea— o se posterga con su razón.
18
20
  1. Curar una idea desde INBOX.
19
21
  2. Escribir una épica con resultados observables, contexto actual y criterios `C1..CN`.
20
22
  3. Descomponerla en historias de máximo cuatro horas, cada una rastreada a uno o más criterios.
@@ -9,9 +9,12 @@ invariantes.
9
9
  `(service: ruta)`.
10
10
  - Hito: `## Hito slug — Título`.
11
11
  - Tarea: `- [ ] **slug** [express|directo|lite|full] — descripción. _Aceptación: observable._ (service: ruta) (cast: quien-entrega → quien-revisa, otro)`;
12
- puede heredar aceptación usando `(→ CN) (epic: NNN)`. Lane y cast son opcionales: sin ellos la tarea
13
- está sin clasificar, que es un estado y no un error.
14
- - DONE: entrada `[x]` con `acept:`, `done:`, `qa:`, `tests:` y `commit:`. `tests:` enlaza cada criterio
12
+ puede heredar aceptación usando `(→ CN) (epic: NNN)` y declarar `(depende: slug, otro)`. Lane y cast son
13
+ opcionales: sin ellos la tarea está sin clasificar, que es un estado y no un error. Una tarea con
14
+ dependencias no se ofrece ni se toma hasta que todas estén en DONE.
15
+ - DONE: un archivo por tarea cerrada, `done/<slug>.md`, con su entrada `[x]` y los campos `acept:`,
16
+ `fecha:` en AAAA-MM-DD, `done:`, `qa:`, `tests:` y `commit:`. La fecha es la del cierre, y es lo que
17
+ ordena una evidencia que ya no depende de su posición dentro de un archivo. `tests:` enlaza cada criterio
15
18
  mediante `CN → prueba`; usa `A → prueba` cuando no hay épica o `n/a — razón` si no existe una
16
19
  superficie ejecutable. `decisions:` es opcional y, si aparece, cita `[fuente: ...]` o
17
20
  `[supuesto: ...]`. `commit:` apunta a `<sha> <asunto>`, o a `n/a — razón` cuando la tarea no
@@ -20,12 +23,23 @@ invariantes.
20
23
  en el vocabulario cerrado `pendiente | resuelta` —la fecha puede ir detrás—. Mientras la fila no
21
24
  esté resuelta, su tarea no se toma; un estado fuera del vocabulario es un error de `check` y no un
22
25
  bloqueo silencioso.
23
- - WIP activo: frontmatter y checklist; inactivo: `status: IDLE`.
26
+ - Recurrencia: fila `| qué | cada | desde | tarea y aceptación |` bajo `## Recurrencias`, con `cada` en
27
+ el vocabulario cerrado `mensual | trimestral | semestral | anual` y la celda de tarea escrita como la
28
+ cola de su línea de BACKLOG. Vencer no bloquea: cada vuelta se promueve con el período en el slug
29
+ —`<qué>-AAAA-MM`— y esa promoción la escribe una persona. Postergar se registra bajo
30
+ `## Postergaciones` con `- **qué** AAAA-MM-DD — razón`.
31
+ - Reclamo: `claims/<tarea>.md` con frontmatter `task/owner/runner/started/service`; el nombre del
32
+ archivo es el slug que reserva, y por eso un `task` que diga otra cosa es un error. `owner` dice a
33
+ quién preguntarle y `runner` decide de quién es: con varios agentes en una máquina la persona es
34
+ la misma y el árbol de trabajo no.
35
+ - WIP activo: frontmatter y checklist en `wip/<runner>.md`; inactivo cuando el archivo no está. Es
36
+ local y no viaja por git: existe para recuperar la sesión de quien lo escribió, y es uno por runner
37
+ porque una instancia sidecar la comparten todos los agentes de esa máquina.
24
38
 
25
39
  ## Gates de arranque
26
40
 
27
41
  1. Si existe `AWAITING_REVIEW.md`, parar y mostrar la acción que contiene.
28
- 2. Si WIP está activo y puede pertenecer a otro runner, parar: es el mutex.
42
+ 2. Si tu WIP está activo, la tarea es ésa: es el mutex del runner, y sólo se lee el propio.
29
43
  3. Si WIP está activo tras una interrupción confirmada, verificar los pasos `[x]` en disco y continuar
30
44
  desde el primer `[ ]`; no replanear.
31
45
  4. Si WIP apunta a una tarea ya en DONE y fuera de BACKLOG, reparar el cierre dejando WIP en IDLE.
@@ -33,7 +47,8 @@ invariantes.
33
47
  ## Máquina por tarea
34
48
 
35
49
  1. Triage: inspeccionar estado y cambios existentes.
36
- 2. Pick: primera tarea no bloqueada del primer hito.
50
+ 2. Pick: primera tarea no bloqueada ni reclamada por otro runner, recorriendo los hitos en orden;
51
+ reclamarla antes de empezar y empujar ese reclamo, que sin empujar no reserva nada.
37
52
  3. Classify: si la tarea no declara lane y cast, decidirlos y escribirlos en su línea.
38
53
  4. Ready: exigir aceptación concreta y decisiones resueltas.
39
54
  5. Decompose: dividir trabajo mayor a `maxTaskHours` o con más de cinco condiciones de aceptación.
@@ -44,7 +59,8 @@ invariantes.
44
59
  10. Verify: ejecutar los gates declarados por el servicio y registrar exit codes.
45
60
  11. QA: probar la aceptación por el camino que usa un consumidor real.
46
61
  12. Commit: stage explícito y commits verificables, uno por naturaleza del diff.
47
- 13. Done: mover la tarea, registrar evidencia, limpiar WIP y cerrar/archivar la épica si corresponde.
62
+ 13. Done: sacar la tarea de la cola, escribir su evidencia en `done/<slug>.md`, limpiar WIP, soltar
63
+ el reclamo y cerrar la épica si no le queda ninguna historia abierta.
48
64
  14. Cierre: check verde, deuda residual al INBOX y checkpoint entre hitos.
49
65
 
50
66
  ## Lanes
@@ -68,7 +84,8 @@ chequeo de permisos es `full`, y un componente entero de presentación puede ser
68
84
  ## Invariantes
69
85
 
70
86
  1. Una tarea tiene un dueño de estado: roadmap → BACKLOG → overlay WIP → DONE.
71
- 2. Un solo runner a la vez; WIP activo es mutex — `business-rules/system/BR-OPS-001`.
87
+ 2. Un runner lleva una tarea a la vez —WIP, que es local: `business-rules/system/BR-OPS-001`— y una
88
+ tarea la lleva un runner —el reclamo, que es compartido: `business-rules/system/BR-OPS-005`—.
72
89
  3. INBOX nunca se ejecuta automáticamente — `business-rules/system/BR-OPS-002`.
73
90
  4. No declarar éxito sin comandos, resultados y exit codes reales — `business-rules/system/BR-OPS-004`.
74
91
  5. No inventar credenciales ni decisiones; registrar HUMAN_ACTIONS.
@@ -7,8 +7,8 @@ Se lee y se escribe en cada tarea.
7
7
  | Pieza | Responsabilidad |
8
8
  |---|---|
9
9
  | `BACKLOG.md` | Única cola de tareas promovidas y listas. |
10
- | `WIP.md` | Única tarea en vuelo; recuperación y mutex. |
11
- | `DONE.md` | Evidencia activa de tareas terminadas. |
10
+ | `wip/` | El plan en vuelo de cada runner; recuperación y mutex por runner. No viaja por git. |
11
+ | `claims/` | Qué tarea tomó cada quien; un archivo por tarea. |
12
12
  | `HUMAN_ACTIONS.md` | Acciones externas que requieren una persona. |
13
13
  | `AWAITING_REVIEW.md` | Gate efímero; mientras existe no inicia trabajo. |
14
14
 
@@ -19,6 +19,7 @@ Se decide antes de ejecutar y no cambia dentro de una tarea.
19
19
  | Pieza | Responsabilidad |
20
20
  |---|---|
21
21
  | `INBOX.md` | Ideas y deuda sin autorización de ejecución. |
22
+ | `RECURRING.md` | Trabajo que vuelve cada tanto; declarado, nunca encolado solo. |
22
23
  | `roadmap/` | Especificaciones de épicas y criterios del QUÉ. |
23
24
  | `adr/` | Decisiones arquitectónicas durables. |
24
25
  | `business-rules/` | Invariantes observables de negocio y operación. |
@@ -31,7 +32,7 @@ Evidencia que no se reescribe.
31
32
 
32
33
  | Pieza | Responsabilidad |
33
34
  |---|---|
34
- | `done/` | Historial inmutable: una épica cerrada por archivo, más las acciones humanas resueltas. |
35
+ | `done/` | Evidencia de lo terminado: una tarea cerrada por archivo, más las acciones humanas resueltas. |
35
36
  | `reports/` | Informes de recorridos de equipo. |
36
37
 
37
38
  El protocolo exacto está en `PROTOCOL.md`, la explicación visual en `FLOW.md` y los principios que
@@ -0,0 +1,77 @@
1
+ # Trabajo que vuelve
2
+
3
+ Lo que hay que hacer cada tanto y no una vez: actualizar dependencias, revisar quién tiene acceso a
4
+ producción, mirar el gasto del mes, recorrer el INBOX entero. No es una categoría de trabajo —puede ser
5
+ cualquier cosa— sino una forma de declararlo: acá vive el enunciado, y cada vuelta se promueve a
6
+ `BACKLOG.md` como una tarea más.
7
+
8
+ **Nada se dispara.** Este archivo no ejecuta ni encola: declara cada cuánto algo debería mirarse, y el
9
+ vencimiento se calcula cuando alguien corre el CLI. Promover sigue siendo un acto humano, igual que en
10
+ `INBOX.md`. Lo que la máquina aporta es que no se te pase, no decidir por vos.
11
+
12
+ ## Cada fila
13
+
14
+ - **Qué** — un identificador estable, en minúsculas y sin espacios. No cambia nunca: es lo que ata la
15
+ fila a las vueltas que ya se hicieron.
16
+ - **Cada** — vocabulario cerrado: `mensual`, `trimestral`, `semestral`, `anual`. No hay expresiones de
17
+ cron, y esa ausencia es el enunciado: si hiciera falta una, lo que estarías declarando es otra cosa.
18
+ Tampoco hay `semanal`, porque el slug de cada vuelta tiene grano de mes.
19
+ - **Desde** — `AAAA-MM-DD`. Ancla la primera vuelta y después no se toca.
20
+ - **Tarea y aceptación** — lo que se va a promover, con su aceptación observable escrita una sola vez y
21
+ con calma. Improvisada en cada vuelta, la misma recurrencia termina significando cosas distintas sin
22
+ que nadie lo decida.
23
+
24
+ ## Cuándo vence
25
+
26
+ Se cuenta desde la última vez que se cerró, no desde un día fijo del calendario: una recurrencia
27
+ atrasada no debe tres vueltas, debe una, la que no se hizo.
28
+
29
+ La fecha de ese último cierre **no se escribe acá**. Sale de `done/` — la entrada más nueva cuyo slug
30
+ sea `<qué>-AAAA-MM`—, que es la evidencia de que efectivamente se hizo y no la afirmación de que se
31
+ hizo. Una celda que alguien tiene que acordarse de actualizar miente a los tres meses, y el estado no se
32
+ copia para representar progreso.
33
+
34
+ Por eso cada vuelta se promueve con su período en el slug —`deps-2026-10`, después `deps-2026-11`— y no
35
+ con el identificador pelado. Reusarlo tiene además su propio castigo: dos entradas de DONE con el mismo
36
+ slug son un error de `check`, y ese error llega un mes tarde.
37
+
38
+ ## Lo que este archivo no es
39
+
40
+ - **No bloquea.** Una recurrencia vencida no frena ninguna tarea. Lo que sí frena vive en
41
+ `HUMAN_ACTIONS.md`; ponerlo acá entrena a ignorar lo que vence, que es lo único que este archivo hace.
42
+ - **No es una cola.** Nada de acá está aprobado para ejecutarse. `BACKLOG.md` sigue siendo la única cola
43
+ y se escribe a mano.
44
+ - **No es el INBOX.** Una idea se promueve una vez y se borra; esto vuelve, y por eso se queda.
45
+
46
+ ## Recurrencias
47
+
48
+ | Qué | Cada | Desde | Tarea y aceptación observable |
49
+ |---|---|---|---|
50
+
51
+ <!--
52
+ | deps | mensual | 2026-09-01 | Actualizar dependencias. _Aceptación: `npm outdated` no deja una versión mayor sin decisión escrita y la puerta queda verde._ |
53
+ | accesos | trimestral | 2026-07-01 | Revisar quién tiene acceso a producción. _Aceptación: cada cuenta activa figura en `organization/`, y las demás están dadas de baja._ |
54
+ | costos | mensual | 2026-09-01 | Revisar el gasto de infraestructura del mes. _Aceptación: cada línea que subió más de 20% tiene una razón escrita._ |
55
+ | inbox | trimestral | 2026-08-01 | Recorrer el INBOX entero. _Aceptación: ninguna viñeta queda sin decisión de promover, dejar o borrar._ |
56
+ -->
57
+
58
+ ## Postergaciones
59
+
60
+ Saltear una vuelta es legítimo y se escribe. Lo que no puede perderse es la razón: sin ella queda una
61
+ recurrencia atrasada y nadie sabe si fue una decisión o un olvido.
62
+
63
+ Postergar compra **un período**, no una fecha elegida: la vuelta siguiente vuelve a preguntar. Las
64
+ postergaciones se cuentan desde el último cierre y el contador se reinicia al cerrar. Tres seguidas no
65
+ son un atraso — son una recurrencia mal declarada, y lo que hay que revisar es la cadencia o la fila
66
+ entera.
67
+
68
+ La salida definitiva es borrar la fila. «Esto ya no lo hacemos» es un diff que alguien revisa; un estado
69
+ `retirada` es una línea que nadie vuelve a leer.
70
+
71
+ Cada una se escribe con el nombre de su fila en negrita, la fecha y la razón —`- **qué** AAAA-MM-DD —
72
+ razón`—, igual que un ítem del INBOX y por el mismo motivo: el nombre es con lo que se cita la fila.
73
+ Sólo se agrega al final; una línea escrita acá no se edita ni se borra.
74
+
75
+ <!--
76
+ - **deps** 2026-10-02 — Esperando el release de la 2.0; subir dependencias antes lo ensucia.
77
+ -->
@@ -13,8 +13,9 @@ en conversaciones, tickets y memoria del runner hace imposible saber qué está
13
13
  ## Decisión
14
14
 
15
15
  **La instancia usa `planning/` como fuente de verdad operativa, legible y validable.** `INBOX.md` recibe ideas,
16
- el roadmap define resultados, `BACKLOG.md` contiene trabajo promovido, `WIP.md` conserva una única ejecución y
17
- `DONE.md` registra evidencia. El protocolo define las transiciones permitidas.
16
+ el roadmap define resultados, `BACKLOG.md` contiene trabajo promovido, `wip/<runner>.md` conserva la ejecución de cada runner y
17
+ y `done/<slug>.md` registra la evidencia de cada tarea cerrada, un archivo por tarea. El protocolo
18
+ define las transiciones permitidas.
18
19
 
19
20
  ## Alternativas consideradas
20
21
 
@@ -1,8 +1,9 @@
1
1
  # Una sola tarea activa
2
2
 
3
- > **Dominio:** planning | **Estado:** vigente | **Actualizado:** 2026-08-14
3
+ > **Dominio:** planning | **Estado:** vigente | **Actualizado:** 2026-09-07
4
4
 
5
- WIP protege la exclusión mutua y permite recuperar una ejecución interrumpida.
5
+ WIP protege la exclusión mutua dentro de un runner y permite recuperar una ejecución interrumpida.
6
+ Que dos runners no tomen la misma tarea es otra cosa, y la sostiene `BR-OPS-005-una-tarea-un-runner.md`.
6
7
  [fuente: ../../adr/system/OPS-001-planificacion-como-fuente-de-verdad.md]
7
8
 
8
9
  Elabora el invariante 2 de `../../PROTOCOL.md`, que lo enuncia en una línea: acá viven sus bordes
@@ -12,7 +13,7 @@ y su evidencia. Cambiar una sin la otra las separa.
12
13
 
13
14
  | ID | Regla | Condición y resultado |
14
15
  |---|---|---|
15
- | BR-OPS-001 | WIP es mutex | Si WIP está activo, ningún runner toma otra tarea hasta continuarlo o resolverlo. |
16
+ | BR-OPS-001 | WIP es mutex | Si WIP está activo, ese runner no toma otra tarea hasta continuarlo o resolverlo. |
16
17
 
17
18
  ## Por qué existe cada regla
18
19
 
@@ -24,7 +25,8 @@ y su evidencia. Cambiar una sin la otra las separa.
24
25
  |---|---|
25
26
  | Sesión interrumpida | Se verifican pasos persistidos y se continúa la misma tarea. |
26
27
  | Tarea ya cerrada | Se repara el cierre y WIP vuelve a `IDLE`; no se ejecuta otra vez. |
27
- | Dueño incierto | Se detiene y solicita revisión; no se asume abandono. |
28
+ | WIP ausente | Se lee como IDLE. El archivo es local y un clon nuevo no lo trae; eso no es un error. |
29
+ | Tarea de otro runner | No la ve: el WIP ajeno no viaja. Lo que la reserva es su reclamo (BR-OPS-005). |
28
30
 
29
31
  ## Evidencia
30
32
 
@@ -36,3 +38,4 @@ y su evidencia. Cambiar una sin la otra las separa.
36
38
  | Fecha | Cambio | Origen |
37
39
  |---|---|---|
38
40
  | 2026-08-14 | Creación | OPS-001 y `PROTOCOL.md`. |
41
+ | 2026-09-07 | El mutex se acota al runner; el WIP pasa a ser local | Trabajo en equipo: `../../delivery/teamwork.md`. |
@@ -0,0 +1,44 @@
1
+ # Una tarea, un runner
2
+
3
+ > **Dominio:** planning | **Estado:** vigente | **Actualizado:** 2026-09-07
4
+
5
+ El reclamo protege la exclusión mutua entre runners y hace visible quién sostiene cada tarea.
6
+ [fuente: ../../adr/system/OPS-001-planificacion-como-fuente-de-verdad.md]
7
+
8
+ Es la contracara de `BR-OPS-001-una-sola-tarea-activa.md`, y las dos juntas son el invariante 2 de
9
+ `../../PROTOCOL.md`. Se parecen y no son la misma: aquélla impide que un runner lleve dos tareas y vive
10
+ en su `wip/<runner>.md`, que es local; ésta impide que dos runners lleven la misma y vive en `claims/`, que es
11
+ compartido. Con una sola, un equipo trabaja una tarea por vez o duplica trabajo sin enterarse.
12
+
13
+ ## Reglas
14
+
15
+ | ID | Regla | Condición y resultado |
16
+ |---|---|---|
17
+ | BR-OPS-005 | El reclamo reserva | Una tarea reclamada no se ofrece a otro runner ni se toma hasta que su reclamo se suelte. |
18
+
19
+ ## Por qué existe cada regla
20
+
21
+ - **BR-OPS-005:** sin reserva, dos runners que preguntan a la vez reciben la misma tarea y ninguno lo
22
+ nota: el trabajo se duplica y el conflicto aparece recién al mergear, cuando ya se pagó dos veces.
23
+
24
+ ## Casos borde
25
+
26
+ | Caso | Comportamiento esperado |
27
+ |---|---|
28
+ | Reclamo propio | Se continúa esa tarea; es lo que el runner declaró que iba a hacer. |
29
+ | Reclamo de otro | La tarea no se ofrece; se toma la siguiente libre. |
30
+ | Reclamo sin empujar | No protege a nadie: el otro runner lee lo que hay en su copia. |
31
+ | Reclamo abandonado | Se avisa por antigüedad; soltarlo es un acto humano, no un comando. |
32
+ | Tarea ya en DONE | El reclamo sobra y se avisa; la evidencia no depende de él. |
33
+
34
+ ## Evidencia
35
+
36
+ - `ops context` no devuelve una tarea con reclamo ajeno y nombra quién la tiene.
37
+ - `ops check` rechaza un reclamo cuya tarea no existe en BACKLOG ni DONE.
38
+ - `ops claim` se niega a pisar el reclamo de otro.
39
+
40
+ ## Historial
41
+
42
+ | Fecha | Cambio | Origen |
43
+ |---|---|---|
44
+ | 2026-09-07 | Creación | Trabajo en equipo: `../../delivery/teamwork.md`. |
@@ -0,0 +1,70 @@
1
+ # Reclamos
2
+
3
+ Un archivo por tarea tomada, con el slug de la tarea como nombre: `dashboard-filtros.md` dice que esa
4
+ tarea la está haciendo alguien. Crearlo es tomarla; borrarlo es soltarla.
5
+
6
+ ```bash
7
+ node tools/ops.js claim planning dashboard-filtros
8
+ node tools/ops.js release planning dashboard-filtros
9
+ ```
10
+
11
+ Los dos escriben acá y sólo acá. `BACKLOG.md` no lo toca ningún comando del motor: la cola es de lo
12
+ aprobado y la escribe una persona.
13
+
14
+ ## Por qué un archivo por tarea y no uno por persona
15
+
16
+ Dos personas en tareas distintas no tocan nunca el mismo archivo, así que tomar trabajo no produce
17
+ conflictos. Y dos que toman la misma sí chocan, en git, al mergear — que es exactamente donde el choque
18
+ significa algo y donde alguien lo va a ver.
19
+
20
+ Un archivo por persona invierte las dos propiedades: dos agentes de la misma persona pelean por su
21
+ archivo, y dos personas que tomaron lo mismo no chocan hasta que alguien lo nota a mano.
22
+
23
+ ## Quién es «yo»: el runner, no la persona
24
+
25
+ El archivo declara dos cosas distintas. `owner` es la persona —a quién preguntarle— y sale de
26
+ `git config user.email`. `runner` es **el agente que la está haciendo**, y es lo que decide si una tarea
27
+ es tuya.
28
+
29
+ La diferencia sólo se nota con varios agentes en la misma máquina, y ahí es decisiva: dos sesiones tuyas
30
+ resuelven el mismo email, así que si lo que decidiera «esto es mío» fuera la persona, el segundo agente
31
+ tomaría por propia la tarea del primero y los dos construirían lo mismo sin que nada fallara.
32
+
33
+ Cada agente exporta el suyo:
34
+
35
+ ```bash
36
+ export CAUCE_RUNNER=/ruta/de/su/arbol-de-trabajo
37
+ ```
38
+
39
+ Sin la variable se deduce del árbol donde corre el proceso, lo que acierta si el agente invoca desde el
40
+ suyo y devuelve el mismo id para todos si invocan desde una instancia compartida. Eso **no queda en
41
+ silencio**: un runner lleva una tarea a la vez, así que el segundo reclamo choca y el mensaje dice qué
42
+ poner. `ops worktree` la imprime hecha.
43
+
44
+ ## Qué no va acá
45
+
46
+ El plan, los pasos tildados y las decisiones en curso viven en `wip/<runner>.md`, que es local y no viaja por
47
+ git: cambian en cada paso y no le sirven a nadie más. Acá va lo poco que el equipo necesita —qué está
48
+ tomado y por quién—, que cambia dos veces por tarea.
49
+
50
+ Son también dos exclusiones distintas: el reclamo evita que dos runners tomen la misma tarea, y el WIP
51
+ evita que un runner lleve dos.
52
+
53
+ ## Un reclamo sin empujar no protege
54
+
55
+ El otro runner lee lo que hay en su copia. Tomar una tarea y no commitear el archivo se ve igual que no
56
+ haberla tomado, y por eso `ops claim` lo recuerda al terminar.
57
+
58
+ ## Cuando alguien se va
59
+
60
+ Un reclamo abandonado bloquea su tarea para siempre. `ops check` avisa a los tres días **sin señales de
61
+ avance**, que no es lo mismo que tres días desde que se tomó: lo que mira es si la rama `task/<tarea>`
62
+ tiene commits **propios**, los que no están en el tronco. Una rama recién creada hereda la historia
63
+ entera, así que sin esa distinción toda rama parecería haber avanzado el día que se creó. Una tarea larga que sigue recibiendo commits no se apura nunca; una que se detuvo se ve aunque el
64
+ reclamo sea de anteayer.
65
+
66
+ Sin repositorio resoluble —el `service:` no cae en ninguna raíz declarada, o el proyecto nombra sus ramas
67
+ de otra forma— el aviso vuelve a mirar sólo la fecha. Degrada a lo que había antes, no rompe.
68
+
69
+ Soltarlo es borrar el archivo a mano, y `ops release` se niega a hacerlo por vos: liberar el trabajo de
70
+ otro es una decisión, no un comando.
@@ -12,6 +12,7 @@ declara en `project.md` qué partes existen, cuáles aplican y qué deuda separa
12
12
  | `environments.md` | Pregunta, datos y ciclo de vida de cada ambiente. | Sistemas desplegables. |
13
13
  | `flags.md` | Release toggles temporales. | Productos con activación gradual. |
14
14
  | `multi-repo.md` | Versionado y compatibilidad entre repos. | Solo workspaces multi-repo. |
15
+ | `teamwork.md` | Qué comparte el equipo, qué no, y cómo crece. | Más de una persona o más de un agente. |
15
16
  | `project.md` | Estado real, decisiones adoptadas y evolución. | Obligatorio personalizar. |
16
17
 
17
18
  Un proyecto puede adoptar una parte sin fingir que adoptó las demás. Una desviación durable se documenta en
@@ -19,6 +19,17 @@ manifiesto es evidencia del pipeline, no una lista que una persona edita manualm
19
19
  - Bases de datos y APIs aplican expand/contract durante la ventana de convivencia.
20
20
  - Una entrega cross-repo registra qué PR y versión satisface cada lado del contrato.
21
21
 
22
+ ## El `service:` de una tarea tiene que resolver a un solo repositorio
23
+
24
+ Con varias raíces declaradas, un `service:` que existe en más de una es ambiguo: `.` existe en todas, y un
25
+ `src` puede existir en dos. `ops worktree` lo nombra y se niega en vez de elegir la primera, porque elegir
26
+ da una respuesta plausible y equivocada —el árbol de trabajo en el repositorio que no era— sin que nada lo
27
+ diga. El aviso de avance de un reclamo degrada por lo mismo: sin poder resolver el repositorio, mira sólo
28
+ la fecha en que se tomó.
29
+
30
+ La salida es escribir servicios que sólo existan en una raíz. Si dos repositorios tienen un directorio con
31
+ el mismo nombre y los dos son servicios de verdad, conviene una instancia por repositorio.
32
+
22
33
  ## Cuándo coordinar
23
34
 
24
35
  Coordinar solo cuando una propiedad no puede preservarse mediante compatibilidad temporal, por ejemplo una