@agile-vibe-coding/avc 0.2.3 → 0.3.2

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 (262) hide show
  1. package/README.md +475 -3
  2. package/cli/agents/agent-selector.md +23 -0
  3. package/cli/agents/code-implementer.md +117 -0
  4. package/cli/agents/code-validator.md +80 -0
  5. package/cli/agents/context-reviewer-epic.md +101 -0
  6. package/cli/agents/context-reviewer-story.md +92 -0
  7. package/cli/agents/context-writer-epic.md +145 -0
  8. package/cli/agents/context-writer-story.md +111 -0
  9. package/cli/agents/doc-writer-epic.md +42 -0
  10. package/cli/agents/doc-writer-story.md +43 -0
  11. package/cli/agents/duplicate-detector.md +110 -0
  12. package/cli/agents/epic-story-decomposer.md +318 -39
  13. package/cli/agents/mission-scope-generator.md +68 -4
  14. package/cli/agents/mission-scope-validator.md +40 -6
  15. package/cli/agents/project-context-extractor.md +21 -6
  16. package/cli/agents/scaffolding-generator.md +99 -0
  17. package/cli/agents/seed-validator.md +71 -0
  18. package/cli/agents/story-scope-reviewer.md +147 -0
  19. package/cli/agents/story-splitter.md +83 -0
  20. package/cli/agents/validator-documentation.json +31 -0
  21. package/cli/agents/validator-documentation.md +3 -1
  22. package/cli/api-reference-tool.js +368 -0
  23. package/cli/checks/catalog.json +76 -0
  24. package/cli/checks/code/quality.json +26 -0
  25. package/cli/checks/code/testing.json +14 -0
  26. package/cli/checks/code/traceability.json +26 -0
  27. package/cli/checks/cross-refs/epic.json +171 -0
  28. package/cli/checks/cross-refs/story.json +149 -0
  29. package/cli/checks/epic/api.json +114 -0
  30. package/cli/checks/epic/backend.json +126 -0
  31. package/cli/checks/epic/cloud.json +126 -0
  32. package/cli/checks/epic/data.json +102 -0
  33. package/cli/checks/epic/database.json +114 -0
  34. package/cli/checks/epic/developer.json +182 -0
  35. package/cli/checks/epic/devops.json +174 -0
  36. package/cli/checks/epic/frontend.json +162 -0
  37. package/cli/checks/epic/mobile.json +102 -0
  38. package/cli/checks/epic/qa.json +90 -0
  39. package/cli/checks/epic/security.json +184 -0
  40. package/cli/checks/epic/solution-architect.json +192 -0
  41. package/cli/checks/epic/test-architect.json +90 -0
  42. package/cli/checks/epic/ui.json +102 -0
  43. package/cli/checks/epic/ux.json +90 -0
  44. package/cli/checks/fixes/epic-fix-template.md +10 -0
  45. package/cli/checks/fixes/story-fix-template.md +10 -0
  46. package/cli/checks/story/api.json +186 -0
  47. package/cli/checks/story/backend.json +102 -0
  48. package/cli/checks/story/cloud.json +102 -0
  49. package/cli/checks/story/data.json +210 -0
  50. package/cli/checks/story/database.json +102 -0
  51. package/cli/checks/story/developer.json +168 -0
  52. package/cli/checks/story/devops.json +102 -0
  53. package/cli/checks/story/frontend.json +174 -0
  54. package/cli/checks/story/mobile.json +102 -0
  55. package/cli/checks/story/qa.json +210 -0
  56. package/cli/checks/story/security.json +198 -0
  57. package/cli/checks/story/solution-architect.json +230 -0
  58. package/cli/checks/story/test-architect.json +210 -0
  59. package/cli/checks/story/ui.json +102 -0
  60. package/cli/checks/story/ux.json +102 -0
  61. package/cli/coding-order.js +401 -0
  62. package/cli/dependency-checker.js +72 -0
  63. package/cli/epic-story-validator.js +284 -799
  64. package/cli/index.js +0 -0
  65. package/cli/init-model-config.js +17 -10
  66. package/cli/init.js +514 -92
  67. package/cli/kanban-server-manager.js +1 -2
  68. package/cli/llm-claude.js +98 -31
  69. package/cli/llm-gemini.js +29 -5
  70. package/cli/llm-local.js +493 -0
  71. package/cli/llm-openai.js +262 -41
  72. package/cli/llm-provider.js +147 -8
  73. package/cli/llm-token-limits.js +113 -4
  74. package/cli/llm-verifier.js +209 -1
  75. package/cli/llm-xiaomi.js +143 -0
  76. package/cli/message-constants.js +3 -12
  77. package/cli/messaging-api.js +6 -12
  78. package/cli/micro-check-fixer.js +335 -0
  79. package/cli/micro-check-runner.js +449 -0
  80. package/cli/micro-check-scorer.js +148 -0
  81. package/cli/micro-check-validator.js +538 -0
  82. package/cli/model-pricing.js +23 -0
  83. package/cli/model-selector.js +3 -2
  84. package/cli/prompt-logger.js +57 -0
  85. package/cli/repl-ink.js +106 -346
  86. package/cli/repl-old.js +1 -2
  87. package/cli/seed-processor.js +194 -24
  88. package/cli/sprint-planning-processor.js +2638 -289
  89. package/cli/template-processor.js +50 -3
  90. package/cli/token-tracker.js +50 -23
  91. package/cli/tools/generate-story-validators.js +1 -1
  92. package/cli/validation-router.js +70 -8
  93. package/cli/worktree-runner.js +654 -0
  94. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  95. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  96. package/kanban/client/dist/index.html +2 -2
  97. package/kanban/client/src/App.jsx +43 -14
  98. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  99. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  100. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  101. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  102. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  103. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  104. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  105. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  106. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  107. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  108. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  109. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  110. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  111. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  112. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  113. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  114. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  115. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  116. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  117. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  118. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  119. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  120. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  121. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  122. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  123. package/kanban/client/src/hooks/useGrouping.js +59 -0
  124. package/kanban/client/src/lib/api.js +118 -4
  125. package/kanban/client/src/lib/status-grouping.js +10 -0
  126. package/kanban/client/src/store/kanbanStore.js +8 -0
  127. package/kanban/server/index.js +23 -2
  128. package/kanban/server/routes/ceremony.js +153 -4
  129. package/kanban/server/routes/costs.js +9 -3
  130. package/kanban/server/routes/openai-oauth.js +366 -0
  131. package/kanban/server/routes/settings.js +447 -14
  132. package/kanban/server/routes/websocket.js +7 -2
  133. package/kanban/server/routes/work-items.js +141 -1
  134. package/kanban/server/services/CeremonyService.js +275 -24
  135. package/kanban/server/services/TaskRunnerService.js +261 -0
  136. package/kanban/server/workers/run-task-worker.js +121 -0
  137. package/kanban/server/workers/seed-worker.js +94 -0
  138. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  139. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  140. package/package.json +2 -3
  141. package/cli/agents/solver-epic-api.json +0 -15
  142. package/cli/agents/solver-epic-api.md +0 -39
  143. package/cli/agents/solver-epic-backend.json +0 -15
  144. package/cli/agents/solver-epic-backend.md +0 -39
  145. package/cli/agents/solver-epic-cloud.json +0 -15
  146. package/cli/agents/solver-epic-cloud.md +0 -39
  147. package/cli/agents/solver-epic-data.json +0 -15
  148. package/cli/agents/solver-epic-data.md +0 -39
  149. package/cli/agents/solver-epic-database.json +0 -15
  150. package/cli/agents/solver-epic-database.md +0 -39
  151. package/cli/agents/solver-epic-developer.json +0 -15
  152. package/cli/agents/solver-epic-developer.md +0 -39
  153. package/cli/agents/solver-epic-devops.json +0 -15
  154. package/cli/agents/solver-epic-devops.md +0 -39
  155. package/cli/agents/solver-epic-frontend.json +0 -15
  156. package/cli/agents/solver-epic-frontend.md +0 -39
  157. package/cli/agents/solver-epic-mobile.json +0 -15
  158. package/cli/agents/solver-epic-mobile.md +0 -39
  159. package/cli/agents/solver-epic-qa.json +0 -15
  160. package/cli/agents/solver-epic-qa.md +0 -39
  161. package/cli/agents/solver-epic-security.json +0 -15
  162. package/cli/agents/solver-epic-security.md +0 -39
  163. package/cli/agents/solver-epic-solution-architect.json +0 -15
  164. package/cli/agents/solver-epic-solution-architect.md +0 -39
  165. package/cli/agents/solver-epic-test-architect.json +0 -15
  166. package/cli/agents/solver-epic-test-architect.md +0 -39
  167. package/cli/agents/solver-epic-ui.json +0 -15
  168. package/cli/agents/solver-epic-ui.md +0 -39
  169. package/cli/agents/solver-epic-ux.json +0 -15
  170. package/cli/agents/solver-epic-ux.md +0 -39
  171. package/cli/agents/solver-story-api.json +0 -15
  172. package/cli/agents/solver-story-api.md +0 -39
  173. package/cli/agents/solver-story-backend.json +0 -15
  174. package/cli/agents/solver-story-backend.md +0 -39
  175. package/cli/agents/solver-story-cloud.json +0 -15
  176. package/cli/agents/solver-story-cloud.md +0 -39
  177. package/cli/agents/solver-story-data.json +0 -15
  178. package/cli/agents/solver-story-data.md +0 -39
  179. package/cli/agents/solver-story-database.json +0 -15
  180. package/cli/agents/solver-story-database.md +0 -39
  181. package/cli/agents/solver-story-developer.json +0 -15
  182. package/cli/agents/solver-story-developer.md +0 -39
  183. package/cli/agents/solver-story-devops.json +0 -15
  184. package/cli/agents/solver-story-devops.md +0 -39
  185. package/cli/agents/solver-story-frontend.json +0 -15
  186. package/cli/agents/solver-story-frontend.md +0 -39
  187. package/cli/agents/solver-story-mobile.json +0 -15
  188. package/cli/agents/solver-story-mobile.md +0 -39
  189. package/cli/agents/solver-story-qa.json +0 -15
  190. package/cli/agents/solver-story-qa.md +0 -39
  191. package/cli/agents/solver-story-security.json +0 -15
  192. package/cli/agents/solver-story-security.md +0 -39
  193. package/cli/agents/solver-story-solution-architect.json +0 -15
  194. package/cli/agents/solver-story-solution-architect.md +0 -39
  195. package/cli/agents/solver-story-test-architect.json +0 -15
  196. package/cli/agents/solver-story-test-architect.md +0 -39
  197. package/cli/agents/solver-story-ui.json +0 -15
  198. package/cli/agents/solver-story-ui.md +0 -39
  199. package/cli/agents/solver-story-ux.json +0 -15
  200. package/cli/agents/solver-story-ux.md +0 -39
  201. package/cli/agents/validator-epic-api.json +0 -93
  202. package/cli/agents/validator-epic-api.md +0 -137
  203. package/cli/agents/validator-epic-backend.json +0 -93
  204. package/cli/agents/validator-epic-backend.md +0 -130
  205. package/cli/agents/validator-epic-cloud.json +0 -93
  206. package/cli/agents/validator-epic-cloud.md +0 -137
  207. package/cli/agents/validator-epic-data.json +0 -93
  208. package/cli/agents/validator-epic-data.md +0 -130
  209. package/cli/agents/validator-epic-database.json +0 -93
  210. package/cli/agents/validator-epic-database.md +0 -137
  211. package/cli/agents/validator-epic-developer.json +0 -74
  212. package/cli/agents/validator-epic-developer.md +0 -153
  213. package/cli/agents/validator-epic-devops.json +0 -74
  214. package/cli/agents/validator-epic-devops.md +0 -153
  215. package/cli/agents/validator-epic-frontend.json +0 -74
  216. package/cli/agents/validator-epic-frontend.md +0 -153
  217. package/cli/agents/validator-epic-mobile.json +0 -93
  218. package/cli/agents/validator-epic-mobile.md +0 -130
  219. package/cli/agents/validator-epic-qa.json +0 -93
  220. package/cli/agents/validator-epic-qa.md +0 -130
  221. package/cli/agents/validator-epic-security.json +0 -74
  222. package/cli/agents/validator-epic-security.md +0 -154
  223. package/cli/agents/validator-epic-solution-architect.json +0 -74
  224. package/cli/agents/validator-epic-solution-architect.md +0 -156
  225. package/cli/agents/validator-epic-test-architect.json +0 -93
  226. package/cli/agents/validator-epic-test-architect.md +0 -130
  227. package/cli/agents/validator-epic-ui.json +0 -93
  228. package/cli/agents/validator-epic-ui.md +0 -130
  229. package/cli/agents/validator-epic-ux.json +0 -93
  230. package/cli/agents/validator-epic-ux.md +0 -130
  231. package/cli/agents/validator-story-api.json +0 -104
  232. package/cli/agents/validator-story-api.md +0 -152
  233. package/cli/agents/validator-story-backend.json +0 -104
  234. package/cli/agents/validator-story-backend.md +0 -152
  235. package/cli/agents/validator-story-cloud.json +0 -104
  236. package/cli/agents/validator-story-cloud.md +0 -152
  237. package/cli/agents/validator-story-data.json +0 -104
  238. package/cli/agents/validator-story-data.md +0 -152
  239. package/cli/agents/validator-story-database.json +0 -104
  240. package/cli/agents/validator-story-database.md +0 -152
  241. package/cli/agents/validator-story-developer.json +0 -104
  242. package/cli/agents/validator-story-developer.md +0 -152
  243. package/cli/agents/validator-story-devops.json +0 -104
  244. package/cli/agents/validator-story-devops.md +0 -152
  245. package/cli/agents/validator-story-frontend.json +0 -104
  246. package/cli/agents/validator-story-frontend.md +0 -152
  247. package/cli/agents/validator-story-mobile.json +0 -104
  248. package/cli/agents/validator-story-mobile.md +0 -152
  249. package/cli/agents/validator-story-qa.json +0 -104
  250. package/cli/agents/validator-story-qa.md +0 -152
  251. package/cli/agents/validator-story-security.json +0 -104
  252. package/cli/agents/validator-story-security.md +0 -152
  253. package/cli/agents/validator-story-solution-architect.json +0 -104
  254. package/cli/agents/validator-story-solution-architect.md +0 -152
  255. package/cli/agents/validator-story-test-architect.json +0 -104
  256. package/cli/agents/validator-story-test-architect.md +0 -152
  257. package/cli/agents/validator-story-ui.json +0 -104
  258. package/cli/agents/validator-story-ui.md +0 -152
  259. package/cli/agents/validator-story-ux.json +0 -104
  260. package/cli/agents/validator-story-ux.md +0 -152
  261. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  262. package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
@@ -0,0 +1,102 @@
1
+ {
2
+ "perspective": "ui",
3
+ "scope": "story",
4
+ "checks": [
5
+ {
6
+ "id": "ui-story-01",
7
+ "tier": 1,
8
+ "perspective": "ui",
9
+ "severity": "critical",
10
+ "category": "acceptance-criteria",
11
+ "universal": false,
12
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements? (Does it include component specs, styling, or visual layout?)",
13
+ "question": "Is each acceptance criterion testable and measurable?",
14
+ "failDescription": "One or more acceptance criteria are not testable or measurable",
15
+ "failSuggestion": "Make each AC testable: specify exact visual outcomes, component states, or measurable UI properties"
16
+ },
17
+ {
18
+ "id": "ui-story-02",
19
+ "tier": 1,
20
+ "perspective": "ui",
21
+ "severity": "major",
22
+ "category": "acceptance-criteria",
23
+ "universal": false,
24
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
25
+ "question": "Do criteria cover happy path, edge cases, and error scenarios?",
26
+ "failDescription": "Criteria do not cover UI edge cases or error states",
27
+ "failSuggestion": "Add UI edge cases: overflow text, empty states, loading skeletons, error displays, responsive breakpoints"
28
+ },
29
+ {
30
+ "id": "ui-story-03",
31
+ "tier": 1,
32
+ "perspective": "ui",
33
+ "severity": "major",
34
+ "category": "acceptance-criteria",
35
+ "universal": false,
36
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
37
+ "question": "Are UI requirements explicitly stated?",
38
+ "failDescription": "UI requirements are not explicitly stated",
39
+ "failSuggestion": "State UI requirements: component variants, colors, spacing, typography, responsive behavior"
40
+ },
41
+ {
42
+ "id": "ui-story-04",
43
+ "tier": 1,
44
+ "perspective": "ui",
45
+ "severity": "major",
46
+ "category": "implementation-clarity",
47
+ "universal": false,
48
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
49
+ "question": "Does the story provide enough UI detail for implementation?",
50
+ "failDescription": "Insufficient UI detail for implementation",
51
+ "failSuggestion": "Add UI details: component dimensions, color values, spacing units, font sizes, animation timing"
52
+ },
53
+ {
54
+ "id": "ui-story-05",
55
+ "tier": 1,
56
+ "perspective": "ui",
57
+ "severity": "minor",
58
+ "category": "implementation-clarity",
59
+ "universal": false,
60
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
61
+ "question": "Are UI patterns and approaches specified?",
62
+ "failDescription": "UI patterns and approaches are not specified",
63
+ "failSuggestion": "Specify UI patterns: component composition, design token usage, responsive strategy, theme support"
64
+ },
65
+ {
66
+ "id": "ui-story-06",
67
+ "tier": 1,
68
+ "perspective": "ui",
69
+ "severity": "major",
70
+ "category": "testability",
71
+ "universal": false,
72
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
73
+ "question": "Does the story have a test-boundary AC naming specific scenarios a developer must test?",
74
+ "failDescription": "Story lacks a test-boundary AC",
75
+ "failSuggestion": "Add test-boundary AC: 'Tests must cover: (1) default state, (2) hover/focus, (3) error state, (4) responsive, (5) accessibility'"
76
+ },
77
+ {
78
+ "id": "ui-story-07",
79
+ "tier": 1,
80
+ "perspective": "ui",
81
+ "severity": "minor",
82
+ "category": "scope-dependencies",
83
+ "universal": false,
84
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
85
+ "question": "Are dependencies on other stories explicit?",
86
+ "failDescription": "Dependencies on other stories are not explicit",
87
+ "failSuggestion": "Make dependencies explicit: reference design system stories, component library dependencies"
88
+ },
89
+ {
90
+ "id": "ui-story-08",
91
+ "tier": 1,
92
+ "perspective": "ui",
93
+ "severity": "minor",
94
+ "category": "best-practices",
95
+ "universal": false,
96
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
97
+ "question": "Does the story follow UI best practices?",
98
+ "failDescription": "UI best practices are not followed",
99
+ "failSuggestion": "Follow UI best practices: consistent design tokens, accessibility contrast ratios, responsive design, visual hierarchy"
100
+ }
101
+ ]
102
+ }
@@ -0,0 +1,102 @@
1
+ {
2
+ "perspective": "ux",
3
+ "scope": "story",
4
+ "checks": [
5
+ {
6
+ "id": "ux-story-01",
7
+ "tier": 1,
8
+ "perspective": "ux",
9
+ "severity": "critical",
10
+ "category": "acceptance-criteria",
11
+ "universal": false,
12
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design? (Does it define user journeys, navigation, or usability requirements?)",
13
+ "question": "Is each acceptance criterion testable and measurable?",
14
+ "failDescription": "One or more acceptance criteria are not testable or measurable",
15
+ "failSuggestion": "Make each AC testable: specify user actions, expected outcomes, and measurable UX metrics"
16
+ },
17
+ {
18
+ "id": "ux-story-02",
19
+ "tier": 1,
20
+ "perspective": "ux",
21
+ "severity": "major",
22
+ "category": "acceptance-criteria",
23
+ "universal": false,
24
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
25
+ "question": "Do criteria cover happy path, edge cases, and error scenarios?",
26
+ "failDescription": "Criteria do not cover UX edge cases or error scenarios",
27
+ "failSuggestion": "Add UX edge cases: empty states, error recovery flows, timeout handling, progressive disclosure"
28
+ },
29
+ {
30
+ "id": "ux-story-03",
31
+ "tier": 1,
32
+ "perspective": "ux",
33
+ "severity": "major",
34
+ "category": "acceptance-criteria",
35
+ "universal": false,
36
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
37
+ "question": "Are UX requirements explicitly stated?",
38
+ "failDescription": "UX requirements are not explicitly stated",
39
+ "failSuggestion": "State UX requirements: user flow steps, interaction patterns, feedback mechanisms, accessibility needs"
40
+ },
41
+ {
42
+ "id": "ux-story-04",
43
+ "tier": 1,
44
+ "perspective": "ux",
45
+ "severity": "major",
46
+ "category": "implementation-clarity",
47
+ "universal": false,
48
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
49
+ "question": "Does the story provide enough UX detail for implementation?",
50
+ "failDescription": "Insufficient UX detail for implementation",
51
+ "failSuggestion": "Add UX details: user flow diagrams, interaction states, feedback timing, animation expectations"
52
+ },
53
+ {
54
+ "id": "ux-story-05",
55
+ "tier": 1,
56
+ "perspective": "ux",
57
+ "severity": "minor",
58
+ "category": "implementation-clarity",
59
+ "universal": false,
60
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
61
+ "question": "Are UX patterns and approaches specified?",
62
+ "failDescription": "UX patterns and approaches are not specified",
63
+ "failSuggestion": "Specify UX patterns: progressive disclosure, inline validation, optimistic feedback, error recovery"
64
+ },
65
+ {
66
+ "id": "ux-story-06",
67
+ "tier": 1,
68
+ "perspective": "ux",
69
+ "severity": "major",
70
+ "category": "testability",
71
+ "universal": false,
72
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
73
+ "question": "Does the story have a test-boundary AC naming specific scenarios a developer must test?",
74
+ "failDescription": "Story lacks a test-boundary AC",
75
+ "failSuggestion": "Add test-boundary AC: 'Tests must cover: (1) happy flow, (2) error recovery, (3) empty state, (4) loading state, (5) accessibility'"
76
+ },
77
+ {
78
+ "id": "ux-story-07",
79
+ "tier": 1,
80
+ "perspective": "ux",
81
+ "severity": "minor",
82
+ "category": "scope-dependencies",
83
+ "universal": false,
84
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
85
+ "question": "Are dependencies on other stories explicit?",
86
+ "failDescription": "Dependencies on other stories are not explicit",
87
+ "failSuggestion": "Make dependencies explicit: reference related user flow stories and shared UX patterns"
88
+ },
89
+ {
90
+ "id": "ux-story-08",
91
+ "tier": 1,
92
+ "perspective": "ux",
93
+ "severity": "minor",
94
+ "category": "best-practices",
95
+ "universal": false,
96
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
97
+ "question": "Does the story follow UX best practices?",
98
+ "failDescription": "UX best practices are not followed",
99
+ "failSuggestion": "Follow UX best practices: minimize cognitive load, provide clear feedback, support undo, maintain consistency"
100
+ }
101
+ ]
102
+ }
@@ -0,0 +1,401 @@
1
+ /**
2
+ * coding-order.js — Computes implementation ordering from epic/story dependency graphs.
3
+ *
4
+ * Pure functions: no side effects, no file I/O. All I/O is done by the caller
5
+ * (SprintPlanningProcessor.generateCodingOrder).
6
+ */
7
+
8
+ /**
9
+ * Build adjacency maps from hierarchy dependencies.
10
+ * @param {{ epics: Array }} hierarchy
11
+ * @returns {{ epicGraph: Map<string,Set<string>>, storyGraphs: Map<string,Map<string,Set<string>>>, allNodes: Map<string,{id,name,type,parentId?}> }}
12
+ */
13
+ export function buildDependencyGraph(hierarchy) {
14
+ const epicGraph = new Map(); // epicId → Set<epicId it depends on>
15
+ const storyGraphs = new Map(); // epicId → Map<storyId, Set<storyId>>
16
+ const allNodes = new Map(); // id → { id, name, type, parentId? }
17
+
18
+ for (const epic of hierarchy.epics || []) {
19
+ const epicId = epic.id;
20
+ allNodes.set(epicId, { id: epicId, name: epic.name, type: 'epic' });
21
+
22
+ // Epic-level deps: only keep references that look like epic IDs (context-XXXX)
23
+ const epicDeps = new Set();
24
+ for (const dep of epic.dependencies || []) {
25
+ if (/^context-\d{4}$/.test(dep) && dep !== epicId) {
26
+ epicDeps.add(dep);
27
+ }
28
+ }
29
+ epicGraph.set(epicId, epicDeps);
30
+
31
+ // Story-level: intra-epic deps only
32
+ const storyMap = new Map();
33
+ const epicStoryIds = new Set((epic.stories || []).map(s => s.id));
34
+
35
+ for (const story of epic.stories || []) {
36
+ allNodes.set(story.id, { id: story.id, name: story.name, type: 'story', parentId: epicId });
37
+ const storyDeps = new Set();
38
+ for (const dep of story.dependencies || []) {
39
+ if (epicStoryIds.has(dep) && dep !== story.id) {
40
+ storyDeps.add(dep); // intra-epic story dependency
41
+ }
42
+ // Cross-epic story deps → promote to epic dependency
43
+ if (/^context-\d{4}$/.test(dep) && dep !== epicId) {
44
+ epicDeps.add(dep);
45
+ }
46
+ }
47
+ storyMap.set(story.id, storyDeps);
48
+ }
49
+
50
+ storyGraphs.set(epicId, storyMap);
51
+ }
52
+
53
+ return { epicGraph, storyGraphs, allNodes };
54
+ }
55
+
56
+ /**
57
+ * Kahn's algorithm — topological sort with cycle detection.
58
+ * @param {Map<string,Set<string>>} graph — nodeId → Set<dependency nodeIds>
59
+ * @returns {{ sorted: string[], hasCycle: boolean, cycleNodes: string[] }}
60
+ */
61
+ export function topologicalSort(graph) {
62
+ const inDegree = new Map();
63
+ const adjList = new Map(); // forward edges: dep → [dependents]
64
+
65
+ for (const [node] of graph) {
66
+ if (!inDegree.has(node)) inDegree.set(node, 0);
67
+ if (!adjList.has(node)) adjList.set(node, []);
68
+ }
69
+
70
+ for (const [node, deps] of graph) {
71
+ for (const dep of deps) {
72
+ if (!graph.has(dep)) continue; // skip refs to non-existent nodes
73
+ if (!adjList.has(dep)) adjList.set(dep, []);
74
+ adjList.get(dep).push(node);
75
+ inDegree.set(node, (inDegree.get(node) || 0) + 1);
76
+ }
77
+ }
78
+
79
+ const queue = [];
80
+ for (const [node, deg] of inDegree) {
81
+ if (deg === 0) queue.push(node);
82
+ }
83
+ queue.sort(); // deterministic ordering for ties
84
+
85
+ const sorted = [];
86
+ while (queue.length > 0) {
87
+ const node = queue.shift();
88
+ sorted.push(node);
89
+ for (const dependent of adjList.get(node) || []) {
90
+ const newDeg = inDegree.get(dependent) - 1;
91
+ inDegree.set(dependent, newDeg);
92
+ if (newDeg === 0) {
93
+ queue.push(dependent);
94
+ queue.sort();
95
+ }
96
+ }
97
+ }
98
+
99
+ const hasCycle = sorted.length < graph.size;
100
+ const cycleNodes = hasCycle
101
+ ? [...graph.keys()].filter(n => !sorted.includes(n))
102
+ : [];
103
+
104
+ // If cycle, append remaining nodes in ID order to still produce output
105
+ if (hasCycle) {
106
+ for (const node of cycleNodes.sort()) {
107
+ sorted.push(node);
108
+ }
109
+ }
110
+
111
+ return { sorted, hasCycle, cycleNodes };
112
+ }
113
+
114
+ /**
115
+ * Group epics into implementation phases by longest-path distance from root nodes.
116
+ * Phase 0 = no dependencies, Phase N = longest dep chain is N.
117
+ * @param {Map<string,Set<string>>} epicGraph
118
+ * @returns {Array<{ phase: number, epicIds: string[] }>}
119
+ */
120
+ export function computePhases(epicGraph) {
121
+ const depth = new Map();
122
+
123
+ function getDepth(node, visited = new Set()) {
124
+ if (depth.has(node)) return depth.get(node);
125
+ if (visited.has(node)) return 0; // cycle guard
126
+ visited.add(node);
127
+
128
+ const deps = epicGraph.get(node) || new Set();
129
+ let maxDepth = 0;
130
+ for (const dep of deps) {
131
+ if (epicGraph.has(dep)) {
132
+ maxDepth = Math.max(maxDepth, getDepth(dep, visited) + 1);
133
+ }
134
+ }
135
+ depth.set(node, maxDepth);
136
+ return maxDepth;
137
+ }
138
+
139
+ for (const [node] of epicGraph) getDepth(node);
140
+
141
+ // Group by phase
142
+ const phaseMap = new Map();
143
+ for (const [node, d] of depth) {
144
+ if (!phaseMap.has(d)) phaseMap.set(d, []);
145
+ phaseMap.get(d).push(node);
146
+ }
147
+
148
+ return [...phaseMap.entries()]
149
+ .sort((a, b) => a[0] - b[0])
150
+ .map(([phase, epicIds]) => ({ phase, epicIds: epicIds.sort() }));
151
+ }
152
+
153
+ /**
154
+ * Find the longest path through the epic dependency graph (critical path).
155
+ * @param {Map<string,Set<string>>} epicGraph
156
+ * @returns {{ path: string[], length: number }}
157
+ */
158
+ export function computeCriticalPath(epicGraph) {
159
+ const memo = new Map();
160
+
161
+ function longestFrom(node, visited = new Set()) {
162
+ if (memo.has(node)) return memo.get(node);
163
+ if (visited.has(node)) return [node]; // cycle guard
164
+ visited.add(node);
165
+
166
+ // Find all nodes that depend on this one
167
+ const dependents = [];
168
+ for (const [n, deps] of epicGraph) {
169
+ if (deps.has(node)) dependents.push(n);
170
+ }
171
+
172
+ let best = [node];
173
+ for (const dep of dependents) {
174
+ const sub = longestFrom(dep, new Set(visited));
175
+ if (sub.length + 1 > best.length) {
176
+ best = [node, ...sub];
177
+ }
178
+ }
179
+ memo.set(node, best);
180
+ return best;
181
+ }
182
+
183
+ // Find roots (nodes with no dependencies)
184
+ const roots = [];
185
+ for (const [node, deps] of epicGraph) {
186
+ if (deps.size === 0) roots.push(node);
187
+ }
188
+
189
+ let criticalPath = [];
190
+ for (const root of roots) {
191
+ const path = longestFrom(root);
192
+ if (path.length > criticalPath.length) criticalPath = path;
193
+ }
194
+
195
+ return { path: criticalPath, length: criticalPath.length };
196
+ }
197
+
198
+ /**
199
+ * Topologically sort stories within a single epic.
200
+ * @param {Map<string,Set<string>>} storyGraph — storyId → Set<intra-epic dep storyIds>
201
+ * @returns {string[]}
202
+ */
203
+ export function orderStoriesWithinEpic(storyGraph) {
204
+ return topologicalSort(storyGraph).sorted;
205
+ }
206
+
207
+ /**
208
+ * Render the coding order as a Markdown document.
209
+ */
210
+ export function generateCodingOrderMd(phases, storyOrders, allNodes, criticalPath) {
211
+ const lines = [
212
+ '# Coding Order',
213
+ '',
214
+ `Generated: ${new Date().toISOString()}`,
215
+ '',
216
+ ];
217
+
218
+ // Mermaid dependency graph
219
+ lines.push('## Dependency Graph', '', '```mermaid', 'graph LR');
220
+ for (const [id, node] of allNodes) {
221
+ if (node.type === 'epic') {
222
+ const label = node.name.replace(/"/g, "'");
223
+ lines.push(` ${id}["${label}"]`);
224
+ }
225
+ }
226
+ // Edges: for each epic, draw edges FROM its dependencies TO it
227
+ for (const phase of phases) {
228
+ for (const epicId of phase.epicIds) {
229
+ // Find this epic's node in allNodes and look up its deps
230
+ // We need the original graph — reconstruct from phases
231
+ }
232
+ }
233
+ // Use phases to reconstruct edges from allNodes
234
+ // Actually we need epicGraph — let's take it as parameter
235
+ lines.push('```', '');
236
+
237
+ // Critical path
238
+ lines.push('## Critical Path', '');
239
+ if (criticalPath.path.length > 0) {
240
+ const pathStr = criticalPath.path
241
+ .map(id => { const n = allNodes.get(id); return n ? `${id} (${n.name})` : id; })
242
+ .join(' → ');
243
+ lines.push(pathStr);
244
+ lines.push(``, `Length: ${criticalPath.length} epics`, '');
245
+ } else {
246
+ lines.push('No dependencies — all epics are independent.', '');
247
+ }
248
+
249
+ // Implementation phases
250
+ lines.push('## Implementation Phases', '');
251
+ for (const phase of phases) {
252
+ const parallel = phase.epicIds.length > 1 ? ' (parallel)' : '';
253
+ const depNote = phase.phase === 0 ? ' — no dependencies' : ` — depends on Phase ${phase.phase}`;
254
+ lines.push(`### Phase ${phase.phase + 1}${parallel}${depNote}`, '');
255
+
256
+ for (const epicId of phase.epicIds) {
257
+ const epic = allNodes.get(epicId);
258
+ const epicName = epic ? epic.name : epicId;
259
+ lines.push(`#### ${epicId}: ${epicName}`, '');
260
+
261
+ const stories = storyOrders.get(epicId) || [];
262
+ if (stories.length > 0) {
263
+ lines.push('| # | Story | ID |', '|---|-------|-----|');
264
+ stories.forEach((storyId, idx) => {
265
+ const story = allNodes.get(storyId);
266
+ const storyName = story ? story.name : storyId;
267
+ lines.push(`| ${idx + 1} | ${storyName} | ${storyId} |`);
268
+ });
269
+ lines.push('');
270
+ }
271
+ }
272
+ }
273
+
274
+ return lines.join('\n');
275
+ }
276
+
277
+ /**
278
+ * Render the coding order as structured JSON for the kanban API.
279
+ */
280
+ export function generateCodingOrderJson(phases, storyOrders, allNodes, criticalPath) {
281
+ return {
282
+ generatedAt: new Date().toISOString(),
283
+ criticalPath: {
284
+ epicIds: criticalPath.path,
285
+ length: criticalPath.length,
286
+ epics: criticalPath.path.map(id => {
287
+ const n = allNodes.get(id);
288
+ return { id, name: n?.name || id };
289
+ }),
290
+ },
291
+ phases: phases.map(phase => ({
292
+ phase: phase.phase + 1,
293
+ parallel: phase.epicIds.length > 1,
294
+ epics: phase.epicIds.map(epicId => {
295
+ const epic = allNodes.get(epicId);
296
+ const stories = (storyOrders.get(epicId) || []).map((storyId, idx) => {
297
+ const story = allNodes.get(storyId);
298
+ return { order: idx + 1, id: storyId, name: story?.name || storyId };
299
+ });
300
+ return { id: epicId, name: epic?.name || epicId, stories };
301
+ }),
302
+ })),
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Main entry point — compute everything from a hierarchy.
308
+ * @param {{ epics: Array }} hierarchy
309
+ * @returns {{ md: string, json: object, phases: Array, criticalPath: object }}
310
+ */
311
+ export function computeCodingOrder(hierarchy) {
312
+ const { epicGraph, storyGraphs, allNodes } = buildDependencyGraph(hierarchy);
313
+ const phases = computePhases(epicGraph);
314
+ const criticalPath = computeCriticalPath(epicGraph);
315
+
316
+ // Order stories within each epic
317
+ const storyOrders = new Map();
318
+ for (const [epicId, storyGraph] of storyGraphs) {
319
+ storyOrders.set(epicId, orderStoriesWithinEpic(storyGraph));
320
+ }
321
+
322
+ // Render mermaid edges using epicGraph
323
+ const md = generateCodingOrderMdWithGraph(phases, storyOrders, allNodes, criticalPath, epicGraph);
324
+ const json = generateCodingOrderJson(phases, storyOrders, allNodes, criticalPath);
325
+
326
+ return { md, json, phases, criticalPath };
327
+ }
328
+
329
+ /**
330
+ * Full Markdown rendering with mermaid graph edges.
331
+ */
332
+ function generateCodingOrderMdWithGraph(phases, storyOrders, allNodes, criticalPath, epicGraph) {
333
+ const lines = [
334
+ '# Coding Order',
335
+ '',
336
+ `Generated: ${new Date().toISOString()}`,
337
+ '',
338
+ '## Dependency Graph',
339
+ '',
340
+ '```mermaid',
341
+ 'graph LR',
342
+ ];
343
+
344
+ // Nodes
345
+ for (const [id, node] of allNodes) {
346
+ if (node.type === 'epic') {
347
+ const label = node.name.replace(/"/g, "'");
348
+ lines.push(` ${id}["${label}"]`);
349
+ }
350
+ }
351
+
352
+ // Edges
353
+ for (const [epicId, deps] of epicGraph) {
354
+ for (const dep of deps) {
355
+ lines.push(` ${dep} --> ${epicId}`);
356
+ }
357
+ }
358
+
359
+ // Highlight critical path
360
+ if (criticalPath.path.length > 1) {
361
+ lines.push(` style ${criticalPath.path.join(' stroke:#f44,stroke-width:3px; style ')} stroke:#f44,stroke-width:3px`);
362
+ }
363
+
364
+ lines.push('```', '');
365
+
366
+ // Critical path
367
+ lines.push('## Critical Path', '');
368
+ if (criticalPath.path.length > 0) {
369
+ const pathStr = criticalPath.path
370
+ .map(id => { const n = allNodes.get(id); return n ? `**${n.name}**` : id; })
371
+ .join(' → ');
372
+ lines.push(pathStr, '', `Length: ${criticalPath.length} epics`, '');
373
+ } else {
374
+ lines.push('No dependencies — all epics are independent.', '');
375
+ }
376
+
377
+ // Phases
378
+ lines.push('## Implementation Phases', '');
379
+ for (const phase of phases) {
380
+ const parallel = phase.epicIds.length > 1 ? ' (parallel)' : '';
381
+ const depNote = phase.phase === 0 ? '' : ` — requires Phase ${phase.phase} complete`;
382
+ lines.push(`### Phase ${phase.phase + 1}${parallel}${depNote}`, '');
383
+
384
+ for (const epicId of phase.epicIds) {
385
+ const epic = allNodes.get(epicId);
386
+ lines.push(`#### ${epicId}: ${epic?.name || epicId}`, '');
387
+
388
+ const stories = storyOrders.get(epicId) || [];
389
+ if (stories.length > 0) {
390
+ lines.push('| # | Story | ID |', '|---|-------|-----|');
391
+ stories.forEach((storyId, idx) => {
392
+ const story = allNodes.get(storyId);
393
+ lines.push(`| ${idx + 1} | ${story?.name || storyId} | \`${storyId}\` |`);
394
+ });
395
+ lines.push('');
396
+ }
397
+ }
398
+ }
399
+
400
+ return lines.join('\n');
401
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * dependency-checker.js — Pure-function module for checking work item dependency readiness.
3
+ *
4
+ * No side effects, no file I/O. All data passed in as arguments.
5
+ */
6
+
7
+ /**
8
+ * Extract the parent ID from a work item ID by stripping the last segment.
9
+ * context-0001-0001-0001 → context-0001-0001
10
+ * context-0001-0001 → context-0001
11
+ * context-0001 → null
12
+ * @param {string} id
13
+ * @returns {string|null}
14
+ */
15
+ export function getParentId(id) {
16
+ const match = id.match(/^(context-\d{4}(?:-\d{4})*)-\d{4}$/);
17
+ return match ? match[1] : null;
18
+ }
19
+
20
+ /**
21
+ * Check if all dependencies of a work item are completed.
22
+ * Walks up the parent chain: task checks parent story deps,
23
+ * story checks parent epic deps, etc.
24
+ *
25
+ * @param {string} itemId - The work item to check
26
+ * @param {Map<string,object>|object} items - Map of id → work item, or plain object
27
+ * @returns {{ ready: boolean, blockers: Array<{id: string, name: string, type: string, status: string}> }}
28
+ */
29
+ export function checkDependenciesReady(itemId, items) {
30
+ const get = (id) => items instanceof Map ? items.get(id) : items[id];
31
+ const blockers = [];
32
+ const seen = new Set();
33
+
34
+ function collectBlockers(id) {
35
+ if (!id || seen.has(id)) return;
36
+ seen.add(id);
37
+
38
+ const item = get(id);
39
+ if (!item) return;
40
+
41
+ // Check direct dependencies
42
+ for (const depId of item.dependencies || []) {
43
+ if (seen.has(depId)) continue;
44
+ const dep = get(depId);
45
+ if (!dep) continue;
46
+ if (dep.status !== 'completed') {
47
+ blockers.push({
48
+ id: depId,
49
+ name: dep.name || depId,
50
+ type: dep.type || 'unknown',
51
+ status: dep.status || 'planned',
52
+ });
53
+ }
54
+ }
55
+
56
+ // Walk up to parent and check its dependencies too
57
+ const parentId = getParentId(id);
58
+ if (parentId) {
59
+ collectBlockers(parentId);
60
+ }
61
+ }
62
+
63
+ collectBlockers(itemId);
64
+
65
+ // Deduplicate blockers by id
66
+ const unique = [...new Map(blockers.map(b => [b.id, b])).values()];
67
+
68
+ return {
69
+ ready: unique.length === 0,
70
+ blockers: unique,
71
+ };
72
+ }