@ingeniomaps/cauce 0.77.0 → 0.78.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.
- package/CHANGELOG.md +38 -0
- package/automatization/workflows/autobuild.js +34 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,44 @@ desde este repositorio no va, porque el que lee no puede actuar sobre eso. Cuand
|
|
|
14
14
|
unas pocas líneas casi siempre es porque cuenta cómo se descubrió el problema o por qué se eligió el
|
|
15
15
|
diseño — eso vive en el commit y en el código.
|
|
16
16
|
|
|
17
|
+
## [0.78.0] - 2026-09-10
|
|
18
|
+
|
|
19
|
+
### Corregido
|
|
20
|
+
|
|
21
|
+
- **Las puertas que revisan un recorrido leen los literales de regex.** Tres pruebas analizan cada
|
|
22
|
+
workflow como texto —que su `meta` sea un literal puro, que no llame a nada inexistente y que no use un
|
|
23
|
+
nombre que no declaró— y ninguna sabía qué es un regex. La barra escapada que cierra uno deja un `//`
|
|
24
|
+
literal, que se leía como el arranque de un comentario: a partir de ahí se perdía el resto de la línea,
|
|
25
|
+
en silencio. Dos recorridos del catálogo tenían cuatro líneas así.
|
|
26
|
+
|
|
27
|
+
**Qué cambia para vos**: nada en lo que recibís, y sí en lo que se puede confiar. Un recorrido propio
|
|
28
|
+
con un regex adentro ahora se revisa entero en vez de a medias, y un `meta` con un regex o con una
|
|
29
|
+
interpolación —que hasta acá pasaba siempre, porque esa regla no podía dispararse— se rechaza.
|
|
30
|
+
- **El nombre de un banco de pruebas no trae nada que la prueba no haya pedido.** La suite aísla lo que
|
|
31
|
+
cada prueba mide filtrando la salida de `check`, y esa salida empieza con la ruta del banco: cuando el
|
|
32
|
+
sufijo aleatorio del directorio terminó en `adr`, un error ajeno entró a una prueba de plantillas de
|
|
33
|
+
ADR y la puso en rojo. Falla una vez cada muchas corridas y se lee como un hipo del entorno.
|
|
34
|
+
|
|
35
|
+
**Qué cambia para vos**: nada — es la suite del toolkit, no algo que recibas. Va acá porque una puerta
|
|
36
|
+
que falla al azar enseña a relanzar en vez de a mirar, y eso sí llega a quien la usa.
|
|
37
|
+
|
|
38
|
+
- **`autobuild` lee `blocked` por su valor y no por su verdad.** El campo del contexto es un vocabulario
|
|
39
|
+
de tres valores —vacío, `awaiting-review` y `blocked-on-human`—, y el recorrido lo probaba con un `if`
|
|
40
|
+
a secas. Dos consecuencias, y la que más costaba no era intermitente: una cola trabada por acciones
|
|
41
|
+
humanas frenaba con el motivo del checkpoint de hito y mandaba a mirar `AWAITING_REVIEW.md`, un archivo
|
|
42
|
+
que en ese escenario no existe. Ahora cada bloqueo para con su motivo y nombra su archivo:
|
|
43
|
+
`AWAITING_REVIEW.md` para el checkpoint, `HUMAN_ACTIONS.md` —con las tareas trabadas— para la cola.
|
|
44
|
+
|
|
45
|
+
La otra es la que se ve al azar: el agente que transcribe el contexto a veces entrega el vacío como la
|
|
46
|
+
cadena de dos comillas, y eso frenaba la corrida en la fase 1 sin que hubiera nada que resolver. Medido
|
|
47
|
+
sobre siete corridas de una instancia real: 3 de 24 lecturas llegaron así, y una de cada siete cayó en
|
|
48
|
+
la única lectura que consulta el campo. Las formas equivocadas del vacío se desenvuelven antes de leer.
|
|
49
|
+
|
|
50
|
+
Y lo que no está en el vocabulario ya no se adivina en ninguna de las dos direcciones: no se sigue como
|
|
51
|
+
si no hubiera bloqueo ni se inventa cuál es — para diciendo que el contexto llegó fuera del
|
|
52
|
+
vocabulario. El esquema declara los tres valores, igual que `lane`; eso documenta el contrato, y lo que
|
|
53
|
+
sostiene el arreglo es la lectura.
|
|
54
|
+
|
|
17
55
|
## [0.77.0] - 2026-09-10
|
|
18
56
|
|
|
19
57
|
### Corregido
|
|
@@ -38,6 +38,11 @@ const GATE = `${P}/AWAITING_REVIEW.md`
|
|
|
38
38
|
const ROADMAP = `${P}/roadmap`
|
|
39
39
|
|
|
40
40
|
// Estado de planning tal como lo emite `ops context --json`; ningún modelo parsea BACKLOG ni WIP.
|
|
41
|
+
// De a pares, y sin regex: una comilla dentro de un literal de regex desincroniza a las dos puertas que
|
|
42
|
+
// leen este archivo sin parsearlo —caso 084—, y de a pares es además lo correcto, porque una comilla
|
|
43
|
+
// suelta no es un envoltorio. Por eso también la escapada en vez de alternar el estilo de comillas.
|
|
44
|
+
const QUOTES = ['\'', '"']
|
|
45
|
+
|
|
41
46
|
const CONTEXT = {
|
|
42
47
|
type: 'object', additionalProperties: false,
|
|
43
48
|
required: ['blocked', 'hasTask', 'wipActive', 'queued', 'cast', 'readOk'],
|
|
@@ -46,7 +51,13 @@ const CONTEXT = {
|
|
|
46
51
|
// exactamente lo que un modelo completa cuando no tiene qué poner. Sin este campo esa invención se
|
|
47
52
|
// lee igual que una cola terminada, y Pick la toma como permiso para promover.
|
|
48
53
|
readOk: { type: 'boolean' },
|
|
49
|
-
|
|
54
|
+
// Vocabulario cerrado, igual que `lane` acá abajo, y por la misma razón: el motor emite tres valores
|
|
55
|
+
// y nada más —`ops context` los decide con un `existsSync` y un conteo—, así que dejarlo como texto
|
|
56
|
+
// libre le pedía a quien lo transcribe que acertara una convención invisible. Un modelo que rellena
|
|
57
|
+
// «el valor vacío» puede escribir la cadena vacía o **escribir las comillas**, y las dos satisfacían
|
|
58
|
+
// el esquema: medido en una instancia real, 3 de 24 lecturas llegaron como `"\"\""` (caso 083).
|
|
59
|
+
blocked: { type: 'string', enum: ['', 'awaiting-review', 'blocked-on-human'] },
|
|
60
|
+
hasTask: { type: 'boolean' }, wipActive: { type: 'boolean' },
|
|
50
61
|
queued: { type: 'integer' }, slug: { type: 'string' }, hito: { type: 'string' },
|
|
51
62
|
service: { type: 'string' }, acceptance: { type: 'string' }, epic: { type: 'string' },
|
|
52
63
|
// Sin declararlo acá no llega: `additionalProperties: false` lo descartaría, y el aplanado de la
|
|
@@ -364,7 +375,28 @@ if (!planning) return stop('context-unavailable', `no se pudo leer el estado de
|
|
|
364
375
|
// Que el agente conteste no significa que haya leído: el schema se completa igual con ceros. Parar acá
|
|
365
376
|
// cuesta una corrida; seguir sobre una lectura fallida escribe en el BACKLOG, y eso no se revierte solo.
|
|
366
377
|
if (!planning.readOk) return stop('context-unavailable', `${P} no se pudo leer; revisá la ruta y el cwd`)
|
|
367
|
-
|
|
378
|
+
// `blocked` se lee por su valor y no por su verdad. Como verdad, **cualquier** cadena no vacía frenaba la
|
|
379
|
+
// corrida con el mismo motivo, y eso mentía dos veces: con `blocked-on-human` —la cola trabada por
|
|
380
|
+
// acciones humanas, que es otra cosa— mandaba a mirar un gate que no existe, y eso no era intermitente;
|
|
381
|
+
// y con la cadena `""` que a veces llega del transcriptor, frenaba sin que hubiera nada que resolver.
|
|
382
|
+
//
|
|
383
|
+
// El vacío se normaliza antes porque sus formas equivocadas no son ambiguas: dos comillas o unos espacios
|
|
384
|
+
// no son ningún bloqueo legítimo. Lo que no se reconoce **no se adivina**: para diciendo que el contexto
|
|
385
|
+
// llegó fuera del vocabulario, que es lo que esta familia de casos —056, 074, 075— pide para lo que no se
|
|
386
|
+
// pudo determinar.
|
|
387
|
+
let blocker = String(planning.blocked || '').trim()
|
|
388
|
+
while (blocker.length > 1 && QUOTES.includes(blocker[0]) && blocker[blocker.length - 1] === blocker[0]) {
|
|
389
|
+
blocker = blocker.slice(1, -1).trim()
|
|
390
|
+
}
|
|
391
|
+
if (blocker === 'awaiting-review') {
|
|
392
|
+
return stop('awaiting-human-review', `${GATE} tiene un checkpoint humano sin resolver`)
|
|
393
|
+
}
|
|
394
|
+
if (blocker === 'blocked-on-human') {
|
|
395
|
+
return stop('blocked-on-human', `toda la cola espera una acción humana. Está en ${HUMAN}`
|
|
396
|
+
+ `${(planning.blockedTasks || []).length ? `, sobre ${planning.blockedTasks.join(', ')}` : ''}`)
|
|
397
|
+
}
|
|
398
|
+
if (blocker) return stop('context-unavailable', `${P} contestó blocked=${JSON.stringify(planning.blocked)}, `
|
|
399
|
+
+ 'que no es del vocabulario. No se sabe si hay bloqueo, así que no se sigue como si no lo hubiera.')
|
|
368
400
|
|
|
369
401
|
let currentMilestone = planning.wipActive ? planning.hito : ''
|
|
370
402
|
const completed = []
|