opencastle 0.31.7 → 0.32.1

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 (220) hide show
  1. package/README.md +4 -1
  2. package/bin/cli.mjs +15 -0
  3. package/dist/cli/agents.d.ts.map +1 -1
  4. package/dist/cli/agents.js +19 -5
  5. package/dist/cli/agents.js.map +1 -1
  6. package/dist/cli/artifacts-cli.d.ts +3 -0
  7. package/dist/cli/artifacts-cli.d.ts.map +1 -0
  8. package/dist/cli/artifacts-cli.js +36 -0
  9. package/dist/cli/artifacts-cli.js.map +1 -0
  10. package/dist/cli/baselines.d.ts.map +1 -1
  11. package/dist/cli/baselines.js +11 -0
  12. package/dist/cli/baselines.js.map +1 -1
  13. package/dist/cli/convoy/artifacts.d.ts +25 -0
  14. package/dist/cli/convoy/artifacts.d.ts.map +1 -0
  15. package/dist/cli/convoy/artifacts.js +129 -0
  16. package/dist/cli/convoy/artifacts.js.map +1 -0
  17. package/dist/cli/convoy/artifacts.test.d.ts +2 -0
  18. package/dist/cli/convoy/artifacts.test.d.ts.map +1 -0
  19. package/dist/cli/convoy/artifacts.test.js +169 -0
  20. package/dist/cli/convoy/artifacts.test.js.map +1 -0
  21. package/dist/cli/convoy/compaction.d.ts +23 -0
  22. package/dist/cli/convoy/compaction.d.ts.map +1 -0
  23. package/dist/cli/convoy/compaction.js +117 -0
  24. package/dist/cli/convoy/compaction.js.map +1 -0
  25. package/dist/cli/convoy/compaction.test.d.ts +2 -0
  26. package/dist/cli/convoy/compaction.test.d.ts.map +1 -0
  27. package/dist/cli/convoy/compaction.test.js +205 -0
  28. package/dist/cli/convoy/compaction.test.js.map +1 -0
  29. package/dist/cli/convoy/contracts.d.ts +22 -0
  30. package/dist/cli/convoy/contracts.d.ts.map +1 -0
  31. package/dist/cli/convoy/contracts.js +254 -0
  32. package/dist/cli/convoy/contracts.js.map +1 -0
  33. package/dist/cli/convoy/contracts.test.d.ts +2 -0
  34. package/dist/cli/convoy/contracts.test.d.ts.map +1 -0
  35. package/dist/cli/convoy/contracts.test.js +239 -0
  36. package/dist/cli/convoy/contracts.test.js.map +1 -0
  37. package/dist/cli/convoy/dag-analysis.d.ts +40 -0
  38. package/dist/cli/convoy/dag-analysis.d.ts.map +1 -0
  39. package/dist/cli/convoy/dag-analysis.js +282 -0
  40. package/dist/cli/convoy/dag-analysis.js.map +1 -0
  41. package/dist/cli/convoy/dag-analysis.test.d.ts +2 -0
  42. package/dist/cli/convoy/dag-analysis.test.d.ts.map +1 -0
  43. package/dist/cli/convoy/dag-analysis.test.js +289 -0
  44. package/dist/cli/convoy/dag-analysis.test.js.map +1 -0
  45. package/dist/cli/convoy/effort-scaling.d.ts +20 -0
  46. package/dist/cli/convoy/effort-scaling.d.ts.map +1 -0
  47. package/dist/cli/convoy/effort-scaling.js +82 -0
  48. package/dist/cli/convoy/effort-scaling.js.map +1 -0
  49. package/dist/cli/convoy/effort-scaling.test.d.ts +2 -0
  50. package/dist/cli/convoy/effort-scaling.test.d.ts.map +1 -0
  51. package/dist/cli/convoy/effort-scaling.test.js +120 -0
  52. package/dist/cli/convoy/effort-scaling.test.js.map +1 -0
  53. package/dist/cli/convoy/engine.d.ts.map +1 -1
  54. package/dist/cli/convoy/engine.js +280 -6
  55. package/dist/cli/convoy/engine.js.map +1 -1
  56. package/dist/cli/convoy/engine.test.js +155 -18
  57. package/dist/cli/convoy/engine.test.js.map +1 -1
  58. package/dist/cli/convoy/event-schemas.d.ts.map +1 -1
  59. package/dist/cli/convoy/event-schemas.js +55 -0
  60. package/dist/cli/convoy/event-schemas.js.map +1 -1
  61. package/dist/cli/convoy/isolation.d.ts +27 -0
  62. package/dist/cli/convoy/isolation.d.ts.map +1 -0
  63. package/dist/cli/convoy/isolation.js +120 -0
  64. package/dist/cli/convoy/isolation.js.map +1 -0
  65. package/dist/cli/convoy/isolation.test.d.ts +2 -0
  66. package/dist/cli/convoy/isolation.test.d.ts.map +1 -0
  67. package/dist/cli/convoy/isolation.test.js +105 -0
  68. package/dist/cli/convoy/isolation.test.js.map +1 -0
  69. package/dist/cli/convoy/review-stages.d.ts +9 -0
  70. package/dist/cli/convoy/review-stages.d.ts.map +1 -0
  71. package/dist/cli/convoy/review-stages.js +134 -0
  72. package/dist/cli/convoy/review-stages.js.map +1 -0
  73. package/dist/cli/convoy/review-stages.test.d.ts +2 -0
  74. package/dist/cli/convoy/review-stages.test.d.ts.map +1 -0
  75. package/dist/cli/convoy/review-stages.test.js +197 -0
  76. package/dist/cli/convoy/review-stages.test.js.map +1 -0
  77. package/dist/cli/convoy/skill-refinement.d.ts +39 -0
  78. package/dist/cli/convoy/skill-refinement.d.ts.map +1 -0
  79. package/dist/cli/convoy/skill-refinement.js +239 -0
  80. package/dist/cli/convoy/skill-refinement.js.map +1 -0
  81. package/dist/cli/convoy/skill-refinement.test.d.ts +2 -0
  82. package/dist/cli/convoy/skill-refinement.test.d.ts.map +1 -0
  83. package/dist/cli/convoy/skill-refinement.test.js +230 -0
  84. package/dist/cli/convoy/skill-refinement.test.js.map +1 -0
  85. package/dist/cli/convoy/spec-builder.d.ts +1 -0
  86. package/dist/cli/convoy/spec-builder.d.ts.map +1 -1
  87. package/dist/cli/convoy/spec-builder.js +11 -0
  88. package/dist/cli/convoy/spec-builder.js.map +1 -1
  89. package/dist/cli/convoy/spec-builder.test.js +54 -0
  90. package/dist/cli/convoy/spec-builder.test.js.map +1 -1
  91. package/dist/cli/convoy/store.d.ts +3 -2
  92. package/dist/cli/convoy/store.d.ts.map +1 -1
  93. package/dist/cli/convoy/store.js +20 -2
  94. package/dist/cli/convoy/store.js.map +1 -1
  95. package/dist/cli/convoy/store.test.js +15 -15
  96. package/dist/cli/convoy/store.test.js.map +1 -1
  97. package/dist/cli/convoy/tdd-gate.d.ts +15 -0
  98. package/dist/cli/convoy/tdd-gate.d.ts.map +1 -0
  99. package/dist/cli/convoy/tdd-gate.js +119 -0
  100. package/dist/cli/convoy/tdd-gate.js.map +1 -0
  101. package/dist/cli/convoy/tdd-gate.test.d.ts +2 -0
  102. package/dist/cli/convoy/tdd-gate.test.d.ts.map +1 -0
  103. package/dist/cli/convoy/tdd-gate.test.js +227 -0
  104. package/dist/cli/convoy/tdd-gate.test.js.map +1 -0
  105. package/dist/cli/convoy/types.d.ts +91 -0
  106. package/dist/cli/convoy/types.d.ts.map +1 -1
  107. package/dist/cli/convoy/types.js +8 -0
  108. package/dist/cli/convoy/types.js.map +1 -1
  109. package/dist/cli/insights.d.ts +3 -0
  110. package/dist/cli/insights.d.ts.map +1 -0
  111. package/dist/cli/insights.js +94 -0
  112. package/dist/cli/insights.js.map +1 -0
  113. package/dist/cli/lesson.d.ts.map +1 -1
  114. package/dist/cli/lesson.js +7 -0
  115. package/dist/cli/lesson.js.map +1 -1
  116. package/dist/cli/log.d.ts.map +1 -1
  117. package/dist/cli/log.js +7 -0
  118. package/dist/cli/log.js.map +1 -1
  119. package/dist/cli/package-config.d.ts +12 -0
  120. package/dist/cli/package-config.d.ts.map +1 -0
  121. package/dist/cli/package-config.js +37 -0
  122. package/dist/cli/package-config.js.map +1 -0
  123. package/dist/cli/package.d.ts +23 -0
  124. package/dist/cli/package.d.ts.map +1 -0
  125. package/dist/cli/package.js +285 -0
  126. package/dist/cli/package.js.map +1 -0
  127. package/dist/cli/package.test.d.ts +2 -0
  128. package/dist/cli/package.test.d.ts.map +1 -0
  129. package/dist/cli/package.test.js +236 -0
  130. package/dist/cli/package.test.js.map +1 -0
  131. package/dist/cli/pipeline.d.ts +6 -0
  132. package/dist/cli/pipeline.d.ts.map +1 -1
  133. package/dist/cli/pipeline.js +15 -2
  134. package/dist/cli/pipeline.js.map +1 -1
  135. package/dist/cli/run/schema.d.ts.map +1 -1
  136. package/dist/cli/run/schema.js +32 -0
  137. package/dist/cli/run/schema.js.map +1 -1
  138. package/dist/cli/run/schema.test.js +51 -0
  139. package/dist/cli/run/schema.test.js.map +1 -1
  140. package/dist/cli/skills.d.ts +3 -0
  141. package/dist/cli/skills.d.ts.map +1 -0
  142. package/dist/cli/skills.js +107 -0
  143. package/dist/cli/skills.js.map +1 -0
  144. package/dist/cli/types.d.ts +4 -1
  145. package/dist/cli/types.d.ts.map +1 -1
  146. package/dist/dashboard/scripts/etl.d.ts.map +1 -1
  147. package/dist/dashboard/scripts/etl.js +44 -11
  148. package/dist/dashboard/scripts/etl.js.map +1 -1
  149. package/package.json +2 -1
  150. package/src/cli/agents.ts +20 -5
  151. package/src/cli/artifacts-cli.ts +41 -0
  152. package/src/cli/baselines.ts +12 -0
  153. package/src/cli/convoy/artifacts.test.ts +201 -0
  154. package/src/cli/convoy/artifacts.ts +186 -0
  155. package/src/cli/convoy/compaction.test.ts +245 -0
  156. package/src/cli/convoy/compaction.ts +164 -0
  157. package/src/cli/convoy/contracts.test.ts +279 -0
  158. package/src/cli/convoy/contracts.ts +280 -0
  159. package/src/cli/convoy/dag-analysis.test.ts +349 -0
  160. package/src/cli/convoy/dag-analysis.ts +371 -0
  161. package/src/cli/convoy/effort-scaling.test.ts +140 -0
  162. package/src/cli/convoy/effort-scaling.ts +90 -0
  163. package/src/cli/convoy/engine.test.ts +175 -18
  164. package/src/cli/convoy/engine.ts +301 -7
  165. package/src/cli/convoy/event-schemas.ts +55 -0
  166. package/src/cli/convoy/isolation.test.ts +137 -0
  167. package/src/cli/convoy/isolation.ts +165 -0
  168. package/src/cli/convoy/review-stages.test.ts +235 -0
  169. package/src/cli/convoy/review-stages.ts +166 -0
  170. package/src/cli/convoy/skill-refinement.test.ts +277 -0
  171. package/src/cli/convoy/skill-refinement.ts +306 -0
  172. package/src/cli/convoy/spec-builder.test.ts +61 -0
  173. package/src/cli/convoy/spec-builder.ts +9 -0
  174. package/src/cli/convoy/store.test.ts +15 -15
  175. package/src/cli/convoy/store.ts +26 -4
  176. package/src/cli/convoy/tdd-gate.test.ts +281 -0
  177. package/src/cli/convoy/tdd-gate.ts +154 -0
  178. package/src/cli/convoy/types.ts +51 -0
  179. package/src/cli/insights.ts +99 -0
  180. package/src/cli/lesson.ts +8 -0
  181. package/src/cli/log.ts +8 -0
  182. package/src/cli/package-config.ts +48 -0
  183. package/src/cli/package.test.ts +276 -0
  184. package/src/cli/package.ts +329 -0
  185. package/src/cli/pipeline.ts +21 -2
  186. package/src/cli/run/schema.test.ts +58 -0
  187. package/src/cli/run/schema.ts +33 -0
  188. package/src/cli/skills.ts +121 -0
  189. package/src/cli/types.ts +4 -1
  190. package/src/dashboard/dist/_astro/index.D6quLrA6.css +1 -0
  191. package/src/dashboard/dist/data/convoy-list.json +21 -7
  192. package/src/dashboard/dist/data/convoys/demo-api-v2.json +3 -3
  193. package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +5 -5
  194. package/src/dashboard/dist/data/convoys/demo-convoy-1.json +2 -2
  195. package/src/dashboard/dist/data/convoys/demo-convoy-2.json +1 -1
  196. package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +7 -7
  197. package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +3 -3
  198. package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +2 -2
  199. package/src/dashboard/dist/data/convoys/demo-docs-update.json +2 -2
  200. package/src/dashboard/dist/data/convoys/demo-perf-opt.json +4 -4
  201. package/src/dashboard/dist/index.html +306 -33
  202. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  203. package/src/dashboard/public/data/convoy-list.json +21 -7
  204. package/src/dashboard/public/data/convoys/demo-api-v2.json +3 -3
  205. package/src/dashboard/public/data/convoys/demo-auth-revamp.json +5 -5
  206. package/src/dashboard/public/data/convoys/demo-convoy-1.json +2 -2
  207. package/src/dashboard/public/data/convoys/demo-convoy-2.json +1 -1
  208. package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +7 -7
  209. package/src/dashboard/public/data/convoys/demo-data-pipeline.json +3 -3
  210. package/src/dashboard/public/data/convoys/demo-deploy-ci.json +2 -2
  211. package/src/dashboard/public/data/convoys/demo-docs-update.json +2 -2
  212. package/src/dashboard/public/data/convoys/demo-perf-opt.json +4 -4
  213. package/src/dashboard/scripts/etl.test.ts +14 -0
  214. package/src/dashboard/scripts/etl.ts +48 -16
  215. package/src/dashboard/scripts/generate-demo-db.ts +18 -10
  216. package/src/dashboard/src/pages/index.astro +348 -45
  217. package/src/dashboard/src/styles/dashboard.css +56 -0
  218. package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
  219. package/src/orchestrator/prompts/generate-convoy.prompt.md +19 -0
  220. package/src/dashboard/dist/_astro/index.BRDFmNzR.css +0 -1
@@ -0,0 +1,20 @@
1
+ export interface EffortProfile {
2
+ complexity: number;
3
+ tier: 'economy' | 'standard' | 'utility' | 'premium';
4
+ max_agents: number;
5
+ timeout: string;
6
+ max_retries: number;
7
+ review: 'none' | 'auto' | 'fast' | 'panel';
8
+ expected_tokens: number;
9
+ description: string;
10
+ }
11
+ export declare const EFFORT_TABLE: EffortProfile[];
12
+ /**
13
+ * Returns the EffortProfile for a given complexity score.
14
+ * - Exact match: returns that profile
15
+ * - Between defined values: rounds up to the next profile
16
+ * - Below 1: returns the complexity-1 profile
17
+ * - Above 13: returns the complexity-13 profile
18
+ */
19
+ export declare function getEffortProfile(complexity: number): EffortProfile;
20
+ //# sourceMappingURL=effort-scaling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effort-scaling.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/effort-scaling.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAA;IACpD,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAC1C,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,aAAa,EA6DvC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAQlE"}
@@ -0,0 +1,82 @@
1
+ export const EFFORT_TABLE = [
2
+ {
3
+ complexity: 1,
4
+ tier: 'economy',
5
+ max_agents: 1,
6
+ timeout: '5m',
7
+ max_retries: 1,
8
+ review: 'auto',
9
+ expected_tokens: 5_000,
10
+ description: 'Trivial — single file edit, copy change, config tweak',
11
+ },
12
+ {
13
+ complexity: 2,
14
+ tier: 'economy',
15
+ max_agents: 1,
16
+ timeout: '10m',
17
+ max_retries: 1,
18
+ review: 'auto',
19
+ expected_tokens: 15_000,
20
+ description: 'Simple — small bug fix, add a test, update docs',
21
+ },
22
+ {
23
+ complexity: 3,
24
+ tier: 'standard',
25
+ max_agents: 1,
26
+ timeout: '15m',
27
+ max_retries: 2,
28
+ review: 'fast',
29
+ expected_tokens: 30_000,
30
+ description: 'Moderate — new component, API endpoint, or utility',
31
+ },
32
+ {
33
+ complexity: 5,
34
+ tier: 'standard',
35
+ max_agents: 2,
36
+ timeout: '20m',
37
+ max_retries: 2,
38
+ review: 'fast',
39
+ expected_tokens: 60_000,
40
+ description: 'Significant — multi-file feature, integration work',
41
+ },
42
+ {
43
+ complexity: 8,
44
+ tier: 'standard',
45
+ max_agents: 3,
46
+ timeout: '30m',
47
+ max_retries: 2,
48
+ review: 'fast',
49
+ expected_tokens: 120_000,
50
+ description: 'Complex — cross-cutting feature, schema change + UI + tests',
51
+ },
52
+ {
53
+ complexity: 13,
54
+ tier: 'premium',
55
+ max_agents: 5,
56
+ timeout: '45m',
57
+ max_retries: 3,
58
+ review: 'panel',
59
+ expected_tokens: 250_000,
60
+ description: 'Epic — architecture change, security overhaul, major refactor',
61
+ },
62
+ ];
63
+ /**
64
+ * Returns the EffortProfile for a given complexity score.
65
+ * - Exact match: returns that profile
66
+ * - Between defined values: rounds up to the next profile
67
+ * - Below 1: returns the complexity-1 profile
68
+ * - Above 13: returns the complexity-13 profile
69
+ */
70
+ export function getEffortProfile(complexity) {
71
+ if (complexity <= EFFORT_TABLE[0].complexity)
72
+ return EFFORT_TABLE[0];
73
+ const last = EFFORT_TABLE[EFFORT_TABLE.length - 1];
74
+ if (complexity >= last.complexity)
75
+ return last;
76
+ for (const profile of EFFORT_TABLE) {
77
+ if (complexity <= profile.complexity)
78
+ return profile;
79
+ }
80
+ return last;
81
+ }
82
+ //# sourceMappingURL=effort-scaling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effort-scaling.js","sourceRoot":"","sources":["../../../src/cli/convoy/effort-scaling.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,YAAY,GAAoB;IAC3C;QACE,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM;QACd,eAAe,EAAE,KAAK;QACtB,WAAW,EAAE,uDAAuD;KACrE;IACD;QACE,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM;QACd,eAAe,EAAE,MAAM;QACvB,WAAW,EAAE,iDAAiD;KAC/D;IACD;QACE,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM;QACd,eAAe,EAAE,MAAM;QACvB,WAAW,EAAE,oDAAoD;KAClE;IACD;QACE,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM;QACd,eAAe,EAAE,MAAM;QACvB,WAAW,EAAE,oDAAoD;KAClE;IACD;QACE,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,MAAM;QACd,eAAe,EAAE,OAAO;QACxB,WAAW,EAAE,6DAA6D;KAC3E;IACD;QACE,UAAU,EAAE,EAAE;QACd,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,OAAO;QACf,eAAe,EAAE,OAAO;QACxB,WAAW,EAAE,+DAA+D;KAC7E;CACF,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,IAAI,UAAU,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU;QAAE,OAAO,YAAY,CAAC,CAAC,CAAC,CAAA;IACpE,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAClD,IAAI,UAAU,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA;IAC9C,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,UAAU,IAAI,OAAO,CAAC,UAAU;YAAE,OAAO,OAAO,CAAA;IACtD,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=effort-scaling.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effort-scaling.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/effort-scaling.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { getEffortProfile, EFFORT_TABLE } from './effort-scaling.js';
3
+ describe('getEffortProfile', () => {
4
+ it('returns complexity-1 profile for score 1', () => {
5
+ const p = getEffortProfile(1);
6
+ expect(p.complexity).toBe(1);
7
+ expect(p.tier).toBe('economy');
8
+ expect(p.timeout).toBe('5m');
9
+ expect(p.max_retries).toBe(1);
10
+ expect(p.review).toBe('auto');
11
+ expect(p.expected_tokens).toBe(5000);
12
+ });
13
+ it('returns complexity-2 profile for score 2', () => {
14
+ const p = getEffortProfile(2);
15
+ expect(p.complexity).toBe(2);
16
+ expect(p.tier).toBe('economy');
17
+ expect(p.timeout).toBe('10m');
18
+ expect(p.max_retries).toBe(1);
19
+ expect(p.review).toBe('auto');
20
+ expect(p.expected_tokens).toBe(15000);
21
+ });
22
+ it('returns complexity-3 profile for score 3', () => {
23
+ const p = getEffortProfile(3);
24
+ expect(p.complexity).toBe(3);
25
+ expect(p.tier).toBe('standard');
26
+ expect(p.timeout).toBe('15m');
27
+ expect(p.max_retries).toBe(2);
28
+ expect(p.review).toBe('fast');
29
+ expect(p.expected_tokens).toBe(30000);
30
+ });
31
+ it('returns complexity-5 profile for score 5', () => {
32
+ const p = getEffortProfile(5);
33
+ expect(p.complexity).toBe(5);
34
+ expect(p.tier).toBe('standard');
35
+ expect(p.timeout).toBe('20m');
36
+ expect(p.max_retries).toBe(2);
37
+ expect(p.review).toBe('fast');
38
+ expect(p.expected_tokens).toBe(60000);
39
+ });
40
+ it('returns complexity-8 profile for score 8', () => {
41
+ const p = getEffortProfile(8);
42
+ expect(p.complexity).toBe(8);
43
+ expect(p.tier).toBe('standard');
44
+ expect(p.timeout).toBe('30m');
45
+ expect(p.max_retries).toBe(2);
46
+ expect(p.review).toBe('fast');
47
+ expect(p.expected_tokens).toBe(120000);
48
+ });
49
+ it('returns complexity-13 profile for score 13', () => {
50
+ const p = getEffortProfile(13);
51
+ expect(p.complexity).toBe(13);
52
+ expect(p.tier).toBe('premium');
53
+ expect(p.timeout).toBe('45m');
54
+ expect(p.max_retries).toBe(3);
55
+ expect(p.review).toBe('panel');
56
+ expect(p.expected_tokens).toBe(250000);
57
+ });
58
+ it('rounds up score 4 to complexity-5 profile', () => {
59
+ const p = getEffortProfile(4);
60
+ expect(p.complexity).toBe(5);
61
+ });
62
+ it('rounds up score 6 to complexity-8 profile', () => {
63
+ const p = getEffortProfile(6);
64
+ expect(p.complexity).toBe(8);
65
+ });
66
+ it('rounds up score 7 to complexity-8 profile', () => {
67
+ const p = getEffortProfile(7);
68
+ expect(p.complexity).toBe(8);
69
+ });
70
+ it('rounds up score 9 to complexity-13 profile', () => {
71
+ const p = getEffortProfile(9);
72
+ expect(p.complexity).toBe(13);
73
+ });
74
+ it('rounds up score 10 to complexity-13 profile', () => {
75
+ const p = getEffortProfile(10);
76
+ expect(p.complexity).toBe(13);
77
+ });
78
+ it('rounds up score 12 to complexity-13 profile', () => {
79
+ const p = getEffortProfile(12);
80
+ expect(p.complexity).toBe(13);
81
+ });
82
+ it('clamps score 0 to complexity-1 profile', () => {
83
+ const p = getEffortProfile(0);
84
+ expect(p.complexity).toBe(1);
85
+ });
86
+ it('clamps negative score -5 to complexity-1 profile', () => {
87
+ const p = getEffortProfile(-5);
88
+ expect(p.complexity).toBe(1);
89
+ });
90
+ it('clamps large negative score -9999 to complexity-1 profile', () => {
91
+ const p = getEffortProfile(-9999);
92
+ expect(p.complexity).toBe(1);
93
+ });
94
+ it('clamps score 14 to complexity-13 profile', () => {
95
+ const p = getEffortProfile(14);
96
+ expect(p.complexity).toBe(13);
97
+ });
98
+ it('clamps score 100 to complexity-13 profile', () => {
99
+ const p = getEffortProfile(100);
100
+ expect(p.complexity).toBe(13);
101
+ });
102
+ it('clamps very large score 9999 to complexity-13 profile', () => {
103
+ const p = getEffortProfile(9999);
104
+ expect(p.complexity).toBe(13);
105
+ });
106
+ it('returns the same object reference from EFFORT_TABLE for exact matches', () => {
107
+ for (const entry of EFFORT_TABLE) {
108
+ expect(getEffortProfile(entry.complexity)).toBe(entry);
109
+ }
110
+ });
111
+ it('EFFORT_TABLE has 6 entries', () => {
112
+ expect(EFFORT_TABLE).toHaveLength(6);
113
+ });
114
+ it('EFFORT_TABLE entries are ordered by ascending complexity', () => {
115
+ for (let i = 1; i < EFFORT_TABLE.length; i++) {
116
+ expect(EFFORT_TABLE[i].complexity).toBeGreaterThan(EFFORT_TABLE[i - 1].complexity);
117
+ }
118
+ });
119
+ });
120
+ //# sourceMappingURL=effort-scaling.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effort-scaling.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/effort-scaling.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/engine.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,13 @@ import { readLessons, captureLessons, consolidateLessons } from './lessons.js';
20
20
  import { updateExpertise, feedCircuitBreaker } from './expertise.js';
21
21
  import { buildKnowledgeGraph } from './knowledge.js';
22
22
  import { injectDiscoveredIssuesInstruction, checkDiscoveredIssues, consolidateIssues } from './issues.js';
23
+ import { validateOutput, buildContractInstruction, buildContractRetryPrompt } from './contracts.js';
24
+ import { runTwoStageReview } from './review-stages.js';
25
+ import { buildIsolationPreamble, resolveDependencyResults, detectPartitionViolations } from './isolation.js';
26
+ import { checkTDD, formatTDDFailure, DEFAULT_TDD_CONFIG } from './tdd-gate.js';
27
+ import { runSkillRefinementCheck } from './skill-refinement.js';
28
+ import { getArtifactDir, extractArtifactRefs } from './artifacts.js';
29
+ import { shouldCompact, parseCompactionSummary, saveCompaction, canCompact, getMaxCompactions, generateCompactionPrompt, buildContinuationPrompt } from './compaction.js';
23
30
  const execFile = promisify(execFileCb);
24
31
  export class CircuitBreakerManager {
25
32
  states = new Map();
@@ -620,6 +627,7 @@ function pollInjectFile(convoyId, store, events, basePath) {
620
627
  dispute_id: null,
621
628
  drift_score: null,
622
629
  drift_retried: 0,
630
+ compaction_count: 0,
623
631
  outputs: null,
624
632
  inputs: null,
625
633
  discovered_issues: null,
@@ -995,6 +1003,33 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
995
1003
  const specTask = (spec.tasks ?? []).find(t => t.id === taskRecord.id);
996
1004
  const steps = specTask?.steps;
997
1005
  const taskHooks = specTask?.hooks ?? [];
1006
+ // ── Context isolation preamble (Phase 41) ────────────────────────────
1007
+ try {
1008
+ const taskFiles = taskRecord.files ? JSON.parse(taskRecord.files) : [];
1009
+ const depIds = taskRecord.depends_on ? JSON.parse(taskRecord.depends_on) : [];
1010
+ const depResults = resolveDependencyResults(store, convoyId, depIds);
1011
+ const preamble = buildIsolationPreamble({ id: taskRecord.id, description: taskRecord.prompt.slice(0, 200), prompt: taskRecord.prompt, files: taskFiles, agent: taskRecord.agent }, depResults);
1012
+ task.prompt = preamble + '\n\n' + task.prompt;
1013
+ }
1014
+ catch { /* non-critical — isolation preamble is best-effort */ }
1015
+ // ── Artifact output instructions (Phase 43) ────────────────────────────
1016
+ try {
1017
+ const artifactDir = getArtifactDir(convoyId, taskRecord.id);
1018
+ const artifactInstructions = [
1019
+ '',
1020
+ '## Artifact Output (for large results)',
1021
+ 'If your output includes large content (>100 lines of code, full reports, data dumps),',
1022
+ 'write it to an artifact file instead of including it inline:',
1023
+ '',
1024
+ '1. Write the content to: ' + artifactDir + '{filename}',
1025
+ '2. In your response, reference it: `[ARTIFACT: {filename}] {1-line summary}`',
1026
+ '3. Keep your inline response focused on the summary and key decisions.',
1027
+ '',
1028
+ 'Small outputs (< 100 lines) can remain inline.',
1029
+ ].join('\n');
1030
+ task.prompt = task.prompt + '\n' + artifactInstructions;
1031
+ }
1032
+ catch { /* non-critical */ }
998
1033
  // ── Intelligence: inject lessons (Phase 18.1) ─────────────────────────
999
1034
  if (spec.defaults?.inject_lessons !== false) {
1000
1035
  try {
@@ -1027,6 +1062,11 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1027
1062
  if (spec.defaults?.track_discovered_issues) {
1028
1063
  task.prompt = injectDiscoveredIssuesInstruction(task.prompt);
1029
1064
  }
1065
+ // ── Output contract injection ─────────────────────────────────────────
1066
+ const contractInstruction = buildContractInstruction(taskRecord.agent);
1067
+ if (contractInstruction) {
1068
+ task.prompt = task.prompt + '\n\n' + contractInstruction;
1069
+ }
1030
1070
  // ── pre_task hooks ────────────────────────────────────────────────────────
1031
1071
  if (taskHooks.length > 0) {
1032
1072
  const preResult = await runHooks(taskHooks, 'pre_task', {
@@ -1369,6 +1409,91 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1369
1409
  return;
1370
1410
  }
1371
1411
  }
1412
+ // ── Partition violation check (Phase 41) ────────────────────────────
1413
+ if (changedFiles.length > 0) {
1414
+ try {
1415
+ const taskFiles = taskRecord.files ? JSON.parse(taskRecord.files) : [];
1416
+ if (taskFiles.length > 0) {
1417
+ const violation = detectPartitionViolations(taskRecord.id, taskFiles, changedFiles);
1418
+ if (violation) {
1419
+ events.emit('partition_violation', {
1420
+ task_id: taskRecord.id,
1421
+ allowed: violation.allowedFiles,
1422
+ actual: violation.actualFiles,
1423
+ violations: violation.violations,
1424
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
1425
+ process.stdout.write(` ${c.yellow('⚠')} ${c.bold(`[${taskRecord.id}]`)} partition violation: ${violation.violations.join(', ')}\n`);
1426
+ }
1427
+ }
1428
+ }
1429
+ catch { /* non-critical */ }
1430
+ }
1431
+ // ── TDD gate ──────────────────────────────────────────────────────────
1432
+ if (builtInGates.tdd_check && changedFiles.length > 0) {
1433
+ const tddConfig = typeof builtInGates.tdd_check === 'object'
1434
+ ? { ...DEFAULT_TDD_CONFIG, ...builtInGates.tdd_check }
1435
+ : DEFAULT_TDD_CONFIG;
1436
+ const specTaskForTDD = (spec.tasks ?? []).find(t => t.id === taskRecord.id);
1437
+ const tddResult = checkTDD(changedFiles, changedFiles, tddConfig, specTaskForTDD?.agent ?? taskRecord.agent);
1438
+ if (tddResult.skipped) {
1439
+ events.emit('tdd_check_skipped', {
1440
+ task_id: taskRecord.id,
1441
+ reason: tddResult.skip_reason,
1442
+ agent: specTaskForTDD?.agent ?? taskRecord.agent,
1443
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
1444
+ }
1445
+ else if (tddResult.passed) {
1446
+ events.emit('tdd_check_passed', {
1447
+ task_id: taskRecord.id,
1448
+ new_source_files: tddResult.new_source_files.length,
1449
+ existing_test_files: tddResult.existing_test_files.length,
1450
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
1451
+ }
1452
+ else {
1453
+ const failureMsg = formatTDDFailure(tddResult);
1454
+ events.emit('tdd_check_failed', {
1455
+ task_id: taskRecord.id,
1456
+ missing_test_files: tddResult.missing_test_files,
1457
+ new_source_files: tddResult.new_source_files.length,
1458
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
1459
+ if (tddConfig.mode === 'block') {
1460
+ await removeWorktree();
1461
+ const freshRecord = store.getTask(taskRecord.id, convoyId);
1462
+ if (freshRecord.retries < freshRecord.max_retries && spec.on_failure !== 'stop') {
1463
+ store.updateTaskStatus(taskRecord.id, convoyId, 'pending', {
1464
+ retries: freshRecord.retries + 1,
1465
+ worker_id: null,
1466
+ worktree: null,
1467
+ started_at: null,
1468
+ finished_at: null,
1469
+ prompt: `TDD gate failed.\n${failureMsg}\n\nCreate the missing test files and try again.\n\n${taskRecord.prompt}`,
1470
+ });
1471
+ store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
1472
+ process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} TDD gate failed, retry ${freshRecord.retries + 1}/${freshRecord.max_retries}\n`);
1473
+ }
1474
+ else {
1475
+ store.withTransaction(() => {
1476
+ store.updateTaskStatus(taskRecord.id, convoyId, 'gate-failed', {
1477
+ finished_at: finishedAt,
1478
+ output: `Built-in gate (tdd_check) failed:\n${failureMsg}`,
1479
+ exit_code: 1,
1480
+ });
1481
+ store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
1482
+ });
1483
+ completedCount++;
1484
+ process.stdout.write(` ${c.red('✗')} ${c.bold(`[${taskRecord.id}]`)} TDD gate failed ${elapsed} ${c.dim(`[${completedCount}/${totalTasks}]`)}\n`);
1485
+ events.emit('task_failed', { reason: 'gate-failed', gate: 'tdd_check', worker_id: workerId }, { convoy_id: convoyId, task_id: taskRecord.id, worker_id: workerId });
1486
+ handleExhaustion(freshRecord, 'tdd-check', failureMsg);
1487
+ }
1488
+ taskAdapterMap.delete(taskRecord.id);
1489
+ return;
1490
+ }
1491
+ else {
1492
+ // warn mode — log but continue
1493
+ process.stdout.write(` ${c.yellow('⚠')} ${c.bold(`[${taskRecord.id}]`)} TDD gate warning: ${tddResult.missing_test_files.length} source file(s) without tests\n`);
1494
+ }
1495
+ }
1496
+ }
1372
1497
  }
1373
1498
  // ── Drift detection ──────────────────────────────────────────────────
1374
1499
  const specTaskForDrift = (spec.tasks ?? []).find(t => t.id === taskRecord.id);
@@ -1478,7 +1603,20 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1478
1603
  await reviewSemaphore.acquire();
1479
1604
  let reviewResult;
1480
1605
  try {
1481
- if (reviewRunner) {
1606
+ if (reviewRunner && spec.defaults?.review_stages !== false) {
1607
+ // Two-stage review: spec compliance first, then code quality
1608
+ const twoStageResult = await runTwoStageReview(taskRecord, reviewRunner, reviewerModel);
1609
+ for (const stage of twoStageResult.stages) {
1610
+ events.emit('review_stage_completed', { stage: stage.stage, verdict: stage.verdict, tokens: stage.tokens_used, task_id: taskRecord.id, model: reviewerModel }, { convoy_id: convoyId, task_id: taskRecord.id });
1611
+ }
1612
+ reviewResult = {
1613
+ verdict: twoStageResult.overall_verdict,
1614
+ feedback: twoStageResult.stages.flatMap(s => s.issues).join('\n'),
1615
+ tokens: twoStageResult.total_tokens,
1616
+ model: reviewerModel,
1617
+ };
1618
+ }
1619
+ else if (reviewRunner) {
1482
1620
  reviewResult = await reviewRunner(taskRecord, 'fast', reviewerModel);
1483
1621
  }
1484
1622
  else {
@@ -1541,11 +1679,33 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1541
1679
  try {
1542
1680
  const noopRunner = (_t, _l, m) => Promise.resolve({ verdict: 'pass', feedback: '', tokens: 0, model: m });
1543
1681
  const runner = reviewRunner ?? noopRunner;
1544
- panelResults = await Promise.all([
1545
- runner(taskRecord, 'panel', reviewerModel),
1546
- runner(taskRecord, 'panel', reviewerModel),
1547
- runner(taskRecord, 'panel', reviewerModel),
1548
- ]);
1682
+ const twoStageEnabled = spec.defaults?.review_stages !== false;
1683
+ if (twoStageEnabled && reviewRunner) {
1684
+ // Each panel reviewer runs both stages; majority vote on overall_verdict
1685
+ const twoStageResults = await Promise.all([
1686
+ runTwoStageReview(taskRecord, runner, reviewerModel),
1687
+ runTwoStageReview(taskRecord, runner, reviewerModel),
1688
+ runTwoStageReview(taskRecord, runner, reviewerModel),
1689
+ ]);
1690
+ for (const tsr of twoStageResults) {
1691
+ for (const stage of tsr.stages) {
1692
+ events.emit('review_stage_completed', { stage: stage.stage, verdict: stage.verdict, tokens: stage.tokens_used, task_id: taskRecord.id, model: reviewerModel }, { convoy_id: convoyId, task_id: taskRecord.id });
1693
+ }
1694
+ }
1695
+ panelResults = twoStageResults.map(tsr => ({
1696
+ verdict: tsr.overall_verdict,
1697
+ feedback: tsr.stages.flatMap(s => s.issues).join('\n'),
1698
+ tokens: tsr.total_tokens,
1699
+ model: reviewerModel,
1700
+ }));
1701
+ }
1702
+ else {
1703
+ panelResults = await Promise.all([
1704
+ runner(taskRecord, 'panel', reviewerModel),
1705
+ runner(taskRecord, 'panel', reviewerModel),
1706
+ runner(taskRecord, 'panel', reviewerModel),
1707
+ ]);
1708
+ }
1549
1709
  }
1550
1710
  finally {
1551
1711
  reviewSemaphore.release();
@@ -1770,6 +1930,7 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1770
1930
  dispute_id: null,
1771
1931
  drift_score: null,
1772
1932
  drift_retried: 0,
1933
+ compaction_count: 0,
1773
1934
  outputs: null,
1774
1935
  inputs: null,
1775
1936
  discovered_issues: null,
@@ -1815,6 +1976,64 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1815
1976
  if (result.usage.total_tokens != null)
1816
1977
  usageExtra.total_tokens = result.usage.total_tokens;
1817
1978
  }
1979
+ // ── Context compaction check (Phase 44) ─────────────────────────────
1980
+ const compactionConfig = spec.defaults?.compaction;
1981
+ if (compactionConfig?.enabled && usageExtra.total_tokens != null && taskRecord.model) {
1982
+ if (shouldCompact(usageExtra.total_tokens, taskRecord.model, compactionConfig)) {
1983
+ if (canCompact(taskRecord.compaction_count)) {
1984
+ const newCount = taskRecord.compaction_count + 1;
1985
+ store.updateTaskCompaction(taskRecord.id, convoyId, newCount);
1986
+ const summaryFromOutput = parseCompactionSummary(result.output, taskRecord.id, convoyId);
1987
+ let summaryPath;
1988
+ if (summaryFromOutput) {
1989
+ try {
1990
+ summaryPath = saveCompaction(convoyId, taskRecord.id, summaryFromOutput, newCount);
1991
+ }
1992
+ catch { /* non-critical */ }
1993
+ }
1994
+ const compactionTaskFiles = taskRecord.files ? JSON.parse(taskRecord.files) : [];
1995
+ const compactionDepIds = taskRecord.depends_on ? JSON.parse(taskRecord.depends_on) : [];
1996
+ const compactionDepResults = resolveDependencyResults(store, convoyId, compactionDepIds);
1997
+ const compactionPreamble = buildIsolationPreamble({ id: taskRecord.id, description: taskRecord.prompt.slice(0, 200), prompt: taskRecord.prompt, files: compactionTaskFiles, agent: taskRecord.agent }, compactionDepResults);
1998
+ const continuationPrompt = summaryPath
1999
+ ? buildContinuationPrompt(taskRecord.prompt, summaryPath, compactionPreamble)
2000
+ : compactionPreamble + '\n\n' + generateCompactionPrompt(taskRecord.id) + '\n\n' + taskRecord.prompt;
2001
+ store.updateTaskStatus(taskRecord.id, convoyId, 'pending', {
2002
+ worker_id: null,
2003
+ worktree: null,
2004
+ started_at: null,
2005
+ finished_at: null,
2006
+ prompt: continuationPrompt,
2007
+ });
2008
+ store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
2009
+ events.emit('context_compacted', {
2010
+ task_id: taskRecord.id,
2011
+ compaction_count: newCount,
2012
+ summary_path: summaryPath ?? '',
2013
+ model: taskRecord.model,
2014
+ tokens_used: usageExtra.total_tokens,
2015
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
2016
+ taskAdapterMap.delete(taskRecord.id);
2017
+ return;
2018
+ }
2019
+ else {
2020
+ // Max compactions exceeded — fail the task
2021
+ const exhaustedAt = new Date().toISOString();
2022
+ store.updateTaskStatus(taskRecord.id, convoyId, 'failed', {
2023
+ finished_at: exhaustedAt,
2024
+ output: `Context exhausted: reached maximum ${getMaxCompactions()} compactions`,
2025
+ exit_code: 1,
2026
+ });
2027
+ store.updateWorkerStatus(workerId, 'failed', { finished_at: exhaustedAt });
2028
+ events.emit('task_failed', {
2029
+ reason: 'context_exhausted',
2030
+ worker_id: workerId,
2031
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
2032
+ taskAdapterMap.delete(taskRecord.id);
2033
+ return;
2034
+ }
2035
+ }
2036
+ }
1818
2037
  // ── Capture outputs as artifacts ────────────────────────────────────────
1819
2038
  if (taskRecord.outputs) {
1820
2039
  const outputs = JSON.parse(taskRecord.outputs);
@@ -1854,6 +2073,47 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1854
2073
  }
1855
2074
  }
1856
2075
  }
2076
+ // ── Extract filesystem artifacts (Phase 43) ────────────────────────
2077
+ try {
2078
+ const fsArtifactRefs = extractArtifactRefs(taskRecord.id, convoyId, result.output);
2079
+ if (fsArtifactRefs.length > 0) {
2080
+ events.emit('artifacts_extracted', {
2081
+ task_id: taskRecord.id,
2082
+ count: fsArtifactRefs.length,
2083
+ artifacts: fsArtifactRefs.map(r => ({ filename: r.filename, summary: r.summary })),
2084
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
2085
+ }
2086
+ }
2087
+ catch (err) {
2088
+ process.stderr.write(`[artifacts] Warning: extraction failed for task ${taskRecord.id}: ${err.message}\n`);
2089
+ }
2090
+ // ── Output contract validation ────────────────────────────────────────
2091
+ const contractResult = validateOutput(taskRecord.agent, result.output);
2092
+ if (!contractResult.valid) {
2093
+ const freshRecordForContract = store.getTask(taskRecord.id, convoyId);
2094
+ if (freshRecordForContract.retries < freshRecordForContract.max_retries) {
2095
+ const retryPrefix = buildContractRetryPrompt(contractResult) + '\n\n';
2096
+ store.updateTaskStatus(taskRecord.id, convoyId, 'pending', {
2097
+ retries: freshRecordForContract.retries + 1,
2098
+ worker_id: null,
2099
+ worktree: null,
2100
+ started_at: null,
2101
+ finished_at: null,
2102
+ prompt: retryPrefix + taskRecord.prompt,
2103
+ });
2104
+ store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
2105
+ process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} contract retry ${freshRecordForContract.retries + 1}/${freshRecordForContract.max_retries}\n`);
2106
+ taskAdapterMap.delete(taskRecord.id);
2107
+ return;
2108
+ }
2109
+ events.emit('contract_violation', {
2110
+ task_id: taskRecord.id,
2111
+ agent: taskRecord.agent,
2112
+ missing: contractResult.missing,
2113
+ warnings: contractResult.warnings,
2114
+ }, { convoy_id: convoyId, task_id: taskRecord.id });
2115
+ process.stdout.write(` ${c.yellow('⚠')} ${c.bold(`[${taskRecord.id}]`)} contract violation: missing ${contractResult.missing.join(', ')}\n`);
2116
+ }
1857
2117
  // ── Intelligence: capture persistent agent identity (Phase 17.2) ─────
1858
2118
  const specTaskForCapture = (spec.tasks ?? []).find(t => t.id === taskRecord.id);
1859
2119
  if (specTaskForCapture?.persistent && result.output) {
@@ -1895,6 +2155,7 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1895
2155
  output: result.output,
1896
2156
  exit_code: result.exitCode,
1897
2157
  ...usageExtra,
2158
+ contract_result: JSON.stringify(contractResult),
1898
2159
  });
1899
2160
  store.updateWorkerStatus(workerId, 'done', { finished_at: finishedAt });
1900
2161
  });
@@ -2175,6 +2436,18 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
2175
2436
  }
2176
2437
  catch { /* non-critical */ }
2177
2438
  }
2439
+ // ── Intelligence: skill refinement check ───────────────────────────────
2440
+ try {
2441
+ const proposals = runSkillRefinementCheck(convoyId, basePath);
2442
+ for (const p of proposals) {
2443
+ events.emit('skill_refinement_proposed', {
2444
+ skill_name: p.skill,
2445
+ proposal_path: p.proposalPath,
2446
+ }, { convoy_id: convoyId });
2447
+ process.stdout.write(` ${c.yellow('◆')} Skill refinement proposed for "${p.skill}". Review at ${p.proposalPath}\n`);
2448
+ }
2449
+ }
2450
+ catch { /* non-critical */ }
2178
2451
  // ── Final status & summary ────────────────────────────────────────────────
2179
2452
  const allTasksFinal = store.getTasksByConvoy(convoyId);
2180
2453
  const summary = {
@@ -2590,6 +2863,7 @@ export function createConvoyEngine(options) {
2590
2863
  dispute_id: null,
2591
2864
  drift_score: null,
2592
2865
  drift_retried: 0,
2866
+ compaction_count: 0,
2593
2867
  outputs: null,
2594
2868
  inputs: null,
2595
2869
  discovered_issues: null,