@ingeniomaps/cauce 0.67.0 → 0.68.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 CHANGED
@@ -14,6 +14,36 @@ 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.68.0] - 2026-09-07
18
+
19
+ ### Cambiado
20
+
21
+ - **`upgrade` deja de borrar una ruta retirada cuyo contenido no puede probar suyo.** Retirar una ruta
22
+ nunca volvió al toolkit dueño de lo que hay adentro, y hasta acá se borraba el directorio entero: quien
23
+ tenía sus propios workflows en `automatization/workflows` los perdía sin confirmación y sin vuelta
24
+ atrás. De las seis rutas retiradas, cuatro viven bajo `system/` o son un archivo con nombre del
25
+ toolkit y se siguen retirando igual; las dos que un proyecto también usa para lo suyo
26
+ —`automatization/runners` y `automatization/workflows`— se conservan.
27
+
28
+ **Lo que te pide algo**: esas dos rutas quedan en disco con lo que tengas adentro, la corrida te dice
29
+ cuántos archivos son, y `check` las cuenta en cada corrida hasta que las muevas o las borres. Si lo
30
+ que tenés ahí son restos viejos del toolkit y querés limpiarlos, `--force` las retira.
31
+
32
+ - **La regla R9 dice cómo se prueba una quita.** Una prueba que comprueba que aparece lo nuevo no
33
+ comprueba que desapareció lo viejo, y lo que se quita tiene dependientes que no se anuncian —el
34
+ mensaje que afirmaba la invariante, la condición que la deducía—. Sale de una regresión de 0.67.0 que
35
+ entró exactamente por ahí.
36
+
37
+ ### Corregido
38
+
39
+ - **El informe de `upgrade` afirmaba descartes que no ocurrieron.** 0.67.0 pasó a conservar los archivos
40
+ editados y la salida siguió enumerándolos como `− descartado tu cambio en …`, uno por uno, después de
41
+ la línea que anuncia que terminó bien. En una instancia real fueron diecinueve renglones falsos, y
42
+ entre ellos iba la única línea destructiva verdadera de esa corrida, indistinguible. Ahora el informe
43
+ recibe qué pasó —descartado, conservado, pendiente— en vez de deducirlo de una condición que dejó de
44
+ valer, y la línea «planning, organization y todo lo propio quedaron intactos» sale justo cuando es
45
+ cierto, que es cuando se conservó algo.
46
+
17
47
  ## [0.67.0] - 2026-09-07
18
48
 
19
49
  ### Agregado
@@ -370,10 +370,19 @@ function upgrade(dir, cli) {
370
370
 
371
371
  // Retirar lo que el toolkit ya no distribuye, después de haber actualizado lo que sí.
372
372
  const retired = []
373
+ const pendientes = []
373
374
  for (const relative of O.RETIRED) {
374
375
  const target = path.join(root, relative)
375
376
  if (!fs.existsSync(target)) continue
376
377
  F.assertNoSymlinkPath(root, target)
378
+ // Retirar una ruta no vuelve al toolkit dueño de lo que hay adentro. En las dos que un proyecto
379
+ // también usa para lo suyo, borrar el directorio entero se llevaba puesto contenido que nadie
380
+ // había entregado —un `autobuild.js` propio, los workflows de una empresa— sin confirmación y sin
381
+ // vuelta atrás. Se conserva y se nombra; `--force` es la salida, igual que para una edición local.
382
+ const contenido = O.RETIRED_COMPARTIDO.includes(relative) && fs.statSync(target).isDirectory()
383
+ ? O.treeFiles(target)
384
+ : []
385
+ if (contenido.length && !force) { pendientes.push({ relative, files: contenido }); continue }
377
386
  fs.rmSync(target, { recursive: true, force: true })
378
387
  retired.push(relative)
379
388
  }
@@ -404,7 +413,13 @@ function upgrade(dir, cli) {
404
413
  // Acá es donde las tres versiones se saben a la vez, así que es donde pueden quedar diciendo lo mismo.
405
414
  const pinned = pinEngine(root, to)
406
415
 
407
- reportUpgrade({ root, from, to, system, changed, retired, added, overrides, pinned, droppedBlocks })
416
+ // El informe recibe qué pasó y no una condición de la que deducirlo: `changed` es «lo que estaba
417
+ // editado», y sin `--force` eso se conserva. Deducirlo hizo que 0.67.0 afirmara diecinueve descartes
418
+ // que no ocurrieron (caso 048).
419
+ reportUpgrade({
420
+ root, from, to, system, retired, added, overrides, pinned, droppedBlocks,
421
+ descartados: force ? changed : [], conservados: [...conservados], pendientes,
422
+ })
408
423
  }
409
424
 
410
425
  module.exports = { copyTemplate, scaffold, providerNames, upgrade, destroy, PROJECT_ROOT }
@@ -144,6 +144,15 @@ function check(dir, cli) {
144
144
  + '`upgrade` los conserva y no les trae mejoras')
145
145
  }
146
146
 
147
+ // Y lo que `upgrade` no retiró porque no pudo demostrar que fuera suyo: queda ahí, sin colgar de
148
+ // ningún mecanismo, hasta que alguien lo mueva o lo borre. Se cuenta por lo mismo que los congelados
149
+ // — un resto que no se ve se vuelve permanente.
150
+ const restos = O.RETIRED_COMPARTIDO.filter((relative) => fs.existsSync(path.join(root, '..', relative)))
151
+ if (restos.length) {
152
+ warnings.push(`${restos.length} ruta(s) retiradas siguen en disco con contenido tuyo `
153
+ + `(${restos.join(', ')}); Cauce ya no las distribuye ni las toca`)
154
+ }
155
+
147
156
  const integration = I.validate(path.resolve(root, '..'))
148
157
  errors.push(...integration.errors)
149
158
  warnings.push(...integration.warnings)
@@ -72,12 +72,23 @@ function adviceFor(changed) {
72
72
  // propias, agentes editados— queda intacto por construcción, no por comparación.
73
73
  // Qué le pasó a la instancia en esta actualización, contado a quien la corrió. Recibe el resultado
74
74
  // entero en vez de recalcular nada: lo que se informa es exactamente lo que ocurrió.
75
- function reportUpgrade({ root, from, to, system, changed, retired, added, overrides, pinned, droppedBlocks }) {
75
+ function reportUpgrade({
76
+ root, from, to, system, retired, added, overrides, pinned, droppedBlocks,
77
+ descartados, conservados, pendientes,
78
+ }) {
76
79
  console.log(`✓ Cauce ${from || '(previa)'} → ${to}`)
77
80
  // Descartar con --force es legítimo; hacerlo sin dejar rastro no. Queda en la salida del comando,
78
- // que es la evidencia que el protocolo pide para cualquier cambio.
79
- for (const file of changed) console.log(`− descartado tu cambio en ${file}`)
81
+ // que es la evidencia que el protocolo pide para cualquier cambio. Y lo que se conservó no se vuelve
82
+ // a enumerar acá: ya salió con su consejo antes de escribir nada, y repetirlo con el glifo del
83
+ // descarte es lo que volvía ilegible el bloque.
84
+ for (const file of descartados) console.log(`− descartado tu cambio en ${file}`)
85
+ if (conservados.length) console.log(`= ${conservados.length} archivo(s) conservados por tu edición`)
80
86
  for (const relative of retired) console.log(`− retirado ${relative}: Cauce ya no lo distribuye`)
87
+ // Sin glifo de acción porque no hubo ninguna: la ruta sigue ahí y el contenido también.
88
+ for (const { relative, files } of pendientes) {
89
+ console.log(` ${relative}: ${files.length} archivo(s) que Cauce no entregó; la ruta se retiró y `
90
+ + 'el contenido queda. Movelo adonde lo quieras y borrala, o repetí con --force.')
91
+ }
81
92
  // Nombrarlos importa tanto como crearlos: existen para que los completes, y uno que aparece sin
82
93
  // aviso no lo completa nadie.
83
94
  for (const relative of added) console.log(`+ ${relative}: lo agrega esta versión, completalo`)
@@ -90,9 +101,9 @@ function reportUpgrade({ root, from, to, system, changed, retired, added, overri
90
101
  for (const override of overrides) {
91
102
  console.log(`= conservado ${override.collection}/${override.project}: sobrescribe ${override.system}`)
92
103
  }
93
- // Sólo cuando es cierto: llegar acá con algo en `changed` es haber descartado contenido de la
94
- // empresa con --force, que las líneas de arriba enumeran.
95
- if (!changed.length) console.log(' planning, organization y todo lo propio quedaron intactos')
104
+ // Sólo cuando es cierto, y ahora lo decide lo que pasó y no una condición: se dice justo cuando no
105
+ // se descartó nada, que incluye la corrida que conservó veinte archivos.
106
+ if (!descartados.length) console.log(' planning, organization y todo lo propio quedaron intactos')
96
107
  // No se borra: sin la dependencia declarada, quitarle `.ops/` la dejaría sin motor. Se avisa y
97
108
  // decide una persona.
98
109
  if (fs.existsSync(path.join(root, '.ops', 'engine'))) {
@@ -231,6 +231,14 @@ const RETIRED = [
231
231
 
232
232
  // Aprendizaje que quedó dentro de una ruta retirada. Es lo único ahí que no se puede reponer, así
233
233
  // que se detecta antes de borrar nada: perderlo en silencio sería peor que dejar el directorio.
234
+ // De las rutas retiradas, las que un proyecto también usa para lo suyo. El resto de la lista vive bajo
235
+ // `system/` o es un archivo con nombre propio del toolkit, y ahí nadie más escribe; éstas dos se llaman
236
+ // como el concepto general, así que quien adoptó Cauce cuando se distribuían tiene los suyos justo ahí.
237
+ //
238
+ // El manifiesto no las puede desempatar: `trackedPaths()` nunca las registró, así que para el toolkit
239
+ // todo su contenido es igual de ajeno. Sin poder demostrar que lo entregó, no lo borra.
240
+ const RETIRED_COMPARTIDO = ['automatization/runners', 'automatization/workflows']
241
+
234
242
  function retiredWithLearning(root) {
235
243
  const found = []
236
244
  for (const relative of RETIRED) {
@@ -294,6 +302,7 @@ function localChanges(root) {
294
302
 
295
303
  module.exports = {
296
304
  RETIRED,
305
+ RETIRED_COMPARTIDO,
297
306
  TEMPLATE_OWN,
298
307
  TEMPLATE_PREFIXES,
299
308
  addedPaths,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingeniomaps/cauce",
3
- "version": "0.67.0",
3
+ "version": "0.68.0",
4
4
  "description": "Sistema portable de planificación y ejecución verificable para cualquier proyecto",
5
5
  "keywords": [
6
6
  "planning",
@@ -31,6 +31,18 @@ y la cobertura no lo va a decir: mide qué líneas se ejecutan, no qué defectos
31
31
  La precondición del caso también cuenta. Si el estado en que arranca no puede ocurrir por el camino de
32
32
  producción, lo que prueba tampoco: queda verde para siempre sobre algo que nadie va a vivir.
33
33
 
34
+ **Y quitar un comportamiento se prueba al revés que agregarlo.** Una prueba que comprueba que aparece lo
35
+ nuevo no comprueba que desapareció lo viejo: los dos pueden convivir, y ahí el verde dice que la mitad
36
+ del cambio ocurrió. La aserción que hace falta es de ausencia —que la salida vieja ya no esté, que la
37
+ rama vieja ya no corra—, y es la que no se escribe sola porque nadie la extraña.
38
+
39
+ Lo que se quita, además, tiene dependientes, y no se anuncian. Una invariante que deja de valer se lleva
40
+ puesto a quien la daba por cierta: el mensaje que la afirmaba, la condición que la deducía, el comentario
41
+ que la explicaba. Suelen vivir en otro archivo, que es donde una premisa vieja se pudre sin que nada
42
+ falle. Antes de entregar una quita se busca quién dependía de ella —qué la afirmaba, qué la deducía— y
43
+ cada uno se corrige o se declara. Recorrer la enumeración de la tarea no encuentra esto: la enumeración
44
+ dice qué había que hacer, no qué se apoyaba en lo que había.
45
+
34
46
  ## R10 — Publicación humana por defecto
35
47
 
36
48
  Push, PR, merge, tags, deploy y rollback requieren la autorización configurada para el proyecto.