ndomo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/.bun-version +1 -0
  2. package/.dockerignore +79 -0
  3. package/.editorconfig +18 -0
  4. package/.env.example +19 -0
  5. package/.github/CODEOWNERS +8 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +2 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.yml +34 -0
  9. package/.github/dependabot.yml +36 -0
  10. package/.github/pull_request_template.md +24 -0
  11. package/.github/release.yml +30 -0
  12. package/.github/workflows/gitleaks.yml +28 -0
  13. package/.github/workflows/release-please.yml +27 -0
  14. package/.github/workflows/smoke.yml +29 -0
  15. package/.husky/commit-msg +1 -0
  16. package/CHANGELOG.md +114 -0
  17. package/Dockerfile +32 -0
  18. package/README.es.md +174 -0
  19. package/README.md +187 -0
  20. package/agents/chronicler.md +98 -0
  21. package/agents/ci-smith.md +136 -0
  22. package/agents/craftsman.md +341 -0
  23. package/agents/deploy-smith.md +138 -0
  24. package/agents/foreman.md +377 -0
  25. package/agents/go-smith.md +164 -0
  26. package/agents/guild.md +188 -0
  27. package/agents/inspector.md +83 -0
  28. package/agents/js-smith.md +127 -0
  29. package/agents/ops-scout.md +173 -0
  30. package/agents/painter.md +200 -0
  31. package/agents/python-smith.md +120 -0
  32. package/agents/ranger.md +307 -0
  33. package/agents/release-smith.md +165 -0
  34. package/agents/rust-smith.md +159 -0
  35. package/agents/sage.md +178 -0
  36. package/agents/scout.md +144 -0
  37. package/agents/scribe.md +156 -0
  38. package/agents/smith.md +201 -0
  39. package/agents/vue-smith.md +155 -0
  40. package/agents/warden.md +216 -0
  41. package/agents/zig-smith.md +156 -0
  42. package/bin/ndomo-analyses.ts +4 -0
  43. package/bin/ndomo-status.ts +4 -0
  44. package/biome.json +57 -0
  45. package/bun.lock +514 -0
  46. package/commitlint.config.js +3 -0
  47. package/config/ndomo.config.json +258 -0
  48. package/config/ndomo.schema.json +166 -0
  49. package/docs/agents.md +375 -0
  50. package/docs/bugs/plan-create-orphan-fk.md +131 -0
  51. package/docs/bugs/task_create_batch-order-index-collision.md +158 -0
  52. package/docs/configuration.md +276 -0
  53. package/docs/database.md +364 -0
  54. package/docs/features/feature-flexible-builder-v1.md +724 -0
  55. package/docs/features/feature-flexible-builder-v2.md +882 -0
  56. package/docs/features/feature-flexible-builder.md +974 -0
  57. package/docs/http-server.md +244 -0
  58. package/docs/installation.md +259 -0
  59. package/docs/integrations.md +129 -0
  60. package/docs/operations/anti-pattern-sub-agent-verify-2026-06-21.md +32 -0
  61. package/docs/operations/audit-v1.md +417 -0
  62. package/docs/operations/audit-v2.md +197 -0
  63. package/docs/operations/audit-v3.md +306 -0
  64. package/docs/operations/db-optimize-foundations.md +123 -0
  65. package/docs/operations/verify-gate-architecture.md +82 -0
  66. package/docs/workflows.md +448 -0
  67. package/opencode.json +5 -0
  68. package/package.json +65 -0
  69. package/release-please-config.json +11 -0
  70. package/scripts/dev-bust-cache.sh +164 -0
  71. package/scripts/install.sh +688 -0
  72. package/scripts/smoke-e2e.ts +704 -0
  73. package/scripts/smoke-hot.ts +417 -0
  74. package/scripts/smoke-http.sh +228 -0
  75. package/scripts/smoke-v4.ts +256 -0
  76. package/scripts/smoke-v5.ts +397 -0
  77. package/scripts/smoke.sh +9 -0
  78. package/scripts/uninstall.sh +224 -0
  79. package/skills/api-security-best-practices/SKILL.md +915 -0
  80. package/skills/bash-scripting/SKILL.md +201 -0
  81. package/skills/bun/SKILL.md +313 -0
  82. package/skills/cavecrew/SKILL.md +82 -0
  83. package/skills/caveman/SKILL.md +74 -0
  84. package/skills/caveman-review/README.md +33 -0
  85. package/skills/caveman-review/SKILL.md +55 -0
  86. package/skills/find-skills/SKILL.md +142 -0
  87. package/skills/frontend-design/LICENSE.txt +177 -0
  88. package/skills/frontend-design/SKILL.md +55 -0
  89. package/skills/golang-patterns/SKILL.md +674 -0
  90. package/skills/golang-security/SKILL.md +185 -0
  91. package/skills/golang-security/evals/evals.json +595 -0
  92. package/skills/golang-security/references/architecture.md +268 -0
  93. package/skills/golang-security/references/checklist.md +80 -0
  94. package/skills/golang-security/references/cookies.md +200 -0
  95. package/skills/golang-security/references/cryptography.md +424 -0
  96. package/skills/golang-security/references/filesystem.md +285 -0
  97. package/skills/golang-security/references/injection.md +315 -0
  98. package/skills/golang-security/references/logging.md +163 -0
  99. package/skills/golang-security/references/memory-safety.md +241 -0
  100. package/skills/golang-security/references/network.md +253 -0
  101. package/skills/golang-security/references/secrets.md +189 -0
  102. package/skills/golang-security/references/third-party.md +159 -0
  103. package/skills/golang-security/references/threat-modeling.md +189 -0
  104. package/skills/golang-testing/SKILL.md +720 -0
  105. package/skills/grill-me/SKILL.md +7 -0
  106. package/skills/javascript-testing-patterns/SKILL.md +537 -0
  107. package/skills/javascript-testing-patterns/references/advanced-testing-patterns.md +513 -0
  108. package/skills/modern-javascript-patterns/SKILL.md +43 -0
  109. package/skills/modern-javascript-patterns/references/advanced-patterns.md +487 -0
  110. package/skills/modern-javascript-patterns/references/details.md +457 -0
  111. package/skills/python-anti-patterns/SKILL.md +349 -0
  112. package/skills/python-design-patterns/SKILL.md +85 -0
  113. package/skills/python-design-patterns/references/details.md +353 -0
  114. package/skills/python-error-handling/SKILL.md +193 -0
  115. package/skills/python-error-handling/references/details.md +171 -0
  116. package/skills/python-testing-patterns/SKILL.md +278 -0
  117. package/skills/python-testing-patterns/references/advanced-patterns.md +411 -0
  118. package/skills/python-testing-patterns/references/details.md +349 -0
  119. package/skills/rust-patterns/SKILL.md +500 -0
  120. package/skills/rust-testing/SKILL.md +501 -0
  121. package/skills/security-review/SKILL.md +504 -0
  122. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  123. package/skills/vue-best-practices/SKILL.md +154 -0
  124. package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
  125. package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
  126. package/skills/vue-best-practices/references/component-async.md +97 -0
  127. package/skills/vue-best-practices/references/component-data-flow.md +307 -0
  128. package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
  129. package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
  130. package/skills/vue-best-practices/references/component-slots.md +216 -0
  131. package/skills/vue-best-practices/references/component-suspense.md +228 -0
  132. package/skills/vue-best-practices/references/component-teleport.md +108 -0
  133. package/skills/vue-best-practices/references/component-transition-group.md +128 -0
  134. package/skills/vue-best-practices/references/component-transition.md +125 -0
  135. package/skills/vue-best-practices/references/composables.md +290 -0
  136. package/skills/vue-best-practices/references/directives.md +162 -0
  137. package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
  138. package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
  139. package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
  140. package/skills/vue-best-practices/references/plugins.md +166 -0
  141. package/skills/vue-best-practices/references/reactivity.md +344 -0
  142. package/skills/vue-best-practices/references/render-functions.md +201 -0
  143. package/skills/vue-best-practices/references/sfc.md +310 -0
  144. package/skills/vue-best-practices/references/state-management.md +135 -0
  145. package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
  146. package/skills/vue-pinia-best-practices/SKILL.md +21 -0
  147. package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
  148. package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
  149. package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
  150. package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
  151. package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
  152. package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
  153. package/skills/zig-0.16/SKILL.md +840 -0
  154. package/skills/zig-0.16/scripts/check-zig-version.sh +21 -0
  155. package/src/cli/analyses.ts +280 -0
  156. package/src/cli/index.ts +108 -0
  157. package/src/cli/serve.ts +192 -0
  158. package/src/cli/smoke.ts +131 -0
  159. package/src/cli/status.test.ts +204 -0
  160. package/src/cli/status.ts +263 -0
  161. package/src/cli/vacuum.test.ts +82 -0
  162. package/src/cli/vacuum.ts +96 -0
  163. package/src/config/schema.test.ts +88 -0
  164. package/src/config/schema.ts +64 -0
  165. package/src/db/analyses-migration.test.ts +210 -0
  166. package/src/db/analyses.test.ts +466 -0
  167. package/src/db/analyses.ts +375 -0
  168. package/src/db/auto-checkpoint.ts +131 -0
  169. package/src/db/client.test.ts +129 -0
  170. package/src/db/client.ts +55 -0
  171. package/src/db/fts-escape.ts +20 -0
  172. package/src/db/incidents.test.ts +201 -0
  173. package/src/db/incidents.ts +93 -0
  174. package/src/db/index.ts +86 -0
  175. package/src/db/migrations-v13.test.ts +141 -0
  176. package/src/db/migrations-v8.test.ts +301 -0
  177. package/src/db/migrations.ts +147 -0
  178. package/src/db/plan-archive.test.ts +180 -0
  179. package/src/db/plan-archive.ts +274 -0
  180. package/src/db/plan-create.test.ts +276 -0
  181. package/src/db/plan-create.ts +78 -0
  182. package/src/db/plan-files.test.ts +289 -0
  183. package/src/db/plan-update-status.ts +287 -0
  184. package/src/db/plans.test.ts +490 -0
  185. package/src/db/plans.ts +534 -0
  186. package/src/db/resolve-project-dir.test.ts +143 -0
  187. package/src/db/resolve-project-dir.ts +75 -0
  188. package/src/db/rollbacks.test.ts +150 -0
  189. package/src/db/rollbacks.ts +67 -0
  190. package/src/db/schema.ts +907 -0
  191. package/src/db/sessions.test.ts +80 -0
  192. package/src/db/sessions.ts +135 -0
  193. package/src/db/shutdown.test.ts +147 -0
  194. package/src/db/shutdown.ts +45 -0
  195. package/src/db/tasks.test.ts +921 -0
  196. package/src/db/tasks.ts +747 -0
  197. package/src/db/types.ts +619 -0
  198. package/src/http/__tests__/auth.test.ts +196 -0
  199. package/src/http/__tests__/routes.test.ts +465 -0
  200. package/src/http/__tests__/sse.test.ts +317 -0
  201. package/src/http/auth.ts +72 -0
  202. package/src/http/middleware/cors.ts +53 -0
  203. package/src/http/middleware/security-headers.ts +21 -0
  204. package/src/http/routes/events.ts +112 -0
  205. package/src/http/routes/health.ts +51 -0
  206. package/src/http/routes/plans.ts +66 -0
  207. package/src/http/routes/sessions.ts +50 -0
  208. package/src/http/routes/tasks.ts +60 -0
  209. package/src/http/server.ts +95 -0
  210. package/src/http/sse.ts +116 -0
  211. package/src/index.ts +37 -0
  212. package/src/lib.ts +65 -0
  213. package/src/mem/scoped.ts +65 -0
  214. package/src/orchestrator/background.test.ts +268 -0
  215. package/src/orchestrator/background.ts +293 -0
  216. package/src/orchestrator/memory-hook.ts +182 -0
  217. package/src/orchestrator/reconciler.ts +123 -0
  218. package/src/orchestrator/scheduler.test.ts +300 -0
  219. package/src/orchestrator/scheduler.ts +243 -0
  220. package/src/plugin.test.ts +2574 -0
  221. package/src/plugin.ts +1690 -0
  222. package/src/sdk/client.ts +66 -0
  223. package/src/worktrees/manager.ts +236 -0
  224. package/src/worktrees/state.ts +87 -0
  225. package/tests/integration/ranger-flow.test.ts +257 -0
  226. package/tools/analysis_archive.ts +28 -0
  227. package/tools/analysis_create.ts +55 -0
  228. package/tools/analysis_get.ts +33 -0
  229. package/tools/analysis_link_plan.ts +44 -0
  230. package/tools/analysis_list.ts +48 -0
  231. package/tools/analysis_search.ts +36 -0
  232. package/tools/analysis_update.ts +44 -0
  233. package/tools/plan_approve.ts +31 -0
  234. package/tools/plan_create.ts +58 -0
  235. package/tools/plan_get.ts +40 -0
  236. package/tools/plan_list.ts +37 -0
  237. package/tools/plan_search.ts +34 -0
  238. package/tools/plan_update_status.ts +71 -0
  239. package/tools/session_checkpoint.ts +31 -0
  240. package/tools/session_end.ts +26 -0
  241. package/tools/session_start.ts +43 -0
  242. package/tools/task_create_batch.ts +70 -0
  243. package/tools/task_list.ts +35 -0
  244. package/tools/task_next_for_agent.ts +30 -0
  245. package/tools/task_search.ts +34 -0
  246. package/tools/task_update_status.ts +37 -0
  247. package/tsconfig.json +31 -0
package/docs/agents.md ADDED
@@ -0,0 +1,375 @@
1
+ # Agent Reference
2
+
3
+ ## Overview
4
+
5
+ ndomo defines 22 agents grouped by function (4 primaries + 18 subagents). All agent definitions live as Markdown files in `agents/` with YAML frontmatter specifying model, temperature, permissions, and mode.
6
+
7
+ ## Primaries
8
+
9
+ Four primary agents operate independently. The user switches between them manually via TUI.
10
+
11
+ ### foreman
12
+
13
+ **Planner puro.** Analiza, explora, planifica y persiste planes en DB. No implementa. Solo planifica; la ejecución es del craftsman.
14
+
15
+ - **Model:** minimax/MiniMax-M3 (default), deepseek-v4-flash (budget)
16
+ - **Temperature:** 0.3
17
+ - **Permissions:** edit (ask), write (ask), bash (ask), question (allow)
18
+ - **Delegates to:** scout, scribe, sage, guild (exploración y análisis únicamente)
19
+ - **File:** `agents/foreman.md`
20
+
21
+ Flow (4 pasos):
22
+ 1. **Aclaración** — identifica intención, pregunta si ambigüo, sugiere craftsman si ≤5 archivos
23
+ 2. **Exploración** — memory search + scout/scribe/sage/guild según necesidad
24
+ 3. **Plan Atómico** — desglosa en ≤5 steps con archivos esperados y dependencias
25
+ 4. **Persistir** — `plan_create` + `task_create_batch` en DB
26
+
27
+ ### craftsman
28
+
29
+ **Implementador artesano.** Primary agent para bugs, features pequeñas y refactors acotados. Opera en 4 estados según alcance.
30
+
31
+ - **Model:** opencode-go/deepseek-v4-flash
32
+ - **Temperature:** 0.1
33
+ - **Permissions:** edit (allow), write (allow), bash (ask con permit list), question (allow)
34
+ - **Delegates to:** smiths, painter, chronicler, inspector, scout, scribe (por routing interno)
35
+ - **File:** `agents/craftsman.md`
36
+
37
+ **Cuándo usar:**
38
+ - **Ad-hoc (cambio directo):** Tareas ≤5 archivos, bien definidas — cambiar a craftsman en TUI sin pasar por foreman
39
+ - **Plan formal:** Foreman creó un plan con tasks asignadas a `craftsman` — craftsman lee `plan_get`/`task_next_for_agent` y ejecuta
40
+ - **Diferencia con foreman:** Foreman planifica (solo DB writes), craftsman implementa (code + DB writes). Foreman NO delega a smiths; craftsman sí.
41
+
42
+ **Threshold 2/5/1:**
43
+ | Estado | Archivos | Comportamiento |
44
+ |--------|----------|----------------|
45
+ | 1 — Trivial | ≤2 | Implementación directa, sin `plan_db` |
46
+ | 2 — Multi-archivo acotado | 3-5 | Crea `plan_create` + `task_create_batch` propio |
47
+ | 3 — Plan formal | — | Lee plan existente del foreman y ejecuta |
48
+ | 4 — Fuera de dominio | >5 | **Rechaza** — "fuera de mi dominio" → cambiar a foreman |
49
+
50
+ **Routing interno (por extensión de archivo):**
51
+ | Extensión / Contexto | Sub-agente |
52
+ |---|---|
53
+ | `.go` | `go-smith` |
54
+ | `.vue` / `.svelte` | `vue-smith` |
55
+ | `.ts` / `.tsx` / `.js` / `.jsx` | `js-smith` |
56
+ | `.py` | `python-smith` |
57
+ | `.rs` | `rust-smith` |
58
+ | `.zig` | `zig-smith` |
59
+ | UI/design + `type=design` | `painter` (solo vía craftsman) |
60
+ | Documentación / markdown | `chronicler` |
61
+ | Auditoría / seguridad | `inspector` |
62
+ | Sin match | `smith` (genérico) |
63
+
64
+ `task.metadata.stack` actúa como override explícito sobre la extensión. Si no hay match, usa `smith`.
65
+
66
+ **Painter solo craftsman:** El agente UI/UX `painter` solo es invocable desde craftsman, no desde foreman. Craftsman decide: painter si `stack="vue"` y `type="design"`, o vue-smith para implementación lógica.
67
+
68
+ ### warden
69
+
70
+ **Custodio de operaciones.** Primary agent para CI/CD, deploy, releases, monitoring, secrets, branch strategy y security ops. Opera en paralelo con foreman (planificación) y craftsman (implementación) — su dominio es exclusivamente ops.
71
+
72
+ - **Model:** opencode-go/deepseek-v4-flash
73
+ - **Temperature:** 0.3
74
+ - **Permissions:** edit (ask), write (ask), bash (ask con read-only allow), webfetch (allow), question (allow), task (allow)
75
+ - **Delegates to:** ci-smith, deploy-smith, release-smith, ops-scout (own fleet), sage, inspector (reused)
76
+ - **File:** `agents/warden.md`
77
+
78
+ **Cuándo usar:**
79
+ - **Ad-hoc (cambio directo):** Ops simple — cambiar a warden en TUI sin pasar por foreman. Ej: bump version, restart service, audit one-off.
80
+ - **Plan formal:** Warden crea plan con `metadata.category="ops"`, dispatcha via `task_create_batch` con agent="ci-smith"/"deploy-smith"/etc.
81
+ - **Dispatched:** Foreman crea plan code+ops, dispatcha warden para portions ops. Warden hereda `plan_id` via session.
82
+
83
+ **Regla de oro:** Warden NUNCA dispatcha a craftsman/smith/foreman. Si la tarea es code+ops → pedir al usuario que foreman planifique primero.
84
+
85
+ ### ranger
86
+
87
+ **Analyst / Cartographer / Onboarding.** Primary agent para análisis profundo, mapeo estructural y context-loading. NO implementa lógica de negocio. NO crea planes — produce filas en tabla `analyses` (linkable a planes via `source_plan_id`).
88
+
89
+ - **Model:** minimax/MiniMax-M3
90
+ - **Temperature:** 0.3
91
+ - **Permissions:** edit (deny código fuente, allow `docs/analyses/**`), write (ask), bash (ask con read-only allow), webfetch (ask), question (allow), task (scout/sage/scribe)
92
+ - **Delegates to:** scout, sage, scribe (exploración y análisis únicamente)
93
+ - **File:** `agents/ranger.md`
94
+
95
+ **Cuándo usar:**
96
+ - **Ad-hoc:** Análisis directo sin plan — onboarding de proyecto, auditoría exploratoria, context-loading rápido. Cambiar a ranger en TUI sin pasar por foreman.
97
+ - **Plan-mode (consumidor):** Foreman/craftsman/warden crea plan con task agent="ranger". Ranger hereda plan_id y produce analysis linkeada a `source_plan_id`.
98
+ - **Dispatched:** Analysis standalone consultable por otros primaries via `analysis_get`/`analysis_search`.
99
+
100
+ **Tres roles híbridos:**
101
+ | Rol | Output típico |
102
+ |---|---|
103
+ | Analyst | Auditoría arquitectura, deuda técnica, security review, performance hotspots — findings con severity + location + recommendation |
104
+ | Cartographer | Dependency graphs, module maps, convention detection, symbol indexes |
105
+ | Onboarding | Stack detection, conventions extraction, entry points, context-load denso para humanos/AI nuevos |
106
+
107
+ **Routing interno (sub-agentes permitidos):**
108
+ | Sub-agente | Uso |
109
+ |---|---|
110
+ | `scout` | Mapear repo, localizar archivos, dependency graphs |
111
+ | `sage` | Evaluar arquitectura, trade-offs, debugging complejo |
112
+ | `scribe` | Research docs externas, APIs, versiones |
113
+
114
+ **NO delega a:** smiths, painter, chronicler, inspector, foreman, craftsman, warden, guild.
115
+
116
+ **Regla de oro:** ranger analiza y mapea. Craftsman implementa. Warden opera. Foreman planifica.
117
+
118
+ ## Explorers
119
+
120
+ Read-only agents for investigation and research.
121
+
122
+ ### scout
123
+
124
+ Codebase reconnaissance. Navigates repositories at maximum speed: maps structures, locates symbols, finds patterns, traces dependencies.
125
+
126
+ - **Model:** opencode-go/minimax-m2.7
127
+ - **Temperature:** 0.3
128
+ - **Permissions:** edit (deny), bash (allow), question (allow)
129
+ - **File:** `agents/scout.md`
130
+ - **Use when:** "find where X is defined", "map the auth flow", "what calls this function"
131
+
132
+ ### scribe
133
+
134
+ External knowledge retrieval. Searches documentation, APIs, libraries, and web resources. Does not modify code.
135
+
136
+ - **Model:** opencode-go/minimax-m2.7
137
+ - **Temperature:** 0.3
138
+ - **Permissions:** edit (deny), bash (allow), question (allow)
139
+ - **File:** `agents/scribe.md`
140
+ - **Use when:** "research best practices for X", "find docs for this library", "what version of Y should we use"
141
+
142
+ ## Builders
143
+
144
+ Write code. Divided into generic smith and stack-specific smiths.
145
+
146
+ ### painter
147
+
148
+ UI/UX designer. Handles visual composition, component design, and frontend styling. Triggered only when `stack === "vue"` and `type === "design"`.
149
+
150
+ - **Model:** opencode-go/kimi-k2.6
151
+ - **Temperature:** 0.2
152
+ - **Permissions:** edit (allow), write (allow), bash (allow), question (allow)
153
+ - **File:** `agents/painter.md`
154
+ - **Use when:** "design a login page", "create a dashboard layout", "style this component"
155
+
156
+ ### smith
157
+
158
+ Generic fast implementation specialist. Stack-agnostic — handles well-defined tasks in any language. Default fallback for unknown stacks.
159
+
160
+ - **Model:** opencode-go/deepseek-v4-flash
161
+ - **Temperature:** 0.1
162
+ - **Permissions:** edit (allow), write (allow), bash (allow), question (allow)
163
+ - **File:** `agents/smith.md`
164
+ - **Use when:** small fixes, config changes, simple features, mechanical refactors in any language
165
+
166
+ ### go-smith
167
+
168
+ Go implementation specialist. Idiomatic Go patterns, testing with table-driven tests, concurrency, error handling.
169
+
170
+ - **Model:** xiaomi/mimo-v2.5-pro
171
+ - **Temperature:** 0.1
172
+ - **Permissions:** edit (allow), write (allow), bash (allow)
173
+ - **File:** `agents/go-smith.md`
174
+
175
+ ### js-smith
176
+
177
+ JavaScript/TypeScript implementation specialist. Frontend and backend JS/TS, modern patterns, typing.
178
+
179
+ - **Model:** xiaomi/mimo-v2.5-pro
180
+ - **Temperature:** 0.1
181
+ - **Permissions:** edit (allow), write (allow), bash (allow)
182
+ - **File:** `agents/js-smith.md`
183
+
184
+ ### python-smith
185
+
186
+ Python implementation specialist. Pythonic idioms, type hints, testing with pytest.
187
+
188
+ - **Model:** xiaomi/mimo-v2.5-pro
189
+ - **Temperature:** 0.1
190
+ - **Permissions:** edit (allow), write (allow), bash (allow)
191
+ - **File:** `agents/python-smith.md`
192
+
193
+ ### vue-smith
194
+
195
+ Vue 3 / Pinia implementation specialist. Composition API, `<script setup>`, Vue Router, Pinia stores.
196
+
197
+ - **Model:** xiaomi/mimo-v2.5-pro
198
+ - **Temperature:** 0.1
199
+ - **Permissions:** edit (allow), write (allow), bash (allow)
200
+ - **File:** `agents/vue-smith.md`
201
+
202
+ ### zig-smith
203
+
204
+ Zig 0.16 implementation specialist. Systems programming, Zig idioms, memory management.
205
+
206
+ - **Model:** xiaomi/mimo-v2.5-pro
207
+ - **Temperature:** 0.1
208
+ - **Permissions:** edit (allow), write (allow), bash (allow)
209
+ - **File:** `agents/zig-smith.md`
210
+
211
+ ### rust-smith
212
+
213
+ Rust implementation specialist. Ownership, lifetimes, traits, async/Tokio, zero-cost abstractions, compile-time SQL checks.
214
+
215
+ - **Model:** opencode-go/mimo-v2.5-pro
216
+ - **Temperature:** 0.1
217
+ - **Permissions:** edit (allow), write (allow), bash (allow)
218
+ - **File:** `agents/rust-smith.md`
219
+ - **Skills:** `rust-patterns`, `rust-testing`
220
+
221
+ ## Advisors
222
+
223
+ Provide analysis, guidance, and multi-perspective evaluation. Read-only (edit denied).
224
+
225
+ ### sage
226
+
227
+ Architecture advisor and high-risk debugger. Deep reasoning for complex problems, trade-off analysis, architecture decisions.
228
+
229
+ - **Model:** opencode-go/deepseek-v4-pro
230
+ - **Temperature:** 0.2
231
+ - **Permissions:** edit (deny), bash (allow), question (allow)
232
+ - **File:** `agents/sage.md`
233
+ - **Use when:** "review this architecture", "debug this complex issue", "what's the best approach for X"
234
+ - **Manual call:** `sage <question>`
235
+ - **Auto-triggered:** when `type === "debug" && risk === "high"`, or `high risk implement` (as advisory parallel to the stack-smith)
236
+
237
+ ### guild
238
+
239
+ Multi-LLM consensus and architectural debate. Simulates multiple perspectives to reach consensus on high-risk decisions.
240
+
241
+ - **Model:** opencode-go/deepseek-v4-pro
242
+ - **Temperature:** 0.3
243
+ - **Permissions:** edit (deny), bash (allow), question (allow)
244
+ - **File:** `agents/guild.md`
245
+ - **Use when:** "should we use X or Y architecture", "is this design safe"
246
+ - **Note:** Manual delegation only — never auto-routed by the scheduler. The foreman only delegates to guild on explicit user request (`type: "debate"`).
247
+
248
+ ## Quality
249
+
250
+ Review and documentation agents. Invoked after implementation phases.
251
+
252
+ ### inspector
253
+
254
+ Code quality and security auditor. Reviews diffs for bugs, anti-patterns, security issues, and style violations.
255
+
256
+ - **Model:** opencode-go/deepseek-v4-pro
257
+ - **Temperature:** 0.2
258
+ - **Permissions:** edit (deny), bash (allow), question (allow)
259
+ - **File:** `agents/inspector.md`
260
+ - **Use when:** "review this diff", "audit this PR", "check for security issues"
261
+ - **Auto-triggered:** craftsman invokes inspector on the resulting diff before closing any task
262
+
263
+ ### chronicler
264
+
265
+ Technical documentation writer. Analyzes code and generates Markdown documentation. Read-only on existing code; writes documentation files.
266
+
267
+ - **Model:** opencode-go/deepseek-v4-flash
268
+ - **Temperature:** 0.2
269
+ - **Permissions:** edit (allow), write (allow), bash (deny)
270
+ - **File:** `agents/chronicler.md`
271
+ - **Use when:** "document this API", "generate README", "write migration guide"
272
+
273
+ ## Ops Sub-Agents
274
+
275
+ Warden delega en 4 sub-agentes especializados en operaciones:
276
+
277
+ ### ci-smith
278
+
279
+ **CI/CD pipeline specialist.** Crea/modifica GitHub Actions, GitLab CI, CircleCI workflows.
280
+
281
+ - **Model:** opencode-go/deepseek-v4-flash
282
+ - **Temperature:** 0.5
283
+ - **Permissions:** edit (allow for `.github/workflows/*.yml`), bash (allow for `gh workflow*`)
284
+ - **Delegates to:** none (focused specialist)
285
+ - **File:** `agents/ci-smith.md`
286
+
287
+ ### deploy-smith
288
+
289
+ **Deployment automation specialist.** Scripts de deploy, Docker, k8s, rollback procedures.
290
+
291
+ - **Model:** opencode-go/deepseek-v4-flash
292
+ - **Temperature:** 0.5
293
+ - **Permissions:** edit (allow for `scripts/deploy*`, `Dockerfile*`, `k8s/`)
294
+ - **Delegates to:** none
295
+ - **File:** `agents/deploy-smith.md`
296
+
297
+ ### release-smith
298
+
299
+ **Release management specialist.** Semver, CHANGELOG, GitHub releases, branch strategy enforcement.
300
+
301
+ - **Model:** opencode-go/deepseek-v4-flash
302
+ - **Temperature:** 0.3
303
+ - **Permissions:** edit (allow for `CHANGELOG.md`, `package.json`)
304
+ - **Delegates to:** none
305
+ - **File:** `agents/release-smith.md`
306
+
307
+ ### ops-scout
308
+
309
+ **Infrastructure reconnaissance specialist.** Audit de CI/CD/deploy/monitoring/secrets. Read-only.
310
+
311
+ - **Model:** opencode-go/deepseek-v4-flash
312
+ - **Temperature:** 0.5
313
+ - **Permissions:** edit (deny), write (deny), bash (allow read-only)
314
+ - **Delegates to:** none
315
+ - **File:** `agents/ops-scout.md`
316
+ - **Note:** Cross-primary — único sub-agent dispatchable por warden O foreman.
317
+
318
+ ## Routing Tables
319
+
320
+ Routing is split across two tiers: foreman (planner) and craftsman (implementer). The old centralized scheduler in `src/orchestrator/scheduler.ts` is deprecated.
321
+
322
+ ### Foreman Routing (planning only)
323
+
324
+ Foreman delegates exclusively to exploration/analysis agents:
325
+
326
+ | Petición | Delegar a |
327
+ |----------|-----------|
328
+ | Localizar código / mapear repo / detectar stack | `scout` |
329
+ | Research docs / APIs / libraries / versiones | `scribe` |
330
+ | Arquitectura / debugging difícil / trade-offs | `sage` |
331
+ | Consenso multi-modelo / debate arquitectónico | `guild` (solo manual) |
332
+
333
+ **NO delegar a:** smiths, painter, chronicler, inspector — esos van al craftsman. **ranger es primary peer** (no sub-agente de foreman) — foreman puede crear planes con `task agent="ranger"` para análisis pre-implement, pero NO lo dispatcha como sub-agente de exploración.
334
+
335
+ ### Craftsman Routing (implementation)
336
+
337
+ Craftsman selecciona sub-agente por extensión de archivo (`task.files`) con `task.metadata.stack` como override:
338
+
339
+ | Extensión | Sub-agente |
340
+ |-----------|------------|
341
+ | `.go` | `go-smith` |
342
+ | `.vue` / `.svelte` | `vue-smith` |
343
+ | `.ts` / `.tsx` / `.js` / `.jsx` | `js-smith` |
344
+ | `.py` | `python-smith` |
345
+ | `.rs` | `rust-smith` |
346
+ | `.zig` | `zig-smith` |
347
+ | UI/design + `type=design` | `painter` |
348
+ | Documentación / markdown | `chronicler` |
349
+ | Auditoría / diff review | `inspector` |
350
+ | Sin match | `smith` (genérico) |
351
+
352
+ Si no hay match por extensión ni stack, usa `smith` como fallback genérico.
353
+
354
+ ### Cross-Primary Routing (ranger)
355
+
356
+ Ranger es primary peer. Craftsman, foreman y warden pueden **invocar** ranger vía:
357
+
358
+ | Mecanismo | Uso |
359
+ |---|---|
360
+ | `analysis_*` tools | Consumir analyses existentes (read) — todos los primaries |
361
+ | `task_create_batch` con `agent: "ranger"` | Dispatchar análisis como task en un plan (foreman/craftsman) |
362
+ | `session_start({planId})` (ranger hereda) | Análisis linkeado a plan via `source_plan_id` |
363
+
364
+ **Cuándo craftsman invoca ranger:**
365
+ - Pre-implement context-loading profundo (antes de refactor multi-archivo)
366
+ - Auditoría de deuda técnica antes de fix
367
+ - Validación de assumptions arquitectónicas
368
+
369
+ **Cuándo warden invoca ranger:**
370
+ - Auditoría de proyecto pre-CI overhaul
371
+ - Security scan profundo pre-deploy
372
+
373
+ ## Custom Agents
374
+
375
+ See [configuration.md](configuration.md#custom-agents) for instructions on adding new specialist agents to the routing table.
@@ -0,0 +1,131 @@
1
+ # Bug: Plan orphaned in `draft` — `plan_approve` / `plan_update_status` fail with FK session validation
2
+
3
+ ## Resumen
4
+
5
+ Planes creados mediante `plan_create` no pueden transicionar a `approved` ni a ningún estado terminal porque `plan_approve` y `plan_update_status` validan que `ctx.sessionID` exista en la tabla `sessions` (`src/db/plans.ts:118-121`, `src/db/plans.ts:159-162`). Dicho ID nunca se inserta en `sessions` porque corresponde a la sesión del harness (OpenCode), no a un `session_start` explícito. El plan queda bloqueado permanentemente en `draft`.
6
+
7
+ ## Entorno
8
+
9
+ | Atributo | Valor |
10
+ |---|---|
11
+ | Sistema | ndomo plugin (OpenCode) |
12
+ | Fecha de detección | 2026-06-19 |
13
+ | Plan afectado | `7e6659fd-1e54-415d-84d5-ca52804145c5` / `test-plan-creation-2026-06-19` |
14
+ | Sesión smoke test | `ses_test_smoke_2026-06-19` |
15
+ | Sesión OpenCode (no insertada) | `ses_11ef21ff8ffeC9CTJhd8nlcgBP` |
16
+ | Estado actual del plan | `draft` (irreversible) |
17
+
18
+ ## Reproducción
19
+
20
+ 1. Crear plan:
21
+ ```
22
+ plan_create({slug: "test-plan-creation-2026-06-19", title: "...", overview: "..."})
23
+ ```
24
+ → Plan creado en status `draft`.
25
+
26
+ 2. Crear tareas (opcional, no interfiere):
27
+ ```
28
+ task_create_batch({planId: "7e6659fd-...", tasks: [...]})
29
+ ```
30
+ → `task_create_batch` funciona correctamente (no valida sessionId).
31
+
32
+ 3. Intentar aprobar:
33
+ ```
34
+ plan_approve({id: "7e6659fd-1e54-415d-84d5-ca52804145c5"})
35
+ ```
36
+ → Error:
37
+ ```
38
+ ndomo: session_id does not exist: ses_11ef21ff8ffeC9CTJhd8nlcgBP
39
+ ```
40
+
41
+ 4. Intentar cerrar (alternativa, mismo error):
42
+ ```
43
+ plan_update_status({id: "7e6659fd-...", status: "completed"})
44
+ ```
45
+ → Error idéntico:
46
+ ```
47
+ ndomo: session_id does not exist: ses_11ef21ff8ffeC9CTJhd8nlcgBP
48
+ ```
49
+
50
+ ## Comportamiento esperado vs observado
51
+
52
+ | Operación | Esperado | Observado |
53
+ |---|---|---|
54
+ | `plan_approve` | Plan transiciona a `approved` con `approved_at` seteado | Error `session_id does not exist`; plan permanece `draft` |
55
+ | `plan_update_status` | Plan transiciona a `completed`/`failed`/`abandoned` y se auto-archiva | Error `session_id does not exist`; plan permanece `draft` |
56
+ | Auto-archive en terminal status | Markdown generado en `<project>/.ndomo/archives/plans/` | Nunca se invoca (bloqueado por error previo) |
57
+
58
+ ## Causa raíz
59
+
60
+ El bug es un side-effect del **Fix #1** (validación FK de `session_id` introducida para integridad referencial entre `plans` y `sessions`). Las tools MCP pasan `ctx.sessionID` (ID de sesión interno del harness OpenCode) como `opts.sessionId` a las funciones de transición:
61
+
62
+ - `plan_approve` → `src/plugin.ts:649-651`: llama `approvePlan(db, args.id, {sessionId: ctx.sessionID, ...})`.
63
+ - `plan_update_status` → `src/plugin.ts:672-675`: llama `updatePlanStatus(db, args.id, args.status, {sessionId: ctx.sessionID, ...})`.
64
+
65
+ Ambas funciones en `src/db/plans.ts` ejecutan la validación FK:
66
+
67
+ - `updatePlanStatus` → `src/db/plans.ts:118-121`: `SELECT 1 FROM sessions WHERE id = ?` — si no existe fila, lanza error.
68
+ - `approvePlan` → `src/db/plans.ts:159-162`: idéntica validación.
69
+
70
+ La tabla `sessions` solo recibe filas mediante `session_start` explícito (`src/db/sessions.ts:24-38`). El `ctx.sessionID` del harness OpenCode (`ses_11ef21ff8ffeC9CTJhd8nlcgBP`) **nunca es insertado** en `sessions`. Por tanto, cualquier transición de estado que pase `ctx.sessionID` falla.
71
+
72
+ `plan_create` no se ve afectado porque su implementación no valida `sessionId` contra la tabla (`src/plugin.ts:556-592`). `task_create_batch` tampoco valida — solo pasa `planId`.
73
+
74
+ ## Workarounds
75
+
76
+ 1. **Ninguno desde user-side**: El harness OpenCode no expone control sobre `ctx.sessionID`, por lo que no es posible invocar `session_start` con un ID que coincida antes de `plan_approve`.
77
+
78
+ 2. **SQL directo (acceso a DB)**: Si se tiene acceso al archivo `.ndomo/state.db`, se puede insertar manualmente la fila faltante:
79
+ ```sql
80
+ INSERT INTO sessions (id, started_at, last_checkpoint, goal, state, agent_history)
81
+ VALUES ('ses_11ef21ff8ffeC9CTJhd8nlcgBP', 1729300000000, 1729300000000, 'fix orphan plan FK', '{}', '[]');
82
+ ```
83
+ Luego `plan_approve` y `plan_update_status` funcionarán. No es aplicable en producción / entorno multi-agente.
84
+
85
+ 3. **No recomendado**: Deshabilitar la validación FK localmente editando `src/db/plans.ts`. Rompe la integridad referencial y se pierde en el próximo pull.
86
+
87
+ ## Fix propuesto
88
+
89
+ Tres opciones, ordenadas por impacto/costo descendente:
90
+
91
+ ### a) Auto-insertar fila en `sessions` al primer `plan_create`
92
+
93
+ Capturar `ctx.sessionID` en `plan_create` e insertar automáticamente un registro en `sessions` si no existe. Zero-touch para el usuario. Garantiza que toda tool posterior que use el mismo `ctx.sessionID` encuentre la fila. Costo: ~5 líneas en `src/plugin.ts:plan_create`.
94
+
95
+ ### b) Relajar validación con upsert automático (lazy)
96
+
97
+ En `approvePlan` y `updatePlanStatus`, si `opts.sessionId` no existe en `sessions`, hacer un `INSERT OR IGNORE` automático antes de la transición. Similar a (a) pero diferido al momento de la primera transición. Menos intrusivo, pero permite que se cree la fila sin goal ni metadata.
98
+
99
+ ### c) Documentar requisito de `session_start` previo
100
+
101
+ Exigir que toda transición de plan esté precedida por un `session_start` explícito en el mismo flujo. Workaround oficial pero no práctico para el foreman — añade un paso manual frágil.
102
+
103
+ **Opción recomendada**: (a) por simplicidad y cobertura total del lifecycle.
104
+
105
+ ## Impacto
106
+
107
+ - Todo plan creado por el foreman (o cualquier agente) en una sesión de OpenCode sin `session_start` previo queda bloqueado en `draft`.
108
+ - La DB acumula planes `draft` no cerrables que nunca reciben auto-archive.
109
+ - El `plan_update_status` con status terminal (`completed`, `failed`, `abandoned`) nunca se ejecuta, por lo que el auto-archive a markdown (`src/plugin.ts:677-688`) no se dispara.
110
+ - El lifecycle de 10 pasos del foreman (`docs/database.md:202-219`) se rompe en el paso 3 (`plan_approve`).
111
+ - No hay pérdida de datos — los planes existen en DB — pero no se pueden gestionar programáticamente.
112
+
113
+ ## Referencias
114
+
115
+ - Código tool MCP `plan_approve`: `src/plugin.ts:644-655`
116
+ - Código tool MCP `plan_update_status`: `src/plugin.ts:657-689`
117
+ - Validación FK en `updatePlanStatus`: `src/db/plans.ts:117-121`
118
+ - Validación FK en `approvePlan`: `src/db/plans.ts:158-162`
119
+ - Inserción de sesiones solo vía `session_start`: `src/db/sessions.ts:24-38`
120
+ - Tool MCP `plan_create`: `src/plugin.ts:556-592`
121
+ - Plan afectado: `7e6659fd-1e54-415d-84d5-ca52804145c5` / `test-plan-creation-2026-06-19`
122
+ - Sesión OpenCode no insertada: `ses_11ef21ff8ffeC9CTJhd8nlcgBP`
123
+ - Mensaje original del error: `msg_ee10e0bab001kwzDMkf5gpxY7T`
124
+
125
+ ## Status
126
+
127
+ | Campo | Valor |
128
+ |---|---|
129
+ | Estado | `Detected` |
130
+ | Workaround | `none user-side` |
131
+ | Fix | `pending` |
@@ -0,0 +1,158 @@
1
+ # Bug: `task_create_batch` UNIQUE constraint collision on retries/splits
2
+
3
+ ## Resumen
4
+
5
+ `task_create_batch` falla con `UNIQUE constraint failed: plan_tasks.plan_id, plan_tasks.order_index` cuando el caller invoca la tool 2+ veces para el mismo plan (retry post-abort, dispatch cross-step, o re-creación tras abort). El bug también se manifiesta en splits cross-stack cuando los decimales generados colisionan con order_indices existentes.
6
+
7
+ ## Entorno
8
+
9
+ | Atributo | Valor |
10
+ |---|---|
11
+ | Sistema | ndomo plugin (OpenCode) |
12
+ | Fecha de detección | 2026-06-22 |
13
+ | Plan de evidencia | `18252705-9c4e-4f5b-85a8-4f7153ceb101` |
14
+ | Plan de fix | `ca69222a-808a-41b0-9dae-05f7641be308` |
15
+ | Sesión de fix | `ses_craftsman_ca69222a` |
16
+ | Archivos afectados | `src/db/tasks.ts`, `tools/task_create_batch.ts`, `src/plugin.ts` |
17
+
18
+ ## Reproducción
19
+
20
+ 1. Crear plan y poblar con 1 task (1ra invocación de `task_create_batch`):
21
+ ```
22
+ plan_create({slug: "feat-x", title: "...", overview: "..."})
23
+ task_create_batch({planId: "...", tasks: [{description: "task 0", agent: "craftsman"}]})
24
+ ```
25
+ → Task creada en `order_index=0`. OK.
26
+
27
+ 2. Invocar `task_create_batch` nuevamente para el mismo plan (2da invocación):
28
+ ```
29
+ task_create_batch({planId: "...", tasks: [
30
+ {description: "task A", agent: "craftsman"},
31
+ {description: "task B", agent: "js-smith"},
32
+ ...
33
+ ]})
34
+ ```
35
+ → Error:
36
+ ```
37
+ UNIQUE constraint failed: plan_tasks.plan_id, plan_tasks.order_index
38
+ ```
39
+
40
+ 3. El bug también ocurre en splits cross-stack: si un task con files multi-stack genera sub-tasks con `orderIndex = parentOrder + 0.1 * stackIdx`, los decimales pueden colisionar con order_indices existentes.
41
+
42
+ ## Comportamiento esperado vs observado
43
+
44
+ | Operación | Esperado | Observado |
45
+ |---|---|---|
46
+ | 2da invocación de `task_create_batch` | Nuevas tasks asignadas a order_index secuenciales sin colisión | `UNIQUE constraint failed` — transacción abortada |
47
+ | Split cross-stack con decimales ocupados | Sub-tasks reasignadas a slots libres | `UNIQUE constraint failed` si decimal colisiona |
48
+ | Caller pasa `orderIndex` explícito que colisiona | Core reasigna a slot libre | `UNIQUE constraint failed` |
49
+
50
+ ## Causa raíz
51
+
52
+ Doble causa: callers + core confiaban en `orderIndex` del caller sin validación contra DB existente.
53
+
54
+ ### Caller: `orderIndex: idx` forzado
55
+
56
+ Los callers en `tools/task_create_batch.ts:47` y `src/plugin.ts:965` pasaban `orderIndex: idx` desde `array.map((t, idx) => ...)`:
57
+
58
+ ```typescript
59
+ // tools/task_create_batch.ts (ANTES del fix)
60
+ args.tasks.map((t, idx) => ({
61
+ orderIndex: idx, // ← solo único intra-batch, no considera tasks existentes
62
+ ...
63
+ }))
64
+ ```
65
+
66
+ `idx` es 0, 1, 2... dentro del batch, pero no considera tasks ya persistidas en el plan. En la 2da invocación, `idx=0` colisiona con la task existente en `order_index=0`.
67
+
68
+ ### Core: `createTasksBatch` confiaba en caller's `orderIndex`
69
+
70
+ `src/db/tasks.ts:createTasksBatch` usaba `effectiveTask.orderIndex ?? i` como autoridad directa para el INSERT, sin validar contra `plan_tasks` existentes:
71
+
72
+ ```typescript
73
+ // src/db/tasks.ts (ANTES del fix)
74
+ const orderIndex = effectiveTask.orderIndex ?? i;
75
+ db.query(`INSERT INTO plan_tasks ... VALUES (...)`).run(id, planId, orderIndex, ...);
76
+ ```
77
+
78
+ Sin pre-loop `SELECT MAX(order_index)`, sin set de order_indices usados, sin retry on UNIQUE violation.
79
+
80
+ ### Split cross-stack: decimales sin validación
81
+
82
+ El split M7 generaba `orderIndex = (t.orderIndex ?? results.length) + stackIdx * 0.1` sin verificar si los decimales ya existían en la DB.
83
+
84
+ ## Workaround histórico
85
+
86
+ Mientras el fix no estaba aplicado, el foreman usó INSERT directo via `bun:sqlite` con `order_index` explícito pre-calculado desde `MAX+1`:
87
+
88
+ ```typescript
89
+ const db = new Database('.ndomo/state.db');
90
+ const maxRow = db.query("SELECT MAX(order_index) as m FROM plan_tasks WHERE plan_id = ? AND archived_at IS NULL").get(planId);
91
+ let order = (maxRow?.m ?? -1) + 1;
92
+ // for each task: INSERT with order_index=order++ en transacción
93
+ ```
94
+
95
+ 4 tasks del plan `ca69222a` fueron creadas via este workaround. Sus metadatos fueron actualizados con `{bugWorkaroundApplied: true, bugSlug: "task_create_batch-order-index-collision", originalInsertMethod: "bun-sqlite3-direct", fixedIn: "ca69222a-..."}`.
96
+
97
+ ## Fix aplicado
98
+
99
+ **Estrategia**: defense-in-depth en `createTasksBatch` — el core es la autoridad para `order_index`, no el caller.
100
+
101
+ ### Cambios en `src/db/tasks.ts:createTasksBatch`
102
+
103
+ 1. **Pre-loop `SELECT MAX(order_index)`**: calcula `nextFreeInteger` desde el MAX de tasks no-archived.
104
+ 2. **`usedOrderIndices` set**: recolecta TODOS los order_indices existentes (incluyendo archived) para collision detection. El `UNIQUE(plan_id, order_index)` no filtra por `archived_at`.
105
+ 3. **`allocateOrderIndex(preferred)` helper**: intenta el slot preferido del caller; si está ocupado o undefined, cae a `nextFreeInteger` e incrementa hasta encontrar slot libre.
106
+ 4. **`allocateSplitOrderIndex(parentOrder, stackIdx)` helper**: `stackIdx=0` → parentOrder (ya alocado); `stackIdx>0` → `parentOrder + stackIdx * 0.1`; si decimal ocupado → escala a siguiente integer libre.
107
+ 5. **Try/catch SQLITE_CONSTRAINT UNIQUE con retry**: defense-in-depth — si una race condition o edge case produce colisión, reasigna y reintenta (hasta 10 intentos).
108
+ 6. **Signature change**: `orderIndex` ahora es optional en el input type (`Omit<PlanTask, ... | "orderIndex"> & { orderIndex?: number }`).
109
+
110
+ ### Cambios en callers
111
+
112
+ - `tools/task_create_batch.ts`: eliminado `orderIndex: idx` del `.map()`.
113
+ - `src/plugin.ts`: eliminado `orderIndex: idx` del `.map()`.
114
+
115
+ Los callers ahora pasan `orderIndex: undefined` (implícito), y el core aloca dinámicamente.
116
+
117
+ ## Tests de regresión
118
+
119
+ 7 tests añadidos a `src/db/tasks.test.ts`:
120
+
121
+ | Test | Escenario |
122
+ |---|---|
123
+ | (a) | Plan pre-poblado (task en 0) + nueva task con `orderIndex=0` → reasigna a 1 |
124
+ | (b) | Split cross-stack con plan pre-poblado → parent=1, decimal=1.1 |
125
+ | (c) | Split cross-stack con decimales ocupados (0.1, 0.2) → escala a integers 1, 2 |
126
+ | (d) | Caller pasa `orderIndex` colisionante → core reasigna |
127
+ | (e) | Reproduce bug exacto: 1st batch OK, 2nd batch 4 tasks con `orderIndex` colisionante → todas reasignadas |
128
+ | (f) | Caller omite `orderIndex` → core asigna secuencial desde MAX+1 |
129
+ | (g) | Archived task ocupa slot → nueva task evita colisión |
130
+
131
+ ## Lección replicable
132
+
133
+ > Any tool que mapea `array → unique-constraint-key` es unsafe para re-invocación sobre mismo parent. Always: lookup current max/sequence BEFORE generating keys, never trust caller-provided sequential indices.
134
+
135
+ El patrón `array.map((item, idx) => ({ orderIndex: idx, ... }))` es seguro solo intra-batch. Para safety cross-batch, el core debe:
136
+ 1. Query DB state antes de generar keys
137
+ 2. Tratar caller-provided keys como hints, no como autoridad
138
+ 3. Retry on constraint violation con reasignación
139
+
140
+ ## Referencias
141
+
142
+ - Schema constraint: `src/db/schema.ts:53` — `UNIQUE(plan_id, order_index)`
143
+ - Core fix: `src/db/tasks.ts:createTasksBatch` — pre-loop MAX + allocateOrderIndex + allocateSplitOrderIndex + try/catch retry
144
+ - Caller fix (tools): `tools/task_create_batch.ts:44` — eliminado `orderIndex: idx`
145
+ - Caller fix (plugin): `src/plugin.ts:962` — eliminado `orderIndex: idx`
146
+ - Tests: `src/db/tasks.test.ts` — describe "order_index collision-safe allocation"
147
+ - Plan de fix: `ca69222a-808a-41b0-9dae-05f7641be308`
148
+ - Plan de evidencia: `18252705-9c4e-4f5b-85a8-4f7153ceb101`
149
+
150
+ ## Status
151
+
152
+ | Campo | Valor |
153
+ |---|---|
154
+ | Estado | `Resolved` |
155
+ | Workaround | `bun:sqlite direct INSERT con order_index manual` (obsoleto post-fix) |
156
+ | Fix | `ca69222a-808a-41b0-9dae-05f7641be308` — applied 2026-06-22 |
157
+ | Tests | 7 regression tests — 49/49 pass (42 existing + 7 new) |
158
+ | Suite | 356/356 pass (full project) |