@ingeniomaps/cauce 0.15.0 → 0.16.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 +58 -0
- package/agents/roles/system/data-analyst/evaluations/results/2026-08-16.md +919 -783
- package/agents/roles/system/legal-counsel/evaluations/results/2026-08-16.md +983 -783
- package/agents/roles/system/security-engineer/evaluations/results/2026-08-16.md +754 -635
- package/automatization/hooks/README.md +17 -1
- package/automatization/hooks/guard-engine.sh +4 -0
- package/automatization/workflows/agent-eval.js +19 -1
- package/engine/automation/index.js +1 -0
- package/engine/cli/ops.js +0 -1
- package/engine/config/validate.js +17 -5
- package/engine/hooks/run.js +35 -2
- package/engine/schemas/ops-config.schema.json +1 -2
- package/package.json +1 -1
- package/template/ops.config.json +0 -1
- package/agents/roles/system/product-manager/evaluations/results/2026-08-16.md +0 -770
|
@@ -39,7 +39,7 @@ runner, mientras la lógica se prueba y mantiene una sola vez en `engine/hooks/r
|
|
|
39
39
|
| Grupo | Guards | Wrapper |
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| `pre-shell` | destructive, git-add, dependencies, governance, verify | `guard-shell.sh` |
|
|
42
|
-
| `pre-files` | secrets, generated, workspace-boundary, migrations, integration-snapshot | `guard-files.sh` |
|
|
42
|
+
| `pre-files` | secrets, generated, workspace-boundary, engine, migrations, integration-snapshot | `guard-files.sh` |
|
|
43
43
|
| `stop` | planning-drift | `guard-planning-drift.sh` |
|
|
44
44
|
|
|
45
45
|
Registrar el grupo gasta un proceso por herramienta en lugar de cinco, con el mismo orden y la misma
|
|
@@ -51,3 +51,19 @@ Para inspeccionar qué hace cada hook y cuándo se ejecuta:
|
|
|
51
51
|
```bash
|
|
52
52
|
node tools/ops.js automation list-hooks .
|
|
53
53
|
```
|
|
54
|
+
|
|
55
|
+
## El motor no se edita desde la empresa
|
|
56
|
+
|
|
57
|
+
`engine` es el único guard cuyo comportamiento depende de dónde corre, y la distinción es deliberada:
|
|
58
|
+
en una instancia bloquea toda escritura bajo `node_modules/@ingeniomaps/cauce`; en el repositorio del
|
|
59
|
+
toolkit —`mode: toolkit` en `ops.config.json`— queda inerte, porque ahí el motor es el producto.
|
|
60
|
+
|
|
61
|
+
`workspace-boundary` no alcanzaba: en una instalación `node_modules/` cae dentro de la raíz declarada,
|
|
62
|
+
así que editar el motor le parecía legítimo. Y el daño de esa edición es silencioso por partida doble.
|
|
63
|
+
El próximo `npm install` la borra, de modo que el arreglo se pierde justo cuando alguien creyó haberlo
|
|
64
|
+
hecho; y hasta entonces la empresa corre un motor que no coincide con la versión que declara, que es la
|
|
65
|
+
forma habitual de un bug irreproducible.
|
|
66
|
+
|
|
67
|
+
La regla que codifica: **un problema del motor se reporta y se arregla arriba.** Lo que sí es de cada
|
|
68
|
+
empresa —sus cargos, sus equipos, sus integraciones, su planificación— queda abierto y el guard no lo
|
|
69
|
+
toca.
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
// Si los viera, el caso mediría su capacidad de repetirlos. Y quien juzga no es quien respondió, por
|
|
8
8
|
// la misma razón por la que nadie corrige su propio examen.
|
|
9
9
|
//
|
|
10
|
+
// **Dónde se corre importa.** Un cargo cuyo trabajo es producir artefactos de planning —una épica, una
|
|
11
|
+
// entrada de INBOX— necesita un `planning/` donde escribir sea legítimo. Corrido dentro del repositorio
|
|
12
|
+
// del toolkit, ese directorio es `template/planning`, que se distribuye a cada instalación: el cargo se
|
|
13
|
+
// niega, con razón, y su caso lo cuenta como fallo. Medido así, `product-manager` falla exactamente los
|
|
14
|
+
// dos casos que piden escribir, y ninguno de los otros tres.
|
|
15
|
+
//
|
|
16
|
+
// Por eso el recorrido se niega cuando `mode` es `toolkit`. Dejarlo escrito en este comentario no
|
|
17
|
+
// alcanzaba: un comentario no impide nada, y la primera vez que pasó fue justamente porque estaba
|
|
18
|
+
// documentado y nadie lo leyó a tiempo. Evaluar los cargos que Cauce distribuye exige una instancia.
|
|
19
|
+
//
|
|
10
20
|
// La respuesta no lleva tope de extensión, y eso se probó: con un tope de doce líneas, dos casos que
|
|
11
21
|
// pasan fallaban. Un comportamiento esperado puede exigir seis elementos —«versión, entorno, datos,
|
|
12
22
|
// pasos, frecuencia y artefactos»— y cuatro de esos no entran en doce líneas. El caso define qué hace
|
|
@@ -41,6 +51,7 @@ const CASES = {
|
|
|
41
51
|
},
|
|
42
52
|
} },
|
|
43
53
|
skill: { type: 'string' },
|
|
54
|
+
mode: { type: 'string' },
|
|
44
55
|
},
|
|
45
56
|
}
|
|
46
57
|
|
|
@@ -80,12 +91,19 @@ const contexto = await agent(
|
|
|
80
91
|
`1. "node tools/ops.js evaluate ${AGENT} --cases --json" — the cases, verbatim.\n` +
|
|
81
92
|
`2. "node tools/ops.js agents list --json" — set skill to "${ROOT}/<path>/SKILL.md" using the path it ` +
|
|
82
93
|
`printed for ${AGENT}. That command prints paths relative to ${ROOT} and the next agents run from ` +
|
|
83
|
-
`elsewhere, so the prefix is not optional
|
|
94
|
+
`elsewhere, so the prefix is not optional.\n` +
|
|
95
|
+
`Then read ${ROOT}/ops.config.json and set mode to its "mode" field, verbatim.`,
|
|
84
96
|
{ schema: CASES, label: 'cases' },
|
|
85
97
|
)
|
|
86
98
|
if (!contexto || !contexto.items || !contexto.items.length) {
|
|
87
99
|
return stop('sin-casos', `${AGENT} no tiene casos, o no se pudieron leer`)
|
|
88
100
|
}
|
|
101
|
+
if (contexto.mode === 'toolkit') {
|
|
102
|
+
return stop('en-el-toolkit',
|
|
103
|
+
'este recorrido mide cargos trabajando, y acá no pueden: `planningDir` apunta a la plantilla que ' +
|
|
104
|
+
'se distribuye, así que un cargo que deba escribir en planning se niega —con razón— y su caso lo ' +
|
|
105
|
+
'cuenta como fallo. Medido así el resultado no dice nada del cargo. Corrélo desde una instancia.')
|
|
106
|
+
}
|
|
89
107
|
log(`${contexto.items.length} caso(s) de ${AGENT}`)
|
|
90
108
|
|
|
91
109
|
const veredictos = await pipeline(
|
package/engine/cli/ops.js
CHANGED
|
@@ -155,7 +155,6 @@ function init(target) {
|
|
|
155
155
|
copyTemplate(path.join(PROJECT_ROOT, 'template'), root, {
|
|
156
156
|
'{{PROJECT_NAME}}': name,
|
|
157
157
|
'{{MODE}}': mode,
|
|
158
|
-
'{{PLANNING_DIR}}': 'planning',
|
|
159
158
|
'{{WORKSPACE_PATH}}': mode === 'embedded' ? '.' : '..',
|
|
160
159
|
}, process.argv.includes('--force'), providerNames())
|
|
161
160
|
// No se copia `.github/`: `ci.yml` valida el toolkit con `npm run ci` —que una instancia no tiene— y
|
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
const MODES = ['embedded', 'sidecar', 'toolkit']
|
|
4
4
|
|
|
5
|
+
// Campos que existieron y se retiraron. Se nombran en vez de caer en «propiedad desconocida» porque
|
|
6
|
+
// quien actualiza merece saber qué hacer con la línea, no sólo que sobra.
|
|
7
|
+
//
|
|
8
|
+
// `planningDir` era obligatorio y nadie lo honraba: el renderizador de la plantilla lo resolvía
|
|
9
|
+
// siempre a `planning`, y `findOpsRoot` y el registro de integraciones lo tienen escrito a mano. Un
|
|
10
|
+
// campo así no configura, promete. En el propio toolkit decía `template/planning` —el molde que se
|
|
11
|
+
// distribuye—, y un cargo que lo leyó concluyó que ahí vivía la planificación del proyecto.
|
|
12
|
+
//
|
|
13
|
+
// Se retira en vez de honrarse porque la ubicación no es opinable: `findOpsRoot` reconoce un
|
|
14
|
+
// repositorio de operaciones justamente por tener `planning/` en la raíz.
|
|
15
|
+
const RETIRED = {
|
|
16
|
+
planningDir: 'el motor siempre busca planning/ en la raíz del repositorio. Borrá la línea',
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
function validateOpsConfig(config) {
|
|
6
20
|
const errors = []
|
|
7
21
|
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
@@ -9,18 +23,16 @@ function validateOpsConfig(config) {
|
|
|
9
23
|
}
|
|
10
24
|
// `cauceVersion` la escribe el toolkit, no la persona: registra de qué versión salió la instancia.
|
|
11
25
|
const allowed = new Set([
|
|
12
|
-
'$schema', 'cauceVersion', 'project', 'mode', '
|
|
26
|
+
'$schema', 'cauceVersion', 'project', 'mode', 'workspaceRoots', 'runner',
|
|
13
27
|
])
|
|
14
28
|
for (const key of Object.keys(config)) {
|
|
15
|
-
if (
|
|
29
|
+
if (RETIRED[key]) errors.push(`ops.config.json: ${key} ya no se usa: ${RETIRED[key]}`)
|
|
30
|
+
else if (!allowed.has(key)) errors.push(`ops.config.json: propiedad desconocida ${key}`)
|
|
16
31
|
}
|
|
17
32
|
if (typeof config.project !== 'string' || !config.project.trim()) {
|
|
18
33
|
errors.push('ops.config.json: project debe ser un string no vacío')
|
|
19
34
|
}
|
|
20
35
|
if (!MODES.includes(config.mode)) errors.push('ops.config.json: mode inválido')
|
|
21
|
-
if (typeof config.planningDir !== 'string' || !config.planningDir.trim()) {
|
|
22
|
-
errors.push('ops.config.json: planningDir debe ser un string no vacío')
|
|
23
|
-
}
|
|
24
36
|
validateWorkspaces(config.workspaceRoots, errors)
|
|
25
37
|
validateRunner(config.runner, errors)
|
|
26
38
|
return errors
|
package/engine/hooks/run.js
CHANGED
|
@@ -324,16 +324,44 @@ function planningDrift(input) {
|
|
|
324
324
|
block(`Planning o integraciones quedaron desalineados:\n${result.output}`)
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
// El motor llega por npm y se actualiza por npm. `workspace-boundary` no lo cubre: en una instalación
|
|
328
|
+
// `node_modules/` cae dentro de la raíz declarada, así que editar el motor le parece legítimo.
|
|
329
|
+
//
|
|
330
|
+
// Editarlo desde la empresa rompe dos veces. El próximo `npm install` borra el cambio sin avisar, así
|
|
331
|
+
// que el arreglo se pierde justo cuando alguien creyó haberlo hecho; y hasta entonces la empresa corre
|
|
332
|
+
// un motor que no coincide con la versión que declara, que es la clase de diferencia que aparece como
|
|
333
|
+
// un bug irreproducible. Un problema del motor se reporta y se arregla arriba, no acá.
|
|
334
|
+
//
|
|
335
|
+
// El toolkit se exceptúa, y esa distinción ya estaba escrita: en su `ops.config.json` el modo es
|
|
336
|
+
// `toolkit`. Ahí el motor es el producto y editarlo es exactamente el trabajo.
|
|
337
|
+
function engineWrites(input) {
|
|
338
|
+
const root = findOpsRoot(process.env.OPS_ROOT || process.env.CLAUDE_PROJECT_DIR || cwdOf(input))
|
|
339
|
+
if (!root) return
|
|
340
|
+
let config
|
|
341
|
+
try { config = JSON.parse(fs.readFileSync(path.join(root, 'ops.config.json'), 'utf8')) } catch { return }
|
|
342
|
+
if (config.mode === 'toolkit') return
|
|
343
|
+
const pkg = path.join(root, 'node_modules', '@ingeniomaps', 'cauce')
|
|
344
|
+
for (const raw of filesOf(input)) {
|
|
345
|
+
const file = path.resolve(cwdOf(input), raw)
|
|
346
|
+
if (file !== pkg && !file.startsWith(`${pkg}${path.sep}`)) continue
|
|
347
|
+
block(`${raw} pertenece al motor de Cauce, que se actualiza con npm.\n` +
|
|
348
|
+
'Un cambio acá lo borra el próximo install y mientras tanto corrés un motor que no coincide ' +
|
|
349
|
+
'con la versión que declarás. Actualizá con "npm update @ingeniomaps/cauce" y reportá el ' +
|
|
350
|
+
'problema arriba; lo que sí es tuyo son tus cargos, equipos e integraciones.')
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
327
354
|
const guards = {
|
|
328
355
|
destructive, 'git-add': gitAdd, secrets, generated, 'workspace-boundary': workspaceBoundary,
|
|
329
356
|
migrations, dependencies, governance, verify, 'planning-drift': planningDrift,
|
|
330
|
-
'integration-snapshot': integrationSnapshot,
|
|
357
|
+
'integration-snapshot': integrationSnapshot, engine: engineWrites,
|
|
331
358
|
}
|
|
332
359
|
|
|
333
360
|
// Grupos por evento: un runner corre el grupo entero en un solo proceso en lugar de un guard por hook.
|
|
334
361
|
const hookGroups = {
|
|
335
362
|
'pre-shell': ['destructive', 'git-add', 'dependencies', 'governance', 'verify'],
|
|
336
|
-
'pre-files': ['secrets', 'generated', 'workspace-boundary', '
|
|
363
|
+
'pre-files': ['secrets', 'generated', 'workspace-boundary', 'engine', 'migrations',
|
|
364
|
+
'integration-snapshot'],
|
|
337
365
|
stop: ['planning-drift'],
|
|
338
366
|
}
|
|
339
367
|
|
|
@@ -358,6 +386,11 @@ const hookMetadata = [
|
|
|
358
386
|
{ name: 'secrets', event: 'PreToolUse · files', purpose: 'Bloquea escritura de secretos y credenciales.' },
|
|
359
387
|
{ name: 'generated', event: 'PreToolUse · files', purpose: 'Impide editar código generado manualmente.' },
|
|
360
388
|
{ name: 'workspace-boundary', event: 'PreToolUse · files', purpose: 'Limita escrituras a las raíces declaradas.' },
|
|
389
|
+
{
|
|
390
|
+
name: 'engine',
|
|
391
|
+
event: 'PreToolUse · files',
|
|
392
|
+
purpose: 'Impide editar el motor instalado: se actualiza con npm.',
|
|
393
|
+
},
|
|
361
394
|
{ name: 'migrations', event: 'PreToolUse · files', purpose: 'Protege migraciones existentes y SQL destructivo.' },
|
|
362
395
|
{
|
|
363
396
|
name: 'integration-snapshot',
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"title": "Cauce engine configuration",
|
|
4
4
|
"type": "object",
|
|
5
|
-
"required": ["project", "mode", "
|
|
5
|
+
"required": ["project", "mode", "workspaceRoots", "runner"],
|
|
6
6
|
"properties": {
|
|
7
7
|
"$schema": { "type": "string", "minLength": 1 },
|
|
8
8
|
"cauceVersion": { "type": "string", "minLength": 1 },
|
|
9
9
|
"project": { "type": "string", "minLength": 1 },
|
|
10
10
|
"mode": { "enum": ["embedded", "sidecar", "toolkit"] },
|
|
11
|
-
"planningDir": { "type": "string", "minLength": 1 },
|
|
12
11
|
"workspaceRoots": {
|
|
13
12
|
"type": "array",
|
|
14
13
|
"minItems": 1,
|
package/package.json
CHANGED
package/template/ops.config.json
CHANGED