@documentation-robotics/cli 0.2.0 → 0.4.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 (335) hide show
  1. package/README.md +46 -16
  2. package/dist/analysis/relationship-classifier.js +2 -9
  3. package/dist/analysis/relationship-classifier.js.map +2 -2
  4. package/dist/analyzers/active-analyzer.js +62 -0
  5. package/dist/analyzers/active-analyzer.js.map +7 -0
  6. package/dist/analyzers/call-graph-utils.js +2 -2
  7. package/dist/analyzers/call-graph-utils.js.map +2 -2
  8. package/dist/analyzers/cards/build.js +191 -0
  9. package/dist/analyzers/cards/build.js.map +7 -0
  10. package/dist/analyzers/cards/classify.js +42 -0
  11. package/dist/analyzers/cards/classify.js.map +7 -0
  12. package/dist/analyzers/cards/edge-index.js +44 -0
  13. package/dist/analyzers/cards/edge-index.js.map +7 -0
  14. package/dist/analyzers/cards/extract.js +138 -0
  15. package/dist/analyzers/cards/extract.js.map +7 -0
  16. package/dist/analyzers/cards/facts.js +46 -0
  17. package/dist/analyzers/cards/facts.js.map +7 -0
  18. package/dist/analyzers/cards/graph.js +42 -0
  19. package/dist/analyzers/cards/graph.js.map +7 -0
  20. package/dist/analyzers/cards/index.js +8 -0
  21. package/dist/analyzers/cards/index.js.map +7 -0
  22. package/dist/analyzers/cards/routes.js +96 -0
  23. package/dist/analyzers/cards/routes.js.map +7 -0
  24. package/dist/analyzers/cards/tier0.js +18 -0
  25. package/dist/analyzers/cards/tier0.js.map +7 -0
  26. package/dist/analyzers/cards/types.js +1 -0
  27. package/dist/analyzers/cards/types.js.map +7 -0
  28. package/dist/analyzers/cbm-analyzer.js +270 -174
  29. package/dist/analyzers/cbm-analyzer.js.map +2 -2
  30. package/dist/analyzers/cbm-responses.js +342 -0
  31. package/dist/analyzers/cbm-responses.js.map +7 -0
  32. package/dist/analyzers/code-changes.js +159 -0
  33. package/dist/analyzers/code-changes.js.map +7 -0
  34. package/dist/analyzers/edge-relationships.js +49 -0
  35. package/dist/analyzers/edge-relationships.js.map +7 -0
  36. package/dist/analyzers/extraction-plan.js +541 -0
  37. package/dist/analyzers/extraction-plan.js.map +7 -0
  38. package/dist/analyzers/index-job.js +229 -0
  39. package/dist/analyzers/index-job.js.map +7 -0
  40. package/dist/analyzers/mapping-loader.js +9 -0
  41. package/dist/analyzers/mapping-loader.js.map +2 -2
  42. package/dist/analyzers/tier0-rules.js +153 -0
  43. package/dist/analyzers/tier0-rules.js.map +7 -0
  44. package/dist/analyzers/types.js.map +1 -1
  45. package/dist/audit/relationships/ai/prompts.js +10 -10
  46. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  47. package/dist/audit/relationships/analysis/layer-templates.js +52 -52
  48. package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
  49. package/dist/cli.js +23 -11
  50. package/dist/cli.js.map +2 -2
  51. package/dist/coding-agents/default-permissions.js +31 -1
  52. package/dist/coding-agents/default-permissions.js.map +2 -2
  53. package/dist/coding-agents/drbot-mcp.js +269 -0
  54. package/dist/coding-agents/drbot-mcp.js.map +7 -0
  55. package/dist/commands/add.js +7 -4
  56. package/dist/commands/add.js.map +2 -2
  57. package/dist/commands/analyzer.js +143 -40
  58. package/dist/commands/analyzer.js.map +2 -2
  59. package/dist/commands/changeset-verify.js +63 -0
  60. package/dist/commands/changeset-verify.js.map +7 -0
  61. package/dist/commands/changeset.js +80 -29
  62. package/dist/commands/changeset.js.map +2 -2
  63. package/dist/commands/delete.js +10 -4
  64. package/dist/commands/delete.js.map +2 -2
  65. package/dist/commands/farm.js +176 -60
  66. package/dist/commands/farm.js.map +2 -2
  67. package/dist/commands/init.js +9 -26
  68. package/dist/commands/init.js.map +2 -2
  69. package/dist/commands/mcp.js +40 -21
  70. package/dist/commands/mcp.js.map +3 -3
  71. package/dist/commands/relationship.js +208 -37
  72. package/dist/commands/relationship.js.map +2 -2
  73. package/dist/commands/reports.js +3 -3
  74. package/dist/commands/reports.js.map +2 -2
  75. package/dist/commands/update.js +52 -32
  76. package/dist/commands/update.js.map +2 -2
  77. package/dist/commands/upgrade.js +99 -103
  78. package/dist/commands/upgrade.js.map +3 -3
  79. package/dist/commands/validate.js +19 -3
  80. package/dist/commands/validate.js.map +2 -2
  81. package/dist/commands/version.js +1 -1
  82. package/dist/commands/visualize.js +34 -15
  83. package/dist/commands/visualize.js.map +2 -2
  84. package/dist/core/annotation-store.js +15 -5
  85. package/dist/core/annotation-store.js.map +2 -2
  86. package/dist/core/catalog-migration.js +34 -0
  87. package/dist/core/catalog-migration.js.map +7 -0
  88. package/dist/core/changeset-analysis.js +421 -0
  89. package/dist/core/changeset-analysis.js.map +7 -0
  90. package/dist/core/changeset-base-index.js +160 -0
  91. package/dist/core/changeset-base-index.js.map +7 -0
  92. package/dist/core/changeset-brief-compact.js +256 -0
  93. package/dist/core/changeset-brief-compact.js.map +7 -0
  94. package/dist/core/changeset-brief-delta.js +102 -0
  95. package/dist/core/changeset-brief-delta.js.map +7 -0
  96. package/dist/core/changeset-graph.js +281 -0
  97. package/dist/core/changeset-graph.js.map +7 -0
  98. package/dist/core/changeset-only-guard.js +32 -0
  99. package/dist/core/changeset-only-guard.js.map +7 -0
  100. package/dist/core/changeset-summary.js +68 -0
  101. package/dist/core/changeset-summary.js.map +7 -0
  102. package/dist/core/changeset-validator.js +66 -20
  103. package/dist/core/changeset-validator.js.map +2 -2
  104. package/dist/core/changeset-verify.js +848 -0
  105. package/dist/core/changeset-verify.js.map +7 -0
  106. package/dist/core/changeset.js +56 -9
  107. package/dist/core/changeset.js.map +2 -2
  108. package/dist/core/element-type-migration.js +145 -0
  109. package/dist/core/element-type-migration.js.map +7 -0
  110. package/dist/core/extraction-observability.js +161 -0
  111. package/dist/core/extraction-observability.js.map +7 -0
  112. package/dist/core/farm-manifest.js +12 -6
  113. package/dist/core/farm-manifest.js.map +2 -2
  114. package/dist/core/farm-sync-engine.js +1 -1
  115. package/dist/core/farm-sync-engine.js.map +2 -2
  116. package/dist/core/farm-sync-state.js +10 -2
  117. package/dist/core/farm-sync-state.js.map +2 -2
  118. package/dist/core/migration-registry.js +88 -47
  119. package/dist/core/migration-registry.js.map +2 -2
  120. package/dist/core/model-upgrade.js +102 -0
  121. package/dist/core/model-upgrade.js.map +7 -0
  122. package/dist/core/model.js +82 -30
  123. package/dist/core/model.js.map +2 -2
  124. package/dist/core/mutation-handler.js +71 -6
  125. package/dist/core/mutation-handler.js.map +2 -2
  126. package/dist/core/project-init.js +53 -0
  127. package/dist/core/project-init.js.map +7 -0
  128. package/dist/core/relationship-migration-table.js +6639 -0
  129. package/dist/core/relationship-migration-table.js.map +7 -0
  130. package/dist/core/relationship-migration.js +272 -0
  131. package/dist/core/relationship-migration.js.map +7 -0
  132. package/dist/core/relationship-prune.js +49 -0
  133. package/dist/core/relationship-prune.js.map +7 -0
  134. package/dist/core/relationship-staging.js +161 -0
  135. package/dist/core/relationship-staging.js.map +7 -0
  136. package/dist/core/relationships.js +26 -4
  137. package/dist/core/relationships.js.map +2 -2
  138. package/dist/core/report-data-model.js +7 -13
  139. package/dist/core/report-data-model.js.map +2 -2
  140. package/dist/core/staged-changeset-storage.js +145 -18
  141. package/dist/core/staged-changeset-storage.js.map +2 -2
  142. package/dist/core/staged-source-reference.js +28 -0
  143. package/dist/core/staged-source-reference.js.map +7 -0
  144. package/dist/core/staging-area.js +166 -24
  145. package/dist/core/staging-area.js.map +2 -2
  146. package/dist/core/upgrade-plan.js +117 -0
  147. package/dist/core/upgrade-plan.js.map +7 -0
  148. package/dist/core/virtual-projection.js +13 -5
  149. package/dist/core/virtual-projection.js.map +2 -2
  150. package/dist/export/archimate-exporter.js +1 -0
  151. package/dist/export/archimate-exporter.js.map +2 -2
  152. package/dist/generated/compiled-validators.js +2 -2
  153. package/dist/generated/compiled-validators.js.map +2 -2
  154. package/dist/generated/layer-registry.js +16 -16
  155. package/dist/generated/layer-registry.js.map +2 -2
  156. package/dist/generated/node-types.js +186 -168
  157. package/dist/generated/node-types.js.map +2 -2
  158. package/dist/generated/relationship-index.js +2468 -7913
  159. package/dist/generated/relationship-index.js.map +2 -2
  160. package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
  161. package/dist/integrations/claude_code/agents/dr-architect.md +30 -3
  162. package/dist/integrations/claude_code/agents/dr-extractor.md +8 -2
  163. package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
  164. package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
  165. package/dist/integrations/claude_code/commands/dr-map.md +20 -1
  166. package/dist/integrations/claude_code/commands/dr-plan.md +66 -0
  167. package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
  168. package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
  169. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
  170. package/dist/integrations/claude_code/docs/MCP_SERVER.md +47 -26
  171. package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
  172. package/dist/integrations/claude_code/docs/README.md +68 -2
  173. package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
  174. package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
  175. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
  176. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
  177. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
  178. package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
  179. package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
  180. package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
  181. package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
  182. package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
  183. package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
  184. package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
  185. package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
  186. package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
  187. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +95 -15
  188. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +178 -0
  189. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +8 -0
  190. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +6 -1
  191. package/dist/integrations/github_copilot/agents/dr-architect.md +3 -1
  192. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
  193. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
  194. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
  195. package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
  196. package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
  197. package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
  198. package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
  199. package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
  200. package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
  201. package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
  202. package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
  203. package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
  204. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +225 -102
  205. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +177 -0
  206. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
  207. package/dist/integrations/hash-utils.js.map +2 -2
  208. package/dist/mcp/api-key-manager.js +14 -1
  209. package/dist/mcp/api-key-manager.js.map +2 -2
  210. package/dist/mcp/changeset-only.js +45 -0
  211. package/dist/mcp/changeset-only.js.map +7 -0
  212. package/dist/mcp/project-root.js +85 -0
  213. package/dist/mcp/project-root.js.map +7 -0
  214. package/dist/mcp/server-instructions.js +27 -0
  215. package/dist/mcp/server-instructions.js.map +7 -0
  216. package/dist/mcp/strict-schema.js +52 -0
  217. package/dist/mcp/strict-schema.js.map +7 -0
  218. package/dist/mcp/tool-registry.js +55 -5
  219. package/dist/mcp/tool-registry.js.map +2 -2
  220. package/dist/mcp/tools/changeset-analysis-tools.js +98 -0
  221. package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
  222. package/dist/mcp/tools/changeset-commit.js +224 -0
  223. package/dist/mcp/tools/changeset-commit.js.map +7 -0
  224. package/dist/mcp/tools/changeset-editing.js +260 -0
  225. package/dist/mcp/tools/changeset-editing.js.map +7 -0
  226. package/dist/mcp/tools/changeset-lifecycle.js +83 -0
  227. package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
  228. package/dist/mcp/tools/changeset-shared.js +31 -0
  229. package/dist/mcp/tools/changeset-shared.js.map +7 -0
  230. package/dist/mcp/tools/changeset-show.js +17 -1
  231. package/dist/mcp/tools/changeset-show.js.map +2 -2
  232. package/dist/mcp/tools/changeset-verify.js +49 -0
  233. package/dist/mcp/tools/changeset-verify.js.map +7 -0
  234. package/dist/mcp/tools/codebase-extract.js +836 -0
  235. package/dist/mcp/tools/codebase-extract.js.map +7 -0
  236. package/dist/mcp/tools/codebase-index.js +125 -0
  237. package/dist/mcp/tools/codebase-index.js.map +7 -0
  238. package/dist/mcp/tools/codebase-shared.js +265 -0
  239. package/dist/mcp/tools/codebase-shared.js.map +7 -0
  240. package/dist/mcp/tools/codebase-verify.js +48 -0
  241. package/dist/mcp/tools/codebase-verify.js.map +7 -0
  242. package/dist/mcp/tools/index.js +34 -1
  243. package/dist/mcp/tools/index.js.map +2 -2
  244. package/dist/mcp/tools/model-add.js +191 -74
  245. package/dist/mcp/tools/model-add.js.map +2 -2
  246. package/dist/mcp/tools/model-delete.js +2 -2
  247. package/dist/mcp/tools/model-delete.js.map +2 -2
  248. package/dist/mcp/tools/model-search.js +14 -0
  249. package/dist/mcp/tools/model-search.js.map +2 -2
  250. package/dist/mcp/tools/model-show.js +29 -2
  251. package/dist/mcp/tools/model-show.js.map +2 -2
  252. package/dist/mcp/tools/model-trace.js +93 -30
  253. package/dist/mcp/tools/model-trace.js.map +2 -2
  254. package/dist/mcp/tools/model-update.js +46 -26
  255. package/dist/mcp/tools/model-update.js.map +2 -2
  256. package/dist/mcp/tools/model-validate.js +46 -4
  257. package/dist/mcp/tools/model-validate.js.map +2 -2
  258. package/dist/mcp/tools/project-status-collectors.js +381 -0
  259. package/dist/mcp/tools/project-status-collectors.js.map +7 -0
  260. package/dist/mcp/tools/project-status.js +237 -0
  261. package/dist/mcp/tools/project-status.js.map +7 -0
  262. package/dist/mcp/tools/project-tools.js +505 -0
  263. package/dist/mcp/tools/project-tools.js.map +7 -0
  264. package/dist/mcp/tools/relationship-tools.js +167 -0
  265. package/dist/mcp/tools/relationship-tools.js.map +7 -0
  266. package/dist/mcp/tools/review-open.js +210 -0
  267. package/dist/mcp/tools/review-open.js.map +7 -0
  268. package/dist/mcp/tools/shared.js +35 -4
  269. package/dist/mcp/tools/shared.js.map +2 -2
  270. package/dist/mcp/tools/spec-type.js +90 -0
  271. package/dist/mcp/tools/spec-type.js.map +7 -0
  272. package/dist/reports/model-report-orchestrator.js +31 -2
  273. package/dist/reports/model-report-orchestrator.js.map +2 -2
  274. package/dist/schemas/bundled/analyzers/cbm.json +1200 -70
  275. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  276. package/dist/schemas/bundled/api.json +1029 -1658
  277. package/dist/schemas/bundled/apm.json +499 -734
  278. package/dist/schemas/bundled/application.json +735 -371
  279. package/dist/schemas/bundled/base.json +3 -220
  280. package/dist/schemas/bundled/business.json +452 -366
  281. package/dist/schemas/bundled/data-model.json +395 -411
  282. package/dist/schemas/bundled/data-store.json +334 -558
  283. package/dist/schemas/bundled/manifest.json +18 -18
  284. package/dist/schemas/bundled/motivation.json +349 -368
  285. package/dist/schemas/bundled/navigation.json +415 -731
  286. package/dist/schemas/bundled/product.json +325 -159
  287. package/dist/schemas/bundled/security.json +864 -1232
  288. package/dist/schemas/bundled/technology.json +574 -703
  289. package/dist/schemas/bundled/testing.json +865 -1646
  290. package/dist/schemas/bundled/ux.json +739 -1352
  291. package/dist/server/schemas.js +8 -0
  292. package/dist/server/schemas.js.map +2 -2
  293. package/dist/server/server.js +686 -231
  294. package/dist/server/server.js.map +3 -3
  295. package/dist/server/viewer-registry.js +264 -0
  296. package/dist/server/viewer-registry.js.map +7 -0
  297. package/dist/server-entry.js +2 -1
  298. package/dist/server-entry.js.map +2 -2
  299. package/dist/telemetry/index.js +1 -1
  300. package/dist/utils/ansi-suppressor.js +6 -8
  301. package/dist/utils/ansi-suppressor.js.map +2 -2
  302. package/dist/utils/attribute-patch.js +41 -0
  303. package/dist/utils/attribute-patch.js.map +7 -0
  304. package/dist/utils/error-hints.js +29 -0
  305. package/dist/utils/error-hints.js.map +7 -0
  306. package/dist/utils/errors.js +9 -3
  307. package/dist/utils/errors.js.map +2 -2
  308. package/dist/utils/id-generator.js +5 -2
  309. package/dist/utils/id-generator.js.map +2 -2
  310. package/dist/utils/project-paths.js +26 -1
  311. package/dist/utils/project-paths.js.map +2 -2
  312. package/dist/utils/source-reference.js +64 -31
  313. package/dist/utils/source-reference.js.map +2 -2
  314. package/dist/utils/spec-version.js +2 -2
  315. package/dist/utils/spec-version.js.map +1 -1
  316. package/dist/validators/composed-reference-validator.js +5 -27
  317. package/dist/validators/composed-reference-validator.js.map +2 -2
  318. package/dist/validators/model-warnings.js +28 -0
  319. package/dist/validators/model-warnings.js.map +7 -0
  320. package/dist/validators/reference-validator.js +0 -7
  321. package/dist/validators/reference-validator.js.map +2 -2
  322. package/dist/validators/relationship-schema-validator.js +3 -3
  323. package/dist/validators/relationship-schema-validator.js.map +2 -2
  324. package/dist/validators/schema-validator.js +27 -9
  325. package/dist/validators/schema-validator.js.map +2 -2
  326. package/dist/validators/types.js.map +1 -1
  327. package/dist/viewer/README.md +6 -6
  328. package/dist/viewer/assets/main-CUOQGGRA.css +1 -0
  329. package/dist/viewer/assets/main-DvH3gYrI.js +84 -0
  330. package/dist/viewer/index.html +2 -2
  331. package/dist/viewer/manifest.json +10 -10
  332. package/dist/viewer/version.json +1 -1
  333. package/package.json +2 -1
  334. package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
  335. package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
@@ -11,13 +11,13 @@ triggers:
11
11
  "test strategy",
12
12
  "coverage model"
13
13
  ]
14
- version: 0.8.1
14
+ version: 0.8.3
15
15
  ---
16
16
 
17
17
  # Testing Layer Skill
18
18
 
19
19
  **Layer Number:** 12
20
- **Specification:** Metadata Model Spec v0.8.1
20
+ **Specification:** Metadata Model Spec v0.8.3
21
21
  **Purpose:** Defines test coverage using ISP (Input Space Partitioning) Coverage Model, specifying coverage requirements, test cases, and input partitions.
22
22
 
23
23
  ---
@@ -30,7 +30,7 @@ The Testing Layer captures **test coverage strategy**:
30
30
  - **COVERAGE TARGETS** - What needs testing (APIs, features, data)
31
31
  - **INPUT PARTITIONS** - Partition input space for systematic coverage
32
32
  - **TEST CASES** - Concrete test case sketches
33
- - **CONTEXT VARIATIONS** - Environmental and contextual variations
33
+ - **CONTEXT VARIATIONS** - Test strategy variation types (functional, load, security, regression, smoke, exploratory)
34
34
  - **COVERAGE GAPS** - Identified gaps in coverage
35
35
 
36
36
  This layer uses **ISP Coverage Model** (systematic input space partitioning).
@@ -44,26 +44,86 @@ This layer uses **ISP Coverage Model** (systematic input space partitioning).
44
44
  > **CLI Introspection:** Run `dr schema types testing` for the authoritative, always-current list of node types.
45
45
  > Run `dr schema node <type-id>` for full attribute details on any type.
46
46
 
47
- ### Core Testing Entities (17 entities)
48
-
49
- | Entity Type | Description |
50
- | --------------------------- | ---------------------------------------- |
51
- | **TestCoverageModel** | Root coverage model for system/component |
52
- | **TestCoverageTarget** | What needs testing (API, feature, data) |
53
- | **InputSpacePartition** | Partition of input space |
54
- | **PartitionValue** | Value/range within partition |
55
- | **InputPartitionSelection** | Selected partition values for coverage |
56
- | **CoverageRequirement** | Specific coverage requirement |
57
- | **TestCaseSketch** | High-level test case description |
58
- | **OutcomeCategory** | Expected outcome categories |
59
- | **ContextVariation** | Environmental/contextual variation |
60
- | **EnvironmentFactor** | Environment-specific factor |
61
- | **PartitionDependency** | Dependencies between partitions |
62
- | **CoverageGap** | Identified gap in coverage |
63
- | **CoverageExclusion** | Explicitly excluded coverage |
64
- | **CoverageSummary** | Summary of coverage status |
65
- | **TargetCoverageSummary** | Coverage summary for target |
66
- | **TargetInputField** | Input field for target |
47
+ ### Core Testing Entities (17 types)
48
+
49
+ | Entity Type | Description |
50
+ | --------------------------- | ------------------------------------------------------------------------------ |
51
+ | **TestCoverageModel** | Root coverage model for system/component |
52
+ | **TestCoverageTarget** | What needs testing (API, feature, data) |
53
+ | **InputSpacePartition** | Partition of input space |
54
+ | **PartitionValue** | Value/range within partition |
55
+ | **InputPartitionSelection** | Selected partition values for coverage |
56
+ | **InputSelection** | Concrete resolved input value chosen from a partition for a specific test case |
57
+ | **CoverageRequirement** | Specific coverage requirement |
58
+ | **TestCaseSketch** | High-level test case description |
59
+ | **OutcomeCategory** | Expected outcome categories |
60
+ | **ContextVariation** | Environmental/contextual variation |
61
+ | **EnvironmentFactor** | Environment-specific factor |
62
+ | **PartitionDependency** | Dependencies between partitions |
63
+ | **CoverageGap** | Identified gap in coverage |
64
+ | **CoverageExclusion** | Explicitly excluded coverage |
65
+ | **CoverageSummary** | Summary of coverage status |
66
+ | **TargetCoverageSummary** | Coverage summary for target |
67
+ | **TargetInputField** | Input field for target |
68
+
69
+ ---
70
+
71
+ ## Type Decision Tree
72
+
73
+ Use this decision tree **before assigning a type** to any testing concept.
74
+
75
+ ```
76
+ IS this the root coverage plan for a system, service, or feature?
77
+ → testing.testcoveragemodel
78
+
79
+ IS this a specific thing being tested (an API operation, feature, workflow, data field)?
80
+ → testing.testcoveragetarget
81
+
82
+ IS this a division of an input field's possible values (valid/invalid/boundary ranges)?
83
+ → testing.inputspacepartition
84
+
85
+ IS this one specific value or boundary within a partition?
86
+ → testing.partitionvalue
87
+
88
+ IS this a constraint that links partition values to other partitions (e.g., field B depends on field A)?
89
+ → testing.partitiondependency
90
+
91
+ IS this a declarative selection of which partition values to exercise in a test run?
92
+ → testing.inputpartitionselection
93
+
94
+ IS this a single concrete resolved value chosen from a partition for a specific test case?
95
+ → testing.inputselection
96
+
97
+ IS this an overall coverage requirement (criteria like "each-choice", "pairwise")?
98
+ → testing.coveragerequirement
99
+
100
+ IS this a concrete high-level description of a single test case?
101
+ → testing.testcasesketch
102
+
103
+ IS this a category of expected outcomes (success, error, edge-case)?
104
+ → testing.outcomecategory
105
+
106
+ IS this a test strategy variation type — functional, load, security, regression, smoke, or exploratory testing?
107
+ → testing.contextvariation
108
+
109
+ IS this a concrete environmental setting with a specific value (e.g., os=Linux, locale=en-US, network=low-bandwidth)?
110
+ → testing.environmentfactor
111
+
112
+ IS this an input field on a target that is mapped to partitions?
113
+ → testing.targetinputfield
114
+
115
+ IS this an identified gap — something that should be tested but is not?
116
+ → testing.coveragegap
117
+
118
+ IS this a deliberate decision to NOT test something, with documented rationale?
119
+ → testing.coverageexclusion
120
+
121
+ IS this a rollup of coverage metrics across all targets?
122
+ → testing.coveragesummary
123
+
124
+ IS this a per-target rollup of sketch/implementation/automation counts?
125
+ → testing.targetcoveragesummary
126
+ ```
67
127
 
68
128
  ---
69
129
 
@@ -79,22 +139,88 @@ Activate when the user:
79
139
 
80
140
  ---
81
141
 
82
- ## Cross-Layer Relationships
83
-
84
- **Outgoing (Testing → Other Layers):**
142
+ ## Intra-Layer Relationships
143
+
144
+ Each testing type has one composing parent. The model composes targets, partitions, context
145
+ variations, environment factors, exclusions and the summary; a target composes its input fields,
146
+ outcome categories, coverage requirements and test case sketches. A sketch `validates` the one
147
+ requirement it exercises and `references` its context variation and outcome category. Only target
148
+ input fields reference the field under test, so partitions stay reusable. Summaries report with
149
+ `references` and `aggregates`; they never `validates`.
150
+
151
+ | Source Type | Predicate | Target Type | Example |
152
+ | ----------------------- | ---------- | ----------------------- | ------------------------------------------------------------------------- |
153
+ | TestCoverageModel | composes | TestCoverageTarget | "Login API Coverage Model" composes "Login Endpoint Coverage" |
154
+ | TestCoverageModel | composes | ContextVariation | "Login API Coverage Model" composes "Security Testing" |
155
+ | TestCoverageModel | composes | EnvironmentFactor | "Login API Coverage Model" composes "Rate Limiter Enabled" |
156
+ | TestCoverageModel | composes | InputSpacePartition | "Login API Coverage Model" composes "Email Format Partition" |
157
+ | TestCoverageModel | composes | CoverageExclusion | "Login API Coverage Model" composes "SSO Login Out Of Scope" |
158
+ | TestCoverageModel | composes | CoverageSummary | "Login API Coverage Model" composes "Login Coverage Summary" |
159
+ | TestCoverageTarget | composes | TargetInputField | "Login Endpoint Coverage" composes "email field" |
160
+ | TestCoverageTarget | composes | OutcomeCategory | "Login Endpoint Coverage" composes "Invalid Credentials (401)" |
161
+ | TestCoverageTarget | composes | CoverageRequirement | "Login Endpoint Coverage" composes "Pairwise Credentials" |
162
+ | TestCoverageTarget | composes | TestCaseSketch | "Login Endpoint Coverage" composes "Valid Login Test Case" |
163
+ | TargetInputField | references | InputSpacePartition | "email field" references "Email Format Partition" |
164
+ | InputSpacePartition | composes | PartitionValue | "Email Format Partition" composes "Malformed Email" |
165
+ | PartitionDependency | references | PartitionValue | "Locked Account Requires Valid Email" references "Locked Account" |
166
+ | PartitionDependency | references | InputSpacePartition | "Locked Account Requires Valid Email" references "Email Format Partition" |
167
+ | CoverageRequirement | composes | InputPartitionSelection | "Pairwise Credentials" composes "Email x Password Selection" |
168
+ | CoverageRequirement | references | OutcomeCategory | "Pairwise Credentials" references "Invalid Credentials (401)" |
169
+ | CoverageRequirement | references | ContextVariation | "Pairwise Credentials" references "Security Testing" |
170
+ | InputPartitionSelection | references | PartitionValue | "Email x Password Selection" references "Malformed Email" |
171
+ | TestCaseSketch | validates | CoverageRequirement | "Valid Login Test Case" validates "Pairwise Credentials" |
172
+ | TestCaseSketch | composes | InputSelection | "Valid Login Test Case" composes "Valid Email + Valid Password" |
173
+ | InputSelection | references | PartitionValue | "Valid Email + Valid Password" references "Well-Formed Email" |
174
+ | TestCaseSketch | references | OutcomeCategory | "Valid Login Test Case" references "Success (200 + JWT)" |
175
+ | TestCaseSketch | references | ContextVariation | "Brute Force Lockout Test" references "Security Testing" |
176
+ | ContextVariation | references | EnvironmentFactor | "Security Testing" references "Rate Limiter Enabled" |
177
+ | CoverageGap | references | CoverageRequirement | "No MFA Cases" references "Pairwise Credentials" |
178
+ | CoverageExclusion | references | TestCoverageTarget | "SSO Login Out Of Scope" references "Login Endpoint Coverage" |
179
+ | CoverageExclusion | references | CoverageGap | "SSO Login Out Of Scope" references "No SSO Cases" |
180
+ | TargetCoverageSummary | references | TestCoverageTarget | "Login Endpoint Rollup" references "Login Endpoint Coverage" |
181
+ | TargetCoverageSummary | references | CoverageGap | "Login Endpoint Rollup" references "No MFA Cases" |
182
+ | CoverageSummary | aggregates | TargetCoverageSummary | "Login Coverage Summary" aggregates "Login Endpoint Rollup" |
85
183
 
86
- - `motivation.supports-goals` → Motivation Layer (quality goals)
87
- - `motivation.fulfills-requirements` → Motivation Layer (test requirements)
88
- - `business.covers-process` → Business Layer (process coverage)
89
- - `api.tests-operation` → API Layer (API endpoint testing)
90
- - `data.validates-schema` → Data Model Layer (data validation)
91
- - `ux.tests-view` → UX Layer (UI testing)
92
-
93
- **Incoming (Other Layers → Testing):**
184
+ ---
94
185
 
95
- - Motivation Layer → Testing (requirements drive coverage)
96
- - API Layer → Testing (operations need test coverage)
97
- - Business Layer → Testing (processes need testing)
186
+ ## Cross-Layer References
187
+
188
+ ### Outgoing References (Testing → Other Layers)
189
+
190
+ A target `covers` the production artifact it names; a sketch `tests` what it exercises. The model
191
+ covers only the application component, UX application or API document it is for. Requirements and
192
+ summaries reach no other layer. Only the model and test case sketches link to motivation.
193
+
194
+ | Source Type | Predicate | Target Type | Example |
195
+ | ------------------ | ---------------- | ---------------------------------- | --------------------------------------------------------------------- |
196
+ | TestCoverageModel | covers | `application.applicationcomponent` | "Login API Coverage Model" covers "Auth Service" |
197
+ | TestCoverageModel | covers | `api.openapidocument` | "Login API Coverage Model" covers "Auth API" |
198
+ | TestCoverageModel | supports | `motivation.goal` | "Login API Coverage Model" supports "Secure Customer Access" |
199
+ | TestCoverageModel | satisfies | `motivation.requirement` | "Login API Coverage Model" satisfies "Auth Must Be Regression Tested" |
200
+ | TestCoverageModel | measures-outcome | `motivation.outcome` | "Login API Coverage Model" measures-outcome "Fewer Auth Incidents" |
201
+ | TestCoverageTarget | covers | `api.operation` | "Login Endpoint Coverage" covers "POST /auth/login" |
202
+ | TestCoverageTarget | covers | `product.feature` | "Password Reset Coverage" covers "Self-Service Password Reset" |
203
+ | TestCoverageTarget | covers | `ux.view` | "Login Screen Coverage" covers "Login View" |
204
+ | TestCoverageTarget | covers | `data-store.storedlogic` | "Order Total Trigger Coverage" covers "recalc_order_total" |
205
+ | TestCaseSketch | tests | `api.operation` | "Valid Login Test Case" tests "POST /auth/login" |
206
+ | TestCaseSketch | tests | `api.response` | "Invalid Password Test" tests "401 Unauthorized" |
207
+ | TestCaseSketch | tests | `business.businessprocess` | "Complete Checkout E2E" tests "Order Checkout" |
208
+ | TestCaseSketch | tests | `ux.view` | "Login Form Renders Errors" tests "Login View" |
209
+ | TestCaseSketch | tests | `navigation.route` | "Deep Link To Profile" tests "User Profile Route" |
210
+ | TestCaseSketch | tests | `security.threat` | "Brute Force Lockout Test" tests "Credential Stuffing" |
211
+ | TestCaseSketch | tests | `data-model.schemadefinition` | "Reject Unknown Order Fields" tests "Order Schema" |
212
+ | TestCaseSketch | tests | `data-model.objectschema` | "Order Total Is Never Negative" tests "Order" |
213
+ | TestCaseSketch | tests | `data-store.accesspattern` | "Find Owners By Last Name" tests "findByLastName" |
214
+ | TestCaseSketch | tests | `application.applicationcomponent` | "Pet Type Formatter Parses Names" tests "PetTypeFormatter" |
215
+ | TestCaseSketch | satisfies | `motivation.requirement` | "Brute Force Lockout Test" satisfies "Lock After 5 Failures" |
216
+ | TestCaseSketch | accesses | `data-store.collection` | "Order History Test" accesses `orders` |
217
+ | TargetInputField | references | `api.parameter` | "email field" references "email parameter" |
218
+ | TargetInputField | references | `data-model.schemaproperty` | "email field" references "User.email" |
219
+ | EnvironmentFactor | references | `technology.systemsoftware` | "PostgreSQL 16" references "PostgreSQL" |
220
+
221
+ ### Incoming References (Other Layers → Testing)
222
+
223
+ None. Testing is a leaf layer: other layers do not hold relationships pointing into it. Record traceability from the testing side (e.g. `TestCaseSketch tests api.operation`).
98
224
 
99
225
  ---
100
226
 
@@ -114,22 +240,22 @@ Activate when the user:
114
240
 
115
241
  ```bash
116
242
  # Add coverage model
117
- dr add testing test-coverage-model --name "API Coverage Model"
243
+ dr add testing testcoveragemodel "API Coverage Model"
118
244
 
119
245
  # Add coverage target
120
- dr add testing test-coverage-target --name "Login API Coverage"
246
+ dr add testing testcoveragetarget "Login API Coverage"
121
247
 
122
248
  # Add test case sketch
123
- dr add testing test-case-sketch --name "Valid Login Test"
249
+ dr add testing testcasesketch "Valid Login Test"
124
250
 
125
251
  # List coverage models
126
- dr list testing test-coverage-model
252
+ dr list testing --type testcoveragemodel
127
253
 
128
254
  # Validate testing layer
129
- dr validate --layer testing
255
+ dr validate --layers testing
130
256
 
131
257
  # Export coverage report
132
- dr export --layer testing --format markdown
258
+ dr export markdown --layers testing
133
259
  ```
134
260
 
135
261
  ---
@@ -137,22 +263,16 @@ dr export --layer testing --format markdown
137
263
  ## Example: Login API Coverage Model
138
264
 
139
265
  ```yaml
140
- id: testing.coverage-model.login-api
266
+ id: testing.testcoveragemodel.login-api
141
267
  name: "Login API Coverage Model"
142
- type: test-coverage-model
268
+ type: testcoveragemodel
143
269
  properties:
144
- targets:
145
- - testing.target.login-endpoint
146
- coverageCriteria: each-choice
147
- contextVariations:
148
- - browser: [Chrome, Firefox, Safari]
149
- - network: [high-speed, low-speed, offline]
150
- - device: [desktop, mobile, tablet]
151
- motivation:
152
- supports-goals:
153
- - motivation.goal.quality-assurance
154
- fulfills-requirements:
155
- - motivation.requirement.comprehensive-testing
270
+ version: "1.0"
271
+ description: "ISP coverage model for the Login API"
272
+ ```
273
+
274
+ ```bash
275
+ dr relationship add testing.testcoveragemodel.login-api application.applicationcomponent.auth-service --predicate covers
156
276
  ```
157
277
 
158
278
  ---
@@ -160,33 +280,18 @@ properties:
160
280
  ## Example: Login Test Coverage Target
161
281
 
162
282
  ```yaml
163
- id: testing.target.login-endpoint
283
+ id: testing.testcoveragetarget.login-endpoint
164
284
  name: "Login Endpoint Coverage"
165
- type: test-coverage-target
285
+ type: testcoveragetarget
166
286
  properties:
167
- targetRef: api.operation.login
168
- inputFields:
169
- - name: email
170
- partitions:
171
- - valid-email: [user@example.com]
172
- - invalid-format: [notanemail, @example.com]
173
- - missing: [null, empty]
174
- - name: password
175
- partitions:
176
- - valid-password: [StrongPass123!]
177
- - weak-password: [123, abc]
178
- - missing: [null, empty]
179
- - too-long: [1000-char-string]
180
- outcomeCategories:
181
- - success: 200 OK with auth token
182
- - invalid-credentials: 401 Unauthorized
183
- - validation-error: 400 Bad Request
184
- - rate-limited: 429 Too Many Requests
185
- testCases:
186
- - testing.test-case.valid-login
187
- - testing.test-case.invalid-email
188
- - testing.test-case.invalid-password
189
- - testing.test-case.missing-credentials
287
+ targetType: api-endpoint
288
+ description: "POST /auth/login — validates credentials and returns a JWT"
289
+ priority: critical
290
+ ```
291
+
292
+ ```bash
293
+ dr relationship add testing.testcoveragemodel.login-api testing.testcoveragetarget.login-endpoint --predicate composes
294
+ dr relationship add testing.testcoveragetarget.login-endpoint api.operation.login --predicate covers
190
295
  ```
191
296
 
192
297
  ---
@@ -194,30 +299,48 @@ properties:
194
299
  ## Example: Test Case Sketch
195
300
 
196
301
  ```yaml
197
- id: testing.test-case.valid-login
302
+ id: testing.testcasesketch.valid-login
198
303
  name: "Valid Login Test Case"
199
- type: test-case-sketch
304
+ type: testcasesketch
200
305
  properties:
201
- target: testing.target.login-endpoint
202
- description: "Test successful login with valid credentials"
203
- inputSelection:
204
- email: valid-email
205
- password: valid-password
206
- contextSelection:
207
- browser: Chrome
208
- network: high-speed
209
- device: desktop
210
- expectedOutcome: success
211
- expectedResponse:
212
- status: 200
213
- body:
214
- token: JWT token present
215
- user: User object with id and email
216
- motivation:
217
- supports-goals:
218
- - motivation.goal.secure-authentication
306
+ status: draft
307
+ description: "Successful login with valid email and password returns 200 with JWT"
308
+ implementationFormat: automated
219
309
  ```
220
310
 
311
+ ```bash
312
+ dr relationship add testing.testcoveragetarget.login-endpoint testing.testcasesketch.valid-login --predicate composes
313
+ dr relationship add testing.testcasesketch.valid-login testing.coveragerequirement.pairwise-credentials --predicate validates
314
+ dr relationship add testing.testcasesketch.valid-login api.operation.login --predicate tests
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Coverage Completeness Checklist
320
+
321
+ Before declaring testing layer extraction complete, verify each type was considered:
322
+
323
+ - [ ] **testcoveragemodel** — Root coverage model exists for each major system or component under test
324
+ - [ ] **testcoveragetarget** — All APIs, features, workflows, and data paths being tested are captured
325
+ - [ ] **inputspacepartition** — Input fields on each target have their value space partitioned
326
+ - [ ] **partitionvalue** — Each partition has concrete representative values and boundary cases
327
+ - [ ] **partitiondependency** — Cross-field constraints between partitions are documented
328
+ - [ ] **inputpartitionselection** — Coverage selections specify which partition values are exercised
329
+ - [ ] **inputselection** — Concrete resolved inputs are selected for each test case sketch
330
+ - [ ] **coveragerequirement** — Coverage criteria (each-choice, pairwise, etc.) are specified
331
+ - [ ] **testcasesketch** — High-level test case sketches cover the required combinations
332
+ - [ ] **outcomecategory** — Expected outcome categories (success, error, edge) are defined per target
333
+ - [ ] **contextvariation** — Test strategy variation types (functional, load, security, regression, smoke, exploratory) are captured
334
+ - [ ] **environmentfactor** — Specific factor values for each context variation are recorded
335
+ - [ ] **targetinputfield** — Input fields on coverage targets are explicitly mapped to partitions
336
+ - [ ] **coveragegap** — Known gaps in coverage are documented with severity and affected requirements
337
+ - [ ] **coverageexclusion** — Deliberate out-of-scope decisions are recorded with rationale and approver
338
+ - [ ] **coveragesummary** — An overall coverage summary exists if aggregated metrics are needed
339
+ - [ ] **targetcoveragesummary** — Per-target coverage rollups exist for targets with tracked implementation
340
+
341
+ If any type has ZERO elements, explicitly decide:
342
+ "This type doesn't apply to this codebase" with reasoning.
343
+
221
344
  ---
222
345
 
223
346
  ## Pitfalls to Avoid
@@ -0,0 +1,177 @@
1
+ ---
2
+ name: dr_change_planning
3
+ description: Plan a code change as a staged DR changeset through the dr MCP server, pressure-test it against the model, build from its brief, and verify the build against it. Use when asked to plan, design or scope a change in a project with a DR model.
4
+ triggers:
5
+ [
6
+ "plan this change",
7
+ "plan the change",
8
+ "plan a change",
9
+ "plan this feature",
10
+ "how should we build",
11
+ "scope this change",
12
+ "design this change",
13
+ "draft a changeset",
14
+ "changeset brief"
15
+ ]
16
+ ---
17
+
18
+ # Plan a change as a DR changeset
19
+
20
+ In a project with a DR model (`documentation-robotics/model/`), a plan is a staged changeset, not a
21
+ prose document. The changeset says what the change will build. The model says what is built. The
22
+ graph checks the plan for you. The full design is `docs/CHANGE_MODELING.md` in the DR repository.
23
+
24
+ ## Before you start
25
+
26
+ - You need the `dr` MCP server (`dr mcp`, registered in Copilot's MCP configuration; see
27
+ `integrations/claude_code/docs/MCP_SERVER.md`). The
28
+ tool names below are the server's own; Copilot may show them with a server prefix. If the tools
29
+ are missing, tell the user to register the server and stop. Don't fall back to prose.
30
+ - Staging writes files under `documentation-robotics/changesets/`.
31
+ - If the project has no model yet, propose a name and confirm it with the human before
32
+ `project_init`. Then ask whether to bootstrap the model from the code now or let it grow with
33
+ each change, and wait for their answer.
34
+ - When `codebase_extract` returns cards (in a bootstrap, or when you verify), ask the developer about
35
+ the ones you can't place with confidence: whether a card is a model element at all, which type it
36
+ is, or whether to reject it. Don't guess. Collect them and ask once, in one short list (the card,
37
+ your best guess, the question), then stage or reject from the answers.
38
+ - You never land or discard the plan on your own. Commit it (`changeset_commit`) only when the
39
+ human asks you to land it; they confirm it in a dialog. Apply is not an MCP tool. Discard only when
40
+ they agree.
41
+
42
+ ## The loop
43
+
44
+ 1. **Frame.** `changeset_list` first: if a changeset for this change exists, `changeset_activate` it
45
+ and continue. Otherwise propose a short kebab-case `name` and a `description` that states the
46
+ intent (what the change is for and what done looks like), and confirm both with the human before
47
+ you call `changeset_create` with them. Wait for their answer. Find the goal,
48
+ requirement or feature it serves (`model_search` in motivation, business, product). If there is
49
+ none, stage one, or ask the human what the change is for.
50
+ 2. **Orient.** `model_search` / `model_show` / `model_trace` for the elements the change touches.
51
+ Inside a changeset these read the plan as it stands (each result carries a change status).
52
+ `spec_type` for a type you will add: its required attributes, enums, and the relationships the
53
+ catalog allows to and from it. Within reason, every connection the spec models for a type is
54
+ expected, though not every one will exist: treat the catalog's list as the checklist for each
55
+ element the change adds or alters.
56
+ 3. **Draft.** Stage the change in every layer it reaches: `model_add`, `model_update`,
57
+ `model_delete`, `relationship_add`, `relationship_delete`. Relationships may join elements that
58
+ exist only in the changeset. When you wire several, use the lists: `model_add` with
59
+ `elements: [...]` (plus `relationships` that may name elements added in the same call), and
60
+ `relationship_add` with `relationships: [{source, predicate, target, properties?}]`. Each list is
61
+ staged in one write; an invalid item is skipped and reported, so read the per-item results. For
62
+ a planned element with no code yet, send no source fields. Pass `sourceFile` and `sourceSymbol`
63
+ (with `sourceProvenance: "manual"`) only when you know where the code goes.
64
+ Change one attribute with `model_update` `attributePatch`, not by repeating every attribute. Fix a
65
+ mistake with `changeset_unstage` (one element, one relationship, or `source` or `target` alone for
66
+ every staged connection at that end), not by staging the reverse. To drop several, send them as
67
+ `changes: [...]`: one call, one write, a result per item.
68
+ 4. **Pressure-test.** `changeset_brief`, then `changeset_impact` for anything the brief questions.
69
+ The brief is compact by default; pass `detail: "full"` only when you need every section in full.
70
+ Steps 3 and 4 are a loop: a plan comes into focus over many passes. Each pass, stage a little,
71
+ then:
72
+ - Pass the last brief's `revisionToken` as `since`; read the `delta` first. It covers unstages
73
+ too (`unstaged`). If it warns (a hand-edited `changes.yaml`, or a reach back past the last 200
74
+ unstages), read the brief itself.
75
+ - Work through `unwired` for each element you added or changed. The default brief only counts
76
+ it per layer, and `sections` returns only the sections it names, so list the entries with
77
+ `sections: ["unwired"], unwiredLayers: [<the layers the change reaches>]`, narrowed further with
78
+ `layers` or `ids` if you like. Always pass a filter: unfiltered it runs to hundreds of KB on a
79
+ large model. Where `existingCount` is above 0, link an existing element; otherwise decide
80
+ whether the change needs a new one.
81
+ - Walk `changeset_impact` with `from` set to what you just added, not the whole changeset.
82
+ - Read the plan with `changeset_show` `detail: "summary"`, not the full snapshots.
83
+
84
+ Read the brief's gaps:
85
+ - `peer-pattern`: most elements like this one have a connection it lacks.
86
+ - `unconnected`: an added element with no relationships.
87
+ - Intent: a change that reaches no motivation, business or product element.
88
+ - Layers not reached: a new API operation with nothing in data model, testing or APM is a small
89
+ change or an unfinished plan. Decide which.
90
+ - Connections the brief can't flag: for each changed element, compare what `spec_type` says its
91
+ type can connect to with what the plan has. Stage the ones the change needs; leave the ones it
92
+ doesn't, but don't skip the comparison.
93
+
94
+ For each gap, either stage what is missing or accept it. Record an accepted gap where the human
95
+ will see it: an `annotation_create` on the element, or a line in the description
96
+ (`changeset_update`). `model_validate` should pass on the projected model.
97
+
98
+ 5. **Review.** Stop and show the human the brief: changes by layer, gaps fixed and gaps accepted,
99
+ impact, code touched. Call `review_open` and give them its `url`: it opens the plan on the graph
100
+ in the viewer, reusing the viewer already running for the project or starting one. The human
101
+ comments on elements there, including ones the plan adds. Read their comments with
102
+ `annotation_list`, answer with `annotation_reply`, revise, and run the brief again. Don't start building until they agree.
103
+ 6. **Build.** Build from the brief. At the start of the build, read it with
104
+ `sections: ["changes"]`: each changed element's attributes and changed fields, and its
105
+ connections as `predicate → id` lines. For a large plan, read one layer at a time with
106
+ `sections: ["changes"], layers: ["<layer>"]`, taking the layers from the default brief's
107
+ `byLayer`. The default brief's "code touched" list is what you will edit or must not
108
+ break. Keep the changeset staged and commit only the plan's own directory
109
+ (`documentation-robotics/changesets/<id>/`, with the id `changeset_show` reports) on the branch
110
+ with the code. Don't add the whole `changesets/` directory: the `.active` marker and any
111
+ `<name>-as-built` changeset stay out of the commit. If the build has to differ from the plan,
112
+ change the plan to match and say why. Don't verify during the build: no `codebase_extract`, no
113
+ as-built changeset and no `changeset_verify` until the build is committed. Verify is the next
114
+ step, on its own.
115
+ 7. **Verify.** Verify as its own step, after the build (the code and the plan's directory) is
116
+ committed, not in the turn that builds it. Extract what was built, separately from the plan. The
117
+ as-built changeset comes from `codebase_extract` and the code. Never hand-write it, and never copy
118
+ plan elements into it: name each element after its card (the code's symbol), not after the plan's
119
+ element, and don't add planned elements extraction can't see (tests, intent) to make the verdict
120
+ match. Re-index the code once the build is committed: `codebase_index` with `wait: 30` (it re-indexes when source files changed since the last
121
+ index, committed or not), then `status: true` and `wait: 30` until the job is done; don't call it
122
+ in a quick loop. If the result reports `ignoreFile` (the `.cbmignore` it wrote so DR's own folders
123
+ aren't indexed), tell the developer to commit that file. Then `codebase_extract`
124
+ with `since` set to the branch the work started from (e.g. `main`) and
125
+ `changeset: "<name>-as-built"`. It stages what the rules decide in the changed files and leaves
126
+ `<name>-as-built` active. If it staged nothing, it makes no changeset: `changeset_create` with the
127
+ name it gives before you `model_add` its cards. For each card it returns that is a model element, stage it with
128
+ `model_add` (`sourceFile` and `sourceSymbol` from the card, `sourceProvenance: "extracted"`),
129
+ reading the code, not the plan, and ask the developer about the cards you can't place, in one short
130
+ list;
131
+ then call `codebase_extract` again to stage their relationships, and `model_delete` the
132
+ `candidateDeletes` that are really gone. Then `changeset_verify` with `planned: <name>` and
133
+ `against: {"changesetId": "<name>-as-built"}`. Fix each missing, unplanned or divergent item in
134
+ the code or in the plan. `unverifiable` items are planned parts extraction can't see (motivation,
135
+ re-exports, TypeScript tests), and `notes` are description-only differences: neither needs a
136
+ plan edit. Never edit the plan to match extracted placeholder text. A verdict of `unverifiable`
137
+ means the plan has nothing extraction can check; say so rather than call it a failure. Look for missing connections in the as-built too: for each element,
138
+ compare what the spec models for its type with what was staged, and look for evidence of each
139
+ absent one in the code (and the analyzer's graph, `dr analyzer callers` / `callees`). Confirm or
140
+ reject every `probable` match. `changeset_activate` the plan again afterwards (the extract
141
+ result's `previousActive`). After verify, the plan is what lands (step 8), not the as-built
142
+ changeset. Ask the human whether to discard the as-built changeset (`changeset_discard`,
143
+ `confirm: true`) or keep it as a record, and discard it only when they agree. Don't land it:
144
+ landing it first changes the plan's base, so the plan then needs `force`, and the plan's
145
+ descriptions don't apply to elements already in the base. It stays out of git: when you commit
146
+ fixes, add only the plan's directory again. If the as-built changes were landed anyway,
147
+ `against: {"base": true, "extracted": true}` compares the plan with the model, with extraction's blind spots applied.
148
+ 8. **Land.** The PR carries the code and the staged plan, and the human commits the plan in it, not
149
+ the as-built changeset. When they ask you to land it, call `changeset_commit` with its name. The server asks them
150
+ to confirm in a dialog that shows the name, intent, counts by operation, layers and drift, and
151
+ commits only if they confirm; if they decline, leave it staged. If it is refused for drift, show
152
+ them what drifted (`changeset_brief`) and pass `force: true` only if they still want it. Then add
153
+ the model's changed files and the changeset's directory to the branch. If it is refused, they land
154
+ it in the viewer (`review_open`, then Apply on the changeset), or you call it again from an
155
+ interactive session. Never point them to the `dr` CLI.
156
+
157
+ ## Tolerance
158
+
159
+ Tools report odd input and carry on instead of failing. Read the report each time:
160
+
161
+ - `relationship_add` reports a duplicate, or restores a relationship the plan had deleted.
162
+ - `changeset_unstage` reports `not-staged` when there was nothing to drop.
163
+ - In a changeset-only session (DrBot with `--with-changesets`), a write with no active changeset is
164
+ refused. Call `changeset_create` or `changeset_activate` and retry.
165
+ - `changeset_commit` is refused when the human declines or cancels the dialog, when the client
166
+ can't show one (no MCP elicitation), and in DrBot, which doesn't have it. Nothing is written; the
167
+ human lands it in the viewer (`review_open`, then Apply), or from an interactive session.
168
+ - DrBot cannot write annotations (`annotation_create` and `annotation_reply` are not among its
169
+ tools). There, record accepted gaps in the description with `changeset_update` and answer the
170
+ human's comments in the chat.
171
+ - DrBot has no `review_open`: it runs in the viewer, so the human already has the plan in front
172
+ of them. Point them to the changeset in the viewer's Changesets view instead.
173
+
174
+ ## Keep it short
175
+
176
+ Model at the grain of the change. One function, one operation and one test sketch beat a
177
+ speculative tree. Add detail as the build firms up.
@@ -134,6 +134,9 @@ For each addition, check:
134
134
  - [ ] Layer-appropriate properties used
135
135
  - [ ] References point to existing elements
136
136
  - [ ] Status is valid for the element type
137
+ - [ ] Connections the spec models for its type (`dr schema relationship <layer>.<type>`) are present
138
+ where the change needs them; within reason every modeled connection is expected, though not
139
+ every one will exist
137
140
 
138
141
  For each modification, check:
139
142
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/integrations/hash-utils.ts"],
4
- "sourcesContent": ["/**\n * File Hashing Utilities\n *\n * Provides SHA256-based file hashing for change detection in integration files.\n * Uses streaming for memory efficiency when handling large files.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\n/**\n * Compute SHA256 hash of a file, truncated to 8 characters\n *\n * Uses streaming to efficiently handle files of any size without loading\n * them entirely into memory. Matches Python implementation using the same\n * truncation length (8 characters) for consistency.\n *\n * @param filePath - Absolute path to file to hash\n * @returns Promise resolving to 8-character hex hash\n * @throws Error if file cannot be read\n *\n * @example\n * const hash = await computeFileHash('/path/to/file.ts');\n * // Returns: 'a1b2c3d4'\n */\nexport async function computeFileHash(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash(\"sha256\");\n const stream = createReadStream(filePath);\n\n stream.on(\"data\", (data: Buffer) => {\n hash.update(data);\n });\n\n stream.on(\"end\", () => {\n const fullHash = hash.digest(\"hex\");\n resolve(fullHash.substring(0, 8));\n });\n\n stream.on(\"error\", (error: Error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Compute hashes for all files in a directory recursively\n *\n * Scans the directory tree and computes hashes for all files, optionally\n * filtering by a filename prefix. Returns a map of relative paths to hashes,\n * enabling efficient comparison of installed vs. source files.\n *\n * @param baseDir - Base directory to scan\n * @param prefix - Optional prefix filter (only include files matching prefix)\n * @returns Promise resolving to Map of relative paths to 8-character hashes\n * @throws Error if directory cannot be read\n *\n * @example\n * const hashes = await computeDirectoryHashes('/path/to/dir', 'dr-');\n * // Returns: Map { 'dr-file1.md' => 'a1b2c3d4', 'subdir/dr-file2.md' => 'e5f6g7h8' }\n */\nexport async function computeDirectoryHashes(\n baseDir: string,\n prefix?: string\n): Promise<Map<string, string>> {\n const hashes = new Map<string, string>();\n\n // Return empty map if directory doesn't exist\n if (!existsSync(baseDir)) {\n return hashes;\n }\n\n async function scanDir(dir: string, relativePrefix: string = \"\"): Promise<void> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n const relativePath = relativePrefix ? join(relativePrefix, entry.name) : entry.name;\n\n if (entry.isDirectory()) {\n // Recursively scan subdirectories\n await scanDir(fullPath, relativePath);\n } else if (entry.isFile()) {\n // Check prefix filter\n if (prefix && !entry.name.startsWith(prefix)) {\n continue;\n }\n\n // Compute hash for file\n try {\n const hash = await computeFileHash(fullPath);\n hashes.set(relativePath, hash);\n } catch (error) {\n // Log error but continue processing other files\n console.error(`Failed to hash file ${fullPath}:`, error);\n }\n }\n }\n } catch (error) {\n // Re-throw directory read errors\n throw error;\n }\n }\n\n await scanDir(baseDir);\n return hashes;\n}\n"],
5
- "mappings": "AAOA,SAAS,kBAAkB;AAC3B,SAAS,wBAAwB;AACjC,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAiB3B,eAAsB,gBAAgB,UAAgB;AACpD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAU;AACrC,UAAM,OAAO,WAAW,QAAQ,GAC1B,SAAS,iBAAiB,QAAQ;AAExC,WAAO,GAAG,QAAQ,CAAC,SAAgB;AACjC,WAAK,OAAO,IAAI;IAClB,CAAC,GAED,OAAO,GAAG,OAAO,MAAK;AACpB,YAAM,WAAW,KAAK,OAAO,KAAK;AAClC,cAAQ,SAAS,UAAU,GAAG,CAAC,CAAC;IAClC,CAAC,GAED,OAAO,GAAG,SAAS,CAAC,UAAgB;AAClC,aAAO,KAAK;IACd,CAAC;EACH,CAAC;AACH;AAkBA,eAAsB,uBACpB,SACA,QAAe;AAEf,QAAM,SAAS,oBAAI,IAAG;AAGtB,MAAI,CAAC,WAAW,OAAO;AACrB,WAAO;AAGT,iBAAe,QAAQ,KAAa,iBAAyB,IAAE;AAC7D,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,GAAI,CAAE;AAE1D,iBAAW,SAAS,SAAS;AAC3B,cAAM,WAAW,KAAK,KAAK,MAAM,IAAI,GAC/B,eAAe,iBAAiB,KAAK,gBAAgB,MAAM,IAAI,IAAI,MAAM;AAE/E,YAAI,MAAM,YAAW;AAEnB,gBAAM,QAAQ,UAAU,YAAY;iBAC3B,MAAM,OAAM,GAAI;AAEzB,cAAI,UAAU,CAAC,MAAM,KAAK,WAAW,MAAM;AACzC;AAIF,cAAI;AACF,kBAAM,OAAO,MAAM,gBAAgB,QAAQ;AAC3C,mBAAO,IAAI,cAAc,IAAI;UAC/B,SAAS,OAAO;AAEd,oBAAQ,MAAM,uBAAuB,QAAQ,KAAK,KAAK;UACzD;QACF;MACF;IACF,SAAS,OAAO;AAEd,YAAM;IACR;EACF;AAEA,eAAM,QAAQ,OAAO,GACd;AACT;",
4
+ "sourcesContent": ["/**\n * File Hashing Utilities\n *\n * Provides SHA256-based file hashing for change detection in integration files.\n * Uses streaming for memory efficiency when handling large files.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\n/**\n * Compute SHA256 hash of a file, truncated to 8 characters\n *\n * Uses streaming to efficiently handle files of any size without loading\n * them entirely into memory. Matches Python implementation using the same\n * truncation length (8 characters) for consistency.\n *\n * @param filePath - Absolute path to file to hash\n * @returns Promise resolving to 8-character hex hash\n * @throws Error if file cannot be read\n *\n * @example\n * const hash = await computeFileHash('/path/to/file.ts');\n * // Returns: 'a1b2c3d4'\n */\nexport async function computeFileHash(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash(\"sha256\");\n const stream = createReadStream(filePath);\n\n stream.on(\"data\", (data: string | Buffer) => {\n hash.update(data);\n });\n\n stream.on(\"end\", () => {\n const fullHash = hash.digest(\"hex\");\n resolve(fullHash.substring(0, 8));\n });\n\n stream.on(\"error\", (error: Error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Compute hashes for all files in a directory recursively\n *\n * Scans the directory tree and computes hashes for all files, optionally\n * filtering by a filename prefix. Returns a map of relative paths to hashes,\n * enabling efficient comparison of installed vs. source files.\n *\n * @param baseDir - Base directory to scan\n * @param prefix - Optional prefix filter (only include files matching prefix)\n * @returns Promise resolving to Map of relative paths to 8-character hashes\n * @throws Error if directory cannot be read\n *\n * @example\n * const hashes = await computeDirectoryHashes('/path/to/dir', 'dr-');\n * // Returns: Map { 'dr-file1.md' => 'a1b2c3d4', 'subdir/dr-file2.md' => 'e5f6g7h8' }\n */\nexport async function computeDirectoryHashes(\n baseDir: string,\n prefix?: string\n): Promise<Map<string, string>> {\n const hashes = new Map<string, string>();\n\n // Return empty map if directory doesn't exist\n if (!existsSync(baseDir)) {\n return hashes;\n }\n\n async function scanDir(dir: string, relativePrefix: string = \"\"): Promise<void> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n const relativePath = relativePrefix ? join(relativePrefix, entry.name) : entry.name;\n\n if (entry.isDirectory()) {\n // Recursively scan subdirectories\n await scanDir(fullPath, relativePath);\n } else if (entry.isFile()) {\n // Check prefix filter\n if (prefix && !entry.name.startsWith(prefix)) {\n continue;\n }\n\n // Compute hash for file\n try {\n const hash = await computeFileHash(fullPath);\n hashes.set(relativePath, hash);\n } catch (error) {\n // Log error but continue processing other files\n console.error(`Failed to hash file ${fullPath}:`, error);\n }\n }\n }\n } catch (error) {\n // Re-throw directory read errors\n throw error;\n }\n }\n\n await scanDir(baseDir);\n return hashes;\n}\n"],
5
+ "mappings": "AAOA,SAAS,kBAAkB;AAC3B,SAAS,wBAAwB;AACjC,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAiB3B,eAAsB,gBAAgB,UAAgB;AACpD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAU;AACrC,UAAM,OAAO,WAAW,QAAQ,GAC1B,SAAS,iBAAiB,QAAQ;AAExC,WAAO,GAAG,QAAQ,CAAC,SAAyB;AAC1C,WAAK,OAAO,IAAI;IAClB,CAAC,GAED,OAAO,GAAG,OAAO,MAAK;AACpB,YAAM,WAAW,KAAK,OAAO,KAAK;AAClC,cAAQ,SAAS,UAAU,GAAG,CAAC,CAAC;IAClC,CAAC,GAED,OAAO,GAAG,SAAS,CAAC,UAAgB;AAClC,aAAO,KAAK;IACd,CAAC;EACH,CAAC;AACH;AAkBA,eAAsB,uBACpB,SACA,QAAe;AAEf,QAAM,SAAS,oBAAI,IAAG;AAGtB,MAAI,CAAC,WAAW,OAAO;AACrB,WAAO;AAGT,iBAAe,QAAQ,KAAa,iBAAyB,IAAE;AAC7D,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,GAAI,CAAE;AAE1D,iBAAW,SAAS,SAAS;AAC3B,cAAM,WAAW,KAAK,KAAK,MAAM,IAAI,GAC/B,eAAe,iBAAiB,KAAK,gBAAgB,MAAM,IAAI,IAAI,MAAM;AAE/E,YAAI,MAAM,YAAW;AAEnB,gBAAM,QAAQ,UAAU,YAAY;iBAC3B,MAAM,OAAM,GAAI;AAEzB,cAAI,UAAU,CAAC,MAAM,KAAK,WAAW,MAAM;AACzC;AAIF,cAAI;AACF,kBAAM,OAAO,MAAM,gBAAgB,QAAQ;AAC3C,mBAAO,IAAI,cAAc,IAAI;UAC/B,SAAS,OAAO;AAEd,oBAAQ,MAAM,uBAAuB,QAAQ,KAAK,KAAK;UACzD;QACF;MACF;IACF,SAAS,OAAO;AAEd,YAAM;IACR;EACF;AAEA,eAAM,QAAQ,OAAO,GACd;AACT;",
6
6
  "names": []
7
7
  }