@snipcodeit/mgw 0.4.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.
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@snipcodeit/mgw)](https://www.npmjs.com/package/@snipcodeit/mgw)
4
4
  [![CI](https://github.com/snipcodeit/mgw/actions/workflows/ci.yml/badge.svg)](https://github.com/snipcodeit/mgw/actions/workflows/ci.yml)
5
+ [![Coverage](https://img.shields.io/badge/coverage-70%25-brightgreen)](./coverage/lcov-report/index.html)
5
6
  [![npm downloads](https://img.shields.io/npm/dm/@snipcodeit/mgw)](https://www.npmjs.com/package/@snipcodeit/mgw)
6
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
8
  [![node](https://img.shields.io/node/v/@snipcodeit/mgw)](https://nodejs.org)
@@ -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,7 +67,7 @@ QUICK_DIR=".planning/quick/${next_num}-${slug}"
60
67
  mkdir -p "$QUICK_DIR"
61
68
  ```
62
69
 
63
- 3. **Assemble MGW context and spawn planner (task agent):**
70
+ 3. **Assemble MGW context and spawn planner (task agent, with diagnostic capture):**
64
71
 
65
72
  Assemble multi-machine context from GitHub issue comments before spawning:
66
73
  ```bash
@@ -77,6 +84,23 @@ ic.buildGSDPromptContext({
77
84
  " 2>/dev/null || echo "")
78
85
  ```
79
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
+ ```
80
104
  ```
81
105
  Task(
82
106
  prompt="
@@ -127,6 +151,53 @@ Return: ## PLANNING COMPLETE with plan path
127
151
  )
128
152
  ```
129
153
 
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
+
130
201
  4. **Publish plan comment (non-blocking):**
131
202
  ```bash
132
203
  PLAN_FILE="${QUICK_DIR}/${next_num}-PLAN.md"
@@ -150,6 +221,37 @@ PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify plan-structur
150
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.
151
222
 
152
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
+ ```
153
255
  ```
154
256
  Task(
155
257
  prompt="
@@ -191,10 +293,43 @@ Skip: context compliance (no CONTEXT.md), cross-plan deps (single plan), ROADMAP
191
293
  )
192
294
  ```
193
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
+
194
308
  If issues found and iteration < 2: spawn planner revision, then re-check.
195
309
  If iteration >= 2: offer force proceed or abort.
196
310
 
197
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
+ ```
198
333
  ```
199
334
  Task(
200
335
  prompt="
@@ -219,6 +354,52 @@ Execute quick task ${next_num}.
219
354
  )
220
355
  ```
221
356
 
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
+
222
403
  8. **Publish summary comment (non-blocking):**
223
404
  ```bash
224
405
  SUMMARY_FILE="${QUICK_DIR}/${next_num}-SUMMARY.md"
@@ -240,6 +421,39 @@ VERIFY_RESULT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify-summary "$
240
421
  Parse JSON result. Use `passed` field for go/no-go. Checks summary existence, files created, and commits.
241
422
 
242
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
+ ```
243
457
  ```
244
458
  Task(
245
459
  prompt="
@@ -260,6 +474,52 @@ Check must_haves against actual codebase. Create VERIFICATION.md at ${QUICK_DIR}
260
474
  )
261
475
  ```
262
476
 
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
+
263
523
  10. **Publish verification comment (non-blocking, --full only):**
264
524
  ```bash
265
525
  VERIFICATION_FILE="${QUICK_DIR}/${next_num}-VERIFICATION.md"
@@ -294,8 +554,13 @@ If any step above fails (executor or verifier agent returns error, summary missi
294
554
 
295
555
  ```bash
296
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
+
297
561
  FAILURE_CLASS=$(node -e "
298
562
  const { classifyFailure, canRetry, incrementRetry, getBackoffMs } = require('./lib/retry.cjs');
563
+ const { isAdvisory } = require('./lib/agent-criticality.cjs');
299
564
  const { loadActiveIssue } = require('./lib/state.cjs');
300
565
  const fs = require('fs'), path = require('path');
301
566
 
@@ -305,29 +570,43 @@ const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.js
305
570
  const filePath = path.join(activeDir, file);
306
571
  let issueState = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
307
572
 
308
- // Classify the failure from the error context
309
- const error = { message: '${EXECUTION_ERROR_MESSAGE}' };
310
- const result = classifyFailure(error);
311
- console.error('Failure classified as: ' + result.class + ' ' + result.reason);
312
-
313
- // Persist failure class to state
314
- issueState.last_failure_class = result.class;
315
-
316
- if (result.class === 'transient' && canRetry(issueState)) {
317
- const backoff = getBackoffMs(issueState.retry_count || 0);
318
- issueState = incrementRetry(issueState);
319
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
320
- // Output: backoff ms so shell can sleep
321
- 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);
322
579
  } else {
323
- // Permanent failure or retries exhausted dead-letter
324
- issueState.dead_letter = true;
325
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
326
- 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
+ }
327
600
  }
328
601
  ")
329
602
 
330
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
+ ;;
331
610
  retry:*)
332
611
  BACKOFF_MS=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
333
612
  BACKOFF_SEC=$(( (BACKOFF_MS + 999) / 1000 ))
@@ -515,7 +794,7 @@ fi
515
794
  # Parse PHASE_INIT JSON for: planner_model, checker_model
516
795
  ```
517
796
 
518
- **b. Assemble MGW context and spawn planner agent (gsd:plan-phase):**
797
+ **b. Assemble MGW context and spawn planner agent (gsd:plan-phase, with diagnostic capture):**
519
798
 
520
799
  Assemble multi-machine context from GitHub issue comments before spawning:
521
800
  ```bash
@@ -532,6 +811,23 @@ fi
532
811
  " 2>/dev/null || echo "")
533
812
  ```
534
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
+ ```
535
831
  ```
536
832
  Task(
537
833
  prompt="
@@ -565,6 +861,34 @@ fi
565
861
  )
566
862
  ```
567
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
+
568
892
  **b2. Publish plan comment (non-blocking):**
569
893
  ```bash
570
894
  PLAN_FILES=$(ls ${phase_dir}/*-PLAN.md 2>/dev/null)
@@ -590,11 +914,30 @@ fi
590
914
  fi
591
915
  ```
592
916
 
593
- **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):**
594
918
  ```bash
595
919
  EXEC_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init execute-phase "${PHASE_NUMBER}")
596
920
  # Parse EXEC_INIT JSON for: executor_model, verifier_model, phase_dir, plans, incomplete_plans, plan_count
597
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
+ ```
598
941
  ```
599
942
  Task(
600
943
  prompt="
@@ -625,6 +968,34 @@ fi
625
968
  )
626
969
  ```
627
970
 
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
+
628
999
  **d2. Publish summary comment (non-blocking):**
629
1000
  ```bash
630
1001
  SUMMARY_FILES=$(ls ${phase_dir}/*-SUMMARY.md 2>/dev/null)
@@ -639,7 +1010,40 @@ fi
639
1010
  done
640
1011
  ```
641
1012
 
642
- **e. Spawn verifier agent (gsd:verify-phase):**
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
+ ```
643
1047
  ```
644
1048
  Task(
645
1049
  prompt="
@@ -667,6 +1071,34 @@ fi
667
1071
  )
668
1072
  ```
669
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
+
670
1102
  **e2. Publish verification comment (non-blocking):**
671
1103
  ```bash
672
1104
  VERIFICATION_FILES=$(ls ${phase_dir}/*-VERIFICATION.md 2>/dev/null)
@@ -105,6 +105,26 @@ ic.assembleIssueContext(${ISSUE_NUMBER})
105
105
 
106
106
  Read issue state for context.
107
107
 
108
+ <!-- mgw:criticality=critical spawn_point=pr-creator -->
109
+ <!-- Critical: PR creation is the pipeline's final output. Without it,
110
+ the entire pipeline run produces no deliverable. On failure: the
111
+ pipeline marks the issue as failed (no retry — PR creation errors
112
+ are typically permanent: branch conflicts, permissions, etc.). -->
113
+
114
+ **Pre-spawn diagnostic hook (PR creator):**
115
+ ```bash
116
+ DIAG_PR_CREATOR=$(node -e "
117
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
118
+ const id = dh.beforeAgentSpawn({
119
+ agentType: 'general-purpose',
120
+ issueNumber: ${ISSUE_NUMBER},
121
+ prompt: 'Create PR for #${ISSUE_NUMBER}',
122
+ repoRoot: '${REPO_ROOT}'
123
+ });
124
+ process.stdout.write(id);
125
+ " 2>/dev/null || echo "")
126
+ ```
127
+
108
128
  ```
109
129
  Task(
110
130
  prompt="
@@ -207,8 +227,34 @@ ${PROGRESS_TABLE}
207
227
  )
208
228
  ```
209
229
 
230
+ **Post-spawn diagnostic hook (PR creator):**
231
+ ```bash
232
+ node -e "
233
+ const dh = require('${REPO_ROOT}/lib/diagnostic-hooks.cjs');
234
+ dh.afterAgentSpawn({
235
+ diagId: '${DIAG_PR_CREATOR}',
236
+ exitReason: '${PR_NUMBER ? \"success\" : \"error\"}',
237
+ repoRoot: '${REPO_ROOT}'
238
+ });
239
+ " 2>/dev/null || true
240
+ ```
241
+
210
242
  Parse PR number and URL from agent response.
211
243
 
244
+ **Checkpoint: record PR creation (atomic write):**
245
+ ```bash
246
+ # Checkpoint: record PR creation — final checkpoint before pipeline completion.
247
+ node -e "
248
+ const { updateCheckpoint } = require('${REPO_ROOT}/lib/state.cjs');
249
+ updateCheckpoint(${ISSUE_NUMBER}, {
250
+ pipeline_step: 'pr',
251
+ step_progress: { branch_pushed: true, pr_number: ${PR_NUMBER}, pr_url: '${PR_URL}' },
252
+ step_history: [{ step: 'pr', completed_at: new Date().toISOString(), agent_type: 'general-purpose', output_path: '${PR_URL}' }],
253
+ resume: { action: 'cleanup', context: { pr_number: ${PR_NUMBER}, pr_url: '${PR_URL}' } }
254
+ });
255
+ " 2>/dev/null || true
256
+ ```
257
+
212
258
  Update state (at `${REPO_ROOT}/.mgw/active/`):
213
259
  - linked_pr = PR number
214
260
  - pipeline_stage = "pr-created"