@snipcodeit/mgw 0.3.0 → 0.6.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.
@@ -4,9 +4,16 @@ description: Execute GSD pipeline (quick or milestone route) and post execution
4
4
  ---
5
5
 
6
6
  <step name="execute_gsd_quick">
7
- **Execute GSD pipeline (quick / quick --full route):**
7
+ **Execute GSD pipeline (quick / quick --full / plan-phase route):**
8
8
 
9
- Only run this step if gsd_route is "gsd:quick" or "gsd:quick --full".
9
+ Only run this step if gsd_route matches any of these (prefixed or unprefixed):
10
+ - `quick` or `gsd:quick`
11
+ - `quick --full` or `gsd:quick --full`
12
+ - `plan-phase` or `gsd:plan-phase`
13
+
14
+ `plan-phase` follows the same lifecycle as `quick --full` (init -> plan -> check -> execute -> verify -> publish) so it is handled here with FULL_MODE forced on.
15
+
16
+ `plan-phase` follows the same lifecycle as `quick --full` (init → plan → check → execute → verify → publish) so it is handled here with FULL_MODE forced on.
10
17
 
11
18
  **Retry loop initialization:**
12
19
  ```bash
@@ -60,12 +67,47 @@ QUICK_DIR=".planning/quick/${next_num}-${slug}"
60
67
  mkdir -p "$QUICK_DIR"
61
68
  ```
62
69
 
63
- 3. **Spawn planner (task agent):**
70
+ 3. **Assemble MGW context and spawn planner (task agent, with diagnostic capture):**
71
+
72
+ Assemble multi-machine context from GitHub issue comments before spawning:
73
+ ```bash
74
+ MGW_CONTEXT=$(node -e "
75
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
76
+ ic.buildGSDPromptContext({
77
+ milestone: ${MILESTONE_NUM},
78
+ phase: ${PHASE_NUMBER},
79
+ issueNumber: ${ISSUE_NUMBER},
80
+ includeVision: true,
81
+ includePriorSummaries: true,
82
+ includeCurrentPlan: false
83
+ }).then(ctx => process.stdout.write(ctx));
84
+ " 2>/dev/null || echo "")
85
+ ```
86
+
87
+ <!-- mgw:criticality=critical spawn_point=planner -->
88
+ <!-- Critical: plan creation is required for pipeline to proceed.
89
+ On failure: retry via existing retry loop, then dead-letter. -->
90
+
91
+ **Pre-spawn diagnostic hook (planner):**
92
+ ```bash
93
+ DIAG_PLANNER=$(node -e "
94
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
95
+ const id = dh.beforeAgentSpawn({
96
+ agentType: 'gsd-planner',
97
+ issueNumber: ${ISSUE_NUMBER},
98
+ prompt: 'Plan: ${issue_title}',
99
+ repoRoot: '${REPO_ROOT}'
100
+ });
101
+ process.stdout.write(id);
102
+ " 2>/dev/null || echo "")
103
+ ```
64
104
  ```
65
105
  Task(
66
106
  prompt="
67
107
  <planning_context>
68
108
 
109
+ ${MGW_CONTEXT}
110
+
69
111
  **Mode:** ${FULL_MODE ? 'quick-full' : 'quick'}
70
112
  **Directory:** ${QUICK_DIR}
71
113
  **Description:** ${TASK_DESCRIPTION}
@@ -109,7 +151,68 @@ Return: ## PLANNING COMPLETE with plan path
109
151
  )
110
152
  ```
111
153
 
112
- 4. **Verify plan exists** at `${QUICK_DIR}/${next_num}-PLAN.md`
154
+ 4. **Update checkpoint after planner completes:**
155
+ ```bash
156
+ # Checkpoint: record plan completion and set resume to plan-check or execution
157
+ node -e "
158
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
159
+ updateCheckpoint(${ISSUE_NUMBER}, {
160
+ pipeline_step: 'plan',
161
+ step_progress: { plan_path: '${QUICK_DIR}/${next_num}-PLAN.md', plan_checked: false, revision_count: 0 },
162
+ last_agent_output: '${QUICK_DIR}/${next_num}-PLAN.md',
163
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-PLAN.md', type: 'plan', created_at: new Date().toISOString() }],
164
+ step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${QUICK_DIR}/${next_num}-PLAN.md' }],
165
+ resume: { action: '${FULL_MODE ? \"run-plan-checker\" : \"spawn-executor\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
166
+
167
+ **Post-spawn diagnostic hook (planner):**
168
+ ```bash
169
+ PLANNER_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-PLAN.md" ] && echo "success" || echo "error" )
170
+ node -e "
171
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
172
+ dh.afterAgentSpawn({
173
+ diagId: '${DIAG_PLANNER}',
174
+ exitReason: '${PLANNER_EXIT}',
175
+ repoRoot: '${REPO_ROOT}'
176
+ });
177
+ " 2>/dev/null || true
178
+ ```
179
+
180
+ 4. **Checkpoint: record plan completion (atomic write):**
181
+ ```bash
182
+ # Checkpoint: record plan completion and set resume to plan-check or execution.
183
+ # All checkpoint writes use atomicWriteJson() — write to .tmp then rename.
184
+ node -e "
185
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
186
+ updateCheckpoint(${ISSUE_NUMBER}, {
187
+ pipeline_step: 'plan',
188
+ step_progress: { plan_path: '${QUICK_DIR}/${next_num}-PLAN.md', plan_checked: false, revision_count: 0 },
189
+ last_agent_output: '${QUICK_DIR}/${next_num}-PLAN.md',
190
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-PLAN.md', type: 'plan', created_at: new Date().toISOString() }],
191
+ step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${QUICK_DIR}/${next_num}-PLAN.md' }],
192
+ resume: { action: '${FULL_MODE ? \"run-plan-checker\" : \"spawn-executor\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
193
+ });
194
+ " 2>/dev/null || true
195
+ ```
196
+
197
+ 4b. **Publish plan comment (non-blocking):**
198
+
199
+ 4b. **Publish plan comment (non-blocking):**
200
+
201
+ 4. **Publish plan comment (non-blocking):**
202
+ ```bash
203
+ PLAN_FILE="${QUICK_DIR}/${next_num}-PLAN.md"
204
+ if [ -f "$PLAN_FILE" ]; then
205
+ node -e "
206
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
207
+ const fs = require('fs');
208
+ const content = fs.readFileSync('${PLAN_FILE}', 'utf-8');
209
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'plan', content, { phase: ${next_num}, milestone: ${MILESTONE_NUM} })
210
+ .catch(e => console.error('WARNING: Failed to post plan comment:', e.message));
211
+ " 2>/dev/null || true
212
+ fi
213
+ ```
214
+
215
+ 5. **Verify plan exists** at `${QUICK_DIR}/${next_num}-PLAN.md`
113
216
 
114
217
  5. **Pre-flight plan structure check (gsd-tools):**
115
218
  ```bash
@@ -118,6 +221,37 @@ PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify plan-structur
118
221
  Parse the JSON result. If structural issues found, include them in the plan-checker prompt below so it has concrete problems to evaluate rather than searching from scratch.
119
222
 
120
223
  6. **(If --full) Spawn plan-checker, handle revision loop (max 2 iterations):**
224
+
225
+ <!-- mgw:criticality=advisory spawn_point=plan-checker -->
226
+ <!-- Advisory: plan checking is a quality gate, not a pipeline blocker.
227
+ If this agent fails, log a warning and proceed with the unchecked plan.
228
+ The plan was already verified structurally by gsd-tools verify plan-structure.
229
+
230
+ Graceful degradation pattern:
231
+ ```
232
+ PLAN_CHECK_RESULT=$(wrapAdvisoryAgent(Task(...), 'plan-checker', {
233
+ issueNumber: ISSUE_NUMBER,
234
+ fallback: '## VERIFICATION PASSED (plan-checker unavailable — structural check only)'
235
+ }))
236
+ # If fallback returned, skip the revision loop and proceed to execution
237
+ ```
238
+ -->
239
+
240
+ 6. **(If --full) Spawn plan-checker (with diagnostic capture), handle revision loop (max 2 iterations):**
241
+
242
+ **Pre-spawn diagnostic hook (plan-checker):**
243
+ ```bash
244
+ DIAG_CHECKER=$(node -e "
245
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
246
+ const id = dh.beforeAgentSpawn({
247
+ agentType: 'gsd-plan-checker',
248
+ issueNumber: ${ISSUE_NUMBER},
249
+ prompt: 'Check quick plan: ${issue_title}',
250
+ repoRoot: '${REPO_ROOT}'
251
+ });
252
+ process.stdout.write(id);
253
+ " 2>/dev/null || echo "")
254
+ ```
121
255
  ```
122
256
  Task(
123
257
  prompt="
@@ -159,10 +293,43 @@ Skip: context compliance (no CONTEXT.md), cross-plan deps (single plan), ROADMAP
159
293
  )
160
294
  ```
161
295
 
296
+ **Post-spawn diagnostic hook (plan-checker):**
297
+ ```bash
298
+ node -e "
299
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
300
+ dh.afterAgentSpawn({
301
+ diagId: '${DIAG_CHECKER}',
302
+ exitReason: 'success',
303
+ repoRoot: '${REPO_ROOT}'
304
+ });
305
+ " 2>/dev/null || true
306
+ ```
307
+
162
308
  If issues found and iteration < 2: spawn planner revision, then re-check.
163
309
  If iteration >= 2: offer force proceed or abort.
164
310
 
165
311
  7. **Spawn executor (task agent):**
312
+
313
+ <!-- mgw:criticality=critical spawn_point=executor -->
314
+ <!-- Critical: execution produces the code changes. Without it, there is
315
+ nothing to commit or PR. On failure: retry via existing retry loop,
316
+ then dead-letter. -->
317
+
318
+ 7. **Spawn executor (task agent, with diagnostic capture):**
319
+
320
+ **Pre-spawn diagnostic hook (executor):**
321
+ ```bash
322
+ DIAG_EXECUTOR=$(node -e "
323
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
324
+ const id = dh.beforeAgentSpawn({
325
+ agentType: 'gsd-executor',
326
+ issueNumber: ${ISSUE_NUMBER},
327
+ prompt: 'Execute: ${issue_title}',
328
+ repoRoot: '${REPO_ROOT}'
329
+ });
330
+ process.stdout.write(id);
331
+ " 2>/dev/null || echo "")
332
+ ```
166
333
  ```
167
334
  Task(
168
335
  prompt="
@@ -187,13 +354,106 @@ Execute quick task ${next_num}.
187
354
  )
188
355
  ```
189
356
 
190
- 8. **Verify summary (gsd-tools):**
357
+ 8. **Update checkpoint after executor completes:**
358
+ ```bash
359
+ # Checkpoint: record execution completion and set resume to verification
360
+ node -e "
361
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
362
+ updateCheckpoint(${ISSUE_NUMBER}, {
363
+ pipeline_step: 'execute',
364
+ step_progress: { tasks_completed: ${TASK_COUNT}, tasks_total: ${TASK_COUNT} },
365
+ last_agent_output: '${QUICK_DIR}/${next_num}-SUMMARY.md',
366
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-SUMMARY.md', type: 'summary', created_at: new Date().toISOString() }],
367
+ step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${QUICK_DIR}/${next_num}-SUMMARY.md' }],
368
+ resume: { action: '${FULL_MODE ? \"spawn-verifier\" : \"create-pr\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
369
+
370
+ **Post-spawn diagnostic hook (executor):**
371
+ ```bash
372
+ EXECUTOR_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-SUMMARY.md" ] && echo "success" || echo "error" )
373
+ node -e "
374
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
375
+ dh.afterAgentSpawn({
376
+ diagId: '${DIAG_EXECUTOR}',
377
+ exitReason: '${EXECUTOR_EXIT}',
378
+ repoRoot: '${REPO_ROOT}'
379
+ });
380
+ " 2>/dev/null || true
381
+ ```
382
+
383
+ 8. **Checkpoint: record execution completion (atomic write):**
384
+ ```bash
385
+ # Checkpoint: record execution completion and set resume to verification or PR creation.
386
+ node -e "
387
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
388
+ updateCheckpoint(${ISSUE_NUMBER}, {
389
+ pipeline_step: 'execute',
390
+ step_progress: { tasks_completed: ${TASK_COUNT}, tasks_total: ${TASK_COUNT} },
391
+ last_agent_output: '${QUICK_DIR}/${next_num}-SUMMARY.md',
392
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-SUMMARY.md', type: 'summary', created_at: new Date().toISOString() }],
393
+ step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${QUICK_DIR}/${next_num}-SUMMARY.md' }],
394
+ resume: { action: '${FULL_MODE ? \"spawn-verifier\" : \"create-pr\"}', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
395
+ });
396
+ " 2>/dev/null || true
397
+ ```
398
+
399
+ 8b. **Publish summary comment (non-blocking):**
400
+
401
+ 8b. **Publish summary comment (non-blocking):**
402
+
403
+ 8. **Publish summary comment (non-blocking):**
404
+ ```bash
405
+ SUMMARY_FILE="${QUICK_DIR}/${next_num}-SUMMARY.md"
406
+ if [ -f "$SUMMARY_FILE" ]; then
407
+ node -e "
408
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
409
+ const fs = require('fs');
410
+ const content = fs.readFileSync('${SUMMARY_FILE}', 'utf-8');
411
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'summary', content, { phase: ${next_num}, milestone: ${MILESTONE_NUM} })
412
+ .catch(e => console.error('WARNING: Failed to post summary comment:', e.message));
413
+ " 2>/dev/null || true
414
+ fi
415
+ ```
416
+
417
+ 9. **Verify summary (gsd-tools):**
191
418
  ```bash
192
419
  VERIFY_RESULT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify-summary "${QUICK_DIR}/${next_num}-SUMMARY.md")
193
420
  ```
194
421
  Parse JSON result. Use `passed` field for go/no-go. Checks summary existence, files created, and commits.
195
422
 
196
423
  9. **(If --full) Spawn verifier:**
424
+
425
+ <!-- mgw:criticality=advisory spawn_point=verifier -->
426
+ <!-- Advisory: verification is quality assurance after execution is complete.
427
+ The code changes and commits already exist. If verification fails,
428
+ log a warning and proceed to PR creation with a note that verification
429
+ was skipped.
430
+
431
+ Graceful degradation pattern:
432
+ ```
433
+ VERIFY_RESULT=$(wrapAdvisoryAgent(Task(...), 'verifier', {
434
+ issueNumber: ISSUE_NUMBER,
435
+ fallback: null
436
+ }))
437
+ # If fallback returned (null), create a minimal VERIFICATION.md:
438
+ # "## VERIFICATION SKIPPED\nVerifier agent unavailable. Manual review recommended."
439
+ ```
440
+ -->
441
+
442
+ 9. **(If --full) Spawn verifier (with diagnostic capture):**
443
+
444
+ **Pre-spawn diagnostic hook (verifier):**
445
+ ```bash
446
+ DIAG_VERIFIER=$(node -e "
447
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
448
+ const id = dh.beforeAgentSpawn({
449
+ agentType: 'gsd-verifier',
450
+ issueNumber: ${ISSUE_NUMBER},
451
+ prompt: 'Verify: ${issue_title}',
452
+ repoRoot: '${REPO_ROOT}'
453
+ });
454
+ process.stdout.write(id);
455
+ " 2>/dev/null || echo "")
456
+ ```
197
457
  ```
198
458
  Task(
199
459
  prompt="
@@ -214,7 +474,67 @@ Check must_haves against actual codebase. Create VERIFICATION.md at ${QUICK_DIR}
214
474
  )
215
475
  ```
216
476
 
217
- 10. **Post-execution artifact verification (non-blocking):**
477
+ 10. **Update checkpoint after verifier completes (--full only):**
478
+ ```bash
479
+ # Checkpoint: record verification completion and set resume to PR creation
480
+ node -e "
481
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
482
+ updateCheckpoint(${ISSUE_NUMBER}, {
483
+ pipeline_step: 'verify',
484
+ step_progress: { verification_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', must_haves_checked: true },
485
+ last_agent_output: '${QUICK_DIR}/${next_num}-VERIFICATION.md',
486
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', type: 'verification', created_at: new Date().toISOString() }],
487
+ step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md' }],
488
+ resume: { action: 'create-pr', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
489
+
490
+ **Post-spawn diagnostic hook (verifier):**
491
+ ```bash
492
+ VERIFIER_EXIT=$( [ -f "${QUICK_DIR}/${next_num}-VERIFICATION.md" ] && echo "success" || echo "error" )
493
+ node -e "
494
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
495
+ dh.afterAgentSpawn({
496
+ diagId: '${DIAG_VERIFIER}',
497
+ exitReason: '${VERIFIER_EXIT}',
498
+ repoRoot: '${REPO_ROOT}'
499
+ });
500
+ " 2>/dev/null || true
501
+ ```
502
+
503
+ 10. **Checkpoint: record verification completion (atomic write, --full only):**
504
+ ```bash
505
+ # Checkpoint: record verification completion and set resume to PR creation.
506
+ node -e "
507
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
508
+ updateCheckpoint(${ISSUE_NUMBER}, {
509
+ pipeline_step: 'verify',
510
+ step_progress: { verification_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', must_haves_checked: true },
511
+ last_agent_output: '${QUICK_DIR}/${next_num}-VERIFICATION.md',
512
+ artifacts: [{ path: '${QUICK_DIR}/${next_num}-VERIFICATION.md', type: 'verification', created_at: new Date().toISOString() }],
513
+ step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${QUICK_DIR}/${next_num}-VERIFICATION.md' }],
514
+ resume: { action: 'create-pr', context: { quick_dir: '${QUICK_DIR}', plan_num: ${next_num} } }
515
+ });
516
+ " 2>/dev/null || true
517
+ ```
518
+
519
+ 10b. **Publish verification comment (non-blocking, --full only):**
520
+
521
+ 10b. **Publish verification comment (non-blocking, --full only):**
522
+
523
+ 10. **Publish verification comment (non-blocking, --full only):**
524
+ ```bash
525
+ VERIFICATION_FILE="${QUICK_DIR}/${next_num}-VERIFICATION.md"
526
+ if [ -f "$VERIFICATION_FILE" ]; then
527
+ node -e "
528
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
529
+ const fs = require('fs');
530
+ const content = fs.readFileSync('${VERIFICATION_FILE}', 'utf-8');
531
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'verification', content, { phase: ${next_num}, milestone: ${MILESTONE_NUM} })
532
+ .catch(e => console.error('WARNING: Failed to post verification comment:', e.message));
533
+ " 2>/dev/null || true
534
+ fi
535
+ ```
536
+
537
+ 11. **Post-execution artifact verification (non-blocking):**
218
538
  ```bash
219
539
  ARTIFACT_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify artifacts "${QUICK_DIR}/${next_num}-PLAN.md" 2>/dev/null || echo '{"passed":true}')
220
540
  KEYLINK_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify key-links "${QUICK_DIR}/${next_num}-PLAN.md" 2>/dev/null || echo '{"passed":true}')
@@ -234,8 +554,13 @@ If any step above fails (executor or verifier agent returns error, summary missi
234
554
 
235
555
  ```bash
236
556
  # On failure — classify and decide whether to retry
557
+ # CRITICALITY-AWARE: check if the failing agent is advisory first.
558
+ # Advisory agent failures are logged and skipped (pipeline continues).
559
+ # Critical agent failures follow the existing retry/dead-letter flow.
560
+
237
561
  FAILURE_CLASS=$(node -e "
238
562
  const { classifyFailure, canRetry, incrementRetry, getBackoffMs } = require('./lib/retry.cjs');
563
+ const { isAdvisory } = require('./lib/agent-criticality.cjs');
239
564
  const { loadActiveIssue } = require('./lib/state.cjs');
240
565
  const fs = require('fs'), path = require('path');
241
566
 
@@ -245,29 +570,43 @@ const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.js
245
570
  const filePath = path.join(activeDir, file);
246
571
  let issueState = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
247
572
 
248
- // Classify the failure from the error context
249
- const error = { message: '${EXECUTION_ERROR_MESSAGE}' };
250
- const result = classifyFailure(error);
251
- console.error('Failure classified as: ' + result.class + ' ' + result.reason);
252
-
253
- // Persist failure class to state
254
- issueState.last_failure_class = result.class;
255
-
256
- if (result.class === 'transient' && canRetry(issueState)) {
257
- const backoff = getBackoffMs(issueState.retry_count || 0);
258
- issueState = incrementRetry(issueState);
259
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
260
- // Output: backoff ms so shell can sleep
261
- console.log('retry:' + backoff + ':' + result.class);
573
+ // Check if the failing agent is advisory
574
+ const failingSpawnPoint = '${FAILING_SPAWN_POINT}';
575
+ if (failingSpawnPoint && isAdvisory(failingSpawnPoint)) {
576
+ // Advisory agent failure log warning and continue pipeline
577
+ console.error('MGW WARNING: Advisory agent \"' + failingSpawnPoint + '\" failed. Continuing pipeline.');
578
+ console.log('advisory_degraded:' + failingSpawnPoint);
262
579
  } else {
263
- // Permanent failure or retries exhausted dead-letter
264
- issueState.dead_letter = true;
265
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
266
- console.log('dead_letter:' + result.class);
580
+ // Critical agent failure classify and apply retry/dead-letter logic
581
+ const error = { message: '${EXECUTION_ERROR_MESSAGE}' };
582
+ const result = classifyFailure(error);
583
+ console.error('Failure classified as: ' + result.class + ' — ' + result.reason);
584
+
585
+ // Persist failure class to state
586
+ issueState.last_failure_class = result.class;
587
+
588
+ if (result.class === 'transient' && canRetry(issueState)) {
589
+ const backoff = getBackoffMs(issueState.retry_count || 0);
590
+ issueState = incrementRetry(issueState);
591
+ fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
592
+ // Output: backoff ms so shell can sleep
593
+ console.log('retry:' + backoff + ':' + result.class);
594
+ } else {
595
+ // Permanent failure or retries exhausted — dead-letter
596
+ issueState.dead_letter = true;
597
+ fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
598
+ console.log('dead_letter:' + result.class);
599
+ }
267
600
  }
268
601
  ")
269
602
 
270
603
  case "$FAILURE_CLASS" in
604
+ advisory_degraded:*)
605
+ DEGRADED_AGENT=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
606
+ echo "MGW: Advisory agent '${DEGRADED_AGENT}' failed — gracefully degraded, continuing pipeline."
607
+ # Do NOT set EXECUTION_SUCCEEDED=false — pipeline continues
608
+ # Skip to next step (advisory output is optional)
609
+ ;;
271
610
  retry:*)
272
611
  BACKOFF_MS=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
273
612
  BACKOFF_SEC=$(( (BACKOFF_MS + 999) / 1000 ))
@@ -394,6 +733,31 @@ If proceed: apply "mgw:approved" label and continue.
394
733
 
395
734
  Update pipeline_stage to "planning" (at `${REPO_ROOT}/.mgw/active/`).
396
735
 
736
+ **Verify ROADMAP.md was created:**
737
+ ```bash
738
+ if [ ! -f ".planning/ROADMAP.md" ]; then
739
+ echo "MGW ERROR: Roadmapper agent did not produce ROADMAP.md. Cannot proceed with milestone execution."
740
+ FAIL_TS=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs current-timestamp --raw 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
741
+ gh issue comment ${ISSUE_NUMBER} --body "> **MGW** · \`pipeline-failed\` · ${FAIL_TS}
742
+ > Roadmapper agent did not produce ROADMAP.md. Pipeline cannot continue.
743
+ > Re-run with \`/mgw:run ${ISSUE_NUMBER}\` after investigating." 2>/dev/null || true
744
+ # Update pipeline_stage to failed (same pattern as post_execution_update dead_letter block)
745
+ node -e "
746
+ const fs = require('fs'), path = require('path');
747
+ const activeDir = path.join(process.cwd(), '.mgw', 'active');
748
+ const files = fs.readdirSync(activeDir);
749
+ const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
750
+ if (file) {
751
+ const filePath = path.join(activeDir, file);
752
+ const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
753
+ state.pipeline_stage = 'failed';
754
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2));
755
+ }
756
+ " 2>/dev/null || true
757
+ exit 1
758
+ fi
759
+ ```
760
+
397
761
  2. **If resuming with pipeline_stage = "planning" and ROADMAP.md exists:**
398
762
  Discover phases from ROADMAP and run the full per-phase GSD lifecycle:
399
763
 
@@ -430,7 +794,40 @@ If proceed: apply "mgw:approved" label and continue.
430
794
  # Parse PHASE_INIT JSON for: planner_model, checker_model
431
795
  ```
432
796
 
433
- **b. Spawn planner agent (gsd:plan-phase):**
797
+ **b. Assemble MGW context and spawn planner agent (gsd:plan-phase, with diagnostic capture):**
798
+
799
+ Assemble multi-machine context from GitHub issue comments before spawning:
800
+ ```bash
801
+ MGW_CONTEXT=$(node -e "
802
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
803
+ ic.buildGSDPromptContext({
804
+ milestone: ${MILESTONE_NUM},
805
+ phase: ${PHASE_NUMBER},
806
+ issueNumber: ${ISSUE_NUMBER},
807
+ includeVision: true,
808
+ includePriorSummaries: true,
809
+ includeCurrentPlan: false
810
+ }).then(ctx => process.stdout.write(ctx));
811
+ " 2>/dev/null || echo "")
812
+ ```
813
+
814
+ <!-- mgw:criticality=critical spawn_point=milestone-planner -->
815
+ <!-- Critical: phase planning is required — cannot execute without a plan.
816
+ On failure: retry via milestone retry loop, then dead-letter. -->
817
+
818
+ **Pre-spawn diagnostic hook (milestone planner):**
819
+ ```bash
820
+ DIAG_MS_PLANNER=$(node -e "
821
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
822
+ const id = dh.beforeAgentSpawn({
823
+ agentType: 'gsd-planner',
824
+ issueNumber: ${ISSUE_NUMBER},
825
+ prompt: 'Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}',
826
+ repoRoot: '${REPO_ROOT}'
827
+ });
828
+ process.stdout.write(id);
829
+ " 2>/dev/null || echo "")
830
+ ```
434
831
  ```
435
832
  Task(
436
833
  prompt="
@@ -441,6 +838,8 @@ If proceed: apply "mgw:approved" label and continue.
441
838
  - .planning/STATE.md (If exists -- project state)
442
839
  </files_to_read>
443
840
 
841
+ ${MGW_CONTEXT}
842
+
444
843
  You are the GSD planner. Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}.
445
844
 
446
845
  Read and follow the plan-phase workflow:
@@ -462,6 +861,48 @@ If proceed: apply "mgw:approved" label and continue.
462
861
  )
463
862
  ```
464
863
 
864
+ **Post-spawn diagnostic hook (milestone planner):**
865
+ ```bash
866
+ MS_PLANNER_EXIT=$( ls ${phase_dir}/*-PLAN.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
867
+ node -e "
868
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
869
+ dh.afterAgentSpawn({
870
+ diagId: '${DIAG_MS_PLANNER}',
871
+ exitReason: '${MS_PLANNER_EXIT}',
872
+ repoRoot: '${REPO_ROOT}'
873
+ });
874
+ " 2>/dev/null || true
875
+ ```
876
+
877
+ **b1b. Checkpoint: record milestone phase plan completion (atomic write):**
878
+ ```bash
879
+ # Checkpoint: record milestone plan completion for this phase.
880
+ node -e "
881
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
882
+ updateCheckpoint(${ISSUE_NUMBER}, {
883
+ pipeline_step: 'plan',
884
+ step_progress: { gsd_phase: ${PHASE_NUMBER}, plan_path: '${phase_dir}' },
885
+ last_agent_output: '${phase_dir}',
886
+ step_history: [{ step: 'plan', completed_at: new Date().toISOString(), agent_type: 'gsd-planner', output_path: '${phase_dir}' }],
887
+ resume: { action: 'execute-phase', context: { phase_number: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
888
+ });
889
+ " 2>/dev/null || true
890
+ ```
891
+
892
+ **b2. Publish plan comment (non-blocking):**
893
+ ```bash
894
+ PLAN_FILES=$(ls ${phase_dir}/*-PLAN.md 2>/dev/null)
895
+ for PLAN_FILE in $PLAN_FILES; do
896
+ node -e "
897
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
898
+ const fs = require('fs');
899
+ const content = fs.readFileSync('${PLAN_FILE}', 'utf-8');
900
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'plan', content, { phase: ${PHASE_NUMBER}, milestone: ${MILESTONE_NUM} })
901
+ .catch(e => console.error('WARNING: Failed to post plan comment:', e.message));
902
+ " 2>/dev/null || true
903
+ done
904
+ ```
905
+
465
906
  **c. Verify plans exist:**
466
907
  ```bash
467
908
  PLAN_COUNT=$(ls ${phase_dir}/*-PLAN.md 2>/dev/null | wc -l)
@@ -473,11 +914,30 @@ If proceed: apply "mgw:approved" label and continue.
473
914
  fi
474
915
  ```
475
916
 
476
- **d. Init execute-phase and spawn executor agent (gsd:execute-phase):**
917
+ **d. Init execute-phase and spawn executor agent (gsd:execute-phase, with diagnostic capture):**
477
918
  ```bash
478
919
  EXEC_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init execute-phase "${PHASE_NUMBER}")
479
920
  # Parse EXEC_INIT JSON for: executor_model, verifier_model, phase_dir, plans, incomplete_plans, plan_count
480
921
  ```
922
+
923
+ <!-- mgw:criticality=critical spawn_point=milestone-executor -->
924
+ <!-- Critical: phase execution produces the code changes. Without it,
925
+ there is nothing to commit or PR. On failure: retry via milestone
926
+ retry loop, then dead-letter. -->
927
+
928
+ **Pre-spawn diagnostic hook (milestone executor):**
929
+ ```bash
930
+ DIAG_MS_EXECUTOR=$(node -e "
931
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
932
+ const id = dh.beforeAgentSpawn({
933
+ agentType: 'gsd-executor',
934
+ issueNumber: ${ISSUE_NUMBER},
935
+ prompt: 'Execute phase ${PHASE_NUMBER}: ${PHASE_NAME}',
936
+ repoRoot: '${REPO_ROOT}'
937
+ });
938
+ process.stdout.write(id);
939
+ " 2>/dev/null || echo "")
940
+ ```
481
941
  ```
482
942
  Task(
483
943
  prompt="
@@ -508,7 +968,82 @@ If proceed: apply "mgw:approved" label and continue.
508
968
  )
509
969
  ```
510
970
 
511
- **e. Spawn verifier agent (gsd:verify-phase):**
971
+ **Post-spawn diagnostic hook (milestone executor):**
972
+ ```bash
973
+ MS_EXECUTOR_EXIT=$( ls ${phase_dir}/*-SUMMARY.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
974
+ node -e "
975
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
976
+ dh.afterAgentSpawn({
977
+ diagId: '${DIAG_MS_EXECUTOR}',
978
+ exitReason: '${MS_EXECUTOR_EXIT}',
979
+ repoRoot: '${REPO_ROOT}'
980
+ });
981
+ " 2>/dev/null || true
982
+ ```
983
+
984
+ **d1b. Checkpoint: record milestone phase execution completion (atomic write):**
985
+ ```bash
986
+ # Checkpoint: record milestone execution completion for this phase.
987
+ node -e "
988
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
989
+ updateCheckpoint(${ISSUE_NUMBER}, {
990
+ pipeline_step: 'execute',
991
+ step_progress: { gsd_phase: ${PHASE_NUMBER} },
992
+ last_agent_output: '${phase_dir}',
993
+ step_history: [{ step: 'execute', completed_at: new Date().toISOString(), agent_type: 'gsd-executor', output_path: '${phase_dir}' }],
994
+ resume: { action: 'verify-phase', context: { phase_number: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
995
+ });
996
+ " 2>/dev/null || true
997
+ ```
998
+
999
+ **d2. Publish summary comment (non-blocking):**
1000
+ ```bash
1001
+ SUMMARY_FILES=$(ls ${phase_dir}/*-SUMMARY.md 2>/dev/null)
1002
+ for SUMMARY_FILE in $SUMMARY_FILES; do
1003
+ node -e "
1004
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
1005
+ const fs = require('fs');
1006
+ const content = fs.readFileSync('${SUMMARY_FILE}', 'utf-8');
1007
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'summary', content, { phase: ${PHASE_NUMBER}, milestone: ${MILESTONE_NUM} })
1008
+ .catch(e => console.error('WARNING: Failed to post summary comment:', e.message));
1009
+ " 2>/dev/null || true
1010
+ done
1011
+ ```
1012
+
1013
+ **e. Spawn verifier agent (gsd:verify-phase):**
1014
+
1015
+ <!-- mgw:criticality=advisory spawn_point=milestone-verifier -->
1016
+ <!-- Advisory: phase verification is quality assurance after execution
1017
+ completes. The code changes and commits already exist. If verification
1018
+ fails, log a warning and proceed with a note that verification was
1019
+ skipped for this phase.
1020
+
1021
+ Graceful degradation pattern:
1022
+ ```
1023
+ VERIFY_RESULT=$(wrapAdvisoryAgent(Task(...), 'milestone-verifier', {
1024
+ issueNumber: ISSUE_NUMBER,
1025
+ fallback: null
1026
+ }))
1027
+ # If fallback returned, create minimal VERIFICATION.md:
1028
+ # "## VERIFICATION SKIPPED\nVerifier agent unavailable for phase ${PHASE_NUMBER}."
1029
+ ```
1030
+ -->
1031
+
1032
+ **e. Spawn verifier agent (gsd:verify-phase, with diagnostic capture):**
1033
+
1034
+ **Pre-spawn diagnostic hook (milestone verifier):**
1035
+ ```bash
1036
+ DIAG_MS_VERIFIER=$(node -e "
1037
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
1038
+ const id = dh.beforeAgentSpawn({
1039
+ agentType: 'gsd-verifier',
1040
+ issueNumber: ${ISSUE_NUMBER},
1041
+ prompt: 'Verify phase ${PHASE_NUMBER}: ${PHASE_NAME}',
1042
+ repoRoot: '${REPO_ROOT}'
1043
+ });
1044
+ process.stdout.write(id);
1045
+ " 2>/dev/null || echo "")
1046
+ ```
512
1047
  ```
513
1048
  Task(
514
1049
  prompt="
@@ -536,6 +1071,48 @@ If proceed: apply "mgw:approved" label and continue.
536
1071
  )
537
1072
  ```
538
1073
 
1074
+ **Post-spawn diagnostic hook (milestone verifier):**
1075
+ ```bash
1076
+ MS_VERIFIER_EXIT=$( ls ${phase_dir}/*-VERIFICATION.md 2>/dev/null | wc -l | xargs test 0 -lt && echo "success" || echo "error" )
1077
+ node -e "
1078
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
1079
+ dh.afterAgentSpawn({
1080
+ diagId: '${DIAG_MS_VERIFIER}',
1081
+ exitReason: '${MS_VERIFIER_EXIT}',
1082
+ repoRoot: '${REPO_ROOT}'
1083
+ });
1084
+ " 2>/dev/null || true
1085
+ ```
1086
+
1087
+ **e1b. Checkpoint: record milestone phase verification completion (atomic write):**
1088
+ ```bash
1089
+ # Checkpoint: record milestone verification completion for this phase.
1090
+ node -e "
1091
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
1092
+ updateCheckpoint(${ISSUE_NUMBER}, {
1093
+ pipeline_step: 'verify',
1094
+ step_progress: { gsd_phase: ${PHASE_NUMBER}, verification_complete: true },
1095
+ last_agent_output: '${phase_dir}',
1096
+ step_history: [{ step: 'verify', completed_at: new Date().toISOString(), agent_type: 'gsd-verifier', output_path: '${phase_dir}' }],
1097
+ resume: { action: 'next-phase', context: { completed_phase: ${PHASE_NUMBER}, phase_dir: '${phase_dir}' } }
1098
+ });
1099
+ " 2>/dev/null || true
1100
+ ```
1101
+
1102
+ **e2. Publish verification comment (non-blocking):**
1103
+ ```bash
1104
+ VERIFICATION_FILES=$(ls ${phase_dir}/*-VERIFICATION.md 2>/dev/null)
1105
+ for VERIFICATION_FILE in $VERIFICATION_FILES; do
1106
+ node -e "
1107
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
1108
+ const fs = require('fs');
1109
+ const content = fs.readFileSync('${VERIFICATION_FILE}', 'utf-8');
1110
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'verification', content, { phase: ${PHASE_NUMBER}, milestone: ${MILESTONE_NUM} })
1111
+ .catch(e => console.error('WARNING: Failed to post verification comment:', e.message));
1112
+ " 2>/dev/null || true
1113
+ done
1114
+ ```
1115
+
539
1116
  **f. Post phase-complete comment directly (no sub-agent):**
540
1117
  ```bash
541
1118
  PHASE_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")