opencastle 0.27.3 → 0.28.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 (61) hide show
  1. package/bin/cli.mjs +13 -5
  2. package/dist/cli/convoy/engine.js +2 -2
  3. package/dist/cli/convoy/engine.js.map +1 -1
  4. package/dist/cli/convoy/engine.test.js +1 -1
  5. package/dist/cli/convoy/engine.test.js.map +1 -1
  6. package/dist/cli/convoy/issues.js +3 -3
  7. package/dist/cli/convoy/issues.js.map +1 -1
  8. package/dist/cli/convoy/issues.test.js +4 -3
  9. package/dist/cli/convoy/issues.test.js.map +1 -1
  10. package/dist/cli/pipeline.d.ts +3 -0
  11. package/dist/cli/pipeline.d.ts.map +1 -0
  12. package/dist/cli/pipeline.js +305 -0
  13. package/dist/cli/pipeline.js.map +1 -0
  14. package/dist/cli/plan.d.ts +37 -0
  15. package/dist/cli/plan.d.ts.map +1 -1
  16. package/dist/cli/plan.js +321 -161
  17. package/dist/cli/plan.js.map +1 -1
  18. package/dist/cli/validate.d.ts +3 -0
  19. package/dist/cli/validate.d.ts.map +1 -0
  20. package/dist/cli/validate.js +60 -0
  21. package/dist/cli/validate.js.map +1 -0
  22. package/package.json +5 -4
  23. package/src/cli/convoy/engine.test.ts +1 -1
  24. package/src/cli/convoy/engine.ts +2 -2
  25. package/src/cli/convoy/issues.test.ts +3 -2
  26. package/src/cli/convoy/issues.ts +3 -3
  27. package/src/cli/pipeline.ts +343 -0
  28. package/src/cli/plan.ts +357 -153
  29. package/src/cli/validate.ts +65 -0
  30. package/src/dashboard/dist/data/convoy-list.json +54 -9
  31. package/src/dashboard/dist/data/convoys/demo-api-v2.json +177 -0
  32. package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +239 -0
  33. package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +328 -0
  34. package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +187 -0
  35. package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +153 -0
  36. package/src/dashboard/dist/data/convoys/demo-docs-update.json +154 -0
  37. package/src/dashboard/dist/data/convoys/demo-perf-opt.json +227 -0
  38. package/src/dashboard/dist/data/events.ndjson +115 -0
  39. package/src/dashboard/dist/data/overall-stats.json +56 -13
  40. package/src/dashboard/dist/data/pipelines.ndjson +5285 -0
  41. package/src/dashboard/dist/index.html +39 -16
  42. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  43. package/src/dashboard/public/data/convoy-list.json +54 -9
  44. package/src/dashboard/public/data/convoys/demo-api-v2.json +177 -0
  45. package/src/dashboard/public/data/convoys/demo-auth-revamp.json +239 -0
  46. package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +328 -0
  47. package/src/dashboard/public/data/convoys/demo-data-pipeline.json +187 -0
  48. package/src/dashboard/public/data/convoys/demo-deploy-ci.json +153 -0
  49. package/src/dashboard/public/data/convoys/demo-docs-update.json +154 -0
  50. package/src/dashboard/public/data/convoys/demo-perf-opt.json +227 -0
  51. package/src/dashboard/public/data/events.ndjson +115 -0
  52. package/src/dashboard/public/data/overall-stats.json +56 -13
  53. package/src/dashboard/public/data/pipelines.ndjson +5285 -0
  54. package/src/dashboard/scripts/etl.ts +24 -3
  55. package/src/dashboard/scripts/generate-demo-db.ts +482 -115
  56. package/src/dashboard/src/pages/index.astro +46 -23
  57. package/src/orchestrator/prompts/fix-convoy.prompt.md +79 -0
  58. package/src/orchestrator/prompts/generate-convoy.prompt.md +53 -58
  59. package/src/orchestrator/prompts/generate-prd.prompt.md +120 -0
  60. package/src/orchestrator/prompts/validate-convoy.prompt.md +89 -0
  61. package/src/orchestrator/prompts/validate-prd.prompt.md +83 -0
@@ -44,13 +44,13 @@ try {
44
44
  <nav class="dash-sidebar" id="dash-sidebar">
45
45
  <ul class="dash-sidebar__list">
46
46
  <li><a class="dash-sidebar__link dash-sidebar__link--active" href="#overall-section" data-section="overall-section" aria-label="Overview section">Overview</a></li>
47
- <li><a class="dash-sidebar__link" href="#convoy-section" data-section="convoy-section" aria-label="Convoy section">Convoy</a></li>
48
47
  <li><a class="dash-sidebar__link" href="#tasks-section" data-section="tasks-section" aria-label="Tasks section">Tasks</a></li>
49
48
  <li><a class="dash-sidebar__link" href="#quality-section" data-section="quality-section" aria-label="Quality section">Quality</a></li>
50
49
  <li><a class="dash-sidebar__link" href="#reliability-section" data-section="reliability-section" aria-label="Reliability section">Reliability</a></li>
51
50
  <li><a class="dash-sidebar__link" href="#drift-section" data-section="drift-section" aria-label="Drift section">Drift</a></li>
52
51
  <li><a class="dash-sidebar__link" href="#outputs-section" data-section="outputs-section" aria-label="Outputs section">Outputs</a></li>
53
52
  <li><a class="dash-sidebar__link" href="#event-timeline-section" data-section="event-timeline-section" aria-label="Event Log section">Event Log</a></li>
53
+ <li><a class="dash-sidebar__link" href="#convoy-section" data-section="convoy-section" aria-label="Convoy section">Convoy</a></li>
54
54
  </ul>
55
55
  </nav>
56
56
 
@@ -59,11 +59,11 @@ try {
59
59
  <section class="overall-stats" id="overall-section" data-nav-section>
60
60
  <div class="overall-stats__header">
61
61
  <h2 class="overall-stats__title">Overall Stats</h2>
62
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How all runs behave across your project." data-tooltip="How all runs behave across your project.">ℹ️</span>
62
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How all runs behave across your project." data-tooltip="How all runs behave across your project."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
63
63
  </div>
64
64
  <div class="overall-stats__grid">
65
65
  <div class="overall-kpi" id="overall-total-runs">
66
- <span class="overall-kpi__label">Total Runs <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Number of convoy runs executed" data-tooltip="Number of convoy runs executed">ℹ️</span></span>
66
+ <span class="overall-kpi__label">Total Runs <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Number of convoy runs executed" data-tooltip="Number of convoy runs executed"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span></span>
67
67
  <span class="overall-kpi__value">&mdash;</span>
68
68
  </div>
69
69
  <div class="overall-kpi" id="overall-running">
@@ -94,7 +94,7 @@ try {
94
94
  <div class="convoy-detail-header__top">
95
95
  <h2 class="convoy-detail-header__name" id="selected-convoy-name">No convoy selected</h2>
96
96
  <span class="status-badge" id="selected-convoy-status" role="status"></span>
97
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: A convoy is a set of AI tasks working together on one goal." data-tooltip="A convoy is a set of AI tasks working together on one goal.">ℹ️</span>
97
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: A convoy is a set of AI tasks working together on one goal." data-tooltip="A convoy is a set of AI tasks working together on one goal."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
98
98
  </div>
99
99
  <p class="convoy-status-explanation" id="convoy-status-explanation" role="status" aria-live="polite"></p>
100
100
  <div class="convoy-detail-header__meta" id="selected-convoy-meta">
@@ -106,7 +106,7 @@ try {
106
106
  <section class="chart-card" id="tasks-section" data-nav-section style="display:none">
107
107
  <div class="chart-card__header">
108
108
  <h2 class="chart-card__title">Tasks</h2>
109
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Individual units of work in this convoy." data-tooltip="Individual units of work in this convoy.">ℹ️</span>
109
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Individual units of work in this convoy." data-tooltip="Individual units of work in this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
110
110
  <p class="chart-card__desc" id="tasks-section-desc">Task breakdown for the selected convoy</p>
111
111
  </div>
112
112
  <div class="chart-card__body" id="tasks-section-body">
@@ -120,7 +120,7 @@ try {
120
120
  <section class="chart-card" id="quality-section" data-nav-section style="display:none">
121
121
  <div class="chart-card__header">
122
122
  <h2 class="chart-card__title">Quality / Review</h2>
123
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Code review results and dispute resolution." data-tooltip="Code review results and dispute resolution.">ℹ️</span>
123
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Code review results and dispute resolution." data-tooltip="Code review results and dispute resolution."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
124
124
  <p class="chart-card__desc">Code review results and quality gate outcomes for the selected convoy</p>
125
125
  </div>
126
126
  <div class="chart-card__body">
@@ -133,7 +133,7 @@ try {
133
133
  <section class="chart-card" id="reliability-section" data-nav-section style="display:none">
134
134
  <div class="chart-card__header">
135
135
  <h2 class="chart-card__title">Reliability</h2>
136
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Errors, retry attempts, and safety mechanisms." data-tooltip="Errors, retry attempts, and safety mechanisms.">ℹ️</span>
136
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Errors, retry attempts, and safety mechanisms." data-tooltip="Errors, retry attempts, and safety mechanisms."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
137
137
  <p class="chart-card__desc">Retry queue and error overview for the selected convoy</p>
138
138
  </div>
139
139
  <div class="chart-card__body">
@@ -150,7 +150,7 @@ try {
150
150
  <section class="chart-card" id="drift-section" data-nav-section style="display:none">
151
151
  <div class="chart-card__header">
152
152
  <h2 class="chart-card__title">Drift</h2>
153
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How far the actual work deviated from the original plan." data-tooltip="How far the actual work deviated from the original plan.">ℹ️</span>
153
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: How far the actual work deviated from the original plan." data-tooltip="How far the actual work deviated from the original plan."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
154
154
  <p class="chart-card__desc">Plan adherence and deviation metrics for the selected convoy</p>
155
155
  </div>
156
156
  <div class="chart-card__body">
@@ -163,7 +163,7 @@ try {
163
163
  <section class="chart-card" id="outputs-section" data-nav-section style="display:none">
164
164
  <div class="chart-card__header">
165
165
  <h2 class="chart-card__title">Outputs &amp; Artifacts</h2>
166
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy.">ℹ️</span>
166
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
167
167
  <p class="chart-card__desc">Files, summaries, and structured data produced by tasks in this convoy</p>
168
168
  </div>
169
169
  <div class="chart-card__body">
@@ -176,7 +176,7 @@ try {
176
176
  <section class="chart-card" id="event-timeline-section" data-nav-section style="display:none">
177
177
  <div class="chart-card__header">
178
178
  <h2 class="chart-card__title">Event Timeline</h2>
179
- <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Chronological log of everything that happened during this run." data-tooltip="Chronological log of everything that happened during this run.">ℹ️</span>
179
+ <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Chronological log of everything that happened during this run." data-tooltip="Chronological log of everything that happened during this run."><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
180
180
  <p class="chart-card__desc">Convoy events in reverse chronological order</p>
181
181
  </div>
182
182
  <div class="chart-card__body">
@@ -424,8 +424,21 @@ try {
424
424
  }
425
425
  }
426
426
 
427
+ async function loadJson(path) {
428
+ try {
429
+ const res = await fetch(path);
430
+ if (!res.ok) return [];
431
+ return await res.json();
432
+ } catch {
433
+ return [];
434
+ }
435
+ }
436
+
427
437
  // ── Helpers ───────────────────────────────────────────────
428
438
 
439
+ // ── Info Icon SVG ─────────────────────────────────────
440
+ const INFO_ICON = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>';
441
+
429
442
  const TIER_COLORS = {
430
443
  premium: '#f59e0b',
431
444
  standard: '#a78bfa',
@@ -2009,7 +2022,7 @@ try {
2009
2022
  el.innerHTML = cards.map(card =>
2010
2023
  '<div class="task-summary-card task-summary-card--' + card.mod + '">' +
2011
2024
  '<span class="task-summary-card__label">' + escapeHtml(card.label) +
2012
- ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">\u2139\uFE0F</span>' +
2025
+ ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">' + INFO_ICON + '</span>' +
2013
2026
  '</span>' +
2014
2027
  '<span class="task-summary-card__value">' + card.value + '</span>' +
2015
2028
  '</div>'
@@ -2152,7 +2165,7 @@ try {
2152
2165
  cardsEl.innerHTML = qCards.map(function(card) {
2153
2166
  return '<div class="task-summary-card task-summary-card--' + card.mod + '">' +
2154
2167
  '<span class="task-summary-card__label">' + escapeHtml(card.label) +
2155
- ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">\u2139\uFE0F</span>' +
2168
+ ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">' + INFO_ICON + '</span>' +
2156
2169
  '</span>' +
2157
2170
  '<span class="task-summary-card__value">' + card.value + '</span>' +
2158
2171
  '</div>';
@@ -2210,7 +2223,7 @@ try {
2210
2223
  if (dlqCardEl) {
2211
2224
  dlqCardEl.innerHTML =
2212
2225
  '<div class="task-summary-card task-summary-card--' + (dlqCount > 0 ? 'errors' : 'done') + '">' +
2213
- '<span class="task-summary-card__label">Retry Queue <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ)." data-tooltip="Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ).">\u2139\uFE0F</span></span>' +
2226
+ '<span class="task-summary-card__label">Retry Queue <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ)." data-tooltip="Tasks that failed too many times and need manual attention. Also known as Dead Letter Queue (DLQ).">' + INFO_ICON + '</span></span>' +
2214
2227
  '<span class="task-summary-card__value">' + dlqCount + '</span>' +
2215
2228
  '</div>';
2216
2229
  }
@@ -2290,7 +2303,7 @@ try {
2290
2303
  cardsEl.innerHTML = driftCards.map(function(card) {
2291
2304
  return '<div class="task-summary-card task-summary-card--' + card.mod + '">' +
2292
2305
  '<span class="task-summary-card__label">' + escapeHtml(String(card.label)) +
2293
- ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">\u2139\uFE0F</span>' +
2306
+ ' <span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: ' + escapeHtml(card.tooltip) + '" data-tooltip="' + escapeHtml(card.tooltip) + '">' + INFO_ICON + '</span>' +
2294
2307
  '</span>' +
2295
2308
  '<span class="task-summary-card__value">' + card.value + '</span>' +
2296
2309
  '</div>';
@@ -2331,7 +2344,7 @@ try {
2331
2344
  cardsEl.innerHTML =
2332
2345
  '<div class="task-summary-card task-summary-card--done">' +
2333
2346
  '<span class="task-summary-card__label">Outputs Produced ' +
2334
- '<span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy.">\u2139\uFE0F</span>' +
2347
+ '<span class="tooltip-trigger" tabindex="0" role="button" aria-label="Info: Files, data, and summaries produced by this convoy." data-tooltip="Files, data, and summaries produced by this convoy.">' + INFO_ICON + '</span>' +
2335
2348
  '</span>' +
2336
2349
  '<span class="task-summary-card__value">' + artifactCount + '</span>' +
2337
2350
  '</div>';
@@ -2498,6 +2511,7 @@ try {
2498
2511
  async function main() {
2499
2512
  const events = await loadNdjson(base + 'data/events.ndjson');
2500
2513
  const pipelines = await loadNdjson(base + 'data/pipelines.ndjson');
2514
+ const convoys = window.__DASHBOARD_DATA__?.convoyList ?? [];
2501
2515
 
2502
2516
  const sessions = events.filter((e) => e.type === 'session');
2503
2517
  const delegations = events.filter((e) => e.type === 'delegation');
@@ -2578,7 +2592,7 @@ try {
2578
2592
  if (refreshInterval) return;
2579
2593
  refreshInterval = setInterval(async () => {
2580
2594
  const freshEvents = await loadNdjson(base + 'data/events.ndjson');
2581
- const freshConvoys = await loadNdjson(base + 'data/convoys.ndjson');
2595
+ const freshConvoys = await loadJson(base + 'data/convoy-list.json');
2582
2596
  const freshPipelines = await loadNdjson(base + 'data/pipelines.ndjson');
2583
2597
  rawSessions = freshEvents.filter((e) => e.type === 'session');
2584
2598
  rawDelegations = freshEvents.filter((e) => e.type === 'delegation');
@@ -2634,17 +2648,26 @@ try {
2634
2648
 
2635
2649
  sections.forEach((s) => observer.observe(s));
2636
2650
 
2651
+ // Convoy-detail sections that start hidden and need a convoy selected first
2652
+ const CONVOY_DETAIL_SECTIONS = ['tasks-section', 'quality-section', 'reliability-section', 'drift-section', 'outputs-section', 'event-timeline-section'];
2653
+
2637
2654
  // Smooth scroll on click
2638
2655
  links.forEach((link) => {
2639
- link.addEventListener('click', (e) => {
2656
+ link.addEventListener('click', async (e) => {
2640
2657
  e.preventDefault();
2641
2658
  const sectionId = link.dataset.section;
2642
2659
 
2643
- // Auto-select latest convoy/pipeline if section is hidden
2644
- if (sectionId === 'convoy-section') {
2645
- const convoySelect = document.getElementById('filter-convoy');
2646
- if (convoySelect && !convoySelect.value && convoySelect.options.length > 1) {
2647
- convoySelect.value = convoySelect.options[1].value;
2660
+ if (CONVOY_DETAIL_SECTIONS.includes(sectionId)) {
2661
+ // Auto-select and load convoy detail if none selected yet
2662
+ const convoySelectEl = document.getElementById('convoy-select');
2663
+ if (convoySelectEl && !convoySelectEl.value && convoySelectEl.options.length > 1) {
2664
+ convoySelectEl.value = convoySelectEl.options[1].value;
2665
+ await loadConvoyDetail(convoySelectEl.value);
2666
+ }
2667
+ } else if (sectionId === 'convoy-section') {
2668
+ const convoyFilterEl = document.getElementById('filter-convoy');
2669
+ if (convoyFilterEl && !convoyFilterEl.value && convoyFilterEl.options.length > 1) {
2670
+ convoyFilterEl.value = convoyFilterEl.options[1].value;
2648
2671
  applyFilters();
2649
2672
  }
2650
2673
  } else if (sectionId === 'convoy-pipeline-section') {
@@ -2656,7 +2679,7 @@ try {
2656
2679
  }
2657
2680
 
2658
2681
  const target = document.getElementById(sectionId);
2659
- if (target && target.style.display !== 'none') {
2682
+ if (target) {
2660
2683
  target.scrollIntoView({ behavior: 'smooth', block: 'start' });
2661
2684
  }
2662
2685
  });
@@ -0,0 +1,79 @@
1
+ ---
2
+ description: 'Fix schema validation errors in a convoy YAML spec. Goal is the broken spec YAML; context is the error list from the validation step.'
3
+ agent: 'Team Lead (OpenCastle)'
4
+ output: convoy-spec
5
+ ---
6
+
7
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
8
+
9
+ # Fix Convoy Spec
10
+
11
+ You are the Team Lead. The convoy spec below failed validation. Fix **every reported error** and output a complete, corrected spec.
12
+
13
+ ## Failing Spec
14
+
15
+ ```yaml
16
+ {{goal}}
17
+ ```
18
+
19
+ ## Validation Errors
20
+
21
+ {{context}}
22
+
23
+ ---
24
+
25
+ ## Fix Instructions
26
+
27
+ 1. Read every error before touching the YAML.
28
+ 2. Fix **all** reported errors — do not partially fix.
29
+ 3. Do not change the intent, agent assignments, or task scope of any task. Only fix what is broken.
30
+ 4. Preserve all `id`, `prompt`, `agent`, `review`, and `files` values that are not part of the reported errors.
31
+
32
+ ### Common Fix Patterns
33
+
34
+ **Glob patterns in `files`**
35
+ - `src/**/*.ts` → `src/` (use the directory, not a glob)
36
+ - `app/api/**` → `app/api/`
37
+ - `components/*.tsx` → `components/`
38
+
39
+ **Missing required fields**
40
+ - Add `name:` at the top level if missing
41
+ - Add `version: 2` at the top level if missing
42
+ - Add `id:` to any task that lacks one (use kebab-case derived from the task purpose)
43
+ - Add `prompt:` to any task that lacks one — write a 2-sentence self-contained description
44
+
45
+ **Dependency cycles**
46
+ - If A depends on B and B depends on A: remove the weaker edge (the one that can be inferred from ordering)
47
+ - If the cycle is A → B → C → A: introduce a new intermediate task or reorder so earlier tasks do not depend on later ones
48
+
49
+ **Partition conflicts (two parallel tasks sharing files)**
50
+ - Option 1: Add a `depends_on` edge to serialize the conflicting tasks
51
+ - Option 2: Split one task's `files` list to use a more specific path that does not overlap
52
+
53
+ **Invalid `agent` value**
54
+ Replace with the closest valid agent from:
55
+ `api-designer`, `architect`, `content-engineer`, `copywriter`, `data-expert`,
56
+ `database-engineer`, `developer`, `devops-expert`, `documentation-writer`,
57
+ `performance-expert`, `release-manager`, `researcher`, `security-expert`,
58
+ `seo-specialist`, `team-lead`, `testing-expert`, `ui-ux-expert`
59
+
60
+ **Invalid `timeout` format**
61
+ - `"30 minutes"` → `30m`
62
+ - `"1 hour"` → `1h`
63
+ - `"120"` → `120s`
64
+
65
+ ---
66
+
67
+ ## Output
68
+
69
+ Return the **complete corrected YAML** inside a fenced code block (not just the changed lines):
70
+
71
+ ```yaml
72
+ # .opencastle/convoys/<same-filename-as-original>
73
+ name: ...
74
+ version: 2
75
+ tasks:
76
+ ...
77
+ ```
78
+
79
+ Do not add explanatory prose before or after the YAML block.
@@ -37,8 +37,8 @@ The output file must conform to the following schema. Fields marked **(required)
37
37
  | `gates` | array of strings | no | — | Shell commands run after all tasks complete; each must exit 0 |
38
38
  | `gate_retries` | integer ≥ 0 | no | `0` | How many times to retry failing gates with an auto-fix task |
39
39
  | `guard` | object | no | — | Post-convoy guard configuration (see Guard below) |
40
- | `hooks` | array of Hook | no | — | Post-convoy lifecycle hooks (see Hooks below) |
41
- | `watch` | object | no | — | Watch mode configuration for continuous re-runs (see Watch below) |
40
+ | `hooks` | array of Hook | no | — | Post-convoy lifecycle hooks. Use `post_convoy` hooks for notifications or cleanup scripts after the run completes. |
41
+ | `watch` | object | no | — | Watch mode configuration for continuous re-runs. Set this when the goal is a recurring workflow (e.g. nightly sync, CI re-run on file change). |
42
42
  | `tasks` | list | **yes** | — | Non-empty list of task objects |
43
43
  | `depends_on_convoy` | list of strings | no | — | (version 2 only) Other convoy spec names to run before this one |
44
44
 
@@ -49,31 +49,21 @@ All fields are optional. Values are merged into each task unless the task overri
49
49
  | Field | Type | Default | Description |
50
50
  |-------|------|---------|-------------|
51
51
  | `timeout` | duration | `30m` | Default task timeout (`<n><s\|m\|h>`) |
52
- | `model` | string | — | AI model override for all tasks |
53
52
  | `max_retries` | integer | `1` | Default max retry attempts |
54
53
  | `agent` | string | `developer` | Default agent role |
55
- | `adapter` | string | — | Default adapter override |
56
- | `gates` | array of strings | — | Per-task gate commands run after adapter success |
54
+ | `gates` | array of strings | — | Gate commands run after every task completes (use for project-wide lint/type-check) |
57
55
  | `review` | `auto` \| `fast` \| `panel` \| `none` | — | Review level for completed tasks |
58
- | `reviewer_model` | string | — | Model used for reviews |
59
- | `review_budget` | integer | — | Max review token budget |
60
- | `on_review_budget_exceeded` | `skip` \| `downgrade` \| `stop` | — | Action when review budget exhausted |
61
- | `max_concurrent_reviews` | integer | — | Parallel review limit |
62
- | `review_heuristics` | object | — | Auto-routing rules (see Review Heuristics below) |
63
- | `detect_drift` | boolean | — | Enable drift detection on streaming adapters |
64
- | `on_dispute` | `continue` \| `stop` | — | Behavior on panel disputes |
65
- | `on_exhausted` | `dlq` \| `skip` \| `stop` | | Action when max_retries exhausted |
66
- | `escalate_to` | string | — | Agent for DLQ escalation |
67
- | `inject_lessons` | boolean | — | Auto-inject relevant lessons from LESSONS-LEARNED.md into prompts |
68
- | `track_discovered_issues` | boolean | — | Enable discovered issues tracking in prompts |
69
- | `avoid_weak_agents` | boolean | — | Skip assigning agents to tasks matching their weak areas |
70
- | `max_swarm_concurrency` | integer (1–50) | `8` | Max parallel tasks in swarm mode (`concurrency: auto`) |
71
- | `built_in_gates` | object | — | Built-in gate configuration (see Built-in Gates below) |
72
- | `browser_test` | object | — | Default browser test gate config (see Browser Test below) |
73
- | `circuit_breaker` | object | — | Circuit breaker config (see Circuit Breaker below) |
74
- | `mcp_servers` | array of MCPServer | — | MCP servers available to tasks |
75
- | `mcp_approve_all` | boolean | — | Auto-approve all MCP tool calls |
76
- | `mcp_server_approval_timeout` | number | — | Timeout (seconds) for MCP approval prompts |
56
+ | `review_heuristics` | object | — | Auto-routing rules (see Review Heuristics below). Use to automatically assign `panel` review for security-sensitive paths or agents. |
57
+ | `detect_drift` | boolean | — | Enable drift detection on streaming adapters. Set `true` for long-running (>1h) tasks on streaming adapters to catch scope creep early. |
58
+ | `on_exhausted` | `dlq` \| `skip` \| `stop` | — | Action when max_retries exhausted. Use `dlq` for critical tasks in unattended overnight runs so failures are tracked. |
59
+ | `escalate_to` | string | — | Agent for DLQ escalation (e.g. `architect`). Pair with `on_exhausted: dlq`. |
60
+ | `inject_lessons` | boolean | — | Auto-inject relevant lessons from LESSONS-LEARNED.md into prompts. **Always set `true`.** |
61
+ | `track_discovered_issues` | boolean | — | Enable discovered issues tracking in prompts. **Always set `true`.** |
62
+ | `avoid_weak_agents` | boolean | — | Skip assigning agents to tasks matching their weak areas. **Always set `true`.** |
63
+ | `max_swarm_concurrency` | integer (1–50) | `8` | Max parallel tasks in swarm mode. Only relevant when `concurrency: auto`. |
64
+ | `built_in_gates` | object | — | Built-in gate configuration (see Built-in Gates below). Enable `secret_scan: true` for any task writing auth/config/env files; `dependency_audit: true` when the run adds new packages. |
65
+ | `browser_test` | object | — | Default browser test gate config (see Browser Test below). Set when the goal involves UI changes. |
66
+ | `circuit_breaker` | object | — | Circuit breaker config (see Circuit Breaker below). Set for long multi-agent runs to prevent cascading failures. |
77
67
 
78
68
  ### Built-in Gates
79
69
 
@@ -170,21 +160,19 @@ Enables continuous re-execution triggered by file changes, cron, or git push.
170
160
  | `agent` | string | no | `developer` | Agent role hint (see Agent Roster below) |
171
161
  | `description` | string | no | same as `id` | Short human label shown in progress output |
172
162
  | `depends_on` | list of ids | no | `[]` | Task ids that must finish before this one starts |
173
- | `files` | list of globs | no | `[]` | File scope the agent is allowed to modify |
163
+ | `files` | list of paths | no | `[]` | File scope the agent is allowed to modify. Must be plain file paths or directory paths. **Glob patterns (`*`, `?`, `**`) are not allowed** — use a plain directory path (e.g., `components/`) to cover a whole directory. |
174
164
  | `timeout` | duration | no | `30m` | Max wall time (`<number><s\|m\|h>`, e.g. `10m`, `1h`) |
175
- | `max_retries` | integer | no | from `defaults` or `1` | Max retry attempts for this task |
176
- | `model` | string | no | — | AI model override for this task |
177
- | `adapter` | string | no | — | Per-task adapter override |
178
- | `gates` | list of strings | no | — | Per-task gate commands run after adapter success |
165
+ | `max_retries` | integer | no | from `defaults` or `1` | Max retry attempts for this task. Override to `3` for high-risk tasks (DB migrations, security changes) or `0` for tasks that must not auto-retry. |
166
+ | `gates` | list of strings | no | — | Per-task gate commands when this task needs specific validation beyond global `gates` (e.g. a task-specific test suite or a schema diff check). |
179
167
  | `review` | `auto` \| `fast` \| `panel` \| `none` | no | from `defaults` | Review level for this task |
180
- | `detect_drift` | boolean | no | — | Enable drift detection (streaming adapters only) |
181
- | `persistent` | boolean | no | — | Enable persistent agent identity across convoy runs |
182
- | `steps` | list of TaskStep | no | — | Multi-step sub-prompts (see Steps below) |
183
- | `hooks` | list of Hook | no | — | Per-task lifecycle hooks |
184
- | `outputs` | list of TaskOutput | no | — | Named artifacts this task produces |
185
- | `inputs` | list of TaskInput | no | — | Named artifacts this task consumes from upstream tasks |
186
- | `browser_test` | object | no | — | Per-task browser test config (same schema as defaults) |
187
- | `built_in_gates` | object | no | — | Per-task built-in gates override |
168
+ | `detect_drift` | boolean | no | — | Enable drift detection (streaming adapters only). Set `true` for long (>1h) streaming-adapter tasks to catch scope creep. |
169
+ | `persistent` | boolean | no | — | Enable persistent agent identity across convoy runs. Set `true` for research, exploration, or multi-session implementation tasks where the agent's accumulated discoveries and decisions should be available in future convoy runs targeting the same workstream. Omit (defaults to `false`) for short, self-contained tasks. |
170
+ | `steps` | list of TaskStep | no | — | Multi-step sub-prompts. Use when a task has distinct sequential phases that need intermediate gates (e.g. step 1: generate migration, gate: dry-run; step 2: apply migration). |
171
+ | `hooks` | list of Hook | no | — | Per-task lifecycle hooks. Uncommon at task level; prefer top-level `hooks` for post-convoy actions. |
172
+ | `outputs` | list of TaskOutput | no | — | Named artifacts this task produces (used with `inputs` for explicit artifact passing between tasks). |
173
+ | `inputs` | list of TaskInput | no | — | Named artifacts this task consumes from upstream tasks. |
174
+ | `browser_test` | object | no | — | Per-task browser test config. Set when only this task's output requires visual/a11y validation. |
175
+ | `built_in_gates` | object | no | — | Per-task built-in gates override. Use to enable `secret_scan: true` for specific tasks writing credentials or keys. |
188
176
 
189
177
  ### Task Steps
190
178
 
@@ -218,18 +206,6 @@ Tasks can produce named artifacts and consume artifacts from upstream tasks.
218
206
  | `name` | string | **yes** | Artifact name from the source task |
219
207
  | `as` | string | no | Rename the artifact in the consuming task |
220
208
 
221
- ### MCP Server Config
222
-
223
- | Field | Type | Required | Description |
224
- |-------|------|----------|-------------|
225
- | `name` | string | **yes** | Server identifier |
226
- | `type` | string | **yes** | Server type (e.g. `stdio`, `http`) |
227
- | `local` | boolean | no | Whether the server runs locally |
228
- | `command` | string | no | Command to start the server |
229
- | `args` | list of strings | no | Arguments for the command |
230
- | `url` | string | no | URL for HTTP-based servers |
231
- | `config` | object | no | Additional server configuration |
232
-
233
209
  ### Agent Roster
234
210
 
235
211
  Available values for the `agent` field:
@@ -263,9 +239,16 @@ For each workstream, break it down into the smallest meaningful unit of work tha
263
239
 
264
240
  1. **Single responsibility** — each task does exactly one thing.
265
241
  2. **Self-contained prompt** — the `prompt` field must contain everything the agent needs: objective, file paths, constraints, acceptance criteria. The agent has no other context.
266
- 3. **Explicit file scopes** — list every directory or file the task may touch in `files`. This prevents conflicts between parallel tasks.
267
- 4. **Appropriate agent** — pick the agent whose speciality matches the task (e.g., `testing-expert` for tests, `database-engineer` for migrations).
268
- 5. **Realistic timeouts** — default 30 m is fine for most tasks; use `1h` for large refactors or test suites; use `10m` for small docs or config changes.
242
+ 3. **Explicit file scopes** — list every directory or file the task may touch in `files`. Use plain paths only: exact file paths (e.g., `app/page.tsx`) or directory paths with a trailing slash (e.g., `app/about/`). **Glob patterns (`*`, `?`, `**`) are not allowed** — the engine rejects them.
243
+
244
+ 4. **No partition conflicts** — two tasks may not share a `files` entry if they run in parallel (same phase). Resolve conflicts by either:
245
+ - **Specificity**: replace a broad directory path with the specific files each task actually creates (e.g., instead of both tasks claiming `components/`, one gets `components/Hero.tsx` and the other gets `components/ProjectCard.tsx`)
246
+ - **Sequencing**: add a `depends_on` edge from the later task to the earlier one, so they run in different phases
247
+
248
+ > **Common mistake:** multiple tasks all depending on a single `setup` task will run in parallel and conflict if they share a directory like `components/`, `app/globals.css`, or `app/layout.tsx`. Always use specific file paths or sequence conflicting tasks.
249
+
250
+ 5. **Appropriate agent** — pick the agent whose speciality matches the task (e.g., `testing-expert` for tests, `database-engineer` for migrations).
251
+ 6. **Realistic timeouts** — default 30 m is fine for most tasks; use `1h` for large refactors or test suites; use `10m` for small docs or config changes.
269
252
 
270
253
  ### 3. Define the Dependency Graph (DAG)
271
254
 
@@ -287,12 +270,20 @@ For each workstream, break it down into the smallest meaningful unit of work tha
287
270
  - `on_failure` — use `continue` (default) when tasks are independent so one failure doesn't waste the whole run. Use `stop` when every subsequent task depends on success.
288
271
  - `adapter` — **omit this field** to let the CLI auto-detect the first available adapter. Only set explicitly if the user requests a specific adapter.
289
272
  - `branch` — derive from the goal, e.g., `feat/auth-refactor`. Use a descriptive branch name.
290
- - `defaults` — set sensible defaults for timeout, max_retries, and review. Enable `inject_lessons: true` for self-improving runs, `track_discovered_issues: true` for issue discovery, and `avoid_weak_agents: true` to route around known weaknesses. Model can be left unset for auto-detection.
273
+ - `defaults` — always include `inject_lessons: true`, `track_discovered_issues: true`, and `avoid_weak_agents: true`. Omit `model` and `adapter` to allow auto-detection.
291
274
  - `gates` — include standard validation gates (lint, type-check, test) unless the user specifies otherwise.
292
275
  - `gate_retries` — set to 1–2 if you want the engine to auto-fix gate failures by spawning a fix-up task.
293
276
  - `guard` — enable for post-convoy compliance checks (observability, cleanup, cost reporting).
294
- - For security-sensitive or database migration tasks, use `review: panel` or set `review_heuristics.panel_paths` to target critical paths.
295
- - For long-running or unreliable tasks, configure `circuit_breaker` with a `fallback_agent`.
277
+ - `review` / `review_heuristics` use `review: fast` as the default. Upgrade to `panel` for security, auth, and database migration tasks. Use `review_heuristics.panel_paths` to auto-escalate specific file patterns (e.g. `db/migrations/`, `libs/auth/`) without setting per-task overrides.
278
+ - `built_in_gates` set `secret_scan: true` in `defaults.built_in_gates` whenever the run touches auth, config, or env files. Set `dependency_audit: true` when adding new packages.
279
+ - `on_exhausted` + `escalate_to` — set `on_exhausted: dlq` and `escalate_to: architect` in `defaults` for unattended overnight runs so exhausted tasks are queued for human review rather than silently skipped.
280
+ - `detect_drift` — set `detect_drift: true` in `defaults` for runs with tasks longer than 1h on streaming adapters.
281
+ - `circuit_breaker` — configure with a `fallback_agent` for long multi-agent runs to prevent one flaky agent from stalling the whole convoy.
282
+ - `persistent` — set `persistent: true` on individual tasks that do research, codebase exploration, or long implementation work where the agent's accumulated discoveries should persist across future convoy runs (e.g. a Researcher task mapping the auth system, or a Database Engineer task discovering schema quirks). Omit for short, self-contained tasks.
283
+ - `steps` — use on a task when it has distinct sequential phases that need intermediate validation gates between them (e.g. generate migration → dry-run gate → apply migration). Do not use `steps` just to split a large prompt; use separate tasks instead.
284
+ - Per-task `gates` — add to a task only when that specific task needs validation gates beyond the global `gates` (e.g. a dedicated test suite for a specific module, a schema diff command).
285
+ - Per-task `max_retries` — override to `3` for high-risk tasks (DB migrations, security changes) or `0` when a task must not auto-retry (e.g. payment processing changes).
286
+ - `hooks` — use top-level `post_convoy` hooks for notifications, changelog generation, or cleanup scripts that should run once after all tasks complete.
296
287
 
297
288
  ### 5. Write the Prompts
298
289
 
@@ -317,7 +308,8 @@ Before presenting the YAML, mentally verify:
317
308
  - [ ] Every task has a unique `id`
318
309
  - [ ] Every `depends_on` reference points to a valid `id` defined earlier in the list
319
310
  - [ ] No dependency cycles exist
320
- - [ ] No two parallel tasks share the same `files` entries (partition check)
311
+ - [ ] No two parallel tasks share the same `files` entries — group tasks by phase and check each phase for overlaps; resolve with specific file paths or `depends_on` (see Step 2, rule 4)
312
+ - [ ] No `files` entry contains `*`, `?`, or `**` — use plain file paths or directory paths (trailing `/`) only
321
313
  - [ ] Prompts are self-contained — an agent with zero context can execute them
322
314
  - [ ] Timeouts are reasonable for the scope of each task
323
315
  - [ ] `outputs`/`inputs` references are consistent (consuming task depends on producing task)
@@ -347,7 +339,9 @@ tasks:
347
339
  description: <short label>
348
340
  timeout: <duration>
349
341
  files:
350
- - <glob>
342
+ - app/some-file.tsx
343
+ - components/Hero.tsx
344
+ - components/Button.tsx
351
345
  prompt: |
352
346
  <full self-contained instruction>
353
347
 
@@ -356,7 +350,8 @@ tasks:
356
350
  - <task-id>
357
351
  agent: <agent>
358
352
  files:
359
- - <glob>
353
+ - app/other-file.tsx
354
+ - components/OtherComponent.tsx
360
355
  prompt: |
361
356
  <full self-contained instruction>
362
357
 
@@ -0,0 +1,120 @@
1
+ ---
2
+ description: 'Generate a Product Requirements Document from a high-level feature prompt. Output feeds directly into the generate-convoy step.'
3
+ agent: 'Team Lead (OpenCastle)'
4
+ output: prd
5
+ ---
6
+
7
+ <!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
8
+
9
+ # Generate PRD
10
+
11
+ You are the Team Lead. Convert the feature request below into a structured Product Requirements Document (PRD). The PRD will be consumed by the `generate-convoy` step to produce an automated agent task spec, so every section must be **concrete**, **specific**, and **implementation-ready**.
12
+
13
+ ## Feature Request
14
+
15
+ {{goal}}
16
+
17
+ ## Additional Context
18
+
19
+ {{context}}
20
+
21
+ ---
22
+
23
+ ## Required PRD Structure
24
+
25
+ Produce the PRD in Markdown using **exactly** the sections below. Do not skip or merge sections. Do not wrap the output in a code fence — output raw Markdown starting directly with the `#` heading.
26
+
27
+ ---
28
+
29
+ # [Feature Name] — PRD
30
+
31
+ ## Overview
32
+
33
+ 2–3 sentences: what this feature does, who benefits, and why it matters now.
34
+
35
+ ## Goals
36
+
37
+ Numbered list of specific, measurable outcomes this feature must achieve. Each goal should be a single sentence with a clear success condition.
38
+
39
+ 1. …
40
+ 2. …
41
+
42
+ ## Non-Goals
43
+
44
+ Explicit exclusions — what this work does **not** cover. If nothing is excluded, write "None."
45
+
46
+ ## User Stories & Acceptance Criteria
47
+
48
+ For each primary scenario, write a user story + binary acceptance criteria. Criteria must be testable (pass/fail — no subjective language).
49
+
50
+ **US-1: [Short title]**
51
+ As a [user type], I want [action] so that [benefit].
52
+
53
+ Acceptance criteria:
54
+ - [ ] [Specific, testable condition]
55
+ - [ ] [Another condition]
56
+
57
+ *(Repeat for each user story)*
58
+
59
+ ## Technical Requirements
60
+
61
+ Specific technical constraints the implementation must respect:
62
+ - Libraries, framework versions to use or avoid
63
+ - API contracts or interfaces that must not break
64
+ - Performance thresholds (e.g., "<200 ms p95 latency")
65
+ - Security requirements
66
+ - Browser/platform compatibility
67
+
68
+ ## Implementation Scope
69
+
70
+ List **every file and directory** that will be created, modified, or deleted. Use specific paths — not broad paths like `src/`. Group by concern.
71
+
72
+ | Concern | Files / Directories |
73
+ |---------|---------------------|
74
+ | [Frontend components] | `components/feature/`, `app/feature/page.tsx` |
75
+ | [API routes] | `app/api/feature/route.ts` |
76
+ | [Database] | `db/migrations/add_feature.sql`, `db/schema.ts` |
77
+ | [Shared types] | `types/feature.ts` |
78
+ | [Tests] | `__tests__/feature.test.ts`, `e2e/feature.spec.ts` |
79
+ | [Config / env] | `.env.example` |
80
+
81
+ **File partition rules (important for parallel execution):**
82
+ - No two concurrent workstreams may modify the same file
83
+ - If two workstreams need the same file, they must be sequenced (Phase N+1 after Phase N)
84
+
85
+ ## Task Breakdown
86
+
87
+ Decompose into the minimum number of phases. Tasks in the same phase run in parallel and **must not share any files**.
88
+
89
+ ```
90
+ Phase 1 — Foundation (parallel, no dependencies):
91
+ - [Workstream A title]: [2-sentence description]
92
+ Files: [list exact files]
93
+ - [Workstream B title]: [2-sentence description]
94
+ Files: [list exact files]
95
+
96
+ Phase 2 — Integration (depends on Phase 1):
97
+ - [Workstream C title]: [2-sentence description]
98
+ Files: [list exact files]
99
+ Depends on: Phase 1
100
+
101
+ Phase 3 — Verification (depends on Phase 2):
102
+ - [Tests]: Run full test suite, achieve ≥ 95% coverage on new files
103
+ - [Documentation]: Update READMEs and changelogs
104
+ ```
105
+
106
+ ## Success Criteria
107
+
108
+ Measurable, binary checks that confirm the feature is shippable:
109
+ - [ ] All acceptance criteria in User Stories & Acceptance Criteria pass
110
+ - [ ] TypeScript compiles with zero errors
111
+ - [ ] Lint passes with zero warnings
112
+ - [ ] Unit test coverage ≥ 95% on all new/changed files
113
+ - [ ] [Feature-specific checks]
114
+
115
+ ## Risks & Open Questions
116
+
117
+ - **[Risk title]**: [Description of the risk] — *Mitigation: [How to handle it]*
118
+ - **[Open question]**: [What needs to be decided before implementation can start]
119
+
120
+ If there are no risks or open questions, write "None identified."