@imolko/ultra-agent 0.1.0-beta

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 (239) hide show
  1. package/README.md +93 -0
  2. package/bin/cli.js +2 -0
  3. package/dist-node/bin.d.ts +2 -0
  4. package/dist-node/bin.d.ts.map +1 -0
  5. package/dist-node/bin.js +5 -0
  6. package/dist-node/bin.js.map +1 -0
  7. package/dist-node/cli.d.ts +41 -0
  8. package/dist-node/cli.d.ts.map +1 -0
  9. package/dist-node/cli.js +170 -0
  10. package/dist-node/cli.js.map +1 -0
  11. package/dist-node/index.d.ts +14 -0
  12. package/dist-node/index.d.ts.map +1 -0
  13. package/dist-node/index.js +40 -0
  14. package/dist-node/index.js.map +1 -0
  15. package/dist-node/init-lint.d.ts +43 -0
  16. package/dist-node/init-lint.d.ts.map +1 -0
  17. package/dist-node/init-lint.js +84 -0
  18. package/dist-node/init-lint.js.map +1 -0
  19. package/dist-node/manifest.d.ts +33 -0
  20. package/dist-node/manifest.d.ts.map +1 -0
  21. package/dist-node/manifest.js +59 -0
  22. package/dist-node/manifest.js.map +1 -0
  23. package/dist-node/materializer.d.ts +52 -0
  24. package/dist-node/materializer.d.ts.map +1 -0
  25. package/dist-node/materializer.js +194 -0
  26. package/dist-node/materializer.js.map +1 -0
  27. package/dist-node/package-root.d.ts +5 -0
  28. package/dist-node/package-root.d.ts.map +1 -0
  29. package/dist-node/package-root.js +17 -0
  30. package/dist-node/package-root.js.map +1 -0
  31. package/dist-node/payload.d.ts +22 -0
  32. package/dist-node/payload.d.ts.map +1 -0
  33. package/dist-node/payload.js +49 -0
  34. package/dist-node/payload.js.map +1 -0
  35. package/dist-node/pointer-hub.d.ts +22 -0
  36. package/dist-node/pointer-hub.d.ts.map +1 -0
  37. package/dist-node/pointer-hub.js +50 -0
  38. package/dist-node/pointer-hub.js.map +1 -0
  39. package/dist-node/publication.cli.d.ts +9 -0
  40. package/dist-node/publication.cli.d.ts.map +1 -0
  41. package/dist-node/publication.cli.js +17 -0
  42. package/dist-node/publication.cli.js.map +1 -0
  43. package/dist-node/publication.d.ts +23 -0
  44. package/dist-node/publication.d.ts.map +1 -0
  45. package/dist-node/publication.js +47 -0
  46. package/dist-node/publication.js.map +1 -0
  47. package/dist-node/reconcile.cli.d.ts +11 -0
  48. package/dist-node/reconcile.cli.d.ts.map +1 -0
  49. package/dist-node/reconcile.cli.js +39 -0
  50. package/dist-node/reconcile.cli.js.map +1 -0
  51. package/dist-node/reconcile.d.ts +30 -0
  52. package/dist-node/reconcile.d.ts.map +1 -0
  53. package/dist-node/reconcile.js +51 -0
  54. package/dist-node/reconcile.js.map +1 -0
  55. package/dist-node/ship/prompts/fix.md +22 -0
  56. package/dist-node/ship/prompts/implement.md +34 -0
  57. package/dist-node/ship/prompts/review.md +28 -0
  58. package/dist-node/ship/ship.agent.d.ts +22 -0
  59. package/dist-node/ship/ship.agent.d.ts.map +1 -0
  60. package/dist-node/ship/ship.agent.js +142 -0
  61. package/dist-node/ship/ship.agent.js.map +1 -0
  62. package/dist-node/ship/ship.args.d.ts +15 -0
  63. package/dist-node/ship/ship.args.d.ts.map +1 -0
  64. package/dist-node/ship/ship.args.js +93 -0
  65. package/dist-node/ship/ship.args.js.map +1 -0
  66. package/dist-node/ship/ship.context.d.ts +12 -0
  67. package/dist-node/ship/ship.context.d.ts.map +1 -0
  68. package/dist-node/ship/ship.context.js +3 -0
  69. package/dist-node/ship/ship.context.js.map +1 -0
  70. package/dist-node/ship/ship.d.ts +4 -0
  71. package/dist-node/ship/ship.d.ts.map +1 -0
  72. package/dist-node/ship/ship.js +221 -0
  73. package/dist-node/ship/ship.js.map +1 -0
  74. package/dist-node/ship/ship.mr.d.ts +9 -0
  75. package/dist-node/ship/ship.mr.d.ts.map +1 -0
  76. package/dist-node/ship/ship.mr.js +171 -0
  77. package/dist-node/ship/ship.mr.js.map +1 -0
  78. package/dist-node/ship/ship.output.d.ts +9 -0
  79. package/dist-node/ship/ship.output.d.ts.map +1 -0
  80. package/dist-node/ship/ship.output.js +21 -0
  81. package/dist-node/ship/ship.output.js.map +1 -0
  82. package/dist-node/ship/ship.tracker.d.ts +37 -0
  83. package/dist-node/ship/ship.tracker.d.ts.map +1 -0
  84. package/dist-node/ship/ship.tracker.js +220 -0
  85. package/dist-node/ship/ship.tracker.js.map +1 -0
  86. package/dist-node/version.cli.d.ts +9 -0
  87. package/dist-node/version.cli.d.ts.map +1 -0
  88. package/dist-node/version.cli.js +30 -0
  89. package/dist-node/version.cli.js.map +1 -0
  90. package/dist-node/version.d.ts +24 -0
  91. package/dist-node/version.d.ts.map +1 -0
  92. package/dist-node/version.js +76 -0
  93. package/dist-node/version.js.map +1 -0
  94. package/docs/adr/ADR-0000-proceso-y-formato-de-adrs.md +115 -0
  95. package/docs/adr/foundational/A-001-clean-architecture-4-capas.md +88 -0
  96. package/docs/adr/foundational/A-002-cqrs-semantico.md +58 -0
  97. package/docs/adr/foundational/A-003-tdd.md +97 -0
  98. package/docs/adr/foundational/A-005-either-return-custom-methods.md +80 -0
  99. package/docs/adr/foundational/A-006-feature-completion-criteria.md +47 -0
  100. package/docs/adr/foundational/A-007-data-contract-fail-fast.md +109 -0
  101. package/docs/adr/foundational/A-008-bounded-context-decomposition.md +130 -0
  102. package/docs/adr/foundational/A-009-use-case-taxonomy.md +99 -0
  103. package/docs/adr/foundational/A-010-propiedad-emision-eventos-dominio.md +95 -0
  104. package/docs/adr/foundational/A-011-characterization-first-refactoring.md +90 -0
  105. package/docs/adr/foundational/A-012-helm-mecanismo-primario-despliegue.md +67 -0
  106. package/docs/adr/foundational/A-013-contrato-settings-unica-fuente-configuracion.md +74 -0
  107. package/docs/adr/foundational/A-014-generacion-artefactos-despliegue-desde-contrato-settings.md +75 -0
  108. package/docs/adr/foundational/A-015-cloudevents-estandar-eventos.md +85 -0
  109. package/docs/adr/foundational/A-016-cicd-gitlab-pipeline-raiz-pipelines-modulares.md +92 -0
  110. package/docs/adr/foundational/A-017-taxonomia-repositorios-librerias-sistemas.md +93 -0
  111. package/docs/adr/foundational/A-018-practicas-build-imagenes-docker.md +85 -0
  112. package/docs/adr/foundational/A-019-convenciones-autoria-helm-charts.md +97 -0
  113. package/docs/adr/foundational/A-020-entorno-desarrollo-estandarizado-devcontainer.md +58 -0
  114. package/docs/adr/foundational/A-022-formato-reporte-tests-ctrf.md +55 -0
  115. package/docs/adr/foundational/A-023-composicion-bloques-prompt-agentes.md +65 -0
  116. package/docs/adr/foundational/A-024-features-slices-verticales-portables.md +41 -0
  117. package/docs/adr/foundational/A-025-anatomia-mecanica-feature-puertos-adaptadores-drivers.md +104 -0
  118. package/docs/adr/foundational/A-026-infraestructura-compartida.md +44 -0
  119. package/docs/adr/foundational/A-027-patron-wiring-entry-point.md +67 -0
  120. package/docs/adr/foundational/A-029-verbos-intencion-metodos-lado-negocio.md +54 -0
  121. package/docs/adr/foundational/A-030-global-development-tooling.md +52 -0
  122. package/docs/adr/foundational/A-031-ubiquitous-language.md +64 -0
  123. package/docs/adr/foundational/A-032-domain-artifact-documentation-format.md +128 -0
  124. package/docs/adr/foundational/A-033-estandar-mensajes-commit.md +127 -0
  125. package/docs/adr/foundational/A-034-canonical-skill-set.md +64 -0
  126. package/docs/adr/foundational/A-035-captura-ideas-reanclaje-candies.md +51 -0
  127. package/docs/adr/foundational/A-036-adopcion-wayfinder-ortogonalidad-labels.md +37 -0
  128. package/docs/adr/foundational/A-037-formalizacion-taxonomia-labels.md +98 -0
  129. package/docs/adr/foundational/A-038-issues-referencian-skills-nombre.md +54 -0
  130. package/docs/adr/foundational/A-039-pipeline-ship-issues-hijos-spec.md +64 -0
  131. package/docs/adr/foundational/A-040-punteros-configuracion-repo-skills.md +44 -0
  132. package/docs/adr/foundational/A-041-estrategia-de-ramas.md +45 -0
  133. package/docs/adr/foundational/A-042-formato-documentos-issue-tracker.md +78 -0
  134. package/docs/adr/foundational/A-043-vocabulario-etiquetas-adrs.md +42 -0
  135. package/docs/adr/foundational/A-044-composicion-funcional-procesos-operaciones.md +44 -0
  136. package/docs/adr/foundational/A-045-guardrails-aplicables-no-directrices.md +48 -0
  137. package/docs/adr/foundational/A-046-metricas-de-forma-y-legibilidad-del-codigo.md +50 -0
  138. package/docs/adr/foundational/A-047-dependencias-explicitas-sin-globales-ambientales.md +40 -0
  139. package/docs/adr/foundational/A-048-cobertura-minima-codigo.md +39 -0
  140. package/docs/adr/foundational/A-049-materializacion-bucle-guardrails-extension-nativa-pi.md +49 -0
  141. package/docs/adr/foundational/A-050-el-caso-de-uso-pide-al-dominio-no-lee-su-representacion.md +50 -0
  142. package/docs/adr/foundational/A-051-orden-imports-por-distancia.md +47 -0
  143. package/docs/adr/foundational/A-052-distribucion-metodologia-paquete-versionado.md +42 -0
  144. package/docs/adr/foundational/A-053-errores-compartidos-entre-features-dos-hogares-por-capa.md +43 -0
  145. package/docs/adr/foundational/A-054-contrato-costura-driver-port-raw-data-canal-error.md +65 -0
  146. package/docs/adr/foundational/index.md +98 -0
  147. package/docs/adr/index.md +19 -0
  148. package/docs/adr/python/P-001-dependencias-por-feature-fastapi-depends.md +63 -0
  149. package/docs/adr/python/P-002-inyeccion-token-por-request-sin-persistirlo.md +35 -0
  150. package/docs/adr/python/P-003-sqlalchemy-async-connection-pooling.md +59 -0
  151. package/docs/adr/python/P-004-serializer-json-custom-modelos-pydantic.md +47 -0
  152. package/docs/adr/python/P-005-patrones-pitfalls-nicegui.md +148 -0
  153. package/docs/adr/python/P-006-convenciones-pytest.md +96 -0
  154. package/docs/adr/python/P-007-ci-python-alineacion-poetry-version-unica.md +55 -0
  155. package/docs/adr/python/P-008-empaquetado-infraestructura-compartida-por-tecnologia.md +38 -0
  156. package/docs/adr/python/index.md +14 -0
  157. package/docs/adr/typescript/T-001-ddd-artifact-validation-zod-primitives.md +136 -0
  158. package/docs/adr/typescript/T-002-test-documentation-jsdoc.md +133 -0
  159. package/docs/adr/typescript/T-003-readme-formatting-domain-artifacts.md +51 -0
  160. package/docs/adr/typescript/T-005-input-optionality-use-case-not-entity.md +130 -0
  161. package/docs/adr/typescript/T-006-small-enums-inlined-zod-regex.md +77 -0
  162. package/docs/adr/typescript/T-007-controller-input-zod-schema.md +79 -0
  163. package/docs/adr/typescript/T-008-expressive-use-case-pipe.md +207 -0
  164. package/docs/adr/typescript/T-009-mdx-brace-escaping.md +80 -0
  165. package/docs/adr/typescript/T-010-stack-tooling-typescript-dominio.md +53 -0
  166. package/docs/adr/typescript/T-011-ultra-reporter-herramienta-canonica-documentacion.md +52 -0
  167. package/docs/adr/typescript/T-012-npm-workspaces-estructura-monorepo-clean-architecture.md +54 -0
  168. package/docs/adr/typescript/T-013-definicion-eventos-versionados-ultra-ddd.md +45 -0
  169. package/docs/adr/typescript/T-014-publicacion-distribucion-librerias-npm-semver.md +53 -0
  170. package/docs/adr/typescript/T-015-method-placement-definition.md +35 -0
  171. package/docs/adr/typescript/T-016-contrato-settings-zod.md +34 -0
  172. package/docs/adr/typescript/T-017-characterization-tests-golden-files.md +39 -0
  173. package/docs/adr/typescript/T-018-procedencia-campos-frontmatter.md +55 -0
  174. package/docs/adr/typescript/T-019-ultra-generator-herramienta-canonica-generacion.md +35 -0
  175. package/docs/adr/typescript/T-020-ultra-settings-herramienta-canonica-exportacion-despliegue.md +36 -0
  176. package/docs/adr/typescript/T-021-pipe-flujo-datos-operadores-semantica-contexto-inmutable.md +105 -0
  177. package/docs/adr/typescript/T-022-construction-is-execution-single-boundary.md +112 -0
  178. package/docs/adr/typescript/T-023-registry-cli-declara-dependencias-reales.md +84 -0
  179. package/docs/adr/typescript/T-024-paquete-ultra-agent-manifiesto-pi-peers-cli.md +39 -0
  180. package/docs/adr/typescript/T-025-publicacion-npm-trusted-publishing-procedencia.md +59 -0
  181. package/docs/adr/typescript/index.md +30 -0
  182. package/eslint/index.mjs +721 -0
  183. package/package.json +94 -0
  184. package/pi/extensions/handoff/README.md +92 -0
  185. package/pi/extensions/handoff/handoff-prompt.txt +9 -0
  186. package/pi/extensions/handoff/index.ts +296 -0
  187. package/pi/extensions/handoff/package.json +12 -0
  188. package/pi/extensions/qa-guardrail/README.md +108 -0
  189. package/pi/extensions/qa-guardrail/adapters/cli.ts +100 -0
  190. package/pi/extensions/qa-guardrail/adapters/eslint.ts +90 -0
  191. package/pi/extensions/qa-guardrail/adapters/registry.ts +45 -0
  192. package/pi/extensions/qa-guardrail/baseline.ts +74 -0
  193. package/pi/extensions/qa-guardrail/cerco.ts +134 -0
  194. package/pi/extensions/qa-guardrail/check.ts +185 -0
  195. package/pi/extensions/qa-guardrail/config.ts +189 -0
  196. package/pi/extensions/qa-guardrail/delta.ts +52 -0
  197. package/pi/extensions/qa-guardrail/feedback.ts +26 -0
  198. package/pi/extensions/qa-guardrail/index.ts +311 -0
  199. package/pi/extensions/qa-guardrail/nstop.ts +82 -0
  200. package/pi/extensions/qa-guardrail/package.json +12 -0
  201. package/pi/extensions/qa-guardrail/selection.ts +98 -0
  202. package/pi/extensions/qa-guardrail/types.ts +64 -0
  203. package/scripts/copy-assets.sh +10 -0
  204. package/scripts/reconcile-tags.sh +94 -0
  205. package/scripts/release-beta.sh +64 -0
  206. package/scripts/release-build.sh +53 -0
  207. package/scripts/release.sh +51 -0
  208. package/scripts/verify-adr-consistency.py +217 -0
  209. package/skills/code-review/SKILL.md +66 -0
  210. package/skills/codebase-design/SKILL.md +46 -0
  211. package/skills/configure-repo/SKILL.md +33 -0
  212. package/skills/diagnose-bug/SKILL.md +63 -0
  213. package/skills/domain-modeling/SKILL.md +56 -0
  214. package/skills/grill-me/SKILL.md +34 -0
  215. package/skills/i-have-an-idea/SKILL.md +166 -0
  216. package/skills/implement/SKILL.md +22 -0
  217. package/skills/research/SKILL.md +17 -0
  218. package/skills/ship/SKILL.md +26 -0
  219. package/skills/spike/SKILL.md +27 -0
  220. package/skills/tdd/SKILL.md +68 -0
  221. package/skills/tdd/references/deep-modules.md +53 -0
  222. package/skills/tdd/references/interface-design.md +74 -0
  223. package/skills/tdd/references/mocking.md +80 -0
  224. package/skills/tdd/references/refactoring.md +49 -0
  225. package/skills/tdd/references/tests.md +184 -0
  226. package/skills/to-specs/SKILL.md +141 -0
  227. package/skills/to-tasks/SKILL.md +143 -0
  228. package/skills/triage/SKILL.md +73 -0
  229. package/skills/ultra-generator/SKILL.md +263 -0
  230. package/skills/ultra-generator/references/aggregate-root.md +149 -0
  231. package/skills/ultra-generator/references/domain-event.md +174 -0
  232. package/skills/ultra-generator/references/entity.md +133 -0
  233. package/skills/ultra-generator/references/service.md +92 -0
  234. package/skills/ultra-generator/references/value-object.md +135 -0
  235. package/skills/wayfinder/SKILL.md +201 -0
  236. package/skills/workflow/SKILL.md +31 -0
  237. package/skills/writing-for-agents/SKILL-MECHANICS.md +32 -0
  238. package/skills/writing-for-agents/SKILL.md +86 -0
  239. package/skills/writing-for-agents/references/adrs.md +19 -0
@@ -0,0 +1,90 @@
1
+ # A-011: Refactoring con characterization tests
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2025-07-09
6
+
7
+ **originally**: ultra-reporter-009, ultra-reporter-010
8
+
9
+ **tags**: testing
10
+
11
+ ## Contexto
12
+
13
+ Al enfrentar código legacy o duplicado, el enfoque tradicional de "refactorizar y después probar" es riesgoso: sin tests que capturen el comportamiento actual, los cambios pueden introducir regresiones silenciosas. El riesgo se multiplica cuando existe lógica duplicada en múltiples ubicaciones (módulos compartidos, copias en diferentes lenguajes, métodos inline en clases monolíticas).
14
+
15
+ Antes de modificar la estructura del código, necesitamos una red de seguridad que garantice que el comportamiento observable se preserva.
16
+
17
+ ## Decisión
18
+
19
+ Adoptar el enfoque **characterization-first**: escribir tests de caracterización antes de cualquier refactoring, siguiendo un orden estricto de tres fases.
20
+
21
+ ### Fase 1: Caracterizar
22
+
23
+ Escribir tests que capturen el comportamiento actual del sistema, sin modificarlo. Estos tests:
24
+
25
+ - Ejecutan el código tal como existe hoy, con sus entradas y salidas reales
26
+ - No validan "corrección" — validan "así funciona ahora": el complemento del ciclo TDD, que especifica el comportamiento deseado ([A-003](./A-003-tdd.md))
27
+ - Cubren los caminos principales (happy path) y edge cases visibles
28
+ - Sirven como red de seguridad: si un refactor cambia el comportamiento, los tests lo detectan
29
+
30
+ ### Fase 2: Refactorizar
31
+
32
+ Con los tests de caracterización en verde, modificar la estructura interna del código en un orden específico:
33
+
34
+ 1. **Unificar código duplicado primero.** Extraer lógica común dispersa en múltiples ubicaciones hacia un módulo compartido. Todas las copias pasan a consumir la fuente unificada. Eliminar las copias redundantes.
35
+ 2. **Migrar a la plataforma destino después.** Con la lógica ya consolidada en módulos compartidos, migrar los consumidores a la plataforma destino. Los módulos compartidos son la base estable sobre la que se construye la migración.
36
+ 3. **Descomponer monolitos al final.** Con el código unificado y migrado, dividir archivos que exceden los límites de forma ([A-046](./A-046-metricas-de-forma-y-legibilidad-del-codigo.md)) en unidades composables ([A-044](./A-044-composicion-funcional-procesos-operaciones.md)).
37
+
38
+ **Por qué este orden:**
39
+
40
+ - Unificar primero crea la base compartida que necesitan la migración y la descomposición
41
+ - Migrar segundo se apoya en módulos ya consolidados, reduciendo la superficie de cambio
42
+ - Descomponer al final opera sobre código ya unificado y migrado, con dependencias claras
43
+
44
+ Cada paso tiene un punto de partida definido y tests que lo respaldan. Ningún paso requiere tocar más código del necesario.
45
+
46
+ ### Qué código merece tests de caracterización
47
+
48
+ No todo el código justifica el esfuerzo de caracterizarlo. Aplicar estos criterios:
49
+
50
+ | Situación | ¿Caracterizar? | Razón |
51
+ |-----------|:---:|-------|
52
+ | **Fuente de verdad** (módulo canónico del que otras copias derivan) | ✅ Sí | Es la referencia contra la que se validan las copias |
53
+ | **Lógica duplicada** en múltiples ubicaciones | ❌ No | Testear solo la fuente de verdad; las copias se validan por comparación |
54
+ | **Código que será eliminado** (copias redundantes) | ❌ No | No invertir esfuerzo en código con fecha de caducidad |
55
+ | **Lógica de negocio compleja** con múltiples caminos | ✅ Sí | El riesgo de regresión justifica la inversión |
56
+ | **Coordinación I/O** (orquestación de llamadas externas) | ⚠️ Condicional | Solo si la orquestación tiene complejidad no trivial |
57
+ | **Configuración y wiring** (inyección de dependencias, setup) | ❌ No | Se valida con tests de integración post-refactor |
58
+
59
+ **Regla general**: testear solo la fuente de verdad, no las copias. Las copias se cubren indirectamente cuando, tras la unificación, consumen el módulo compartido.
60
+
61
+ ### Orden de operaciones en la práctica
62
+
63
+ ```
64
+ 1. Identificar código duplicado y su fuente de verdad
65
+ 2. Escribir characterization tests para la fuente de verdad
66
+ 3. Extraer fuente de verdad a módulo compartido
67
+ 4. Redirigir consumidores al módulo compartido
68
+ 5. Eliminar copias redundantes
69
+ 6. Migrar consumidores a plataforma destino
70
+ 7. Descomponer monolitos en unidades composables
71
+ ```
72
+
73
+ Los tests de caracterización se ejecutan después de cada paso para verificar que el comportamiento se preserva.
74
+
75
+ ## Consecuencias
76
+
77
+ ### Positivas
78
+
79
+ - **Red de seguridad antes de tocar código**: los tests de caracterización capturan regresiones inmediatamente
80
+ - **Sin esfuerzo duplicado**: testear solo la fuente de verdad evita escribir los mismos tests para cada copia
81
+ - **Orden con fundamento**: cada fase construye la base para la siguiente, minimizando el riesgo
82
+ - **Criterios claros**: saber qué testear y qué no reduce la parálisis por análisis
83
+ - **Deuda técnica controlada**: las copias redundantes tienen fecha de caducidad desde el inicio
84
+
85
+ ### Negativas
86
+
87
+ - **Inversión inicial**: caracterizar lleva tiempo antes de ver mejoras estructurales
88
+ - **Disciplina de orden**: saltarse una fase (ej. descomponer antes de unificar) crea retrabajo
89
+ - **Tests desechables**: los tests de caracterización pueden volverse redundantes una vez que se escriben tests unitarios post-refactor. Esto es aceptable: cumplieron su propósito como red de seguridad durante la transición
90
+ - **Compatibilidad temporal**: durante la fase de unificación puede ser necesario manejar diferencias de módulo entre el origen y la plataforma destino hasta completar la migración
@@ -0,0 +1,67 @@
1
+ # A-012: Helm como mecanismo primario de despliegue para aplicaciones servidor
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: generator-021
8
+
9
+ **Enriquecido desde**: Generator ADR 021 — Helm Chart Deployment with Pre-Built Docker Image
10
+
11
+ **tags**: despliegue
12
+
13
+ ## Contexto
14
+
15
+ Las aplicaciones servidor de Imolko se ejecutan sobre Kubernetes y requieren un mecanismo de despliegue que sea:
16
+
17
+ - **Declarativo**: el estado deseado se describe en archivos versionados, no en comandos improvisados.
18
+ - **Repetible**: desplegar dos veces con los mismos parámetros produce el mismo resultado.
19
+ - **Versionado**: cada despliegue queda asociado a una versión de chart y una versión de imagen, de modo que se puede volver atrás.
20
+ - **Validable**: los requisitos previos (secretos, config maps, recursos del clúster) se verifican antes de instalar.
21
+
22
+ Desplegar con `kubectl apply` de manifiestos sueltos, o con scripts ad-hoc, produce drift entre entornos, sin historial de versiones y sin validación de requisitos. Mantener esa maquinaria por app multiplica el trabajo y hace que cada app despliegue de una forma distinta.
23
+
24
+ ## Decisión
25
+
26
+ Adoptar **Helm como mecanismo primario de despliegue para toda aplicación servidor**. Helm actúa como gestor de paquetes y de releases sobre Kubernetes: empaqueta los manifiestos en un chart versionado, los parametriza con valores y registra cada instalación como un release con historial y rollback.
27
+
28
+ ### 1. Un chart por aplicación servidor
29
+
30
+ Cada aplicación servidor incluye su propio chart, co-localizado en el repositorio de la aplicación. No se usan charts compartidos entre aplicaciones: un chart expresa la topología de despliegue de una app concreta (deployment, servicio, config maps, secretos, hooks). Una app nueva copia el patrón de una existente y lo adapta.
31
+
32
+ ### 2. Despliegue declarativo con install/upgrade
33
+
34
+ Todo despliegue se realiza con `helm install` (primera vez) y `helm upgrade` (cambios posteriores). No se aplican manifiestos sueltos con `kubectl` para recursos que pertenecen a la app. El historial de releases de Helm es la bitácora de despliegue: ante una regresión, `helm rollback` restaura la versión anterior.
35
+
36
+ ### 3. Valores por entorno sobre una base común
37
+
38
+ Los valores se organizan con una base común y overlays por entorno (desarrollo, pruebas, producción), aplicando la regla de superposición del contrato de settings ([A-013](./A-013-contrato-settings-unica-fuente-configuracion.md)).
39
+
40
+ ### 4. Artefactos de configuración generados, no mantenidos a mano
41
+
42
+ El chart consume los artefactos de configuración que se generan desde el contrato de settings (ver [A-014](./A-014-generacion-artefactos-despliegue-desde-contrato-settings.md)): plantillas de config map, de secretos y de valores de ejemplo. No se mantienen a mano listas de variables de entorno ni config maps duplicados; la fuente de verdad de qué configuración existe vive en el contrato de settings (ver [A-013](./A-013-contrato-settings-unica-fuente-configuracion.md)).
43
+
44
+ ### 5. Imagen preconstruida por el pipeline
45
+
46
+ El chart despliega una imagen de contenedor que ya fue compilada y publicada por el pipeline de CI/CD. El clúster no compila, no instala dependencias y no ejecuta builds: solo despliega la imagen. Los fallos de compilación se detectan en el pipeline, no en producción. Compilar en el clúster — por ejemplo, en un Job hook de Helm en `post-install`/`post-upgrade` — reserva pods sobredimensionados para un trabajo que solo ocurre ocasionalmente.
47
+
48
+ ### 6. Versión de chart e imagen rastreables
49
+
50
+ Cada despliegue referencia explícitamente una versión de chart y una etiqueta de imagen. No se despliega "la última": se despliega una versión concreta, de modo que un rollback es determinista.
51
+
52
+ ## Consecuencias
53
+
54
+ ### Positivas
55
+
56
+ - **Despliegues repetibles**: el mismo chart y los mismos valores producen el mismo resultado en cualquier entorno.
57
+ - **Historial y rollback**: cada cambio queda registrado como release; volver atrás es un comando, no una reconstrucción manual.
58
+ - **Separación build/deploy**: el pipeline construye, Helm despliega. El clúster no necesita acceso a redes de build ni recursos de compilación.
59
+ - **Configuración sin drift**: al consumir artefactos generados desde el contrato de settings, el chart no se desincroniza del código.
60
+ - **Validación de requisitos**: los hooks de Helm pueden verificar secretos y config maps antes de instalar, fallando con mensajes claros.
61
+
62
+ ### Negativas
63
+
64
+ - **Curva de aprendizaje**: el equipo debe dominar la sintaxis de plantillas de Helm y el ciclo install/upgrade/rollback.
65
+ - **Mantenimiento de charts**: cada app mantiene su chart; un cambio de topología implica editar plantillas.
66
+ - **Depuración de plantillas opaca**: el resultado renderizado depende de la combinación de plantillas y valores; depurar por qué un manifiesto no salió como se esperaba puede ser no trivial.
67
+ - **Valores custom fuera del contrato**: los valores de Helm que no corresponden a un campo del contrato de settings se mantienen a mano en el values (excepción acotada, ver [A-014](./A-014-generacion-artefactos-despliegue-desde-contrato-settings.md)).
@@ -0,0 +1,74 @@
1
+ # A-013: Contrato de settings como única fuente de configuración de la aplicación
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: cortex-001, generator-018
8
+
9
+ **Enriquecido desde**: Cortex ADR 001 — UltraSettings pattern; Generator ADR 018 — Settings Contract with schemas and auto-export
10
+
11
+ **tags**: configuracion
12
+
13
+ ## Contexto
14
+
15
+ Cada aplicación necesita configuración que varía entre entornos (local, desarrollo, producción) y entre despliegues: URLs de servicios, flags de features, parámetros del clúster y secretos. Sin un contrato formal, la configuración se dispersa:
16
+
17
+ - Variables de entorno leídas ad-hoc en distintos puntos del código.
18
+ - Archivos de configuración duplicados entre entornos.
19
+ - Valores faltantes o mal tipados que producen errores en runtime en lugar de al arrancar.
20
+ - Drift entre la configuración que el código espera y la que el despliegue provee.
21
+
22
+ Cuando la configuración no tiene una definición única, nadie puede responder con certeza "¿qué settings existen y cuáles son obligatorios?" sin leer todo el código.
23
+
24
+ ## Decisión
25
+
26
+ Declarar **toda la configuración de una aplicación en un único contrato de settings**, tipado y validado, que es la única fuente de verdad sobre qué configuración existe y cómo se valida.
27
+
28
+ ### 1. Un contrato por aplicación, centralizado
29
+
30
+ Cada aplicación define exactamente un contrato de settings en un único archivo. Todo el código lee configuración a través de ese contrato; ningún módulo lee variables de entorno o archivos de configuración por su cuenta. Agregar un setting es editar un solo lugar.
31
+
32
+ ### 2. Cada campo declara tipo y origen
33
+
34
+ Cada setting anota metadatos que clasifican su naturaleza. La taxonomía distingue al menos:
35
+
36
+ | Tipo | Prefijo | Cambia por entorno | Contiene secretos | Ejemplo abstracto |
37
+ |------|---------|:---:|:---:|-------------------|
38
+ | **Metadato** | `APP_` | No | No | nombre y resumen de la app |
39
+ | **Entorno** | `ENV_` | Sí | No | dominio o modo de ejecución |
40
+ | **Infraestructura** | `INFRA_` | Sí | No | URL de un servicio externo |
41
+ | **Clúster** | `CLUSTER_` | Sí | No | réplicas, imagen, recursos |
42
+ | **Secreto** | `SECRET_` | Sí | Sí | token de API, credencial |
43
+
44
+ El prefijo hace visible la clasificación en el propio nombre del setting: `APP_`, `ENV_`, `INFRA_`, `CLUSTER_` y `SECRET_`. Un nombre como `SECRET_API_TOKEN` declara su naturaleza sin necesidad de consultar el metadato.
45
+
46
+ El metadato de cada campo es lo que permite, más adelante, derivar artefactos automáticamente ([A-014](./A-014-generacion-artefactos-despliegue-desde-contrato-settings.md)).
47
+
48
+ ### 3. Validación fail-fast al arrancar
49
+
50
+ El contrato se valida al cargar la configuración, antes de que la aplicación procese trabajo real. Una configuración inválida (campo faltante, tipo incorrecto, secreto vacío) detiene el arranque con un error claro que identifica el campo y la causa. No se toleran valores parcialmente correctos.
51
+
52
+ ### 4. Definición y valores viven en lugares distintos
53
+
54
+ El contrato define **qué** settings existen y cómo se validan. Los **valores** concretos por entorno viven fuera del contrato: archivos de entorno para desarrollo local y overlays por entorno para el despliegue. La regla es "común por defecto, explícito por diferencia": los valores idénticos entre entornos se declaran una sola vez; cada overlay sobrescribe únicamente lo que cambia.
55
+
56
+ Los valores no secretos se versionan en el repositorio junto al contrato: la base común y los overlays por entorno quedan bajo control de versiones, de modo que cada cambio de configuración es rastreable y comparable entre versiones. La única excepción son los secretos: sus valores reales nunca se versionan — no se commitea ningún `.env`, credencial ni `kubeconfig` — y cada entorno los provee en el momento del despliegue, fuera del repositorio. El repositorio solo contiene plantillas `.sample` que muestran la forma de los valores (nombre y tipo) sin su contenido.
57
+
58
+ ### 5. El contrato es agnóstico a la tecnología de validación
59
+
60
+ El patrón (definición central, metadatos por campo, validación fail-fast) es independiente del lenguaje. Cada ecosistema lo implementa con su librería de validación y su sistema de tipos; el contrato de settings no depende de una librería concreta. Lo que se comparte entre proyectos es el patrón, no la implementación.
61
+
62
+ ## Consecuencias
63
+
64
+ ### Positivas
65
+
66
+ - **Una sola fuente de verdad**: la pregunta "¿qué configuración existe?" se responde abriendo un archivo.
67
+ - **Fallos tempranos**: la configuración inválida detiene la app al arrancar con un mensaje claro, no en runtime.
68
+ - **Taxonomía útil**: el metadato de tipo/origen habilita generación de artefactos ([A-014](./A-014-generacion-artefactos-despliegue-desde-contrato-settings.md)).
69
+ - **Entornos coherentes**: los overlays sobre una base común evitan duplicar valores idénticos y hacen explícitas las diferencias.
70
+
71
+ ### Negativas
72
+
73
+ - **El contrato crece**: con el tiempo, el archivo central acumula todos los settings de la app y se vuelve extenso; la taxonomía de tipos es la mitigación para navegarlo.
74
+ - **Riesgo de duplicación tipo/schema**: en ecosistemas con tipos fuertes, la definición puede existir dos veces (schema de validación y tipos del lenguaje); requiere disciplina para mantenerlos sincronizados.
@@ -0,0 +1,75 @@
1
+ # A-014: Generación de artefactos de despliegue desde el contrato de settings
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: cortex-002
8
+
9
+ **Enriquecido desde**: Cortex ADR 002 — Settings-to-Helm contract generation
10
+
11
+ **tags**: despliegue, configuracion
12
+
13
+ ## Contexto
14
+
15
+ Mantener a mano los artefactos de despliegue (valores de ejemplo, config maps, secretos y su esquema de validación) es propenso a errores. Un setting agregado al código pero olvidado en el chart produce una configuración errónea silenciosa en producción: la app arranca con un valor por defecto o falla en runtime, en lugar de fallar donde corresponde.
16
+
17
+ El contrato de settings ([A-013](./A-013-contrato-settings-unica-fuente-configuracion.md)) ya define qué configuración existe, con su tipo y su origen. Si ese contrato es la única fuente de verdad, los artefactos de despliegue deberían **derivarse** de él, no mantenerse como una copia paralela.
18
+
19
+ ## Decisión
20
+
21
+ Generar **todos los artefactos de despliegue desde el contrato de settings**, mediante un comando de exportación que lee el contrato y renderiza plantillas.
22
+
23
+ ### 1. Exportación automática, no edición manual
24
+
25
+ Un único comando de exportación lee el contrato de settings y genera, por cada aplicación:
26
+
27
+ - Muestra de entorno para desarrollo local.
28
+ - Plantilla de secretos para el despliegue.
29
+ - Plantilla de config map para el despliegue.
30
+ - Valores de ejemplo para el chart de Helm.
31
+ - Esquema de validación de valores para el chart.
32
+
33
+ No se editan a mano estos archivos generados. Un cambio de configuración se hace en el contrato y se propaga ejecutando el comando de exportación.
34
+
35
+ ### 2. La clasificación del contrato decide el destino
36
+
37
+ El metadato de tipo/origen de cada campo ([A-013 §2](./A-013-contrato-settings-unica-fuente-configuracion.md)) determina a qué artefacto pertenece:
38
+
39
+ - Un campo marcado como **secreto** se renderiza en la plantilla de secretos, nunca en el config map.
40
+ - Un campo marcado como **clúster** se traduce a la forma que el orquestador espera (por ejemplo, un objeto con `kind`, `name` y `key` que referencia un recurso del clúster).
41
+ - Un campo de **infraestructura** o **entorno** no secreto se renderiza en el config map.
42
+ - Los **metadatos** alimentan la muestra de entorno y la documentación.
43
+
44
+ ### 3. Esquema de validación generado
45
+
46
+ El esquema de valores del chart se genera desde el contrato, con los campos requeridos correctos y las formas de los objetos de clúster. El orquestador puede validar los valores antes de instalar, rechazando configuraciones que el contrato no contempla.
47
+
48
+ ### 4. Excepción acotada: valores fuera del contrato
49
+
50
+ Los valores del chart que no corresponden a ningún campo del contrato (por ejemplo, recursos de cómputo puros o topología de despliegue) se mantienen a mano en el values. Esta excepción es acotada y deliberada: el contrato describe configuración de la aplicación; el chart también necesita valores que no son configuración de la aplicación.
51
+
52
+ ### 5. El chart consume los artefactos generados
53
+
54
+ El chart de Helm ([A-012](./A-012-helm-mecanismo-primario-despliegue.md)) consume los artefactos generados en lugar de redefinir variables de entorno o config maps. La cadena completa es:
55
+
56
+ ```
57
+ contrato de settings → comando de exportación → artefactos de despliegue → chart de Helm
58
+ ```
59
+
60
+ Un setting nuevo recorre la cadena completa sin intervención manual en el chart.
61
+
62
+ ## Consecuencias
63
+
64
+ ### Positivas
65
+
66
+ - **Cero drift entre código y chart**: agregar un setting al contrato y ejecutar la exportación actualiza todos los artefactos derivados.
67
+ - **Secretos a salvo por construcción**: un campo marcado como secreto no puede terminar en un config map porque la clasificación lo excluye del renderizado correspondiente.
68
+ - **Validación previa a la instalación**: el esquema generado permite que el orquestador rechace valores inválidos antes de desplegar.
69
+ - **Bootstrap rápido de apps nuevas**: una app nueva copia el patrón de contrato + plantillas y obtiene su chart generado desde el primer momento.
70
+
71
+ ### Negativas
72
+
73
+ - **Paso de exportación obligatorio**: olvidar ejecutar la exportación tras cambiar un setting deja los artefactos desactualizados hasta el siguiente despliegue.
74
+ - **Depuración de la generación opaca**: el resultado renderizado depende de la combinación de metadatos del contrato y lógica de plantillas; un artefacto incorrecto puede requerir inspeccionar ambos.
75
+ - **Valores custom fuera del flujo**: lo que no mapea a un campo del contrato sigue manteniéndose a mano en el values, con su propio riesgo de drift.
@@ -0,0 +1,85 @@
1
+ # A-015: CloudEvents como estándar de eventos
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: cloudevents
8
+
9
+ **Enriquecido desde**: CloudEvents Specification (CNCF) — cloudevents.io
10
+
11
+ **tags**: eventos
12
+
13
+ ## Contexto
14
+
15
+ Los eventos son el medio por el que las distintas partes de un sistema se comunican: los de dominio, cuya emisión fija [A-010](./A-010-propiedad-emision-eventos-dominio.md), y los de integración que los adaptadores intercambian con sistemas externos. Sin una decisión canónica, cada productor y cada consumidor reinventa su propia envolvente, los eventos quedan legibles solo para quien los escribió y cada integración nueva exige un contrato ad-hoc:
16
+
17
+ - Campos con nombres distintos para lo mismo (`occurredAt` vs `fecha` vs `timestamp`).
18
+ - Falta de metadatos de enrutamiento (¿quién emitió esto? ¿de qué tipo es?).
19
+ - Imposibilidad de que la infraestructura (transporte, observabilidad, proyecciones) procese eventos sin conocer la data específica de cada dominio.
20
+ - Evolución de la data sin reglas: los consumidores se rompen silenciosamente cuando un productor cambia un campo.
21
+
22
+ ## Decisión
23
+
24
+ Adoptar **CloudEvents como estándar para todo evento** que el sistema emite o consume — de dominio y de integración. CloudEvents es una especificación del CNCF que define una envolvente común para describir eventos, independiente del lenguaje y del transporte.
25
+
26
+ ### 1. CloudEvents como envolvente único
27
+
28
+ Todo evento se representa como un CloudEvent conforme a la especificación CloudEvents (versión `1.0`). La especificación separa los atributos de contexto (metadatos estándar) de la data de negocio: la infraestructura enruta y observa usando el contexto, y solo los consumidores que interpretan un tipo concreto leen la data.
29
+
30
+ ### 2. Atributos de contexto
31
+
32
+ Cada evento declara los atributos obligatorios de la especificación:
33
+
34
+ - `id`: identificador único del evento.
35
+ - `source`: fuente que emitió el evento (una URI).
36
+ - `specversion`: versión de la especificación CloudEvents (`1.0`).
37
+ - `type`: tipo semántico del evento (ver punto 3).
38
+
39
+ Y usa los atributos opcionales cuando aportan información:
40
+
41
+ - `time`: instante en que ocurrió el evento.
42
+ - `subject`: entidad a la que se refiere el evento (por ejemplo, el identificador de un agregado).
43
+ - `datacontenttype`: formato de la data (por ejemplo, `application/json`).
44
+ - `dataschema`: URI del esquema versionado de la data (ver punto 4).
45
+
46
+ La data de negocio viaja en el campo `data`, tipada para los consumidores que la interpretan y opaca para el resto.
47
+
48
+ ### 3. `type` identifica la semántica y la familia de compatibilidad
49
+
50
+ El atributo `type` es un identificador estable y legible de la semántica del evento que codifica la familia de compatibilidad de la data: su versión mayor. Por ejemplo, `com.imolko.journal.v1.contact-created` marca la familia `1.x.x`, así que todos los eventos de ese `type` son compatibles dentro de `1.x.x`. El `type` no incluye la versión completa (`mayor.menor.patch`): la versión concreta se expresa por separado (ver punto 4). Así, el enrutamiento y las proyecciones no se rompen cuando la data evoluciona de forma compatible dentro de una familia, y un cambio incompatible produce un `type` nuevo (ver punto 4).
51
+
52
+ ### 4. Versionado semver, append-only y compatible hacia atrás de la data
53
+
54
+ La data de cada tipo de evento se versiona con semver (`mayor.menor.patch`) y su historial de versiones es **append-only**:
55
+
56
+ - **Append-only**: una versión publicada nunca se modifica ni se elimina. Un cambio produce una entrada nueva en el historial, agregada al final; las versiones anteriores permanecen intactas y legibles para siempre.
57
+ - **Compatible hacia atrás**: dentro de una misma versión mayor, los cambios son aditivos — se agregan campos opcionales o se relajan validaciones. Nunca se renombra ni se elimina un campo requerido, ni se cambia su significado. Un consumidor viejo sigue leyendo eventos nuevos sin romperse.
58
+ - **Cambios incompatibles**: un cambio que rompe compatibilidad (eliminar o renombrar un campo requerido, cambiar el significado de un campo) no se publica como una versión nueva de la misma data. Se trata como un contrato nuevo — un `type` nuevo — con su propio ciclo de versionado y, si aplica, migración explícita.
59
+
60
+ La versión concreta de la data de un evento se declara de forma explícita: en el `dataschema` (URI versionada del esquema) y, cuando el ecosistema lo requiera, en un campo de versión dentro de la propia data. Los consumidores leen esa versión y aplican la regla de compatibilidad para interpretar la data.
61
+
62
+ ### 5. Consumidores tolerantes a atributos desconocidos
63
+
64
+ Los consumidores ignoran los atributos de contexto y de data que no conocen, en lugar de fallar. CloudEvents permite atributos de extensión; un consumidor que rechaza eventos con atributos nuevos se convierte en un cuello de botella para la evolución del contrato. La tolerancia aplica tanto a atributos de contexto adicionales como a campos nuevos de la data (que son opcionales por la regla del punto 4).
65
+
66
+ ### 6. Ámbito agnóstico al lenguaje
67
+
68
+ La decisión fija el formato y la disciplina de versionado, no una librería concreta. Cualquier proyecto de Imolko — hoy TypeScript, mañana otro lenguaje — emite y consume CloudEvents y aplica las mismas reglas de versionado. Lo que se comparte entre proyectos es el estándar y el contrato de versionado; la implementación de cada ecosistema es un detalle.
69
+
70
+ ## Consecuencias
71
+
72
+ ### Positivas
73
+
74
+ - **Interoperabilidad**: la infraestructura común (transporte, observabilidad, enrutamiento) procesa cualquier evento sin conocer su data.
75
+ - **Contratos estables**: la data evoluciona de forma aditiva y los consumidores viejos siguen funcionando con eventos nuevos.
76
+ - **Historial inmutable**: las versiones publicadas nunca cambian, por lo que reproducir o auditar un evento viejo siempre es posible.
77
+ - **Descubrimiento**: el `type` y el `dataschema` permiten localizar la definición y el esquema de un evento sin leer código del productor.
78
+ - **Desacoplamiento del lenguaje**: la decisión aplica igual a TypeScript, Python o cualquier ecosistema futuro.
79
+
80
+ ### Negativas
81
+
82
+ - **Disciplina de versionado**: agregar un campo requiere pensar en compatibilidad y registrar una versión nueva, en lugar de editar libremente la data.
83
+ - **Curva de aprendizaje**: el equipo debe conocer los atributos de contexto de CloudEvents y las reglas semver aplicadas a eventos.
84
+ - **Romper compatibilidad es costoso**: un cambio incompatible no se arregla con una versión más; exige un `type` nuevo y, si aplica, una migración.
85
+ - **Manejo de atributos desconocidos**: la tolerancia del punto 5 es una responsabilidad de cada consumidor; un consumidor que la omita reintroduce el acoplamiento que el estándar busca evitar.
@@ -0,0 +1,92 @@
1
+ # A-016: CI/CD con GitLab: pipeline raíz y pipelines modulares por app
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: generator-019
8
+
9
+ **Enriquecido desde**: Generator ADR 019 — CI/CD Store Generator Pipeline; Cortex docs — GitLab CI/CD parent-child pipelines
10
+
11
+ **tags**: despliegue, tooling
12
+
13
+ ## Contexto
14
+
15
+ Todo repositorio de Imolko necesita verificar sus cambios de forma automática — ejecutar tests, compilar, validar requisitos y publicar artefactos — y desplegar las aplicaciones que lo componen. Sin una plataforma y una estructura de pipeline canónicas, cada repositorio reinventa su proceso:
16
+
17
+ - Pipelines con nombres y stages distintos entre proyectos.
18
+ - Validaciones globales mezcladas con los pasos de despliegue de una app concreta.
19
+ - Todas las apps se re-ejecutan en cada cambio, aunque el cambio no las afecte.
20
+ - Un agente o un miembro nuevo no puede descubrir cómo se valida y despliega un proyecto sin leer pipeline a pipeline.
21
+
22
+ ## Decisión
23
+
24
+ Adoptar **GitLab CI/CD como plataforma canónica de integración y despliegue continuo** para todos los proyectos de Imolko, con una estructura de **pipeline raíz + pipelines modulares por app**.
25
+
26
+ ### 1. GitLab como plataforma canónica
27
+
28
+ Todo pipeline de CI/CD se define como un pipeline de GitLab. No se mantiene una segunda plataforma de CI/CD como mecanismo primario. La definición vive en archivos de pipeline versionados junto al código, de modo que la forma de validar y desplegar se descubre leyendo el repositorio.
29
+
30
+ ### 2. Pipeline raíz: validaciones globales y orquestación
31
+
32
+ Cada repositorio tiene exactamente un **pipeline raíz** en su raíz. Su responsabilidad es el trabajo que concierne al repositorio como un todo, no el despliegue de una app concreta:
33
+
34
+ - **Reglas de workflow**: cuándo se ejecuta un pipeline y con qué intención (ver punto 4).
35
+ - **Validación de requisitos globales**: variables y condiciones previas que el pipeline necesita.
36
+ - **Trabajo compartido**: tests y builds de las capas comunes (el dominio y los casos de uso, según [A-001](./A-001-clean-architecture-4-capas.md)) y generación de documentación.
37
+ - **Reporte de tests unificado**: los jobs de test exportan sus resultados en formato CTRF (ver [A-022](./A-022-formato-reporte-tests-ctrf.md)); el pipeline y la documentación generada consumen ese reporte en lugar de los formatos propios de cada runner.
38
+ - **Orquestación de apps**: un job trigger por cada aplicación, que dispara el pipeline modular de esa app solo cuando corresponde (ver punto 3).
39
+
40
+ El pipeline raíz no contiene los pasos de build o despliegue de ninguna aplicación: ese trabajo pertenece al pipeline de la app.
41
+
42
+ ### 3. Pipeline modular por app con disparo por cambios
43
+
44
+ Cada aplicación desplegable ([A-001](./A-001-clean-architecture-4-capas.md)) posee su **propio pipeline**, definido en el directorio de la app. El pipeline raíz lo dispara mediante **parent-child pipelines**, y el trigger usa reglas de **cambios** (`rules:changes`): el pipeline de una app se ejecuta únicamente cuando cambian los archivos que la afectan. Un cambio que no toca a una app no la recompila ni la redespliega.
45
+
46
+ El pipeline de la app es dueño del ciclo específico de esa app:
47
+
48
+ - Verificar los archivos requeridos para desplegar.
49
+ - Construir y publicar la imagen de contenedor.
50
+ - Desplegar con Helm ([A-012](./A-012-helm-mecanismo-primario-despliegue.md)), consumiendo los artefactos generados desde el contrato de settings ([A-014](./A-014-generacion-artefactos-despliegue-desde-contrato-settings.md)).
51
+ - Verificar el despliegue.
52
+
53
+ ### 4. Intención del pipeline declarada en la raíz
54
+
55
+ El pipeline raíz declara la **intención** de cada ejecución en un único lugar, con dos valores:
56
+
57
+ - **Integración**: verificar cambios antes de fusionar (tests y builds, sin despliegue).
58
+ - **Entrega** (delivery): desplegar tras fusionar a una rama protegida.
59
+
60
+ La intención se decide en las reglas de workflow del raíz y se transmite a los pipelines de las apps. Los jobs de test se ejecutan en integración y entrega; los jobs de despliegue solo en entrega. Así, la semántica de "qué hace este pipeline" no se deduce de reglas dispersas.
61
+
62
+ ### 5. Contrato explícito entre raíz y apps mediante inputs
63
+
64
+ Cada pipeline de app declara los parámetros que necesita (por ejemplo, nombre de la app, directorio, entorno a desplegar, intención) como **inputs** con su tipo y descripción. El pipeline raíz se los pasa al disparar el trigger. Los pipelines de app no leen variables globales sueltas: reciben un contrato explícito que documenta qué necesitan y quién se lo provee.
65
+
66
+ ### 6. Convenciones operativas
67
+
68
+ Además de la estructura de dos niveles, los pipelines comparten convenciones operativas canónicas:
69
+
70
+ - **Helpers de CI versionados**: los pipelines usan el módulo de utilidades versionado en el repositorio (`ci-helpers.sh` en la raíz) en lugar de scripts externos no versionados. Ese archivo es la fuente canónica de las funciones disponibles —las familias de logging (`log_*`), las secciones colapsables (`section_start`, `section_end`) y las validaciones de requisitos (`validate_required_*`)—; los pipelines hacen `source` del archivo y consultan su documentación para conocer la lista completa, sin duplicarla en cada pipeline.
71
+ - **Naming `stage:job`**: los nombres de stage y de job siguen una convención explícita y uniforme, de modo que el propósito de un job se deduce de su nombre. La convención concreta vive en la fuente canónica de cada repositorio; este ADR fija la obligación de mantenerla, no duplica la tabla de nombres.
72
+ - **Versionado de imágenes con CalVer**: las imágenes de contenedor se versionan con **CalVer** (p. ej. `YYYY.MM.patch`), no con SemVer. El canal de desarrollo usa el sufijo `-beta` en la rama `develop`. Los **paquetes** (librerías publicables) siguen **SemVer**; CalVer aplica únicamente a imágenes desplegables. Esta distinción evita mezclar el ciclo de un artefacto desplegable con el de un artefacto consumible.
73
+ - **Despliegue Helm con espera y timeout**: el pipeline despliega con `helm upgrade --wait` y un `--timeout` explícito, de modo que Helm espera a que los pods reporten `ready` (coherente con el `readinessProbe` de [A-019](./A-019-convenciones-autoria-helm-charts.md)) antes de dar el despliegue por exitoso, en lugar de regresar de inmediato.
74
+ - **Sin scripts externos no versionados**: todo paso del pipeline ejecuta comandos en línea o scripts versionados en el repositorio. No se depende de scripts alojados fuera del repositorio ni de pasos que un miembro nuevo no pueda inspeccionar.
75
+
76
+ ## Consecuencias
77
+
78
+ ### Positivas
79
+
80
+ - **Modularidad**: cada app evoluciona su pipeline sin tocar el raíz, y el raíz cambia sin reescribir los pipelines de las apps.
81
+ - **Ejecución selectiva**: solo se ejecutan las apps afectadas por un cambio, lo que reduce tiempo y recursos.
82
+ - **Descubribilidad**: la estructura de dos niveles es predecible; un agente o un miembro nuevo encuentra el pipeline raíz y el de cada app sin ambigüedad.
83
+ - **Intención única**: integración versus entrega se define en un solo sitio, sin reglas contradictorias entre jobs.
84
+ - **Contrato claro**: los inputs de cada app documentan sus requisitos de pipeline.
85
+
86
+ ### Negativas
87
+
88
+ - **Complejidad de dos niveles**: depurar parent-child pipelines es más difícil que un pipeline único.
89
+ - **Mantenimiento por app**: cada app mantiene su archivo de pipeline; una app nueva debe crear el suyo.
90
+ - **Reglas de cambios frágiles**: si `rules:changes` no lista todos los paths que afectan a una app, el pipeline puede saltarse un cambio necesario.
91
+ - **Boilerplate de inputs**: declarar y pasar inputs agrega verbosidad frente a usar variables globales.
92
+ - **Disciplina**: mantener el raíz libre de pasos específicos de app requiere revisión constante.
@@ -0,0 +1,93 @@
1
+ # A-017: Taxonomía de repositorios: sistemas, librerías y configuración
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: imolko
8
+
9
+ **tags**: arquitectura
10
+
11
+ ## Contexto
12
+
13
+ Imolko mantiene varios repositorios de naturaleza distinta. Algunos encapsulan una funcionalidad técnica reutilizable (validación, resultados, generación, documentación); otros modelan un dominio de negocio completo con sus reglas y sus aplicaciones desplegables; otros guardan artefactos de despliegue y configuración. Sin una taxonomía explícita:
14
+
15
+ - No queda claro qué estándares aplican a cada repositorio.
16
+ - Se corre el riesgo de imponer estructura de negocio a una utilidad, o de tratar un producto como si fuera una pieza reutilizable.
17
+ - Un miembro nuevo o un agente no puede deducir el propósito de un repositorio a partir de una convención escrita.
18
+
19
+ Las prácticas del equipo se aplican de forma distinta según la naturaleza del repositorio. Fijar la taxonomía permite saber, para cada repositorio, qué reglas aplican.
20
+
21
+ ## Decisión
22
+
23
+ Clasificar todo repositorio de Imolko en exactamente una de tres categorías: **sistema**, **librería** o **configuración**. La clasificación depende del propósito del repositorio — un dominio de negocio, una funcionalidad técnica reutilizable, o artefactos de despliegue y configuración — no del tamaño, del lenguaje ni de la forma de despliegue.
24
+
25
+ ### 1. Librería
26
+
27
+ Una **librería** es un repositorio que provee **funcionalidad específica y reutilizable**, sin un dominio de negocio propio. La «funcionalidad» incluye metodología y documentación reutilizables —por ejemplo skills de agentes y un registro ADR de metodología, como `@imolko/ultra-agent`—, no solo código ejecutable.
28
+
29
+ Características:
30
+
31
+ - **Sin lenguaje ubicuo**: su vocabulario es técnico, no de negocio.
32
+ - **Sin Clean Architecture**: no se organiza en capas concéntricas de negocio. Es una pieza cohesionada — típicamente uno o unos pocos paquetes — que otros repositorios consumen como dependencia.
33
+ - **Problema acotado**: resuelve un problema bien delimitado, no un proceso de negocio completo.
34
+
35
+ Ejemplos abstractos: una librería de validación, una librería de resultados, una herramienta de documentación.
36
+
37
+ ### 2. Sistema
38
+
39
+ Un **sistema** es un repositorio que modela un **dominio de negocio**.
40
+
41
+ Características:
42
+
43
+ - **Con lenguaje ubicuo**: los artefactos y los nombres hablan el lenguaje del negocio.
44
+ - **Clean Architecture**: se organiza en capas concéntricas de negocio.
45
+ - **Aplicaciones desplegables**: posee apps que componen casos de uso y se despliegan de forma independiente.
46
+
47
+ Ejemplos abstractos: un sistema de inventario, un punto de venta, una plataforma de compras.
48
+
49
+ ### 3. Configuración
50
+
51
+ Un repositorio de **configuración** guarda artefactos de despliegue y configuración (settings, Helm charts, pipelines, entornos). No modela un dominio de negocio ni provee funcionalidad reutilizable.
52
+
53
+ Características:
54
+
55
+ - **Sin dominio de negocio**: no tiene capa `domain/` ni lenguaje ubicuo.
56
+ - **Sin lógica reutilizable**: no se consume como dependencia; lo consumen las herramientas de despliegue y el entorno.
57
+ - **Referencia a lo que configura**: un chart o un contrato de settings apunta al sistema (o librería) que despliega o configura.
58
+
59
+ Ejemplos abstractos: un repositorio de Helm charts, un contrato de settings, pipelines de CI/CD.
60
+
61
+ ### 4. Regla de dependencia entre categorías
62
+
63
+ Una **librería nunca depende de un sistema**. Los sistemas pueden depender de librerías, nunca al revés. Esta dirección mantiene las piezas reutilizables independientes de cualquier negocio concreto.
64
+
65
+ La **configuración** no participa del grafo de dependencias de código: referencia los sistemas y librerías que despliega o configura, y ningún repositorio la importa como dependencia.
66
+
67
+ ### 5. La taxonomía decide qué estándares aplican
68
+
69
+ La clasificación determina las expectativas estructurales:
70
+
71
+ - Un **sistema** debe exhibir lenguaje ubicuo ([A-031](./A-031-ubiquitous-language.md)) y Clean Architecture ([A-001](./A-001-clean-architecture-4-capas.md)); es candidato a un dominio DDD completo con sus bounded contexts ([A-008](./A-008-bounded-context-decomposition.md)).
72
+ - Una **librería** no debe cargar con capas de negocio; se mantiene como una pieza técnica cohesionada. Imponerle Clean Architecture es sobre-ingeniería.
73
+ - Un repositorio de **configuración** no aplica DDD ni Clean Architecture; sigue los estándares de despliegue y configuración (settings [A-013](./A-013-contrato-settings-unica-fuente-configuracion.md), Helm [A-019](./A-019-convenciones-autoria-helm-charts.md), CI/CD [A-016](./A-016-cicd-gitlab-pipeline-raiz-pipelines-modulares.md)).
74
+
75
+ ### 6. Clasificación por naturaleza dominante
76
+
77
+ Un repositorio se clasifica por su naturaleza dominante. Si un repositorio adquiere con el tiempo la naturaleza de otra categoría, se reclasifica — y esa reclasificación es una decisión que puede implicar migración estructural.
78
+
79
+ ## Consecuencias
80
+
81
+ ### Positivas
82
+
83
+ - **Clasificación inmediata**: la taxonomía responde "¿es un sistema, una librería o configuración?" sin ambigüedad.
84
+ - **Estándares correctos por repositorio**: un sistema exige DDD y Clean Architecture; una librería no arrastra esa ceremonia; la configuración sigue los estándares de despliegue, sin DDD ni Clean Architecture.
85
+ - **Dirección de dependencias sana**: las librerías permanecen libres de negocio y reutilizables entre sistemas.
86
+ - **Descubribilidad**: un agente o un miembro nuevo sabe qué buscar y qué reglas aplicar al entrar a un repositorio.
87
+ - **Distribución de librerías natural**: las librerías quedan identificadas como candidatas a publicación y versionado independientes.
88
+
89
+ ### Negativas
90
+
91
+ - **Solapamiento parcial**: un sistema puede alojar sus charts y settings en su propio repositorio; la categoría la decide la naturaleza dominante, lo que admite cierto criterio.
92
+ - **Reclasificación costosa**: una librería que crece hasta tener dominio debe migrar a la estructura de sistema.
93
+ - **Riesgo de sobre-ingeniería inversa**: aplicar la taxonomía a la inversa (forzar DDD en una librería, o aplanar un sistema) degrada el diseño.