@smartmemory/compose 0.2.58-beta → 0.3.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 (99) hide show
  1. package/README.md +2 -2
  2. package/bin/compose.js +55 -54
  3. package/dist/assets/{App-s4CulNkO.js → App-DJ5xk_Wx.js} +218 -218
  4. package/dist/assets/{abnfDiagram-VRR7QNED-CDwzQ5wr.js → abnfDiagram-VRR7QNED-BPWGdCFx.js} +1 -1
  5. package/dist/assets/{arc-kIU8DDth.js → arc-DX5jqmcO.js} +1 -1
  6. package/dist/assets/{architectureDiagram-ZJ3FMSHR-CleorO_0.js → architectureDiagram-ZJ3FMSHR-B6jmNVw7.js} +1 -1
  7. package/dist/assets/{blockDiagram-677ZJIJ3-NvEFfoMk.js → blockDiagram-677ZJIJ3-DAx2i-sB.js} +1 -1
  8. package/dist/assets/{c4Diagram-LMCZKHZV-BcDQdTVB.js → c4Diagram-LMCZKHZV-zmsZCplj.js} +1 -1
  9. package/dist/assets/channel-vsDnTvkh.js +1 -0
  10. package/dist/assets/{chunk-2Q5K7J3B-BseRkpm4.js → chunk-2Q5K7J3B-3QSh6sI7.js} +1 -1
  11. package/dist/assets/{chunk-32BRIVSS-DCHhvgFV.js → chunk-32BRIVSS-BiH5Di_y.js} +1 -1
  12. package/dist/assets/{chunk-5VM5RSS4-DcTpMdJ4.js → chunk-5VM5RSS4-C0EfjFLd.js} +1 -1
  13. package/dist/assets/{chunk-EX3LRPZG-BdN8fvWs.js → chunk-EX3LRPZG-BGyfmVm-.js} +1 -1
  14. package/dist/assets/{chunk-JWPE2WC7-DmZJP-8E.js → chunk-JWPE2WC7-Ba0mrNlg.js} +1 -1
  15. package/dist/assets/{chunk-MOJQB5TN-V74uYM17.js → chunk-MOJQB5TN-D3QO9EzH.js} +1 -1
  16. package/dist/assets/{chunk-RYQCIY6F-CoXUXbn_.js → chunk-RYQCIY6F-D1uvNA6d.js} +1 -1
  17. package/dist/assets/{chunk-V7JOEXUC-DUscIydR.js → chunk-V7JOEXUC-fihlnodT.js} +1 -1
  18. package/dist/assets/{chunk-VR4S4FIN-C4UDHq_a.js → chunk-VR4S4FIN-nmRUEo1H.js} +1 -1
  19. package/dist/assets/{chunk-XXDRQBXY-DIH9i8mZ.js → chunk-XXDRQBXY-CM693yEg.js} +1 -1
  20. package/dist/assets/classDiagram-OUVF2IWQ-DO-wdSFZ.js +1 -0
  21. package/dist/assets/classDiagram-v2-EOCWNBFH-DO-wdSFZ.js +1 -0
  22. package/dist/assets/{cose-bilkent-JH36ORCC-Dn6Gy6l1.js → cose-bilkent-JH36ORCC-CkacPn8W.js} +1 -1
  23. package/dist/assets/{cynefin-VYW2F7L2-C2LW5fzB.js → cynefin-VYW2F7L2-BiHaIptG.js} +1 -1
  24. package/dist/assets/{cynefinDiagram-TSTJHNR4-CGoAq7C9.js → cynefinDiagram-TSTJHNR4-CdKxMmiy.js} +1 -1
  25. package/dist/assets/{dagre-VKFMJZFB-BaOKtuBE.js → dagre-VKFMJZFB-BQLY5y_W.js} +1 -1
  26. package/dist/assets/{diagram-FQU43EPY-BdQwqt4x.js → diagram-FQU43EPY-D7uMBHvq.js} +1 -1
  27. package/dist/assets/{diagram-G47NLZAW-Dkcf0o5z.js → diagram-G47NLZAW-B3Z1cuH7.js} +1 -1
  28. package/dist/assets/{diagram-NH7WQ7WH-C_fDi59r.js → diagram-NH7WQ7WH-BZyRD45e.js} +1 -1
  29. package/dist/assets/{diagram-OA4YK3LP-jaTQcOxt.js → diagram-OA4YK3LP-DcThOTt7.js} +1 -1
  30. package/dist/assets/{diagram-WEI45ONY-dEtqVj3s.js → diagram-WEI45ONY-BcgRAkqY.js} +1 -1
  31. package/dist/assets/{ebnfDiagram-CCIWWBDH-s8ImqsSs.js → ebnfDiagram-CCIWWBDH-CGwfO_xH.js} +1 -1
  32. package/dist/assets/{erDiagram-Q63AITRT-5Zy29-SA.js → erDiagram-Q63AITRT-pV58-Ncc.js} +1 -1
  33. package/dist/assets/{flowDiagram-23GEKE2U-DV74V9he.js → flowDiagram-23GEKE2U-DJ_SqE8h.js} +1 -1
  34. package/dist/assets/{ganttDiagram-NO4QXBWP-BND-CiLO.js → ganttDiagram-NO4QXBWP-Dgy0Iyss.js} +1 -1
  35. package/dist/assets/{gitGraphDiagram-IHSO6WYX-B_-Mf9Jo.js → gitGraphDiagram-IHSO6WYX-CbiZw9fb.js} +1 -1
  36. package/dist/assets/{index-CBWbmG7W.js → index-DZTJEk-y.js} +2 -2
  37. package/dist/assets/{infoDiagram-FWYZ7A6U-Duyz8rZM.js → infoDiagram-FWYZ7A6U-CtsyyEc-.js} +1 -1
  38. package/dist/assets/{ishikawaDiagram-FXEZZL3T-D2Qft0e5.js → ishikawaDiagram-FXEZZL3T-BJilNFkK.js} +1 -1
  39. package/dist/assets/{journeyDiagram-5HDEW3XC-q6rG4Rig.js → journeyDiagram-5HDEW3XC-C2UCMP4t.js} +1 -1
  40. package/dist/assets/{kanban-definition-HUTT4EX6-CsPX7gBL.js → kanban-definition-HUTT4EX6-DmLDJBRy.js} +1 -1
  41. package/dist/assets/{linear-CiccpAAd.js → linear-C1paCqE7.js} +1 -1
  42. package/dist/assets/{mindmap-definition-LN4V7U3C-DRW2njpA.js → mindmap-definition-LN4V7U3C-CX-RxKVn.js} +1 -1
  43. package/dist/assets/{pegDiagram-2B236MQR-DoDgm2S_.js → pegDiagram-2B236MQR-CTU32H2W.js} +1 -1
  44. package/dist/assets/{pieDiagram-ENE6RG2P-CNSYLVAF.js → pieDiagram-ENE6RG2P-D8L1aYoo.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-ABIIQ3AL-8-Nd6ony.js → quadrantDiagram-ABIIQ3AL-hQ3bXosy.js} +1 -1
  46. package/dist/assets/{railroadDiagram-RFXS5EU6-bfdg6Bo4.js → railroadDiagram-RFXS5EU6--_vuYcda.js} +1 -1
  47. package/dist/assets/{requirementDiagram-TGXJPOKE-slDkxCQy.js → requirementDiagram-TGXJPOKE-C6h_m3Az.js} +1 -1
  48. package/dist/assets/{sankeyDiagram-HTMAVEWB-CR3CboiK.js → sankeyDiagram-HTMAVEWB-Dpc7CfIQ.js} +1 -1
  49. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BIXw1JS1.js → sequenceDiagram-DBY2YBRQ-CK5ZzbvJ.js} +1 -1
  50. package/dist/assets/{sizeCapture-X5ZJPWSS-BdKI7JyF.js → sizeCapture-X5ZJPWSS-BAxVvM9G.js} +1 -1
  51. package/dist/assets/{stateDiagram-2N3HPSRC-ktVgpBZS.js → stateDiagram-2N3HPSRC-7j33_2PY.js} +1 -1
  52. package/dist/assets/stateDiagram-v2-6OUMAXLB-GviN0FpJ.js +1 -0
  53. package/dist/assets/{swimlanes-5IMT3BWC-CaXpC3FM.js → swimlanes-5IMT3BWC-CBG2yOob.js} +2 -2
  54. package/dist/assets/swimlanesDiagram-G3AALYLV-D0wMoxl1.js +8 -0
  55. package/dist/assets/{timeline-definition-FHXFAJF6-CKWSlRUl.js → timeline-definition-FHXFAJF6-BOnZkQvc.js} +1 -1
  56. package/dist/assets/{vennDiagram-L72KCM5P-CwOhxDyv.js → vennDiagram-L72KCM5P-D52NhIfj.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-EHGQE667-DGavMpEB.js → wardleyDiagram-EHGQE667-YoPY2ZU-.js} +1 -1
  58. package/dist/assets/{xychartDiagram-FW5EYKEG-CWmnmLZz.js → xychartDiagram-FW5EYKEG-BanNfgtO.js} +1 -1
  59. package/dist/index.html +1 -1
  60. package/lib/build-all.js +0 -5
  61. package/lib/build-stream-schema.js +1 -1
  62. package/lib/build.js +1762 -2614
  63. package/lib/consumer-fanout.js +1317 -0
  64. package/lib/feature-validator.js +6 -4
  65. package/lib/flow-state.js +15 -14
  66. package/lib/gsd-budget.js +48 -10
  67. package/lib/gsd-prompt.js +3 -4
  68. package/lib/gsd-stuck.js +1 -1
  69. package/lib/gsd.js +303 -149
  70. package/lib/local-claude-connector.js +149 -0
  71. package/lib/new.js +162 -307
  72. package/lib/result-normalizer.js +233 -18
  73. package/lib/review-lenses.js +1 -1
  74. package/lib/step-prompt.js +41 -119
  75. package/lib/stratum-engine.js +297 -0
  76. package/lib/stratum-mcp-client.js +224 -213
  77. package/lib/vocabulary-compliance.js +268 -0
  78. package/lib/vocabulary-inject.js +1 -36
  79. package/package.json +2 -1
  80. package/pipelines/build-quick.stratum.yaml +5 -17
  81. package/pipelines/build.profiles.json +11 -0
  82. package/pipelines/build.stratum.yaml +288 -467
  83. package/pipelines/gsd.stratum.yaml +73 -125
  84. package/pipelines/new.stratum.yaml +68 -149
  85. package/server/build-routes.js +4 -1
  86. package/server/design-routes.js +37 -21
  87. package/server/index.js +13 -21
  88. package/server/lifecycle-guard.js +1 -1
  89. package/server/pipeline-routes.js +113 -31
  90. package/server/stratum-client.js +33 -47
  91. package/server/stratum-sync.js +3 -4
  92. package/server/vision-server.js +1 -1
  93. package/dist/assets/channel-DiJkE9og.js +0 -1
  94. package/dist/assets/classDiagram-OUVF2IWQ-DS76VBEL.js +0 -1
  95. package/dist/assets/classDiagram-v2-EOCWNBFH-DS76VBEL.js +0 -1
  96. package/dist/assets/stateDiagram-v2-6OUMAXLB-CzPQnlan.js +0 -1
  97. package/dist/assets/swimlanesDiagram-G3AALYLV-rIDv6EuQ.js +0 -8
  98. package/lib/connector-factory-shim.js +0 -167
  99. package/server/agent-mcp.js +0 -10
@@ -3,546 +3,367 @@
3
3
  # label: "Feature Build"
4
4
  # description: "Execute a feature through the full Compose lifecycle — design, plan, implement, review, test, ship"
5
5
  # category: development
6
- # steps: 16
6
+ # steps: 19
7
7
  # estimated_minutes: 120
8
8
 
9
- version: "0.3"
10
-
11
- workflow:
12
- name: build
13
- description: "Execute a feature through the full Compose lifecycle"
14
- input:
15
- featureCode:
16
- type: string
17
- required: true
18
- description:
19
- type: string
20
- required: true
21
- pre_merge_gate:
22
- type: array
23
- required: false # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: default-OFF per-task gate (lint+build), omitted unless capabilities.preMergeGate
24
- implementer_agent:
25
- type: string
26
- required: false # COMP-CODEX-IMPL: who writes the code (default claude; codex under --codex). Compose always supplies it.
27
- reviewer_agent:
28
- type: string
29
- required: false # COMP-CODEX-IMPL: cross-model reviewer, always != implementer (default codex; claude under --codex).
9
+ version: 1
30
10
 
31
11
  contracts:
32
12
  PhaseResult:
33
- phase: {type: string}
34
- artifact: {type: string}
35
- outcome: {type: string, values: [complete, skipped, failed]}
36
- summary: {type: string}
13
+ phase: string
14
+ artifact: string
15
+ outcome: complete|skipped|failed
16
+ summary: string
17
+ plan_items: array?
18
+ files_changed: string[]?
19
+ commit_hash: string?
37
20
 
38
- # Canonical review output — produced by both review_check (Codex) and parallel_review (Claude).
39
- # Schema source: compose/contracts/review-result.json (_roadmap: STRAT-CLAUDE-EFFORT-PARITY)
40
21
  ReviewResult:
41
- clean: {type: boolean}
42
- summary: {type: string}
43
- findings: {type: array}
44
- meta: {type: object}
45
- lenses_run: {type: array}
46
- auto_fixes: {type: array}
47
- asks: {type: array}
22
+ clean: boolean
23
+ summary: string
24
+ findings: array
25
+ meta: object
26
+ lenses_run: string[]
27
+ auto_fixes: array
28
+ asks: array
48
29
 
49
30
  TestResult:
50
- passing: {type: boolean}
51
- summary: {type: string}
52
- failures: {type: array}
31
+ passing: boolean
32
+ summary: string
33
+ failures: string[]
53
34
 
54
35
  TaskGraph:
55
- tasks: {type: array}
36
+ tasks: object[]
56
37
 
57
- LensTask:
58
- id: {type: string}
59
- lens_name: {type: string}
60
- lens_focus: {type: string}
61
- confidence_gate: {type: number}
62
- exclusions: {type: string}
38
+ TaskResult:
39
+ outcome: string
40
+ summary: string
41
+ files_changed: string[]?
63
42
 
64
43
  TriageResult:
65
- tasks: {type: array}
66
-
67
- functions:
68
- design_gate:
69
- mode: gate
70
- timeout: 3600
71
-
72
- plan_gate:
73
- mode: gate
74
- timeout: 3600
75
-
76
- ship_gate:
77
- mode: gate
78
- timeout: 1800
44
+ tasks: object[]
79
45
 
80
46
  flows:
81
- # --- Sub-flow: review ---
82
- # Single-step: codex reviews, stratum retries via ensure_failed.
83
- # Cross-agent fix (claude) is dispatched by build.js when ensure_failed
84
- # fires with a recovery_agent configured on the parent flow step.
47
+ entry: build
48
+
49
+ # Task-only subflow: cross-model implementation review.
85
50
  review_check:
86
51
  input:
87
- task: {type: string}
88
- blueprint: {type: string}
89
- reviewer_agent: {type: string} # COMP-CODEX-IMPL: threaded from the parent build flow (sub-flows have their own $.input scope)
90
- output: ReviewResult
52
+ task: string
53
+ blueprint: string
54
+ reviewer_agent: string
55
+ output:
56
+ from: "${review.output}"
57
+ contract: ReviewResult
91
58
  steps:
92
59
  - id: review
93
- agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: codex by default; claude when codex is the implementer (no self-review)
94
- intent: >
60
+ agent: "$.input.reviewer_agent"
61
+ do: >
95
62
  Review the implementation against the blueprint and task.
96
- inputs:
97
- task: "$.input.task"
98
- blueprint: "$.input.blueprint"
99
- review_mode: "true"
100
- confidence_gate: "7"
101
- output_contract: ReviewResult
63
+ Task: ${input.task}
64
+ Blueprint: ${input.blueprint}
65
+ Return the canonical ReviewResult shape.
66
+ out: ReviewResult
102
67
  ensure:
103
- - "result.clean == True"
104
- retries: 5
105
-
106
- # --- Sub-flow: parallel_review ---
107
- # Multi-lens review: triage selects lenses, parallel dispatch runs them,
108
- # merge deduplicates and classifies findings. Falls back to review_check
109
- # if parallel dispatch is unavailable.
110
- parallel_review:
111
- input:
112
- task: {type: string}
113
- blueprint: {type: string}
114
- diff: {type: string}
115
- prior_dirty_lenses: {type: array, optional: true}
116
- output: ReviewResult
117
- steps:
118
- - id: triage
119
- agent: "claude:orchestrator"
120
- intent: >
121
- Decide which review lenses to activate.
122
-
123
- RETRY PATH — If the file .compose/prior_dirty_lenses.json exists, read it.
124
- It contains a JSON array of lens IDs that had actionable findings in the prior
125
- review run. In this case:
126
- - Activate all lenses listed in that array.
127
- - Always also include diff-quality and contract-compliance (baseline lenses —
128
- they re-run on every retry to catch regressions introduced by the fix, even
129
- if they passed clean last time).
130
- - Skip all other lenses — they already passed clean.
131
-
132
- FIRST RUN PATH — If .compose/prior_dirty_lenses.json does not exist:
133
- - Always include diff-quality and contract-compliance.
134
- - Add security if files touch auth, crypto, SQL, HTTP handlers.
135
- - Add framework if detected framework files (React, Express, Next.js, etc).
136
-
137
- Return JSON: { "tasks": LensTask[] } where each task has id, lens_name,
138
- lens_focus, confidence_gate, exclusions.
139
- inputs:
140
- diff: "$.input.diff"
141
- output_contract: TriageResult
68
+ - expr: "result.clean == true"
69
+ attempts: 5
142
70
 
143
- - id: review_lenses
144
- type: parallel_dispatch
145
- agent: "claude:read-only-reviewer"
146
- source: "$.steps.triage.output.tasks"
147
- max_concurrent: 4
148
- isolation: none
149
- output_contract: ReviewResult
150
- intent_template: >
151
- Lens: {lens_name}. Focus: {lens_focus}.
152
- require: all
153
-
154
- - id: merge
155
- agent: "claude:orchestrator"
156
- intent: >
157
- Merge ReviewResult arrays from all lens runs into a single canonical ReviewResult.
158
- The input contains the parallel dispatch aggregate with tasks[].result for each lens.
159
- 1. Concatenate all findings arrays from completed task results.
160
- Deduplicate by file+line+lens: keep finding with highest confidence;
161
- carry over its applied_gate.
162
- 2. Recompute clean: zero must-fix AND zero should-fix findings (post-dedupe, post-gate).
163
- 3. lenses_run = IDs of lenses that produced any must-fix or should-fix finding.
164
- 4. auto_fixes = mechanical fixes (formatting, typos, simple tests).
165
- 5. asks = findings requiring human judgment.
166
- Return canonical ReviewResult with clean, summary, findings, lenses_run,
167
- auto_fixes, asks, meta.
168
- inputs:
169
- results: "$.steps.review_lenses.output"
170
- task: "$.input.task"
171
- blueprint: "$.input.blueprint"
172
- reduce_mode: "true"
173
- output_contract: ReviewResult
174
- depends_on: [review_lenses]
175
-
176
- # --- Sub-flow: coverage ---
177
- # Single-step: claude runs tests, stratum retries via ensure_failed.
178
- # Cross-agent fix is dispatched by build.js on ensure_failed.
71
+ # Task-only subflow: test generation and coverage sweep.
179
72
  coverage_check:
180
73
  input:
181
- task: {type: string}
182
- plan: {type: string}
183
- output: TestResult
74
+ task: string
75
+ plan: string
76
+ output:
77
+ from: "${run_tests.output}"
78
+ contract: TestResult
184
79
  steps:
185
80
  - id: run_tests
186
- agent: "claude::fast"
187
- intent: >
188
- Run the project test suite. Return structured JSON:
189
- { "passing": boolean, "summary": string, "failures": string[] }.
190
- inputs:
191
- task: "$.input.task"
192
- output_contract: TestResult
81
+ agent: claude
82
+ do: >
83
+ Run the project test suite for ${input.task}, following plan ${input.plan}.
84
+ Return {passing, summary, failures}.
85
+ out: TestResult
193
86
  ensure:
194
- - "result.passing == True"
195
- retries: 15
196
-
197
- # --- Sub-flow: test_review (COMP-TEST-BOOTSTRAP-4-1) ---
198
- # Reviews the test files the coverage step generated this build. The
199
- # implementation review (review/codex_review) runs BEFORE coverage, so
200
- # generated tests are never otherwise reviewed. build.js injects the exact
201
- # generated-test file list into this step's intent, and skips the step
202
- # entirely (synthetic clean stepDone) when coverage produced no test files.
203
- # ADVISORY: no blocking ensure — findings surface to the human, never fail ship.
204
- test_review:
205
- input:
206
- task: {type: string}
207
- blueprint: {type: string}
208
- reviewer_agent: {type: string} # COMP-CODEX-IMPL: threaded from the parent build flow
209
- output: ReviewResult
210
- steps:
211
- - id: review_generated_tests
212
- agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: codex by default; claude when codex implements
213
- intent: >
214
- Review the auto-generated test files listed below (written by the coverage
215
- step this build) and verify their assertions match intent. Read each file.
216
- Flag tests that are placeholders (assert true / pass with no real assertion),
217
- tautological, or assert only on mocks/stubs rather than exercising the
218
- feature's behavior. For each weak test, cite file:line and state what real
219
- assertion is missing. Do NOT flag hand-written tests or pure style. Output a
220
- canonical ReviewResult.
221
- inputs:
222
- task: "$.input.task"
223
- blueprint: "$.input.blueprint"
224
- review_mode: "true"
225
- confidence_gate: "7"
226
- # ADVISORY (COMP-TEST-BOOTSTRAP-4-1): deliberately NO output_contract and NO
227
- # ensure. A schema/postcondition failure here would trigger executeChildFlow's
228
- # blocking fix-retry path and could block ship (report→docs→ship chain through
229
- # test_review). Without either gate the step always completes; build.js captures
230
- # whatever the reviewer returns and surfaces it via the test_review stream event.
231
-
232
- # --- Main flow: compose feature lifecycle ---
87
+ - expr: "result.passing == true"
88
+ attempts: 15
89
+
233
90
  build:
234
91
  input:
235
- featureCode: {type: string}
236
- description: {type: string}
237
- pre_merge_gate: {type: array} # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: optional per-task pre-merge gate
238
- implementer_agent: {type: string} # COMP-CODEX-IMPL: code-writing executor (default claude; codex under --codex)
239
- reviewer_agent: {type: string} # COMP-CODEX-IMPL: cross-model reviewer, always != implementer
240
- output: PhaseResult
92
+ featureCode: string
93
+ description: string
94
+ pre_merge_gate: string[]?
95
+ implementer_agent: string
96
+ reviewer_agent: string
97
+ output:
98
+ from: "${ship.output}"
99
+ contract: PhaseResult
241
100
  max_rounds: 10
242
101
  steps:
243
- # Phase: Explore & Design
244
102
  - id: explore_design
245
103
  agent: claude
246
- intent: >
247
- Explore the codebase and write a design doc for this feature.
248
- Launch 2-3 explorer subagents in parallel to map architecture,
249
- find similar features, and analyze related implementations.
250
- Write the design to docs/features/{featureCode}/design.md.
251
- Return the artifact path in the "artifact" field.
252
- inputs:
253
- featureCode: "$.input.featureCode"
254
- description: "$.input.description"
255
- output_contract: PhaseResult
104
+ do: >
105
+ Explore the codebase and write a design doc for ${input.featureCode}.
106
+ Launch 2-3 explorer subagents in parallel to map architecture, find similar
107
+ features, and analyze related implementations. Feature: ${input.description}.
108
+ Write docs/features/${input.featureCode}/design.md and return PhaseResult.
109
+ out: PhaseResult
256
110
  ensure:
257
- - "result.outcome == 'complete'"
258
- - "file_exists(result.artifact)"
259
- retries: 2
111
+ - expr: "result.outcome == 'complete'"
112
+ - expr: "file_exists(result.artifact)"
113
+ attempts: 2
260
114
 
261
- # Gate: Design review
262
115
  - id: design_gate
263
- function: design_gate
264
- on_approve: prd
265
- on_revise: explore_design
266
- on_kill: null
267
- depends_on: [explore_design]
116
+ after: [explore_design]
117
+ gate:
118
+ on_approve: prd
119
+ on_revise: explore_design
120
+ on_kill: null
268
121
 
269
- # Phase: PRD (skippable)
270
122
  - id: prd
123
+ when: "false"
271
124
  agent: claude
272
- intent: >
273
- Write a product requirements document for this feature.
274
- Write to docs/features/{featureCode}/prd.md.
275
- Return the artifact path in the "artifact" field.
276
- inputs:
277
- featureCode: "$.input.featureCode"
278
- description: "$.input.description"
279
- output_contract: PhaseResult
125
+ do: >
126
+ Write a product requirements document for ${input.featureCode} at
127
+ docs/features/${input.featureCode}/prd.md. Return PhaseResult.
128
+ out: PhaseResult
280
129
  ensure:
281
- - "result.outcome == 'complete'"
282
- - "file_exists(result.artifact)"
283
- retries: 2
284
- skip_if: "true"
285
- skip_reason: "PRD skipped by default — set skip_if to false to enable"
286
- depends_on: [design_gate]
287
-
288
- # Phase: Architecture (skippable)
130
+ - expr: "result.outcome == 'complete'"
131
+ - expr: "file_exists(result.artifact)"
132
+ attempts: 2
133
+
289
134
  - id: architecture
135
+ after: [prd]
136
+ when: "false"
290
137
  agent: claude
291
- intent: >
292
- Write an architecture doc with competing proposals.
293
- Write to docs/features/{featureCode}/architecture.md.
294
- Return the artifact path in the "artifact" field.
295
- inputs:
296
- featureCode: "$.input.featureCode"
297
- description: "$.input.description"
298
- output_contract: PhaseResult
138
+ do: >
139
+ Write an architecture doc with competing proposals for ${input.featureCode}
140
+ at docs/features/${input.featureCode}/architecture.md. Return PhaseResult.
141
+ out: PhaseResult
299
142
  ensure:
300
- - "result.outcome == 'complete'"
301
- - "file_exists(result.artifact)"
302
- retries: 2
303
- skip_if: "true"
304
- skip_reason: "Architecture skipped by default — set skip_if to false to enable"
305
- depends_on: [prd]
306
-
307
- # Phase: Blueprint
143
+ - expr: "result.outcome == 'complete'"
144
+ - expr: "file_exists(result.artifact)"
145
+ attempts: 2
146
+
308
147
  - id: blueprint
309
- agent: "claude::critical"
310
- intent: >
311
- Write an implementation blueprint with file:line references to existing code.
312
- Ground every reference in actual files. Write to docs/features/{featureCode}/blueprint.md.
313
- Return the artifact path in the "artifact" field.
314
- inputs:
315
- featureCode: "$.input.featureCode"
316
- description: "$.input.description"
317
- output_contract: PhaseResult
148
+ after: [architecture]
149
+ agent: claude
150
+ do: >
151
+ Write an implementation blueprint with verified file:line references for
152
+ ${input.featureCode} at docs/features/${input.featureCode}/blueprint.md.
153
+ Return PhaseResult.
154
+ out: PhaseResult
318
155
  ensure:
319
- - "result.outcome == 'complete'"
320
- - "file_exists(result.artifact)"
321
- retries: 3
322
- depends_on: [architecture]
156
+ - expr: "result.outcome == 'complete'"
157
+ - expr: "file_exists(result.artifact)"
158
+ attempts: 3
323
159
 
324
- # Phase: Blueprint Verification
325
160
  - id: verification
161
+ after: [blueprint]
326
162
  agent: claude
327
- intent: >
328
- Verify every file:line reference in the blueprint against the actual codebase.
329
- Flag stale or incorrect references. If the blueprint contains a `## Boundary Map`
330
- section, additionally invoke `validateBoundaryMap` from `lib/boundary-map.js` and
331
- treat its violations as stale references; treat its warnings as informational.
332
- Summarize Boundary Map results (counts of violations and warnings, plus any
333
- must-fix detail) inside the existing `summary` string field of the PhaseResult —
334
- do not add new top-level fields. The phase outcome is `complete` only when every
335
- file:line reference is valid AND the Boundary Map (if present) has zero violations.
336
- inputs:
337
- featureCode: "$.input.featureCode"
338
- description: "$.input.description"
339
- output_contract: PhaseResult
163
+ do: >
164
+ Verify every file:line reference in ${blueprint.output.artifact}. If it has a
165
+ Boundary Map, invoke validateBoundaryMap from lib/boundary-map.js. Return a
166
+ complete PhaseResult only when references are valid and violations are zero.
167
+ out: PhaseResult
340
168
  ensure:
341
- - "result.outcome == 'complete'"
342
- retries: 2
343
- on_fail: blueprint
344
- depends_on: [blueprint]
169
+ - expr: "result.outcome == 'complete'"
170
+ attempts: 2
345
171
 
346
- # Phase: Implementation Plan
347
172
  - id: plan
173
+ after: [verification]
348
174
  agent: claude
349
- intent: >
350
- Write an ordered implementation plan with tasks, dependencies, file paths (new/existing),
351
- and acceptance criteria. Write to docs/features/{featureCode}/plan.md.
352
- Return the artifact path in the "artifact" field.
353
- inputs:
354
- featureCode: "$.input.featureCode"
355
- description: "$.input.description"
356
- output_contract: PhaseResult
175
+ do: >
176
+ Write an ordered implementation plan for ${input.featureCode} with tasks,
177
+ dependencies, file paths, and acceptance criteria at
178
+ docs/features/${input.featureCode}/plan.md. Return PhaseResult.
179
+ out: PhaseResult
357
180
  ensure:
358
- - "result.outcome == 'complete'"
359
- - "file_exists(result.artifact)"
360
- retries: 2
361
- depends_on: [verification]
181
+ - expr: "result.outcome == 'complete'"
182
+ - expr: "file_exists(result.artifact)"
183
+ attempts: 2
362
184
 
363
- # Gate: Plan review
364
185
  - id: plan_gate
365
- function: plan_gate
366
- on_approve: decompose
367
- on_revise: plan
368
- on_kill: null
369
- depends_on: [plan]
186
+ after: [plan]
187
+ gate:
188
+ on_approve: decompose
189
+ on_revise: plan
190
+ on_kill: null
370
191
 
371
- # Phase: Decompose — analyze the plan and emit a task graph
372
192
  - id: decompose
373
- type: decompose
374
193
  agent: claude
375
- intent: >
376
- Read the implementation plan and decompose it into independent tasks.
377
- For each task, identify files_owned (exclusive write), files_read (read-only),
378
- and depends_on (tasks that must complete first).
379
- Return a TaskGraph with the task array.
380
- output_contract: TaskGraph
194
+ do: >
195
+ Read ${plan.output.artifact} and decompose it into independent tasks. For each
196
+ task identify id, description, files_owned, files_read, and depends_on. Reject
197
+ file ownership conflicts. Return {tasks}.
198
+ out: TaskGraph
381
199
  ensure:
382
- - "no_file_conflicts(result.tasks)"
383
- - "len(result.tasks) >= 1"
384
- retries: 2
385
- depends_on: [plan_gate]
200
+ - expr: "len(result.tasks) >= 1"
201
+ attempts: 2
386
202
 
387
- # Phase: Execute parallel dispatch of decomposed tasks
203
+ # v0.3 parallel_dispatch -> TS v1 consumer fanout. Compose owns worktrees,
204
+ # pre-merge commands, retained diffs, and the downstream merge handshake.
388
205
  - id: execute
389
- type: parallel_dispatch
390
- source: "$.steps.decompose.output.tasks"
391
- agent: "$.input.implementer_agent" # COMP-CODEX-IMPL: claude by default, codex under --codex (resolved via STRAT-AGENT-INTERP)
392
- max_concurrent: 3
393
- isolation: worktree
394
- capture_diff: true
395
- defer_advance: true
396
- pre_merge_verify: "$.input.pre_merge_gate" # COMP-PAR-MERGE-QUEUE-CONSUMER-RETRY: optional per-task fast gate (default-OFF)
397
- require: all
398
- merge: sequential_apply
399
- intent_template: >
400
- Implement this task using TDD. Write the test first, watch it fail,
401
- implement, watch it pass.
402
-
403
- Task: {task.description}
404
- You own these files (may create/modify): {task.files_owned}
405
- You may read (but NOT modify): {task.files_read}
406
-
407
- Feature: {task.id}
408
- depends_on: [decompose]
409
-
410
- # Sub-flow: Review (parallel multi-lens review; falls back to review_check)
411
- # Parent-step ensure drives the fix loop: ensure_failed -> build.js fix ->
412
- # retry the whole parallel_review sub-flow, which re-runs fresh triage/lenses/merge.
413
- - id: review
414
- flow: parallel_review
415
- inputs:
416
- task: "$.steps.execute.output.outcome"
417
- blueprint: "$.steps.blueprint.output.artifact"
418
- diff: "$.steps.execute.output.tasks"
419
- ensure:
420
- - "result.clean == True"
421
- depends_on: [execute]
206
+ after: [decompose]
207
+ attempts: 2
208
+ fanout:
209
+ over: "${decompose.output.tasks}"
210
+ dispatch: consumer
211
+ concurrency: 3
212
+ isolation: worktree
213
+ require: all
214
+ merge: sequential
215
+ pre_merge: "$.input.pre_merge_gate"
216
+ steps:
217
+ - agent: "$.input.implementer_agent"
218
+ do: >
219
+ Implement the task described by ${item} using TDD. Write the test first,
220
+ watch it fail, implement, and watch it pass. Honor the item's id,
221
+ files_owned, files_read, description, and dependency fields.
222
+ Return {outcome, summary, files_changed}.
223
+ out: TaskResult
224
+
225
+ - id: execute_merge
226
+ after: [execute]
227
+ gate:
228
+ on_approve: review_triage
229
+ on_revise: execute
230
+ on_kill: null
231
+ max_rounds: 10
232
+
233
+ # The former parallel_review subflow is flattened because TS v1 permits
234
+ # fanout only in the entry flow.
235
+ - id: review_triage
236
+ agent: claude
237
+ do: >
238
+ Select review lenses for the implementation results ${execute.output}.
239
+
240
+ RETRY PATH — If .compose/prior_dirty_lenses.json exists, read its JSON array.
241
+ Activate all lenses listed in that array. Always also include diff-quality
242
+ and contract-compliance. Skip all other lenses because they already passed
243
+ clean.
244
+
245
+ FIRST RUN PATH — If .compose/prior_dirty_lenses.json does not exist, always
246
+ include diff-quality, contract-compliance, and debug-discipline. Add security
247
+ for auth, crypto, SQL, or HTTP-handler changes, and add framework for detected
248
+ framework files.
249
+
250
+ Return {tasks}; each task must include id, lens_name, lens_focus,
251
+ confidence_gate, and exclusions.
252
+ out: TriageResult
253
+
254
+ - id: review_lenses
255
+ after: [review_triage]
256
+ fanout:
257
+ over: "${review_triage.output.tasks}"
258
+ dispatch: consumer
259
+ concurrency: 4
260
+ isolation: none
261
+ require: all
262
+ merge: sequential
263
+ steps:
264
+ - agent: claude
265
+ do: >
266
+ Run the review lens described by ${item}. Honor its lens_name,
267
+ lens_focus, confidence_gate, and exclusions fields. Return the canonical
268
+ ReviewResult shape.
269
+ out: ReviewResult
270
+
271
+ - id: review_lenses_gate
272
+ after: [review_lenses]
273
+ gate:
274
+ on_approve: review_merge
275
+ on_revise: review_triage
276
+ on_kill: null
277
+ max_rounds: 10
278
+
279
+ - id: review_merge
280
+ agent: claude
281
+ do: >
282
+ Merge ${review_lenses.output} into one canonical ReviewResult. Concatenate and
283
+ deduplicate findings by file+line+lens, keep the highest confidence, recompute
284
+ clean, set lenses_run to dirty lens ids, and classify auto_fixes and asks.
285
+ out: ReviewResult
286
+
287
+ # I1: dirty-review recovery is engine-native. review_merge cannot converge on
288
+ # its own (re-running the reducer re-merges the SAME frozen lens outputs), so
289
+ # the cleanliness decision is a GATE. Compose resolves it by policy: a clean
290
+ # merge approves; a dirty merge runs the corrective fixer, persists the dirty
291
+ # lens ids, and REVISES — the engine reroutes to review_triage, whose RETRY
292
+ # PATH reads the sidecar and re-runs only the dirty lenses on the fixed code.
293
+ - id: review_gate
294
+ after: [review_merge]
295
+ gate:
296
+ on_approve: codex_review
297
+ on_revise: review_triage
298
+ on_kill: null
299
+ max_rounds: 10
422
300
 
423
- # Sub-flow: Codex review (independent cross-model pass after Claude lenses + fixes)
424
301
  - id: codex_review
425
- flow: review_check
426
- inputs:
427
- task: "$.steps.execute.output.outcome"
428
- blueprint: "$.steps.blueprint.output.artifact"
429
- reviewer_agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: thread the role into the sub-flow
430
- ensure:
431
- - "result.clean == True"
432
- depends_on: [review]
302
+ after: [review_gate]
303
+ run: review_check
304
+ with:
305
+ task: "${review_merge.output.summary}"
306
+ blueprint: "${blueprint.output.artifact}"
307
+ reviewer_agent: "${input.reviewer_agent}"
433
308
 
434
- # Sub-flow: Coverage (claude runs tests; build.js dispatches fix on ensure_failed)
435
309
  - id: coverage
436
- flow: coverage_check
437
- inputs:
438
- task: "$.steps.execute.output.outcome"
439
- plan: "$.input.description"
440
- ensure:
441
- - "result.passing == True"
442
- depends_on: [codex_review]
310
+ after: [codex_review]
311
+ run: coverage_check
312
+ with:
313
+ task: "${input.description}"
314
+ plan: "${plan.output.artifact}"
443
315
 
444
- # Sub-flow: Test review (COMP-TEST-BOOTSTRAP-4-1) review the tests the
445
- # coverage step generated this build. build.js injects the generated-test
446
- # file list into the intent, and reports a synthetic clean result (skip)
447
- # when coverage produced no test files. Advisory — never blocks ship.
316
+ # Advisory by construction: no output contract and no ensure.
448
317
  - id: test_review
449
- flow: test_review
450
- inputs:
451
- task: "$.steps.execute.output.outcome"
452
- blueprint: "$.steps.blueprint.output.artifact"
453
- reviewer_agent: "$.input.reviewer_agent" # COMP-CODEX-IMPL: thread the role into the sub-flow
454
- depends_on: [coverage]
455
-
456
- # Phase: Report (skippable)
318
+ after: [coverage]
319
+ agent: "$.input.reviewer_agent"
320
+ do: >
321
+ Review tests generated for ${input.featureCode}. Flag placeholders,
322
+ tautologies, and assertions that only exercise mocks. Cite file:line and the
323
+ missing real assertion. This is advisory and must not block ship.
324
+
457
325
  - id: report
326
+ after: [test_review]
327
+ when: "false"
458
328
  agent: claude
459
- intent: >
460
- Write a post-implementation report documenting what was built,
461
- deviations from the plan, and lessons learned.
462
- Write to docs/features/{featureCode}/report.md.
463
- Return the artifact path in the "artifact" field.
464
- inputs:
465
- featureCode: "$.input.featureCode"
466
- description: "$.input.description"
467
- output_contract: PhaseResult
329
+ do: >
330
+ Write docs/features/${input.featureCode}/report.md covering delivered work,
331
+ deviations, and lessons learned. Return PhaseResult.
332
+ out: PhaseResult
468
333
  ensure:
469
- - "result.outcome == 'complete'"
470
- - "file_exists(result.artifact)"
471
- retries: 2
472
- skip_if: "true"
473
- skip_reason: "Report skipped by default — set skip_if to false to enable"
474
- depends_on: [test_review]
475
-
476
- # Phase: Update Docs
334
+ - expr: "result.outcome == 'complete'"
335
+ - expr: "file_exists(result.artifact)"
336
+ attempts: 2
337
+
477
338
  - id: docs
339
+ after: [report]
478
340
  agent: claude
479
- intent: >
480
- Update project documentation for this feature. You MUST:
481
-
482
- 1. CHANGELOG.md Add an entry under today's date with the feature code
483
- and a bullet list of what was built. Read the existing format first.
484
- 2. ROADMAP.md — Find this feature's row and change its status to COMPLETE.
485
- If this completes a parent feature, update the parent header too.
486
- 3. README.md — Update ONLY if the feature changes user-facing setup,
487
- commands, or capabilities. Skip if purely internal.
488
- 4. CLAUDE.md — Update ONLY if new conventions, commands, or architecture
489
- patterns were introduced. Skip if no changes.
490
- 5. Public docs — If the feature introduces or changes any of these, update
491
- the relevant file in docs/:
492
- - New CLI commands or flags → docs/compose-one-pager.md
493
- - New connector or agent type → docs/connectors.md
494
- - New workflow or lifecycle change → docs/use-cases.md
495
- - API or config changes → docs/PRODUCT-SPEC.md
496
- Read each file before editing. Skip if the feature is purely internal
497
- with no user-facing changes.
498
-
499
- Read each file before editing. Do not skip CHANGELOG and ROADMAP —
500
- they are always required. Commit nothing — the ship step handles commits.
501
- inputs:
502
- featureCode: "$.input.featureCode"
503
- description: "$.input.description"
504
- output_contract: PhaseResult
505
- retries: 2
506
- depends_on: [report]
507
-
508
- # Phase: Ship
341
+ do: >
342
+ Update CHANGELOG.md and ROADMAP.md for ${input.featureCode}. Update README.md,
343
+ CLAUDE.md, and public docs only when the feature changes their documented
344
+ surfaces. Commit nothing. Return PhaseResult.
345
+ out: PhaseResult
346
+ attempts: 2
347
+
509
348
  - id: ship
510
- agent: "claude::critical"
511
- intent: >
512
- Final verification and commit. You MUST:
513
-
514
- 1. Run the test suite (npm test or node --test test/*.test.js).
515
- If tests fail, fix them before proceeding.
516
- 2. Run the build (npx vite build). Must pass.
517
- 3. Check git status — verify CHANGELOG.md and ROADMAP.md were updated
518
- by the docs step. If they weren't, update them now.
519
- 4. Stage all changed files for this feature (git add be explicit,
520
- never stage worktrees, pycache, or node_modules).
521
- 5. Commit with message: "feat(<featureCode>): <one-line summary>"
522
- 6. Push to remote.
523
- 7. Read docs/features/{featureCode}/plan.md and extract acceptance criteria
524
- as plan_items: an array of objects { text, file, critical } where:
525
- - text is the checkbox item text
526
- - file is the backtick-quoted file path in the item (null if none)
527
- - critical is true if the item mentions MUST, required, security, or tests
528
- Use lib/plan-parser.js (parsePlanItems) to do this extraction.
529
- 8. Collect the list of files you staged as files_changed.
530
-
531
- Include plan_items and files_changed in your result JSON.
532
- Report the commit hash and files changed.
533
- inputs:
534
- featureCode: "$.input.featureCode"
535
- description: "$.input.description"
536
- output_contract: PhaseResult
537
- ensure:
538
- - "plan_completion(result.plan_items, result.files_changed)"
539
- retries: 2
540
- depends_on: [docs]
349
+ after: [docs]
350
+ agent: claude
351
+ do: >
352
+ Run the full test suite and build for ${input.featureCode}; fix failures.
353
+ Verify CHANGELOG.md and ROADMAP.md, stage only feature files, commit and push.
354
+ Parse plan acceptance criteria with lib/plan-parser.js and return PhaseResult
355
+ including plan_items, files_changed, and commit_hash.
356
+ out: PhaseResult
357
+ # C5: the judged ship ensure was removed it is unevaluable from the
358
+ # {result, input} the judge receives (it fails closed even on evidenced
359
+ # results, so real TS-default builds would plausibly die at ship). Same
360
+ # class as the F5 vocabulary ruling. Ship stays gated by ship_gate; revisit
361
+ # when a deterministic/tunable judge backend exists (stratum follow-up).
362
+ attempts: 2
541
363
 
542
- # Gate: Ship review
543
364
  - id: ship_gate
544
- function: ship_gate
545
- on_approve: null
546
- on_revise: ship
547
- on_kill: null
548
- depends_on: [ship]
365
+ after: [ship]
366
+ gate:
367
+ on_approve: null
368
+ on_revise: ship
369
+ on_kill: null