@ingeniomaps/cauce 0.53.1 → 0.54.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 (130) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +1 -1
  3. package/agents/README.md +24 -0
  4. package/agents/roles/system/accounting-specialist/SKILL.md +2 -0
  5. package/agents/roles/system/ai-governance-lead/SKILL.md +2 -0
  6. package/agents/roles/system/ai-product-manager/SKILL.md +2 -0
  7. package/agents/roles/system/analytics-engineer/SKILL.md +2 -0
  8. package/agents/roles/system/backend-engineer/SKILL.md +4 -2
  9. package/agents/roles/system/backend-engineer/learning/HISTORY.md +1 -0
  10. package/agents/roles/system/business-strategist/SKILL.md +4 -2
  11. package/agents/roles/system/cloud-architect/SKILL.md +5 -0
  12. package/agents/roles/system/cloud-architect/learning/HISTORY.md +4 -0
  13. package/agents/roles/system/community-manager/SKILL.md +2 -0
  14. package/agents/roles/system/content-specialist/SKILL.md +4 -2
  15. package/agents/roles/system/customer-success-manager/SKILL.md +9 -2
  16. package/agents/roles/system/customer-success-manager/learning/HISTORY.md +1 -0
  17. package/agents/roles/system/customer-support-specialist/SKILL.md +4 -2
  18. package/agents/roles/system/data-analyst/SKILL.md +9 -2
  19. package/agents/roles/system/data-analyst/learning/HISTORY.md +1 -0
  20. package/agents/roles/system/data-engineer/SKILL.md +2 -0
  21. package/agents/roles/system/data-governance-steward/SKILL.md +2 -0
  22. package/agents/roles/system/data-scientist/SKILL.md +2 -0
  23. package/agents/roles/system/database-administrator/SKILL.md +2 -0
  24. package/agents/roles/system/database-administrator/learning/HISTORY.md +1 -0
  25. package/agents/roles/system/developer-relations-engineer/SKILL.md +2 -0
  26. package/agents/roles/system/devops-engineer/SKILL.md +4 -2
  27. package/agents/roles/system/engineering-manager/SKILL.md +2 -0
  28. package/agents/roles/system/financial-controller/SKILL.md +4 -2
  29. package/agents/roles/system/finops-engineer/SKILL.md +2 -0
  30. package/agents/roles/system/finops-engineer/learning/HISTORY.md +1 -0
  31. package/agents/roles/system/finops-engineer/learning/sources.yaml +12 -0
  32. package/agents/roles/system/fraud-risk-analyst/SKILL.md +7 -0
  33. package/agents/roles/system/fraud-risk-analyst/learning/HISTORY.md +1 -0
  34. package/agents/roles/system/frontend-engineer/SKILL.md +8 -2
  35. package/agents/roles/system/frontend-engineer/evaluations/cases/09-comment-panel/InternalNote.jsx +30 -0
  36. package/agents/roles/system/frontend-engineer/evaluations/cases/09-comment-panel.md +10 -0
  37. package/agents/roles/system/frontend-engineer/learning/HISTORY.md +1 -0
  38. package/agents/roles/system/growth-marketer/SKILL.md +17 -0
  39. package/agents/roles/system/growth-marketer/evaluations/cases/08-briefing-de-referidos.md +23 -0
  40. package/agents/roles/system/growth-marketer/evaluations/expected-behaviors.yaml +1 -0
  41. package/agents/roles/system/growth-marketer/learning/HISTORY.md +3 -0
  42. package/agents/roles/system/implementation-manager/SKILL.md +10 -0
  43. package/agents/roles/system/implementation-manager/evaluations/cases/08-signed-cutover-runbook/plan-cutover-tesela-rev-b.md +70 -0
  44. package/agents/roles/system/implementation-manager/evaluations/cases/08-signed-cutover-runbook.md +12 -0
  45. package/agents/roles/system/implementation-manager/evaluations/expected-behaviors.yaml +1 -0
  46. package/agents/roles/system/implementation-manager/learning/HISTORY.md +5 -0
  47. package/agents/roles/system/integrations-engineer/SKILL.md +6 -4
  48. package/agents/roles/system/kyc-aml-specialist/SKILL.md +11 -4
  49. package/agents/roles/system/kyc-aml-specialist/learning/HISTORY.md +2 -0
  50. package/agents/roles/system/kyc-aml-specialist/learning/sources.yaml +76 -1
  51. package/agents/roles/system/legal-counsel/SKILL.md +2 -0
  52. package/agents/roles/system/logistics-operations-manager/SKILL.md +17 -0
  53. package/agents/roles/system/logistics-operations-manager/evaluations/cases/07-entrega-a-tiempo/api-seguimiento-andesexpress.md +40 -0
  54. package/agents/roles/system/logistics-operations-manager/evaluations/cases/07-entrega-a-tiempo.md +2 -3
  55. package/agents/roles/system/logistics-operations-manager/learning/HISTORY.md +2 -0
  56. package/agents/roles/system/machine-learning-engineer/SKILL.md +2 -0
  57. package/agents/roles/system/mlops-engineer/SKILL.md +2 -0
  58. package/agents/roles/system/mobile-engineer/SKILL.md +4 -2
  59. package/agents/roles/system/partnerships-manager/SKILL.md +2 -0
  60. package/agents/roles/system/people-operations-manager/SKILL.md +2 -0
  61. package/agents/roles/system/privacy-compliance-specialist/SKILL.md +4 -2
  62. package/agents/roles/system/procurement-manager/SKILL.md +2 -0
  63. package/agents/roles/system/product-manager/SKILL.md +2 -0
  64. package/agents/roles/system/product-marketing-manager/SKILL.md +9 -2
  65. package/agents/roles/system/product-marketing-manager/learning/HISTORY.md +1 -0
  66. package/agents/roles/system/project-manager/SKILL.md +2 -0
  67. package/agents/roles/system/qa-engineer/SKILL.md +11 -2
  68. package/agents/roles/system/qa-engineer/evaluations/cases/07-agent-test-repair.md +1 -1
  69. package/agents/roles/system/qa-engineer/evaluations/cases/11-accessibility-sampling.md +10 -0
  70. package/agents/roles/system/qa-engineer/evaluations/cases/12-quoted-from-a-summary/resumen-legal-wcag22.md +28 -0
  71. package/agents/roles/system/qa-engineer/evaluations/cases/12-quoted-from-a-summary.md +10 -0
  72. package/agents/roles/system/qa-engineer/evaluations/cases/13-matrix-from-a-summary/wiki-plataforma-conformidad.md +24 -0
  73. package/agents/roles/system/qa-engineer/evaluations/cases/13-matrix-from-a-summary.md +10 -0
  74. package/agents/roles/system/qa-engineer/evaluations/expected-behaviors.yaml +2 -0
  75. package/agents/roles/system/qa-engineer/learning/HISTORY.md +4 -0
  76. package/agents/roles/system/qa-engineer/learning/sources.yaml +24 -3
  77. package/agents/roles/system/release-manager/SKILL.md +5 -3
  78. package/agents/roles/system/release-manager/evaluations/cases/09-provenance-without-origin.md +12 -0
  79. package/agents/roles/system/release-manager/learning/HISTORY.md +1 -0
  80. package/agents/roles/system/release-manager/references/operating-model.md +8 -0
  81. package/agents/roles/system/sales-representative/SKILL.md +4 -2
  82. package/agents/roles/system/security-engineer/SKILL.md +4 -2
  83. package/agents/roles/system/security-engineer/learning/HISTORY.md +1 -0
  84. package/agents/roles/system/site-reliability-engineer/SKILL.md +4 -2
  85. package/agents/roles/system/software-architect/SKILL.md +4 -2
  86. package/agents/roles/system/solutions-engineer/SKILL.md +2 -0
  87. package/agents/roles/system/tech-lead/SKILL.md +2 -0
  88. package/agents/roles/system/technical-program-manager/SKILL.md +2 -0
  89. package/agents/roles/system/technical-writer/SKILL.md +2 -0
  90. package/agents/roles/system/treasury-analyst/SKILL.md +6 -4
  91. package/agents/roles/system/ui-designer/SKILL.md +15 -0
  92. package/agents/roles/system/ui-designer/learning/HISTORY.md +2 -0
  93. package/agents/roles/system/user-researcher/SKILL.md +6 -0
  94. package/agents/roles/system/user-researcher/learning/HISTORY.md +1 -0
  95. package/agents/roles/system/ux-designer/SKILL.md +2 -0
  96. package/automatization/shared/eval-measured.js +35 -0
  97. package/automatization/shared/eval-only.js +15 -0
  98. package/automatization/workflows/README.md +27 -0
  99. package/automatization/workflows/agent-eval.js +42 -7
  100. package/automatization/workflows/agent-promote.js +65 -15
  101. package/automatization/workflows/autobuild.js +52 -8
  102. package/automatization/workflows/flow-eval.js +27 -7
  103. package/engine/agents/catalog.js +1 -1
  104. package/engine/agents/fork.js +1 -1
  105. package/engine/agents/learning-files.js +7 -2
  106. package/engine/agents/learning-seal.js +123 -0
  107. package/engine/agents/learning-sources.js +33 -3
  108. package/engine/agents/learning.js +80 -87
  109. package/engine/automation/hooks.js +0 -1
  110. package/engine/automation/index.js +0 -2
  111. package/engine/cli/args.js +2 -2
  112. package/engine/cli/catalog.js +33 -4
  113. package/engine/cli/instance.js +0 -2
  114. package/engine/cli/ops.js +2 -18
  115. package/engine/config/validate.js +7 -2
  116. package/engine/core/onboarding.js +0 -3
  117. package/engine/core/scan.js +1 -1
  118. package/engine/hooks/input.js +1 -1
  119. package/engine/integrations/proposals.js +1 -1
  120. package/engine/integrations/providers/jira.js +1 -1
  121. package/engine/integrations/registry.js +0 -1
  122. package/engine/planning/business-rules.js +1 -1
  123. package/engine/planning/contracts.js +8 -1
  124. package/engine/planning/parser.js +7 -1
  125. package/engine/schemas/ops-config.schema.json +60 -13
  126. package/flows/system/incident-review/flow.json +1 -1
  127. package/flows/system/incident-review/learning/HISTORY.md +1 -0
  128. package/package.json +4 -3
  129. package/template/planning/rules/system/conduct.md +19 -0
  130. package/template/tools/ops.js +2 -2
@@ -132,6 +132,16 @@ function learn(agent, cli) {
132
132
  // aplicada editando frontmatter a mano es justo el paso que un agente hace mal en silencio.
133
133
  // Un recorrido aprende de sus corridas y un cargo de su profesión: mismo ciclo, distinto insumo.
134
134
  const kind = cli.has('--flow') ? 'flow' : 'agent'
135
+ // El tercer destino: se miró y no cambia nada. Sin esto sólo había aplicarla o dejarla esperando,
136
+ // y lo que se hacía era mergear el PR sin firmar — que deja el documento diciendo «sin aplicar»
137
+ // para siempre, indistinguible de una que espera trabajo.
138
+ if (cli.has('--archived')) {
139
+ const result = L.archive(opsRoot(), agent, cli.value('--period'), kind)
140
+ const relative = path.relative(opsRoot(), result.file)
141
+ return console.log(result.already
142
+ ? `= ${relative} ya estaba archivada`
143
+ : `✓ ${relative} queda archivada: se miró y no cambia nada`)
144
+ }
135
145
  if (cli.has('--applied')) {
136
146
  const result = L.seal(opsRoot(), agent, cli.value('--period'), kind)
137
147
  const relative = path.relative(opsRoot(), result.file)
@@ -139,14 +149,28 @@ function learn(agent, cli) {
139
149
  ? `= ${relative} ya estaba aplicada`
140
150
  : `✓ ${relative} queda aplicada: no se vuelve a aplicar`)
141
151
  }
152
+ // Un recorrido no tiene informe semanal: su propuesta se compone de los veredictos de sus propias
153
+ // corridas y nunca lee `learning/reports/`. La forma desnuda —la que para un cargo abre el informe
154
+ // de la semana— no tiene entonces qué abrir acá, y `prepareReport` lo decía resolviendo con el
155
+ // `kind` por defecto: «no existe agents/<tipo>/<slug>/SKILL.md», que manda a crear un cargo que no
156
+ // falta. Negarse nombrando el comando que sí corresponde es lo que cierra R13.
157
+ if (kind === 'flow' && !cli.has('--proposal')) {
158
+ fail(`${agent} es un recorrido: aprende de sus corridas, no de informes semanales.\n`
159
+ + ` Abrí la propuesta con "ops learn ${agent} --flow --proposal".`, 2)
160
+ }
142
161
  // `--period` es para consolidar a mano un mes que no es el de hoy. El ciclo automático no lo
143
162
  // pasa: la propuesta se llama por el mes en que se abre y arrastra lo que todavía no entró.
144
163
  const result = cli.has('--proposal')
145
164
  ? L.prepareProposal(opsRoot(), agent, new Date(), cli.value('--period'), kind)
146
165
  : L.prepareReport(opsRoot(), agent)
147
- // Sin informes pendientes no hay archivo que nombrar, y decirlo es el resultado: el ciclo corrió
148
- // y no había nada que consolidar.
149
- if (!result.file) return console.log('= sin informes pendientes: no se abre propuesta')
166
+ // Sin archivo que nombrar hay dos resultados distintos y decir cuál es el punto: no había material,
167
+ // o lo había y ninguno propuso un cambio. El segundo no es un error ni un mes perdido —el informe
168
+ // es histórico igual— y confundirlo con el primero manda a buscar por qué no se investigó.
169
+ if (!result.file) {
170
+ return console.log(result.quiet
171
+ ? `= ${result.quiet} informe(s) sin recomendación: no hay qué proponer, quedan para el mes que viene`
172
+ : '= sin informes pendientes: no se abre propuesta')
173
+ }
150
174
  console.log(`${result.created ? '+' : '='} ${path.relative(opsRoot(), result.file)}`)
151
175
  // Un cargo consolida informes de su profesión; un recorrido, las corridas que lo midieron.
152
176
  if (typeof result.reports === 'number') {
@@ -170,7 +194,12 @@ function evaluate(agent, caso, cli) {
170
194
  }
171
195
  // El caso es el posicional que sigue al cargo: `evaluate <cargo> --bench <caso>`. Sin él se arma
172
196
  // un banco suelto, para mirarlo a mano; una corrida real pide uno por caso.
173
- return console.log(evaluationBench(root, agent, caso, cli.has('--force'), kind))
197
+ //
198
+ // Relativa a la raíz, como la de `--record`: esta salida la lee el agente que prepara los bancos,
199
+ // y de ahí la ruta viaja a los informes y a las propuestas que después lee otro cargo. Absoluta
200
+ // nombraba el directorio personal de una máquina, y así quedaron mil cuatrocientas ochenta y cinco
201
+ // citas que dejaron de resolver el día que este repositorio cambió de nombre.
202
+ return console.log(path.relative(root, evaluationBench(root, agent, caso, cli.has('--force'), kind)))
174
203
  }
175
204
  try {
176
205
  // Los casos, para que un recorrido los ejecute. Sin `--json` no tiene sentido: es entrada de
@@ -7,7 +7,6 @@
7
7
 
8
8
  const fs = require('node:fs')
9
9
  const path = require('node:path')
10
- const { spawnSync } = require('node:child_process')
11
10
  const F = require('../core/files')
12
11
  const O = require('../core/ownership')
13
12
  const CL = require('../core/changelog')
@@ -15,7 +14,6 @@ const M = require('../core/manifest')
15
14
  const OB = require('../core/onboarding')
16
15
  const P = require('../planning/parser')
17
16
  const ST = require('../planning/state')
18
- const I = require('../integrations/registry')
19
17
  const A = require('../automation')
20
18
  const { fail } = require('./io')
21
19
 
package/engine/cli/ops.js CHANGED
@@ -4,25 +4,9 @@
4
4
  const fs = require('node:fs')
5
5
  const path = require('node:path')
6
6
  const { spawnSync } = require('node:child_process')
7
- const P = require('../planning/parser')
8
- const B = require('../planning/business-rules')
9
- const PC = require('../planning/contracts')
10
- const ST = require('../planning/state')
11
- const I = require('../integrations/registry')
12
- const L = require('../agents/learning')
13
7
  const A = require('../automation')
14
- const F = require('../core/files')
15
- const O = require('../core/ownership')
16
- const CL = require('../core/changelog')
17
- const M = require('../core/manifest')
18
- const SC = require('../core/scan')
19
- const OB = require('../core/onboarding')
20
- const C = require('../config/validate')
21
- const T = require('../flows/registry')
22
- const AG = require('../agents/catalog')
23
- const EV = require('../agents/evaluations')
24
8
  const { FLAGS, parse } = require('./args')
25
- const { fail, opsRoot } = require('./io')
9
+ const { fail } = require('./io')
26
10
  const IN = require('./instance')
27
11
  const PL = require('./planning')
28
12
  const CAT = require('./catalog')
@@ -170,7 +154,7 @@ function usage() {
170
154
  ops automation doctor <ops-root> claude|codex|gemini|antigravity
171
155
  ops automation install <ops-root> claude|codex|gemini|antigravity
172
156
  ops automation uninstall <ops-root> claude|codex|gemini|antigravity
173
- ops learn <agent|flow> [--flow] [--proposal [--period <AAAA-MM>]] [--applied [--period <AAAA-MM>]]
157
+ ops learn <agent|flow> [--flow] [--proposal [--period <AAAA-MM>]] [--applied|--archived [--period <AAAA-MM>]]
174
158
  ops evaluate <agent|flow> [--flow] [--cases [--json]] [--bench [caso]] [--record [AAAA-MM-DD]]
175
159
  ops agents list [ops-root] [--own|--system] [--json]
176
160
  ops agents fork <cargo> [ops-root]
@@ -45,10 +45,15 @@ function validateWorkspaces(workspaces, errors) {
45
45
  continue
46
46
  }
47
47
  for (const key of Object.keys(workspace)) {
48
- if (!['name', 'path'].includes(key)) {
48
+ if (!['name', 'path', 'verify'].includes(key)) {
49
49
  errors.push(`ops.config.json: workspaceRoots[${index}].${key} no está permitido`)
50
50
  }
51
51
  }
52
+ // Opcional: la raíz que no lo declara deja que quien verifica descubra la puerta, como siempre.
53
+ // Declararlo vacío es peor que no declararlo —promete una puerta y no la da—, así que se rechaza.
54
+ if ('verify' in workspace && (typeof workspace.verify !== 'string' || !workspace.verify.trim())) {
55
+ errors.push(`ops.config.json: workspaceRoots[${index}].verify debe ser el comando, o no estar`)
56
+ }
52
57
  if (typeof workspace.name !== 'string' || !workspace.name.trim()) {
53
58
  errors.push(`ops.config.json: workspaceRoots[${index}].name es obligatorio`)
54
59
  }
@@ -78,4 +83,4 @@ function validateRunner(runner, errors) {
78
83
  }
79
84
  }
80
85
 
81
- module.exports = { MODES, validateOpsConfig }
86
+ module.exports = { validateOpsConfig }
@@ -120,8 +120,5 @@ module.exports = {
120
120
  missingSections,
121
121
  orphanCredentials,
122
122
  guide,
123
- OPENING,
124
- DIMENSIONS,
125
- FOLLOW_UPS,
126
123
  PLACEHOLDERS,
127
124
  }
@@ -218,4 +218,4 @@ module.exports = {
218
218
  workspaceRoots,
219
219
  candidates,
220
220
  inventory,
221
- commandsLine, scan, services, expectedEnv, IGNORED, DEPTH, ENV_MAX }
221
+ commandsLine, scan, services }
@@ -124,6 +124,6 @@ function findOpsRoot(start) {
124
124
  }
125
125
 
126
126
  module.exports = {
127
- readInput, commandOf, fileOf, patchOf, filesOf, contentOf, cwdOf, block, configOf,
127
+ readInput, commandOf, patchOf, filesOf, contentOf, cwdOf, block, configOf,
128
128
  gitDirectory, isCommit, stagedFiles, pushAllowed, findOpsRoot,
129
129
  }
@@ -79,4 +79,4 @@ function validate(root, provider, workspaces = []) {
79
79
  return errors
80
80
  }
81
81
 
82
- module.exports = { STATES, TYPES, read, validate }
82
+ module.exports = { read, validate }
@@ -161,4 +161,4 @@ async function fetchItems(config, options = {}) {
161
161
  return issues.map((issue) => normalizeIssue(issue, config))
162
162
  }
163
163
 
164
- module.exports = { adfToMarkdown, deriveAcceptance, fetchItems, normalizeFixture, normalizeIssue, validateConfig }
164
+ module.exports = { fetchItems, normalizeFixture, validateConfig }
@@ -397,7 +397,6 @@ function providerState(root, name) {
397
397
 
398
398
  module.exports = {
399
399
  providerState,
400
- STATES,
401
400
  adapter,
402
401
  frontmatter,
403
402
  promote,
@@ -53,4 +53,4 @@ function validate(root) {
53
53
  return errors
54
54
  }
55
55
 
56
- module.exports = { markdownFiles, validate }
56
+ module.exports = { validate }
@@ -297,6 +297,14 @@ function validateState({ epics, milestones, done, wip, roles = new Set(), humanA
297
297
  for (const milestone of milestones) {
298
298
  if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(milestone.slug)) errors.push(`hito con slug inválido: ${milestone.slug}`)
299
299
  if (milestoneSlugs.has(milestone.slug)) errors.push(`hito duplicado: ${milestone.slug}`)
300
+ // La misma puerta que la épica y la tarea, en el nivel que no la tenía. Un hito agrupa trabajo bajo
301
+ // un nombre, y abrirlo con el nombre puesto para después es el camino natural: nadie promueve una
302
+ // tarea sin aceptación, y en cambio el título del hito se decide al final, cuando ya se construyó
303
+ // debajo. El marcador es lo único que se puede juzgar sin leer — un título vago sigue pasando, y
304
+ // eso es deliberado: acá también un heurístico sobre prosa se equivocaría en los dos sentidos.
305
+ if (PLACEHOLDERS.test(milestone.title)) {
306
+ errors.push(`hito ${milestone.slug}: el título no está decidido — "${milestone.title}"`)
307
+ }
300
308
  milestoneSlugs.add(milestone.slug)
301
309
  for (const task of milestone.tasks) {
302
310
  if (!task.service) errors.push(`BACKLOG ${task.slug}: falta (service: <ruta>)`)
@@ -406,7 +414,6 @@ function oversizedUnits({ epics = [], milestones = [] }) {
406
414
  }
407
415
 
408
416
  module.exports = {
409
- testedCriteria,
410
417
  validateState,
411
418
  oversizedUnits,
412
419
  validateAdr,
@@ -153,6 +153,12 @@ function readCast(rest) {
153
153
  }
154
154
  }
155
155
 
156
+ // El texto de la aceptación, delimitado por las cursivas que lo envuelven. El cierre no es «el
157
+ // próximo guión bajo»: un identificador como `MAX_ATTEMPTS` trae los suyos, y cortar en el primero
158
+ // devolvía `MAX` con `check` en verde, que es la forma cara del error —la tarea se lee completa y no
159
+ // lo está—. Cierra el `_` que markdown cerraría: el que no está entre caracteres de palabra.
160
+ const ACCEPTANCE = /_Aceptaci[oó]n:\s*(.*?\S)_(?![A-Za-z0-9])/i
161
+
156
162
  function readBacklog(dir) {
157
163
  const text = withoutComments(read(path.join(dir, 'BACKLOG.md')))
158
164
  const milestones = []
@@ -175,7 +181,7 @@ function readBacklog(dir) {
175
181
  slug: task[1].trim(), tier: task[2] || '', cast: readCast(rest),
176
182
  epic: ((rest.match(/\(epic:\s*(\d{3})\)/) || [])[1] || ''),
177
183
  service: ((rest.match(/\(service:\s*([^)]+)\)/) || [])[1] || '').trim(),
178
- acceptance: ((rest.match(/_Aceptaci[oó]n:\s*([^_]+)_/i) || [])[1] || '').trim(),
184
+ acceptance: ((rest.match(ACCEPTANCE) || [])[1] || '').trim(),
179
185
  criteria: criteriaRefs(rest),
180
186
  noSplit: noSplitReason(rest),
181
187
  })
@@ -2,33 +2,80 @@
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", "workspaceRoots", "runner"],
5
+ "required": [
6
+ "project",
7
+ "mode",
8
+ "workspaceRoots",
9
+ "runner"
10
+ ],
6
11
  "properties": {
7
- "$schema": { "type": "string", "minLength": 1 },
8
- "cauceVersion": { "type": "string", "minLength": 1 },
9
- "project": { "type": "string", "minLength": 1 },
10
- "mode": { "enum": ["embedded", "sidecar", "toolkit"] },
12
+ "$schema": {
13
+ "type": "string",
14
+ "minLength": 1
15
+ },
16
+ "cauceVersion": {
17
+ "type": "string",
18
+ "minLength": 1
19
+ },
20
+ "project": {
21
+ "type": "string",
22
+ "minLength": 1
23
+ },
24
+ "mode": {
25
+ "enum": [
26
+ "embedded",
27
+ "sidecar",
28
+ "toolkit"
29
+ ]
30
+ },
11
31
  "workspaceRoots": {
12
32
  "type": "array",
13
33
  "minItems": 1,
14
34
  "items": {
15
35
  "type": "object",
16
- "required": ["name", "path"],
36
+ "required": [
37
+ "name",
38
+ "path"
39
+ ],
17
40
  "properties": {
18
- "name": { "type": "string", "minLength": 1 },
19
- "path": { "type": "string", "minLength": 1 }
41
+ "name": {
42
+ "type": "string",
43
+ "minLength": 1
44
+ },
45
+ "path": {
46
+ "type": "string",
47
+ "minLength": 1
48
+ },
49
+ "verify": {
50
+ "type": "string",
51
+ "description": "Comando que corre la puerta de esta raíz —pruebas, lint, typecheck, build—, tal como se invoca desde ella. Sin él, quien verifica tiene que descubrirlo leyendo el repositorio en cada tarea, y eso es trabajo de modelo repetido para siempre sobre una respuesta que no cambia."
52
+ }
20
53
  },
21
54
  "additionalProperties": false
22
55
  }
23
56
  },
24
57
  "runner": {
25
58
  "type": "object",
26
- "required": ["maxTaskHours", "humanCheckpointBetweenMilestones", "commitPerTask", "allowPush"],
59
+ "required": [
60
+ "maxTaskHours",
61
+ "humanCheckpointBetweenMilestones",
62
+ "commitPerTask",
63
+ "allowPush"
64
+ ],
27
65
  "properties": {
28
- "maxTaskHours": { "type": "number", "exclusiveMinimum": 0 },
29
- "humanCheckpointBetweenMilestones": { "type": "boolean" },
30
- "commitPerTask": { "type": "boolean" },
31
- "allowPush": { "type": "boolean" }
66
+ "maxTaskHours": {
67
+ "type": "number",
68
+ "exclusiveMinimum": 0
69
+ },
70
+ "humanCheckpointBetweenMilestones": {
71
+ "type": "boolean"
72
+ },
73
+ "commitPerTask": {
74
+ "type": "boolean"
75
+ },
76
+ "allowPush": {
77
+ "type": "boolean"
78
+ }
32
79
  },
33
80
  "additionalProperties": false
34
81
  }
@@ -60,7 +60,7 @@
60
60
  "No se atribuye responsabilidad a personas; se analizan condiciones, no culpables.",
61
61
  "Una causa sin evidencia se declara como hipótesis, aunque cerrar el informe sea más cómodo.",
62
62
  "Ninguna comunicación a clientes ni notificación regulatoria sale de este recorrido: se propone y la decide una persona.",
63
- "Los seguimientos quedan en el INBOX sin promover; convertirlos en trabajo es una decisión humana."
63
+ "Los seguimientos quedan en el INBOX sin promover y cada uno dice si previene la repetición o sólo acelera la detección; convertirlos en trabajo es una decisión humana, y esa distinción es lo único que permite ordenarlos."
64
64
  ],
65
65
  "completion": [
66
66
  "La línea de tiempo está sostenida por registros, no por reconstrucción de memoria.",
@@ -4,3 +4,4 @@ Registrar únicamente cambios aprobados por una persona, con fecha, la corrida q
4
4
 
5
5
  | Fecha | Propuesta | Decisión | Aprobó | Cambio aplicado |
6
6
  |---|---|---|---|---|
7
+ | 2026-08-30 | `2026-08.md` | aplicada | Manuel Pinzon | Un guardrail, y sólo su texto: cada seguimiento dice si previene la repetición o sólo acelera la detección. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingeniomaps/cauce",
3
- "version": "0.53.1",
3
+ "version": "0.54.0",
4
4
  "description": "Sistema portable de planificación y ejecución verificable para cualquier proyecto",
5
5
  "keywords": [
6
6
  "planning",
@@ -33,8 +33,9 @@
33
33
  "test": "bash test/tools/hooks-smoke.sh && node --test \"test/**/*.test.js\"",
34
34
  "coverage": "bash test/tools/coverage.sh",
35
35
  "coverage:update": "bash test/tools/coverage.sh --update",
36
- "dead-imports": "node test/tools/dead-imports.js",
37
- "ci": "npm run check && npm run automation:check && npm run integration:check && npm run coverage",
36
+ "dead-code": "node test/tools/dead-code.js",
37
+ "dead-code:engine": "node test/tools/dead-code.js --engine",
38
+ "ci": "npm run check && npm run automation:check && npm run integration:check && npm run dead-code:engine && npm run coverage",
38
39
  "prepublishOnly": "npm run ci"
39
40
  },
40
41
  "engines": {
@@ -28,6 +28,25 @@ deja el pedido sin resolver: es la mitad barata del trabajo.
28
28
  - Nombrar lo que falta no reemplaza a entregar lo que se puede: lo que sí se pudo establecer se escribe
29
29
  igual, aunque quede parcial y marcado como tal.
30
30
 
31
+ El primer punto tiene un borde que se cruza sin notarlo. Faltar contexto es no saber **cómo**: qué
32
+ formato, qué borde, qué valor. Eso se supone y se entrega marcado, porque suponerlo mal cuesta una
33
+ corrección. No saber **qué se quiere ni para qué** es otra cosa, y ahí el borrador deja de ser barato:
34
+ todo lo que se construya encima hereda la suposición, y quien lo reciba no tiene cómo ver que el
35
+ objetivo era supuesto. El para qué tampoco es adorno — es lo que permite reconocer una respuesta
36
+ correcta, y sin él se cumple la aceptación al pie y no sirve.
37
+
38
+ Lo que separa los dos casos es si la respuesta existe en algún lado. Si está escrita —en la aceptación,
39
+ en el criterio que la unidad cita, en el contexto de la épica, en el código— entonces la unidad se
40
+ entiende y lo que falta es leerla: eso lo hace quien ejecuta y no interrumpe a nadie. Si contestarla
41
+ exigiera inventarla, no hay nada que leer y es una decisión que el cargo no tiene: se escala con la
42
+ pregunta exacta y con qué se desbloquea al contestarla. Es el mismo criterio con que R6 reparte el
43
+ hallazgo que aparece a mitad de camino —quién puede resolverlo, no cuán grave parece—, aplicado antes
44
+ de empezar en vez de durante.
45
+
46
+ Aclarar la redacción no es ampliar el alcance, y partir tampoco: una unidad que no se entiende porque
47
+ son dos resultados con vidas distintas se entiende partida, y eso no pide ninguna autoridad que el
48
+ cargo no tenga (R17). La pide elegir el objetivo, que es lo único que no se puede suponer.
49
+
31
50
  Esto no afloja ningún límite: no promover, no prometer fechas, no inventar evidencia y no exceder la
32
51
  autoridad del cargo siguen siendo absolutos. Lo que se cierra es la salida de cumplirlos sin entregar.
33
52
 
@@ -4,7 +4,7 @@
4
4
  // Punto de entrada estable del proyecto: nadie —ni una persona ni un agente— necesita saber de
5
5
  // dónde sale el motor. Viene de la dependencia npm, que el lockfile versiona.
6
6
  //
7
- // Nada de `require`, `__dirname` ni `import`: el shim se instala dentro del proyecto y hereda el
7
+ // Nada de `require`, `__dirname` ni un `import` estático: el shim se instala en el proyecto y hereda el
8
8
  // `type` de su `package.json`, así que el mismo archivo se carga como CommonJS en un repo y como
9
9
  // ESM en el de al lado. `import()` dinámico y `process.argv[1]` son las dos únicas formas que
10
10
  // existen bajo los dos cargadores; cualquier otra revienta en la mitad de los proyectos —`require
@@ -16,7 +16,7 @@ const root = self.slice(0, self.lastIndexOf('/', self.lastIndexOf('/') - 1)) ||
16
16
 
17
17
  // El shim sabe dónde vive; quien lo invoca, no. En modo sidecar se lo llama desde la carpeta de la
18
18
  // compañía —`node <empresa>-ops/tools/ops.js …`— y sin esto cada comando resolvería su raíz contra
19
- // el cwd: `agents list` y `team list` devolvían vacío en vez de fallar.
19
+ // el cwd: `agents list` y `flow list` devolvían vacío en vez de fallar.
20
20
  process.env.OPS_ROOT = process.env.OPS_ROOT || root
21
21
 
22
22
  // El especificador se resuelve contra este archivo, así que sube a `<raíz>/node_modules` igual que