@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,97 @@
1
+ # A-003: Desarrollo basado en pruebas (TDD)
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2025-02-25
6
+ **originally**: imolko
7
+
8
+ **tags**: testing
9
+
10
+ ## Contexto
11
+
12
+ Las pruebas automatizadas fijan el comportamiento esperado de todo el código del proyecto, en especial de las reglas de negocio complejas: validaciones de value-objects, transiciones de estado de agregados, políticas de negocio, sagas y cálculos de inventario.
13
+
14
+ La forma de escribirlas necesita una decisión canónica que fije el ciclo, las capas, la nomenclatura y la cobertura de cada artefacto.
15
+
16
+ Mientras esa forma queda implícita, cada artefacto prueba a su manera: los errores de dominio se detectan tarde, las regresiones se acumulan al modificar reglas de validación o lógica de agregados y los expertos del dominio pierden visibilidad de qué comportamientos están cubiertos.
17
+
18
+ ## Decisión
19
+
20
+ Adoptar **Test-Driven Development (TDD)** con el ciclo **red-green-refactor** como metodología obligatoria para todo el código del proyecto.
21
+
22
+ ### Stack de testing
23
+
24
+ El stack concreto de testing (runner, matchers, tipos de error) es específico de cada ecosistema y lo define su tier de lenguaje. Este ADR fija los principios.
25
+
26
+ ### Principios
27
+
28
+ 1. **Red-Green-Refactor**: escribir un test que falle → implementar el código mínimo → refactorizar
29
+ 2. **Slices verticales**: un test → una implementación. No escribir todos los tests primero y luego toda la implementación
30
+ 3. **API pública**: los tests verifican comportamiento a través de la API pública del artefacto, no de sus internos
31
+ 4. **Tests en el idioma del repo**: los nombres y descripciones de los tests van en el idioma del repo (`issue_language`, [A-052](./A-052-distribucion-metodologia-paquete-versionado.md)), el idioma de los colaboradores y expertos del dominio
32
+ 5. **Aserciones semánticas**: usar aserciones que expresen el resultado del dominio (válido / inválido / error) en lugar de asserts genéricos
33
+ 6. **Tracer bullet**: el primer test siempre verifica la creación válida del artefacto
34
+
35
+ ### Pirámide de tests en tres capas
36
+
37
+ Organizamos los tests en tres capas con propósitos diferenciados. Cada capa responde una pregunta distinta sobre el sistema:
38
+
39
+ | Capa | Propósito | Características |
40
+ |------|-----------|-----------------|
41
+ | **Contract** | Validar interfaces, esquemas y contratos — no comportamiento | Sin dependencias externas, validan estructura de datos y tipos |
42
+ | **Unit** | Lógica de dominio aislada con dependencias mockeadas | Rápidos (milisegundos), deterministas, sin I/O |
43
+ | **Integration** | Features punta a punta con infraestructura real o containerizada | Verifican que los adaptadores cumplen los contratos definidos por los puertos |
44
+
45
+ **Regla de proporción**: la mayoría de los tests deben ser unitarios, seguidos por contract, y la menor cantidad deben ser integration. Los tests de integración son más lentos y frágiles; los unitarios y de contrato dan feedback en segundos.
46
+
47
+ **Hogar de cada capa**: los tests unitarios y de contrato de una feature viven en la feature. El test de integración — el flujo completo caso de uso → adaptador → driver contra un driver real — vive en `shared-infra/<tech>/`, junto al driver que verifica ([A-026](./A-026-infraestructura-compartida.md)); la feature puede exportar una suite de contrato reutilizable que cada driver de `shared-infra/<tech>/` ejecuta contra su propia implementación.
48
+
49
+ ### Convenciones de nomenclatura
50
+
51
+ El nombre del archivo de test debe comunicar su capa sin requerir leer su contenido. Usamos un sufijo estandarizado que identifica el tipo de test:
52
+
53
+ - **Contract**: sufijo que denote validación de contrato (ej. `.contract.test.*`, `_contract_test.*`)
54
+ - **Unit**: sufijo estándar de test unitario (ej. `.unit.test.*`, `_test.*` cuando el default es unitario)
55
+ - **Integration**: sufijo que denote integración (ej. `.integration.test.*`, `_integration_test.*`)
56
+
57
+ La convención concreta del sufijo la define el tier de lenguaje de cada ecosistema. Lo importante es que el nombre del archivo distinga la capa.
58
+
59
+ ### Separación de runners por entorno de ejecución
60
+
61
+ Cuando un proyecto tiene múltiples entornos de ejecución (ej. browser y servidor), puede ser necesario separar los tests en runners distintos. Cada runner está optimizado para el entorno donde se ejecuta el código:
62
+
63
+ - **Browser/UI**: runner con DOM simulado para componentes y lógica de presentación
64
+ - **Servidor/CLI**: runner con acceso real a sistema de archivos, variables de entorno y APIs del sistema operativo
65
+
66
+ La separación permite que cada entorno use las herramientas nativas que necesita (ej. acceso al sistema de archivos en servidor, DOM simulado en browser) sin comprometer la velocidad ni la fidelidad de los tests. El CI ejecuta ambos runners secuencialmente.
67
+
68
+ **Criterios para separar runners:**
69
+ 1. Si el código bajo prueba requiere APIs específicas de un entorno (DOM, filesystem, network sockets), usar el runner de ese entorno
70
+ 2. Si el código es puramente lógico y no toca I/O, puede ejecutarse en cualquier runner — preferir el más rápido
71
+ 3. Un comando único debe ejecutar todos los runners para feedback completo en CI
72
+
73
+ ### Cobertura requerida
74
+
75
+ - **Value-objects**: creación válida, tipo inválido, mínimo/máximo, formato, instancia
76
+ - **Entidades**: creación válida con ID, validaciones de propiedades
77
+ - **Agregados**: creación válida, restauración desde snapshot/memento, transiciones de estado
78
+ - **Servicios de dominio**: casos de éxito, casos de error, edge cases
79
+ - **Features (casos de uso)**: flujo exitoso, errores de dominio, errores de infraestructura
80
+
81
+ ### Guía detallada
82
+
83
+ Ver el skill de TDD en el paquete `@imolko/ultra-agent` (la fuente canónica del conjunto, [A-052](./A-052-distribucion-metodologia-paquete-versionado.md)) para patrones de test, ejemplos y referencias.
84
+
85
+ ## Consecuencias
86
+
87
+ ### Positivas
88
+
89
+ - **Confianza en refactors**: los tests garantizan que los cambios no rompen comportamiento existente
90
+ - **Documentación viva**: los tests describen las reglas de negocio, legibles por expertos del dominio
91
+ - **Detección temprana**: errores de dominio se detectan en segundos, no en días
92
+ - **Diseño guiado por tests**: TDD fuerza pensar en la API desde la perspectiva del consumidor
93
+
94
+ ### Negativas
95
+
96
+ - **Tiempo inicial**: escribir tests antes del código requiere más tiempo al inicio (se recupera en mantenimiento)
97
+ - **Disciplina**: requiere que todo el equipo siga la metodología consistentemente
@@ -0,0 +1,80 @@
1
+ # A-005: Métodos del lado del negocio retornan `Result` (Either)
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-05-22
6
+ **originally**: imolko
7
+
8
+ **tags**: dominio
9
+
10
+ ## Contexto
11
+
12
+ Los procesos y operaciones se componen como un pipeline de pasos encadenados ([A-044](./A-044-composicion-funcional-procesos-operaciones.md)). Para que el pipeline no se interrumpa, cada paso produce un valor para el siguiente; un paso que lanza una excepción rompe la composición y obliga al caller a cablear el control de errores a mano.
13
+
14
+ La construcción de un artefacto de dominio ya retorna un `Result`/`Either` que encapsula la posibilidad de error. Los métodos que se agregan manualmente (como `add()`, `subtract()`, `isExpired()`) necesitan la misma convención de retorno. Apartarse de ella toma dos formas incorrectas:
15
+
16
+ 1. **Lanzar excepciones**: el método valida y lanza `throw`; el caller debe envolver cada llamada en try/catch y el pipeline se rompe.
17
+ 2. **Desenvolver el `Result`**: el método extrae el valor y descarta el error, forzando al caller a manejar el error fuera del tipo.
18
+
19
+ Cualquiera de las dos impide componer el método dentro del pipeline.
20
+
21
+ ## Decisión
22
+
23
+ Todo método del lado del negocio — el dominio y los casos de uso, con sus puertos ([A-029](./A-029-verbos-intencion-metodos-lado-negocio.md)) — debe:
24
+
25
+ 1. **Retornar `Result`/`Either`** — el método que produce un valor retorna el error como valor en el canal de error; nunca el valor a secas.
26
+ 2. **No desenvolver el `Result` dentro del método** — se retorna íntegro.
27
+ 3. **No lanzar excepciones** — ningún método del lado del negocio lanza; el error viaja en el canal de error del `Result`.
28
+
29
+ Este ADR fija *qué* retornan los métodos; *por qué* (componer sin interrupciones) lo fija [A-044](./A-044-composicion-funcional-procesos-operaciones.md). El tipo concreto de `Result` y sus operadores los provee el tier de lenguaje de cada ecosistema.
30
+
31
+ ### Regla
32
+
33
+ ```text
34
+ // ✅ CORRECTO: retorna Result, el caller compone
35
+ restar(otro): Result<Errores, Cantidad> {
36
+ return Cantidad.crear({ valor: nuevo })
37
+ }
38
+
39
+ // ❌ INCORRECTO: desenvuelve el Result (descarta el error)
40
+ restar(otro): Cantidad {
41
+ return Cantidad.crear({ valor: nuevo }).valor
42
+ }
43
+
44
+ // ❌ INCORRECTO: lanza excepción
45
+ restar(otro): Cantidad {
46
+ si nuevo <= 0: lanzar Error()
47
+ }
48
+ ```
49
+
50
+ ### Componer, no desmembrar
51
+
52
+ La decisión fija *qué* retorna el método; *cómo* lo consume el caller importa igual, porque de eso depende que la composición se mantenga ([A-044](./A-044-composicion-funcional-procesos-operaciones.md)):
53
+
54
+ 1. **Componer con los operadores del tier** — el caller encadena el `Result` con los operadores que provee el ecosistema; no ramifica sobre los predicados de estado (que son booleanos y no estrechan el tipo).
55
+ 2. **Sin extracción forzada** — el valor se obtiene dentro del operador, donde el tipo ya está resuelto; no con aserciones de no-nulo.
56
+ 3. **Ensanchar el canal de error por anotación de tipo, no por casts** — cuando un paso produce un error más estrecho que el del proceso, se anota el tipo más amplio en la variable que lo recibe.
57
+
58
+ ### Tipos de retorno según la operación
59
+
60
+ | Operación | Tipo de retorno | Justificación |
61
+ |-----------|----------------|---------------|
62
+ | Construcción interna dentro de otro método | `Result<Errores, T>` | La construcción puede fallar; propagar el `Result` |
63
+ | Transformación sin fallo (p. ej. `equals()`, un getter de primitivo) | valor directo (`boolean`, primitivo, …) | No hay posibilidad de error |
64
+ | Validación / consulta con fallo | `Result<Errores, T>` | El fallo es parte del dominio; encapsular en `Result` |
65
+ | Operación aritmética cuyo resultado debe cumplir invariantes | `Result<Errores, T>` | El resultado se construye con un constructor que ya retorna `Result` |
66
+
67
+ ## Consecuencias
68
+
69
+ ### Positivas
70
+
71
+ - **Componibilidad total**: cualquier método se integra en el pipeline sin adaptadores.
72
+ - **Sin excepciones**: los errores de dominio son valores, no saltos de pila — facilita testing y razonamiento.
73
+ - **Consistencia con el constructor**: mismo patrón que la construcción del artefacto.
74
+ - **Errores declarados**: el tipo `Result` documenta todos los fallos posibles.
75
+ - **Testabilidad**: los tests usan aserciones semánticas (válido/inválido); el detalle concreto lo define el tier de lenguaje (integrado en el ciclo TDD, [A-003](./A-003-tdd.md)).
76
+
77
+ ### Negativas
78
+
79
+ - **Verbosidad en callers simples**: si el caller solo necesita el valor, debe manejar el `Result` explícitamente. En la práctica es poco frecuente porque la arquitectura favorece pipelines.
80
+ - **Dependencia del tipo `Result`**: cada método debe importar el tipo y los errores declarados del artefacto.
@@ -0,0 +1,47 @@
1
+ # A-006: Criterios de completitud de artefactos de dominio y features (definition of done)
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-05-27
6
+ **originally**: imolko
7
+
8
+ **tags**: testing
9
+
10
+ ## Contexto
11
+
12
+ Un artefacto de dominio o feature se completa cerrando tres frentes a la vez: la lógica (código y reglas de negocio), la prueba (tests que fijan el comportamiento esperado) y la documentación (el formato canónico de [A-032](./A-032-domain-artifact-documentation-format.md)). Cuando una herramienta de scaffolding lo genera, añade además material de construcción — placeholders e instrucciones de implementación — que guía la implementación pero no es parte del artefacto terminado.
13
+
14
+ La completitud necesita una decisión canónica que fije cuándo un artefacto se declara terminado: qué criterios aplican y cómo se verifican.
15
+
16
+ Mientras esa decisión queda implícita, la completitud se confunde con una señal aislada — **tests verdes** se lee como "terminado" — y quedan sin cerrar la documentación y sin retirar el material de construcción. El artefacto funciona, pero no está documentado para el equipo y arrastra material de construcción ajeno.
17
+
18
+ ## Decisión
19
+
20
+ Un artefacto de dominio o feature se considera **completo** únicamente cuando cumple **todos los criterios de completitud aplicables**, cada uno verificable de forma explícita. No importa quién lo produjo — herramienta de scaffolding, agente o persona. La completitud es un estado **binario y verificable criterio por criterio**, no una señal aislada. El orden de implementación es libre; ningún criterio aplicable puede omitirse.
21
+
22
+ Los criterios concretos los fijan sus ADRs propietarios; este ADR los referencia, no los re-decide:
23
+
24
+ | Frente | Criterio | Lo fija |
25
+ |--------|----------|---------|
26
+ | Lógica | El código compila y los tests pasan | [A-003](./A-003-tdd.md); lo verificable por máquina, [A-045](./A-045-guardrails-aplicables-no-directrices.md) |
27
+ | Flujo | El caso de uso se expresa como composición de pasos | [A-044](./A-044-composicion-funcional-procesos-operaciones.md) |
28
+ | Documentación | Formato y frontmatter canónicos, sin placeholders | [A-032](./A-032-domain-artifact-documentation-format.md) |
29
+ | Scaffolding | El material de construcción no sobrevive al artefacto terminado | el tier de lenguaje define el archivo concreto y su eliminación |
30
+
31
+ Cada criterio se verifica de forma explícita: por máquina (compila, tests verdes, scaffolding ausente) o por revisión (flujo, documentación).
32
+
33
+ ## Consecuencias
34
+
35
+ ### Positivas
36
+
37
+ - **"Terminado" no ambiguo**: cualquier productor — herramienta, agente o persona — dispone de una lista de criterios aplicables para declarar un artefacto completo.
38
+ - **Documentación siempre cerrada**: al ser parte de la completitud, el artefacto terminado describe su dominio para el equipo ([A-032](./A-032-domain-artifact-documentation-format.md)).
39
+ - **Sin material de construcción residual**: el scaffolding no sobrevive al artefacto terminado.
40
+ - **Verificación explícita**: cada criterio se comprueba por máquina o por revisión ([A-045](./A-045-guardrails-aplicables-no-directrices.md)), no por la memoria del productor.
41
+ - **Cierre del ciclo**: la completitud cierra la brecha entre "el código funciona" y "el artefacto está terminado para el equipo".
42
+
43
+ ### Negativas
44
+
45
+ - **Trabajo manual**: completar la documentación es redacción humana, no generación automática ([A-032](./A-032-domain-artifact-documentation-format.md)).
46
+ - **Disciplina**: el equipo debe verificar todos los criterios aplicables antes de declarar el artefacto completo.
47
+ - **El productor aún puede detenerse antes**: si el issue no menciona la completitud, el agente puede detenerse en tests verdes; se mitiga referenciando el skill por nombre en el issue ([A-038](./A-038-issues-referencian-skills-nombre.md)).
@@ -0,0 +1,109 @@
1
+ # A-007: Contrato de datos: fallo en origen, sin fallbacks silenciosos
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: cortex-035
8
+
9
+ **Enriquecido desde**: Cortex ADR 035 — Data Contract Fail-Fast Policy
10
+
11
+ **tags**: testing
12
+
13
+ ## Contexto
14
+
15
+ Un caso de uso consume dependencias de datos: valores que necesita para producir un
16
+ resultado correcto. Una dependencia requerida se satisface en origen, o el caso de uso no
17
+ se ejecuta.
18
+
19
+ El tratamiento de una dependencia insatisfecha necesita una decisión canónica: qué se hace
20
+ cuando el dato requerido no está disponible.
21
+
22
+ Mientras esa decisión queda implícita, cada capa agrega su propio aterrizaje suave — valores
23
+ por defecto, advertencias y continuación — y el efecto acumulativo es que un caso de uso
24
+ reporta ÉXITO con resultados incorrectos o sin sentido. Ninguna capa confía en la capa
25
+ superior; una pérdida de datos produce solo una advertencia en el log.
26
+
27
+ ## Decisión
28
+
29
+ Una dependencia de datos requerida no satisfecha **falla en origen**: sin fallbacks
30
+ silenciosos ni opcionales por defecto. Un caso de uso que reporta ÉXITO garantiza que todos
31
+ sus contratos de datos fueron honrados; no existe el éxito parcial con datos faltantes.
32
+
33
+ ### 1. Fail-fast: sin fallbacks silenciosos
34
+
35
+ Cuando una dependencia de datos requerida no puede satisfacerse, el sistema falla
36
+ inmediatamente. No se admite:
37
+
38
+ - Capturar el error y continuar
39
+ - Advertir y continuar
40
+ - Retornar colecciones vacías en caso de error
41
+ - Reemplazar el dato ausente por un valor por defecto
42
+
43
+ Los errores se propagan por el canal de error del ecosistema. No se crean canales nuevos.
44
+
45
+ ### 2. Modelos de concepto, no bolsas de datos
46
+
47
+ Un modelo de dominio representa un concepto de negocio del lenguaje ubicuo
48
+ ([A-031](./A-031-ubiquitous-language.md)); un modelo genérico con campos mayormente
49
+ opcionales es un DTO de transporte, no un modelo de dominio.
50
+
51
+ ### 3. No-opcional-por-defecto
52
+
53
+ Los campos son requeridos a menos que la realidad del negocio justifique un campo opcional,
54
+ con la razón documentada en el modelo. Un campo que "usualmente está presente pero a veces
55
+ falta" es requerido: la ausencia se maneja explícitamente en el llamador, no se oculta con
56
+ un valor por defecto.
57
+
58
+ ### 4. Invariantes en el momento de construcción
59
+
60
+ Las invariantes de negocio se aplican al construir el modelo, no en métodos de validación
61
+ separados ni en verificaciones posteriores:
62
+
63
+ - Campos requeridos sin valor por defecto
64
+ - Colecciones no vacías como restricción de construcción
65
+ - Números positivos donde el negocio lo exige
66
+ - Validaciones entre campos
67
+
68
+ La construcción falla inmediatamente si una invariante no se cumple. Un modelo no puede
69
+ existir en un estado inválido: no hay ventana de "construir primero, validar después". La
70
+ verificación de estas invariantes sigue el ciclo TDD ([A-003](./A-003-tdd.md)).
71
+
72
+ ### 5. El consumidor confía en el contrato, verificado por máquina
73
+
74
+ La declaración de dependencias de un consumidor — p. ej. la plantilla de un motor de
75
+ renderizado — es su contrato de datos. El consumidor no protege con condicionales un dato
76
+ declarado como requerido: el condicional sobre un dato requerido oculta una violación de
77
+ contrato y se trata como defecto en revisión. El condicional solo es aceptable para conceptos
78
+ genuinamente opcionales con su razón documentada.
79
+
80
+ Cuando el consumidor es declarativo — declara sus dependencias y las referencia en su cuerpo,
81
+ p. ej. una plantilla — la verificación es bidireccional y por máquina, como guardrail
82
+ ([A-045](./A-045-guardrails-aplicables-no-directrices.md)): cada dependencia declarada está
83
+ presente en el contexto, y cada variable referenciada tiene una dependencia declarada. La
84
+ materialización concreta de la verificación es del tier de lenguaje.
85
+
86
+ ## Consecuencias
87
+
88
+ ### Positivas
89
+
90
+ - **Resultados confiables**: ÉXITO significa que se usaron los datos correctos.
91
+ - **Detección temprana**: las violaciones de contrato se detectan en el punto más temprano
92
+ posible (la construcción del modelo).
93
+ - **Sin aterrizajes suaves en cascada**: una falla en el origen, no valores vacíos
94
+ propagándose por N capas.
95
+ - **Contrato auto-documentado**: la declaración de dependencias del consumidor es el contrato
96
+ de datos.
97
+ - **Testing acotado**: los modelos con restricciones de "no vacío" fallan de forma predecible;
98
+ no hay necesidad de probar casos de datos vacíos en cada capa ([A-003](./A-003-tdd.md)).
99
+
100
+ ### Negativas
101
+
102
+ - **Todo campo requerido debe tener datos**: no hay "empezar vacío y ver qué pasa".
103
+ - **Los datos deben estar disponibles antes de que el caso de uso se ejecute**: siempre fue
104
+ cierto, ahora está aplicado.
105
+ - **Migración**: los modelos existentes con valores por defecto deben auditarse y
106
+ actualizarse.
107
+ - **El autor del consumidor mantiene la declaración en sincronía**: las dependencias
108
+ declaradas deben coincidir con las referencias en el cuerpo (aplicado por la verificación
109
+ bidireccional).
@@ -0,0 +1,130 @@
1
+ # A-008: Descomposición en Bounded Contexts
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: sentinel-0001
8
+
9
+ **Enriquecido desde**: Sentinel ADR 0001 — Descomposición en Bounded Contexts del dominio
10
+
11
+ **tags**: arquitectura, dominio
12
+
13
+ ## Contexto
14
+
15
+ Un dominio DDD con múltiples artefactos (agregados, entidades, value objects, servicios,
16
+ eventos, casos de uso) requiere una organización que permita navegar y comprender el sistema.
17
+ La asignación de cada artefacto a un Bounded Context es necesaria para generar documentación
18
+ estructurada y facilitar el descubrimiento.
19
+
20
+ Sin embargo, no todos los artefactos tienen el mismo peso semántico. Algunos son
21
+ value objects genéricos (validaciones de formato, tipos primitivos enriquecidos) que
22
+ carecen de lógica de dominio específica. Otros forman agrupaciones naturales alrededor
23
+ de un agregado raíz. Tratar todos los artefactos como iguales y asignarlos a un único
24
+ contexto plano oscurece la estructura real del dominio.
25
+
26
+ Se necesita un criterio sistemático para identificar agrupaciones naturales (Bounded
27
+ Contexts) y asignar cada artefacto al contexto que le corresponde.
28
+
29
+ ## Decisión
30
+
31
+ ### 1. Identificar agrupaciones naturales
32
+
33
+ Un Bounded Context se identifica respondiendo a la pregunta: **"¿qué grupo de artefactos
34
+ gira alrededor de un mismo agregado raíz o concepto central?"**
35
+
36
+ Cada Bounded Context debe tener:
37
+
38
+ - Un **agregado raíz** o concepto central que le da identidad
39
+ - Artefactos que **dependen principalmente** de otros artefactos dentro del mismo contexto
40
+
41
+ Los contexts de un mismo sistema comparten el lenguaje ubicuo del sistema (ver
42
+ [A-031](./A-031-ubiquitous-language.md)); lo que los separa es la cohesión alrededor de
43
+ un agregado raíz.
44
+
45
+ Síntomas de que dos artefactos pertenecen a contexts distintos:
46
+ - Referencian conceptos de negocio fundamentalmente diferentes
47
+ - Cambian por razones diferentes (diferentes stakeholders, diferentes ritmos de cambio)
48
+
49
+ ### 2. Artefactos genéricos de bajo valor semántico → contexto compartido
50
+
51
+ Los artefactos que implementan validaciones puras (regex, min/max, enum, formato) son
52
+ utilidad sin lógica de dominio: se agrupan en un contexto compartido (p. ej.
53
+ `shared-kernel`) que refleja su naturaleza de utilidad compartida. `scope::core`
54
+ ([A-009](./A-009-use-case-taxonomy.md)) designa la criticidad de un caso de uso, un eje
55
+ independiente del Bounded Context.
56
+
57
+ Características de los artefactos del contexto compartido:
58
+ - Validan solo formato
59
+ - Son reusables entre los demás contexts
60
+ - Son análogos a tipos primitivos enriquecidos (UUID, números naturales, schemas)
61
+
62
+ El contexto compartido funciona como un **Shared Kernel**: artefactos compartidos entre
63
+ contexts que no pertenecen exclusivamente a ninguno de ellos.
64
+
65
+ ### 3. Artefactos compartidos: documentar la dependencia
66
+
67
+ Cuando un artefacto del contexto compartido es consumido por artefactos en otros contexts,
68
+ los artefactos consumidores documentan la dependencia en su documentación — el frontmatter
69
+ y la sección `Relaciones` siguen
70
+ [A-032](./A-032-domain-artifact-documentation-format.md). El artefacto compartido no
71
+ referencia a sus consumidores.
72
+
73
+ ### 4. Proceso de asignación
74
+
75
+ Para asignar artefactos a Bounded Contexts:
76
+
77
+ 1. **Identificar los agregados raíz**: ¿cuáles son las entidades principales del dominio
78
+ que actúan como raíz de agregados?
79
+ 2. **Agrupar dependencias**: para cada agregado raíz, listar todos los artefactos que
80
+ dependen de él o que este referencia directamente.
81
+ 3. **Identificar artefactos huérfanos**: artefactos que no dependen de ningún agregado
82
+ raíz y que son usados por múltiples contexts → candidatos al contexto compartido.
83
+ 4. **Verificar cohesión**: cada contexto debe tener alta cohesión interna (los artefactos
84
+ dentro del contexto se referencian entre sí con frecuencia) y bajo acoplamiento externo
85
+ (las dependencias entre contexts son mínimas y documentadas).
86
+ 5. **Nombrar el contexto**: usar un nombre que refleje el concepto central, no la
87
+ implementación.
88
+
89
+ Criterios adicionales:
90
+ - Los casos de uso se asignan al mismo contexto que el agregado que modifican o consultan
91
+ - Los eventos de dominio se asignan al contexto del agregado cuyos datos describen (quién
92
+ los emite y publica lo define [A-010](./A-010-propiedad-emision-eventos-dominio.md))
93
+ - Si un artefacto depende de dos agregados raíz, revisar si el diseño de bounded contexts
94
+ es correcto o si se necesita una interfaz/contrato entre contexts
95
+
96
+ ### 5. Separación de responsabilidades
97
+
98
+ Cada Bounded Context tiene un propósito documentado que responde a la pregunta: "¿qué
99
+ parte del dominio modela este contexto?"
100
+
101
+ Ejemplo genérico de propósitos:
102
+
103
+ | Contexto | Propósito |
104
+ |---|---|
105
+ | `shared-kernel` | Validaciones genéricas reusables entre contexts (utilidad compartida) |
106
+ | `contexto-a` | Gestión del ciclo de vida de la entidad central A y sus dependencias directas |
107
+ | `contexto-b` | Gestión de la entidad B, sus recursos asociados e integraciones externas |
108
+
109
+ ## Consecuencias
110
+
111
+ **Positivas:**
112
+
113
+ - Separación clara de responsabilidades dentro del dominio
114
+ - La documentación generada se organiza en secciones navegables por contexto
115
+ - Facilita el descubrimiento: un desarrollador nuevo puede identificar rápidamente en qué
116
+ contexto se encuentra lo que busca
117
+ - Proporciona criterios objetivos para decidir dónde reside cada artefacto
118
+
119
+ **Negativas:**
120
+
121
+ - El contexto compartido carece de agregado raíz e identidad de negocio: es una agrupación
122
+ de utilidad, y tratarla como un Bounded Context pleno confunde
123
+ - Añade contextos que pueden parecer artificiales si el dominio es pequeño
124
+
125
+ **Neutrales:**
126
+
127
+ - Los Bounded Contexts son solo una separación lógica y conceptual: no tienen efecto sobre
128
+ la estructura de archivos del repositorio ni sobre las dependencias del código.
129
+ - La herramienta de generación de documentación puede usar los Bounded Contexts como criterio
130
+ de agrupación sin que el sistema de build los conozca
@@ -0,0 +1,99 @@
1
+ # A-009: Taxonomía de criticidad de casos de uso
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-07
6
+
7
+ **originally**: sentinel-0004
8
+
9
+ **tags**: arquitectura, dominio
10
+
11
+ ## Contexto
12
+
13
+ Los casos de uso de un dominio tienen diferentes niveles de criticidad y propósitos. Sin una taxonomía explícita, la clasificación es inconsistente entre desarrolladores y no hay criterios objetivos para decidir qué casos de uso son esenciales y cuáles son auxiliares. Se necesita una taxonomía de criticidad que asigne a cada caso de uso un nivel y permita filtrarlo y priorizarlo según el interés del stakeholder.
14
+
15
+ ## Decisión
16
+
17
+ ### 1. Taxonomía de criticidad: `scope::`
18
+
19
+ Cada caso de uso se clasifica en exactamente uno de tres niveles de criticidad — `scope::core`, `scope::support` o `scope::configuration` — expresados como un tag con prefijo `scope::` en el frontmatter del feature (esquema en [A-032](./A-032-domain-artifact-documentation-format.md)).
20
+
21
+ ### 2. Definiciones explícitas
22
+
23
+ #### `scope::core`
24
+
25
+ Casos de uso que implementan el propósito fundamental del dominio. Si un caso de uso `core` falla o no existe, el dominio **no puede cumplir su función principal**.
26
+
27
+ Características:
28
+ - Representan el flujo de valor primario del dominio
29
+ - Su ausencia es un bloqueo para la puesta en producción
30
+ - Son los primeros en implementarse y los últimos en desactivarse
31
+ - Típicamente representan la mayoría de los casos de uso (~50-70%)
32
+
33
+ Ejemplos genéricos:
34
+ - Registrar una entidad central del dominio
35
+ - Procesar un evento entrante del exterior
36
+ - Validar una operación contra reglas de negocio
37
+ - Ejecutar una transacción que mueve valor entre agregados
38
+
39
+ #### `scope::support`
40
+
41
+ Casos de uso que mejoran la experiencia, habilitan optimizaciones o proporcionan información adicional. El dominio **puede operar** sin ellos, aunque con funcionalidad reducida o menor eficiencia.
42
+
43
+ Características:
44
+ - No son necesarios para el flujo de valor primario
45
+ - Su ausencia degrada la experiencia pero no bloquea la operación
46
+ - Pueden implementarse en iteraciones posteriores al MVP
47
+
48
+ Ejemplos genéricos:
49
+ - Filtrar entidades por criterios secundarios
50
+ - Validar permisos granulares (más allá de la autorización básica)
51
+ - Generar reportes o vistas resumidas
52
+ - Notificar a usuarios sobre eventos no críticos
53
+
54
+ #### `scope::configuration`
55
+
56
+ Casos de uso que configuran el sistema para que los casos `core` y `support` puedan operar. Se ejecutan típicamente durante el onboarding, setup inicial o mantenimiento administrativo.
57
+
58
+ Características:
59
+ - No se ejecutan durante la operación normal del dominio
60
+ - Su frecuencia de ejecución es baja (una vez por tenant, una vez por release, etc.)
61
+ - Frecuentemente requieren privilegios elevados o contexto de administrador
62
+ - Su ausencia no bloquea la operación de un sistema ya configurado
63
+
64
+ Ejemplos genéricos:
65
+ - Registrar un nuevo tenant o cliente en el sistema
66
+ - Configurar reglas de autorización o políticas
67
+ - Definir esquemas de datos o estructuras que otros casos de uso consumen
68
+ - Establecer parámetros de integración con sistemas externos
69
+
70
+ ### 3. Criterios de clasificación
71
+
72
+ Para clasificar un caso de uso, responder las siguientes preguntas en orden:
73
+
74
+ 1. **¿Se ejecuta durante la operación normal del dominio?**
75
+ - NO → `scope::configuration`
76
+ - SÍ → continuar a la pregunta 2
77
+
78
+ 2. **¿Puede el dominio cumplir su propósito principal sin este caso de uso?**
79
+ - NO → `scope::core`
80
+ - SÍ (con degradación) → `scope::support`
81
+
82
+ En caso de ambigüedad, se asigna el nivel más alto (configuration < support < core).
83
+
84
+ ## Consecuencias
85
+
86
+ ### Positivas
87
+
88
+ - **Clasificación explícita y documentada**: cualquier desarrollador puede clasificar nuevos casos de uso consistentemente usando los criterios definidos
89
+ - **Priorización objetiva**: la taxonomía permite decidir qué implementar primero (core antes que support, support antes que configuration)
90
+ - **Generación de vistas**: herramientas de reporting pueden filtrar por scope para generar vistas enfocadas ("mostrar solo casos de uso core", "mostrar solo casos de uso de configuración")
91
+ - **Aliado con el lenguaje ubicuo**: los niveles de criticidad reflejan cómo el domain expert piensa sobre las operaciones del sistema
92
+
93
+ ### Negativas
94
+
95
+ - **Subjetividad en los bordes**: la clasificación `scope::*` puede ser ambigua en casos límite; requiere revisión del domain expert y aplicación de la regla de desempate (asignar el nivel más alto)
96
+
97
+ ### Neutrales
98
+
99
+ - El prefijo `scope::` se eligió para evitar colisiones con otros tags que puedan agregarse en el futuro
@@ -0,0 +1,95 @@
1
+ # A-010: Propiedad de la emisión de eventos de dominio
2
+
3
+ **Estado**: Aceptado
4
+
5
+ **Fecha**: 2026-08-12
6
+
7
+ **originally**: cortex-037
8
+
9
+ **Enriquecido desde**: Cortex ADR 037 — Driver-owned event emission
10
+
11
+ **tags**: arquitectura, eventos
12
+
13
+ ## Contexto
14
+
15
+ Un caso de uso que cambia el estado del dominio hace dos cosas: persiste el cambio y
16
+ publica los eventos de dominio que lo registran. La pregunta es quién posee cada paso, y
17
+ dos patrones fallan por extremos opuestos:
18
+
19
+ - **El caso de uso construye el evento**: llama al puerto de repositorio, recibe un evento
20
+ como valor de retorno — o lo reconstruye a partir del input — y lo publica. El caso de uso
21
+ termina construyendo hechos sobre una mutación que el agregado ejecutó, sin conocer el
22
+ estado resultante ni las invariantes.
23
+ - **El driver emite el evento**: el driver de repositorio emite eventos como efecto
24
+ secundario de la persistencia. Esto acopla el hecho de dominio a la tecnología de
25
+ persistencia y hace que el puerto asuma emisión de eventos.
26
+
27
+ La propiedad correcta es la de DDD: el **agregado** emite el evento porque posee la
28
+ transición de estado; el **caso de uso** lo publica porque posee la orquestación; el
29
+ **driver** lo entrega porque posee el mecanismo.
30
+
31
+ ## Decisión
32
+
33
+ ### 1. El agregado emite el hecho
34
+
35
+ Cuando un método del agregado transiciona estado (p. ej. `crear_entidad`), el agregado
36
+ levanta el evento de dominio correspondiente con la data del estado resultante. El evento
37
+ es un artefacto del dominio: su identificador de agregado y su data nacen del agregado, no
38
+ del input del caso de uso ni del valor de retorno del repositorio.
39
+
40
+ ### 2. El caso de uso publica, no construye
41
+
42
+ El caso de uso orquesta: carga el agregado, invoca su método (con verbos de intención según
43
+ [A-029](./A-029-verbos-intencion-metodos-lado-negocio.md)), lo persiste a través del puerto de
44
+ repositorio y publica los eventos que el agregado levantó a través del puerto publicador de
45
+ eventos. El caso de uso no reconstruye eventos a partir del input ni de valores de retorno. En persistencia event-sourced, el caso de uso no publica por separado: el append al EventStore es la publicación (ver §5).
46
+
47
+ ### 3. El driver entrega, no posee el hecho
48
+
49
+ - El puerto de repositorio persiste estado y retorna agregados o identificadores — nunca
50
+ eventos. (En persistencia event-sourced, persiste apendando los eventos del agregado; ver §5.)
51
+ - El puerto publicador de eventos declara la publicación; el driver que lo implementa posee
52
+ el mecanismo de entrega (un bus en memoria para tests, un transporte real en producción).
53
+ El formato del evento es siempre CloudEvents
54
+ ([A-015](./A-015-cloudevents-estandar-eventos.md)), independiente del transporte.
55
+ - La atomicidad entre persistir y publicar es una responsabilidad de entrega: se resuelve en
56
+ el driver del bus, no moviendo el hecho al driver de repositorio. (En persistencia event-sourced, se resuelve dentro del store; ver §5.)
57
+
58
+ ### 4. La publicación es fail-fast
59
+
60
+ La publicación de eventos es parte de la operación del caso de uso: no hay publicación
61
+ parcial — o la mutación persiste y sus eventos se publican, o la operación falla — conforme a
62
+ [A-007](./A-007-data-contract-fail-fast.md).
63
+
64
+ ### 5. Persistencia event-sourced
65
+
66
+ Cuando la persistencia es event-sourced — el stream de eventos es la fuente de verdad y el estado se reconstruye por replay — los puntos 2 a 4 se materializan así, sin cambiar la propiedad del hecho (el agregado emite, el driver entrega):
67
+
68
+ - **El puerto de repositorio apende los eventos.** El append al EventStore es la **publicación durable**: no hay un paso separado de publicación en el caso de uso; el puerto de repositorio persiste el hecho como eventos, no como estado derivado.
69
+ - **La entrega a suscriptores es un outbox o tail del stream**, poseído por el driver del store: proyecciones, integraciones y notificaciones consumen del stream, no de un segundo canal coordinado.
70
+ - **La atomicidad entre persistir y publicar se resuelve dentro del store**: el append es el hecho atómico; la publicación fail-fast (§4) se cumple porque persistir y publicar son la misma escritura.
71
+ - **El stream se firma y verifica.** Los eventos se firman y el EventStore los verifica al apender y al cargar; el snapshot cache (optimización del store) se firma y verifica al cargar, y se reconstruye desde el stream si su firma no valida.
72
+
73
+ ## Consecuencias
74
+
75
+ ### Positivas
76
+
77
+ - **El hecho vive en el dominio**: el evento nace del agregado con la data del estado
78
+ resultante; el caso de uso y el driver no reconstruyen hechos ajenos.
79
+ - **Puertos sin filtraciones**: el repositorio retorna agregados, no eventos; el puerto
80
+ publicador solo declara publicación.
81
+ - **Entrega intercambiable**: cambiar la tecnología de entrega (un bus en memoria, NATS,
82
+ RabbitMQ o Kafka) toca solo el driver del bus.
83
+ - **Atomicidad localizada**: el driver del bus resuelve la atomicidad entre persistir y
84
+ publicar; la persistencia de estado no se acopla a la emisión.
85
+ - **Tests simples**: se verifica que el agregado levantó el evento y que el caso de uso lo
86
+ publicó, no la construcción de eventos desde el input.
87
+
88
+ ### Negativas
89
+
90
+ - **El agregado debe levantar eventos**: los agregados existentes que solo transicionan
91
+ estado deben empezar a registrar sus eventos.
92
+ - **Migración**: cada feature con eventos debe ajustarse para publicar los eventos del
93
+ agregado, aunque pueden migrarse independientemente.
94
+ - **Disciplina de entrega**: resolver la atomicidad entre persistir y publicar es trabajo
95
+ del driver; sin ello, una caída entre ambos pasos pierde eventos.