@ktpartners/dgs-platform 2.9.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +197 -0
  2. package/README.md +34 -2
  3. package/agents/dgs-executor.md +124 -3
  4. package/agents/dgs-idea-researcher.md +447 -0
  5. package/agents/dgs-plan-checker.md +61 -3
  6. package/agents/dgs-planner.md +51 -8
  7. package/bin/install.js +44 -0
  8. package/commands/dgs/abandon-quick.md +28 -0
  9. package/commands/dgs/add-tests.md +2 -2
  10. package/commands/dgs/audit-milestone.md +4 -3
  11. package/commands/dgs/capture-principle.md +11 -11
  12. package/commands/dgs/cleanup.md +2 -2
  13. package/commands/dgs/complete-milestone.md +11 -11
  14. package/commands/dgs/complete-quick.md +28 -0
  15. package/commands/dgs/create-milestone-job.md +2 -2
  16. package/commands/dgs/debug.md +3 -3
  17. package/commands/dgs/develop-idea.md +1 -1
  18. package/commands/dgs/diff-report.md +124 -0
  19. package/commands/dgs/fast.md +3 -1
  20. package/commands/dgs/health.md +1 -1
  21. package/commands/dgs/map-codebase.md +6 -6
  22. package/commands/dgs/new-milestone.md +5 -5
  23. package/commands/dgs/new-project.md +8 -21
  24. package/commands/dgs/package-scan.md +43 -0
  25. package/commands/dgs/plan-milestone-gaps.md +1 -1
  26. package/commands/dgs/progress.md +3 -3
  27. package/commands/dgs/quick-abandon.md +8 -0
  28. package/commands/dgs/quick-complete.md +8 -0
  29. package/commands/dgs/quick.md +10 -3
  30. package/commands/dgs/research-idea.md +3 -2
  31. package/commands/dgs/research-phase.md +3 -3
  32. package/commands/dgs/switch-project.md +14 -1
  33. package/commands/dgs/write-spec.md +3 -3
  34. package/deliver-great-systems/bin/dgs-tools.cjs +401 -32
  35. package/deliver-great-systems/bin/lib/audit-tolerance.cjs +77 -0
  36. package/deliver-great-systems/bin/lib/audit-tolerance.test.cjs +101 -0
  37. package/deliver-great-systems/bin/lib/commands.cjs +626 -46
  38. package/deliver-great-systems/bin/lib/commands.test.cjs +451 -0
  39. package/deliver-great-systems/bin/lib/commit-verify.test.cjs +236 -0
  40. package/deliver-great-systems/bin/lib/config.cjs +80 -6
  41. package/deliver-great-systems/bin/lib/config.test.cjs +309 -0
  42. package/deliver-great-systems/bin/lib/context.cjs +120 -0
  43. package/deliver-great-systems/bin/lib/core.cjs +35 -14
  44. package/deliver-great-systems/bin/lib/core.test.cjs +79 -1
  45. package/deliver-great-systems/bin/lib/execution.cjs +49 -17
  46. package/deliver-great-systems/bin/lib/fast-routing.cjs +199 -0
  47. package/deliver-great-systems/bin/lib/fast-routing.test.cjs +108 -0
  48. package/deliver-great-systems/bin/lib/final-commit-precondition.test.cjs +87 -0
  49. package/deliver-great-systems/bin/lib/fixtures/package-scan/bundler-audit-gemfile.json +21 -0
  50. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-expected.md +186 -0
  51. package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-runresult.json +235 -0
  52. package/deliver-great-systems/bin/lib/fixtures/package-scan/govulncheck-import.json +3 -0
  53. package/deliver-great-systems/bin/lib/fixtures/package-scan/npm-audit-v10.json +37 -0
  54. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-clean.json +3 -0
  55. package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-vulns.json +77 -0
  56. package/deliver-great-systems/bin/lib/fixtures/package-scan/pip-audit-requirements.json +28 -0
  57. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-lodash.json +30 -0
  58. package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-workspaces.json +55 -0
  59. package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
  60. package/deliver-great-systems/bin/lib/frontmatter.cjs +1 -1
  61. package/deliver-great-systems/bin/lib/governance.cjs +211 -0
  62. package/deliver-great-systems/bin/lib/governance.test.cjs +339 -0
  63. package/deliver-great-systems/bin/lib/health-untracked-phase.test.cjs +269 -0
  64. package/deliver-great-systems/bin/lib/ideas.cjs +206 -91
  65. package/deliver-great-systems/bin/lib/ideas.test.cjs +244 -1
  66. package/deliver-great-systems/bin/lib/init.cjs +357 -61
  67. package/deliver-great-systems/bin/lib/init.test.cjs +625 -8
  68. package/deliver-great-systems/bin/lib/jobs.cjs +131 -25
  69. package/deliver-great-systems/bin/lib/jobs.test.cjs +193 -74
  70. package/deliver-great-systems/bin/lib/migration.cjs +409 -1
  71. package/deliver-great-systems/bin/lib/migration.test.cjs +158 -1
  72. package/deliver-great-systems/bin/lib/milestone.cjs +154 -31
  73. package/deliver-great-systems/bin/lib/milestone.test.cjs +203 -0
  74. package/deliver-great-systems/bin/lib/package-adapters.cjs +530 -0
  75. package/deliver-great-systems/bin/lib/package-adapters.test.cjs +618 -0
  76. package/deliver-great-systems/bin/lib/package-ecosystems.cjs +350 -0
  77. package/deliver-great-systems/bin/lib/package-ecosystems.test.cjs +348 -0
  78. package/deliver-great-systems/bin/lib/package-runner.cjs +199 -0
  79. package/deliver-great-systems/bin/lib/package-runner.test.cjs +198 -0
  80. package/deliver-great-systems/bin/lib/package-scan-provenance.cjs +56 -0
  81. package/deliver-great-systems/bin/lib/package-scan-provenance.test.cjs +103 -0
  82. package/deliver-great-systems/bin/lib/package-scan-report.cjs +1140 -0
  83. package/deliver-great-systems/bin/lib/package-scan-report.test.cjs +1963 -0
  84. package/deliver-great-systems/bin/lib/package-scan-skill.cjs +96 -0
  85. package/deliver-great-systems/bin/lib/package-scan-skill.test.cjs +136 -0
  86. package/deliver-great-systems/bin/lib/package-scan.cjs +919 -0
  87. package/deliver-great-systems/bin/lib/package-scan.test.cjs +2147 -0
  88. package/deliver-great-systems/bin/lib/phase.cjs +146 -3
  89. package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
  90. package/deliver-great-systems/bin/lib/plan-number-validity.test.cjs +48 -0
  91. package/deliver-great-systems/bin/lib/projects.cjs +65 -10
  92. package/deliver-great-systems/bin/lib/projects.test.cjs +198 -2
  93. package/deliver-great-systems/bin/lib/quick.cjs +739 -0
  94. package/deliver-great-systems/bin/lib/quick.test.cjs +730 -0
  95. package/deliver-great-systems/bin/lib/repos.cjs +37 -13
  96. package/deliver-great-systems/bin/lib/review.cjs +1821 -0
  97. package/deliver-great-systems/bin/lib/roadmap.cjs +34 -13
  98. package/deliver-great-systems/bin/lib/specs.cjs +3 -81
  99. package/deliver-great-systems/bin/lib/state-transition-gate.test.cjs +160 -0
  100. package/deliver-great-systems/bin/lib/state.cjs +147 -55
  101. package/deliver-great-systems/bin/lib/summary-frontmatter.cjs +54 -0
  102. package/deliver-great-systems/bin/lib/summary-frontmatter.test.cjs +78 -0
  103. package/deliver-great-systems/bin/lib/sweep-scope.test.cjs +263 -0
  104. package/deliver-great-systems/bin/lib/sync.cjs +75 -0
  105. package/deliver-great-systems/bin/lib/verify.cjs +198 -7
  106. package/deliver-great-systems/bin/lib/verify.test.cjs +82 -0
  107. package/deliver-great-systems/bin/lib/wave-0-template-rename.test.cjs +40 -0
  108. package/deliver-great-systems/bin/lib/worktrees.cjs +790 -0
  109. package/deliver-great-systems/bin/lib/worktrees.test.cjs +963 -0
  110. package/deliver-great-systems/references/agent-step-reliability.md +60 -0
  111. package/deliver-great-systems/references/conflict-resolution.md +4 -0
  112. package/deliver-great-systems/references/context-tiers.md +4 -0
  113. package/deliver-great-systems/references/package-scan-config.md +151 -0
  114. package/deliver-great-systems/references/questioning.md +0 -30
  115. package/deliver-great-systems/references/spec-review-loop.md +1 -2
  116. package/deliver-great-systems/references/workflow-conventions.md +29 -0
  117. package/deliver-great-systems/skills/dgs-tests/package-scan.md +44 -0
  118. package/deliver-great-systems/templates/REVIEW.md +35 -0
  119. package/deliver-great-systems/templates/VALIDATION.md +1 -1
  120. package/deliver-great-systems/templates/claude-md.md +27 -0
  121. package/deliver-great-systems/templates/package-scan-report.md +108 -0
  122. package/deliver-great-systems/templates/project.md +6 -170
  123. package/deliver-great-systems/templates/summary.md +3 -1
  124. package/deliver-great-systems/workflows/abandon-quick.md +89 -0
  125. package/deliver-great-systems/workflows/add-idea.md +3 -3
  126. package/deliver-great-systems/workflows/add-phase.md +5 -0
  127. package/deliver-great-systems/workflows/add-tests.md +14 -0
  128. package/deliver-great-systems/workflows/add-todo.md +1 -0
  129. package/deliver-great-systems/workflows/approve-spec.md +25 -4
  130. package/deliver-great-systems/workflows/audit-milestone.md +66 -10
  131. package/deliver-great-systems/workflows/audit-phase.md +15 -5
  132. package/deliver-great-systems/workflows/cancel-job.md +2 -2
  133. package/deliver-great-systems/workflows/check-todos.md +2 -3
  134. package/deliver-great-systems/workflows/codereview.md +103 -9
  135. package/deliver-great-systems/workflows/complete-milestone.md +218 -24
  136. package/deliver-great-systems/workflows/complete-quick.md +106 -0
  137. package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
  138. package/deliver-great-systems/workflows/create-milestone-job.md +4 -4
  139. package/deliver-great-systems/workflows/develop-idea.md +11 -11
  140. package/deliver-great-systems/workflows/diagnose-issues.md +14 -0
  141. package/deliver-great-systems/workflows/discuss-idea.md +1 -1
  142. package/deliver-great-systems/workflows/discuss-phase.md +3 -2
  143. package/deliver-great-systems/workflows/execute-phase.md +209 -33
  144. package/deliver-great-systems/workflows/execute-plan.md +22 -22
  145. package/deliver-great-systems/workflows/help.md +53 -20
  146. package/deliver-great-systems/workflows/import-spec.md +65 -7
  147. package/deliver-great-systems/workflows/init-product.md +45 -167
  148. package/deliver-great-systems/workflows/new-milestone.md +140 -33
  149. package/deliver-great-systems/workflows/new-project.md +60 -331
  150. package/deliver-great-systems/workflows/package-scan.md +59 -0
  151. package/deliver-great-systems/workflows/plan-phase.md +79 -1
  152. package/deliver-great-systems/workflows/progress-all.md +133 -0
  153. package/deliver-great-systems/workflows/quick-abandon.md +89 -0
  154. package/deliver-great-systems/workflows/quick-complete.md +106 -0
  155. package/deliver-great-systems/workflows/quick.md +328 -26
  156. package/deliver-great-systems/workflows/refine-spec.md +1 -1
  157. package/deliver-great-systems/workflows/research-idea.md +77 -139
  158. package/deliver-great-systems/workflows/resume-project.md +2 -2
  159. package/deliver-great-systems/workflows/run-job.md +29 -43
  160. package/deliver-great-systems/workflows/settings.md +13 -77
  161. package/deliver-great-systems/workflows/validate-phase.md +39 -1
  162. package/deliver-great-systems/workflows/verify-work.md +14 -0
  163. package/deliver-great-systems/workflows/write-spec.md +11 -13
  164. package/hooks/dist/dgs-enforce-discipline.js +196 -0
  165. package/package.json +1 -1
  166. package/scripts/build-hooks.js +1 -0
@@ -26,6 +26,8 @@ Parse `$ARGUMENTS` for:
26
26
  - `--dry-run` flag → store as `$DRY_RUN` (true/false)
27
27
  - `--full` flag → store as `$FULL_MODE` (true/false)
28
28
  - `--discuss` flag → store as `$DISCUSS_MODE` (true/false)
29
+ - `--main` flag → store as `$FORCE_MAIN` (true/false)
30
+ - `--debug` flag → store as `$DEBUG_MODE` (true/false)
29
31
  - Remaining text (after stripping all flags) → use as `$DESCRIPTION` if non-empty
30
32
 
31
33
  If `$DESCRIPTION` is empty after parsing, prompt user interactively:
@@ -82,6 +84,108 @@ If `$FULL_MODE` only:
82
84
 
83
85
  ---
84
86
 
87
+ **Step 1.5: Detect quick mode and handle worktree lifecycle**
88
+
89
+ This step runs for BOTH fast and non-fast paths. For `$FAST_MODE`, it performs mode detection ONLY (no worktree creation) so the fast path can route commits correctly based on the active context.
90
+
91
+ Determine the effective mode flag:
92
+ - If `$DEBUG_MODE`: set `$QUICK_MODE_FLAG = 'debug'`
93
+ - If `$FULL_MODE`: set `$QUICK_MODE_FLAG = 'full'`
94
+ - Otherwise: set `$QUICK_MODE_FLAG = null`
95
+
96
+ Detect whether this is a product-level or milestone-context quick:
97
+
98
+ ```bash
99
+ QUICK_DETECT=$(node -e "
100
+ const q = require('$HOME/.claude/deliver-great-systems/bin/lib/quick.cjs');
101
+ const r = q.detectQuickMode(process.cwd(), ${FORCE_MAIN:-false});
102
+ process.stdout.write(JSON.stringify(r));
103
+ ")
104
+ ```
105
+
106
+ Parse `QUICK_DETECT` for `mode` field.
107
+
108
+ **If mode is 'product':**
109
+
110
+ **If NOT `$FAST_MODE`:**
111
+
112
+ Check the one-active-quick guard and create worktree:
113
+
114
+ ```bash
115
+ QUICK_START=$(node -e "
116
+ const q = require('$HOME/.claude/deliver-great-systems/bin/lib/quick.cjs');
117
+ const r = q.startProductQuick(process.cwd(), '${DESCRIPTION}', ${QUICK_MODE_FLAG ? \"'\" + QUICK_MODE_FLAG + \"'\" : 'null'});
118
+ process.stdout.write(JSON.stringify(r));
119
+ ")
120
+ ```
121
+
122
+ Parse `QUICK_START` result.
123
+
124
+ If `success` is false (guard triggered or creation failed):
125
+ ```
126
+ ╔══════════════════════════════════════════════════════════════╗
127
+ ║ ERROR ║
128
+ ╚══════════════════════════════════════════════════════════════╝
129
+
130
+ ${error message from QUICK_START}
131
+ ```
132
+ End workflow.
133
+
134
+ If `success` is true:
135
+ Set `$QUICK_CONTEXT = 'product'`
136
+ Set `$QUICK_SLUG` from result `slug`
137
+ Set `$QUICK_REPOS` from result `repos` (object mapping repoName -> worktreePath, may be empty `{}`)
138
+ Display: `Product-level quick created: ${QUICK_SLUG}`
139
+
140
+ **If `$FAST_MODE`:**
141
+
142
+ Skip worktree creation entirely. Fast in product mode commits directly to `base_branch` in the main checkout.
143
+
144
+ Set `$QUICK_CONTEXT = 'product'`
145
+ Set `$QUICK_REPO_CWD = null` (unset — git ops run in planning-root cwd)
146
+ Display: `Fast: product-level (no milestone) — committing to base_branch in main checkout.`
147
+
148
+ **If mode is 'milestone-context':**
149
+
150
+ Set `$QUICK_CONTEXT = 'milestone-context'`
151
+ Set `$MILESTONE_SLUG` from `activeMilestone` in detect result
152
+
153
+ **If `$FAST_MODE`:** Resolve the milestone worktree directory for the active repo so fast commits land on the milestone branch:
154
+
155
+ ```bash
156
+ QUICK_REPO_CWD=$(node -e "
157
+ const fs = require('fs');
158
+ const path = require('path');
159
+ const localPath = path.join(process.cwd(), 'config.local.json');
160
+ const local = JSON.parse(fs.readFileSync(localPath, 'utf-8'));
161
+ const { loadConfig } = require('$HOME/.claude/deliver-great-systems/bin/lib/core.cjs');
162
+ const cfg = loadConfig(process.cwd());
163
+ const proj = cfg.current_project;
164
+ const wt = (local.projects && local.projects[proj] && local.projects[proj].worktrees && local.projects[proj].worktrees['${MILESTONE_SLUG}']) || {};
165
+ const repos = Object.entries(wt.repos || {});
166
+ if (repos.length === 0) process.exit(1);
167
+ // Multi-repo: prefer the worktree with pending edits. Single-repo: the
168
+ // only entry. Fall back to the first entry if no diffs are detected.
169
+ const { execSync } = require('child_process');
170
+ let pick = repos[0][1];
171
+ for (const [name, dir] of repos) {
172
+ try {
173
+ const diff = execSync('git -C \"' + dir + '\" diff --stat', { encoding: 'utf-8' }).trim();
174
+ if (diff.length > 0) { pick = dir; break; }
175
+ } catch {}
176
+ }
177
+ process.stdout.write(pick);
178
+ ")
179
+ ```
180
+
181
+ Display: `Fast: milestone-context (${MILESTONE_SLUG}) — committing to milestone branch in worktree ${QUICK_REPO_CWD}.`
182
+
183
+ **If NOT `$FAST_MODE`:** Leave `$QUICK_REPO_CWD` unset. Display: `Working in milestone context (${MILESTONE_SLUG}). Changes will be part of the milestone.`
184
+
185
+ No worktree creation. No guard check. Continue to Step 2.
186
+
187
+ ---
188
+
85
189
  **Step 2: Initialize**
86
190
 
87
191
  ```bash
@@ -136,14 +240,138 @@ Switching to /dgs:quick...
136
240
  ```
137
241
  Then continue from Step 3 as normal quick mode (skip the rest of the fast path).
138
242
 
243
+ **F1.5-pre. Pre-edit dirt check (REL-06; runs only when `$FAST_MODE` is true)**
244
+
245
+ Before any F2 edits, run a dirty-tree check across the planning root and all registered sub-repos. Pre-existing dirt that the user didn't initiate inside this fast-task would otherwise be swept into the F5 commit under a misleading message (the original idea-#27 footgun). Fail loudly with `pre-existing-dirt` exit-code label in non-interactive mode; ask to confirm in interactive mode.
246
+
247
+ ```bash
248
+ DIRT_JSON=$(node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" fast-route 2>/dev/null)
249
+ PRE_DIRTY=$(echo "$DIRT_JSON" | jq -r '
250
+ ((.survey.planningRoot.dirty // false) as $pr |
251
+ ([.survey.subRepos[]? | select(.dirty == true) | .path] | length) as $sr |
252
+ if ($pr or ($sr > 0)) then "true" else "false" end)
253
+ ')
254
+ ```
255
+
256
+ If `$PRE_DIRTY == "true"`:
257
+
258
+ - **Non-interactive mode (no TTY):** Print the dirty paths from `$DIRT_JSON` and exit non-zero with label `pre-existing-dirt`:
259
+ ```
260
+ ╔══════════════════════════════════════════════════════════════╗
261
+ ║ PRE-EXISTING DIRT DETECTED ║
262
+ ╚══════════════════════════════════════════════════════════════╝
263
+
264
+ /dgs:fast cannot proceed — the following repos have uncommitted changes
265
+ that pre-date this invocation:
266
+ - <planning root>: <paths>
267
+ - <sub-repo>: <paths>
268
+
269
+ Commit, stash, or `git restore` the listed paths and re-run, or use
270
+ /dgs:quick if these changes are part of the same intent.
271
+
272
+ exit-code label: pre-existing-dirt
273
+ ```
274
+ End workflow. Do NOT proceed to F1.5.
275
+
276
+ - **Interactive mode:** Surface the dirty paths and prompt:
277
+ ```
278
+ AskUserQuestion(
279
+ header: "Pre-existing dirt",
280
+ question: "The following repos are dirty before this fast invocation: <paths>. Proceed anyway, or stop?",
281
+ options: [
282
+ { label: "Proceed", description: "Continue with /dgs:fast — dirty paths will NOT be included in this commit (only $FAST_EDITED_FILES will be staged)" },
283
+ { label: "Stop", description: "Exit /dgs:fast — manually clean the working tree first" }
284
+ ]
285
+ )
286
+ ```
287
+ If "Stop": exit non-zero with label `pre-existing-dirt`. If "Proceed": continue to F1.5. Submodule warnings (per `decision.warnings`) are surfaced but do NOT block in either mode.
288
+
289
+ After F1.5-pre passes (clean state, OR user confirmed "Proceed"), continue to F1.5 cross-repo rejection guard.
290
+
291
+ **F1.5. Cross-repo rejection guard (product fast only)**
292
+
293
+ This guard is a pre-edit fail-fast check that prevents ambiguous multi-repo
294
+ fast invocations from reaching F2/F5. Since v23.2 / REL-05, F5 invokes
295
+ `dgs-tools fast-route` to pick the correct `--repo-cwd` post-edit, and F2
296
+ passes the tracked file list via the explicit `--files` argument so the
297
+ commit is scoped to the paths actually edited rather than a tree sweep.
298
+ That means a /dgs:fast edit confined to a single sibling repo (with
299
+ planning-root clean) is now safe and supported — F5 will route to that
300
+ repo via `--repo-cwd`. What's NOT safe is an edit that spans multiple
301
+ buckets: planning-root + a sibling, or two distinct siblings. Those would
302
+ fail at F5 with `multi-repo-dirt` anyway; F1.5 catches them earlier with
303
+ a clearer, edit-source-aware message before any disk writes happen.
304
+
305
+ **Activation condition:** this guard runs **only** when `$QUICK_CONTEXT == 'product'` AND `$FAST_MODE` is true. Skip it entirely (early return, no side effects) in any other combination:
306
+ - Milestone-context fast routes commits through `$QUICK_REPO_CWD` via `--repo-cwd`, which is already correct — guard not needed.
307
+ - Non-fast paths use worktrees and planner/executor discipline — guard not needed.
308
+
309
+ When the activation condition holds (`$QUICK_CONTEXT == 'product'` and `$FAST_MODE` is true), run the guard **before** any Read/Edit/Write in F2:
310
+
311
+ 1. **Enumerate sibling repo roots** from both sources (deduplicate by absolute path):
312
+
313
+ a. `config.local.json` → `projects.${current_project}.worktrees.*.repos` is a map of `repoName -> absolute worktree path`. Every value in every worktree's `repos` map is a sibling repo root.
314
+
315
+ b. `REPOS.md` → the markdown table has a `Path` column (typically relative like `../repo-name`). For each entry, resolve the path relative to planning-root cwd to get the absolute sibling repo root.
316
+
317
+ 2. **Determine the absolute path(s) you are about to edit.** Analyze `$DESCRIPTION` plus any codebase exploration needed to locate the target. For each intended edit, build the absolute path.
318
+
319
+ 3. **Check each intended edit against the sibling roots.** Normalize paths (resolve symlinks, strip trailing slashes) and test whether the edit path starts with any sibling repo root. Edits whose absolute path lies under the planning-root cwd itself are always allowed — only flag paths that live under a *registered sibling* repo root.
320
+
321
+ 4. **Partition intended edits into buckets.** For the set of intended-edit absolute paths from step 2:
322
+ - **planning-root bucket:** paths under the planning-root cwd that do NOT lie under any registered sibling root.
323
+ - **sibling-repo bucket(s):** paths whose absolute path starts with a sibling repo root (one bucket per matched sibling root, keyed by absolute root path).
324
+
325
+ Count the non-empty buckets:
326
+
327
+ - **0 non-empty buckets** (no edits inferred yet): proceed to F2; the guard re-checks via F5's post-edit `fast-route` if anything unexpected lands.
328
+ - **1 non-empty bucket** = planning-root only: ALLOWED. Continue to F2.
329
+ - **1 non-empty bucket** = exactly one sibling repo: ALLOWED. Continue to F2. F5's `fast-route` will route the commit through that sibling via `--repo-cwd`. Note in your edit plan which sibling you're targeting so RELATIVE_FILES computation in F5 uses the right STAGE_DIR.
330
+ - **2 or more non-empty buckets** (planning-root + sibling, OR sibling + sibling): BLOCKED. Fail fast with the error block below; do NOT proceed to F2.
331
+
332
+ ```
333
+ ╔══════════════════════════════════════════════════════════════╗
334
+ ║ AMBIGUOUS MULTI-REPO FAST ║
335
+ ╚══════════════════════════════════════════════════════════════╝
336
+
337
+ /dgs:quick --fast in product context supports edits confined to a single
338
+ bucket (planning-root only, OR exactly one sibling repo). The intended
339
+ edits span multiple buckets, which fast-mode cannot auto-route:
340
+
341
+ planning-root edits:
342
+ ${planning_root_paths_or_"(none)"}
343
+
344
+ sibling-repo edits:
345
+ ${for each non-empty sibling bucket: " - ${matched_sibling_root}: ${paths}"}
346
+
347
+ Options:
348
+ 1. Split into separate /dgs:fast invocations, one per bucket. Run them
349
+ sequentially; each invocation auto-routes to the correct cwd.
350
+ 2. If this multi-repo work is part of an active milestone, re-invoke
351
+ under milestone-context (the milestone worktree routes via
352
+ --repo-cwd against the registered repo).
353
+ 3. Use /dgs:quick (full planner+executor) for genuinely cross-repo work
354
+ that must commit atomically across repos.
355
+
356
+ End workflow. Do not proceed to F2.
357
+ ```
358
+
359
+ 5. If exactly one bucket is non-empty (or none yet), continue to F2.
360
+
139
361
  **F2. Make edits**
140
362
 
363
+ By the time F2 runs, the F1.5 cross-repo guard has already passed (in product-fast) or been skipped (in milestone-context fast / non-fast) — every path you touch below is guaranteed to land in the correct repo.
364
+
141
365
  Read the relevant file(s) based on `$DESCRIPTION`, make the requested changes directly using Read/Edit/Write tools. No planner, no executor — the orchestrator acts as the implementer.
142
366
 
367
+ Track every file you edit in a shell array `$FAST_EDITED_FILES` (absolute paths as used with Read/Edit/Write). Initialize to empty before the first edit. Append each path exactly once (deduplicate before F5). This array is the authoritative file list for F5's commit — it replaces the default fallback behaviour of `cmdCommit` (which would otherwise stage `['.']` in `gitCwd` and sweep unrelated dirty state).
368
+
369
+ If `$QUICK_CONTEXT` is `'milestone-context'`, relevant files live under `$QUICK_REPO_CWD` (the milestone worktree). Prefix Read/Edit/Write absolute paths with that directory — the main-checkout paths will be on `base_branch` and miss in-progress milestone work.
370
+
143
371
  If `$DRY_RUN`:
144
372
  After making edits but BEFORE committing, show the diff:
145
373
  ```bash
146
- git diff
374
+ git -C "${QUICK_REPO_CWD:-.}" diff
147
375
  ```
148
376
  Then ask:
149
377
  ```
@@ -158,7 +386,7 @@ If `$DRY_RUN`:
158
386
  ```
159
387
  If user chooses "No, discard":
160
388
  ```bash
161
- git checkout -- .
389
+ git -C "${QUICK_REPO_CWD:-.}" checkout -- .
162
390
  ```
163
391
  Display: "Changes discarded."
164
392
  Skip to completion output with message: "Dry run complete — no changes applied."
@@ -166,9 +394,9 @@ If `$DRY_RUN`:
166
394
 
167
395
  **F3. Post-edit scope check**
168
396
 
169
- After edits are made, check actual scope:
397
+ After edits are made, check actual scope (run in the worktree when milestone-context):
170
398
  ```bash
171
- git diff --stat
399
+ git -C "${QUICK_REPO_CWD:-.}" diff --stat
172
400
  ```
173
401
 
174
402
  Parse the output to count:
@@ -205,15 +433,68 @@ Analyze the description and the actual changes (`git diff`) to infer a conventio
205
433
 
206
434
  Commit message is NOT shown to user before committing — just commit silently.
207
435
 
208
- **F5. Commit**
436
+ **F5. Commit (REL-05 routing-aware)**
437
+
438
+ When `$QUICK_REPO_CWD` is set (milestone-context), route git operations through the worktree via `--repo-cwd`. Config (commit_docs, sync_push, current_project, worktree map) is still loaded from the planning-root cwd.
439
+
440
+ For product-context fast (`$QUICK_CONTEXT == 'product'`, `$QUICK_REPO_CWD` empty), invoke the routing-decision helper to determine the correct `--repo-cwd`:
209
441
 
210
442
  ```bash
211
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "${commit_message}" --push
443
+ DIRT_JSON=$(node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" fast-route 2>/dev/null)
444
+ ROUTE_ACTION=$(echo "$DIRT_JSON" | jq -r '.decision.action')
445
+ ROUTE_REPO=$(echo "$DIRT_JSON" | jq -r '.decision.repoCwd // empty')
446
+ ROUTE_EXIT=$(echo "$DIRT_JSON" | jq -r '.decision.exitCode // empty')
447
+ ROUTE_MSG=$(echo "$DIRT_JSON" | jq -r '.decision.message // empty')
212
448
  ```
213
449
 
214
- Get the short hash:
450
+ Cases:
451
+
452
+ - `$ROUTE_ACTION == 'fail'` AND `$ROUTE_EXIT == 'multi-repo-dirt'`:
453
+ ```
454
+ ╔══════════════════════════════════════════════════════════════╗
455
+ ║ MULTI-REPO DIRT DETECTED ║
456
+ ╚══════════════════════════════════════════════════════════════╝
457
+
458
+ $ROUTE_MSG
459
+
460
+ exit-code label: multi-repo-dirt
461
+ ```
462
+ End workflow with non-zero exit; do NOT commit.
463
+
464
+ - `$ROUTE_ACTION == 'route-to-sub-repo'`: commit with `--repo-cwd $ROUTE_REPO`.
465
+ - `$ROUTE_ACTION == 'route-to-planning-root'`: commit in planning-root cwd (existing behaviour).
466
+
467
+ Pass the tracked file list via `--files` so `cmdCommit` does not fall back to its `['.']` default (which would stage the entire `gitCwd` tree and sweep in unrelated dirty state — see the 260422-q7f incident). Surface any submodule warnings from `decision.warnings` to the user (display, do NOT block).
468
+
215
469
  ```bash
216
- git rev-parse --short HEAD
470
+ # Convert $FAST_EDITED_FILES (absolute paths) to paths relative to the
471
+ # routed staging directory. Paths outside the staging directory should not appear
472
+ # — the F1.5 cross-repo guard rejects them before F2.
473
+ if [ -n "$QUICK_REPO_CWD" ]; then
474
+ STAGE_DIR="$QUICK_REPO_CWD"
475
+ elif [ "$ROUTE_ACTION" = "route-to-sub-repo" ]; then
476
+ STAGE_DIR="$ROUTE_REPO"
477
+ else
478
+ STAGE_DIR="$(pwd)"
479
+ fi
480
+ RELATIVE_FILES=()
481
+ for f in "${FAST_EDITED_FILES[@]}"; do
482
+ # Strip STAGE_DIR prefix + leading slash to get the repo-relative path
483
+ RELATIVE_FILES+=( "${f#${STAGE_DIR}/}" )
484
+ done
485
+
486
+ if [ -n "$QUICK_REPO_CWD" ]; then
487
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "${commit_message}" --push --repo-cwd "$QUICK_REPO_CWD" --files "${RELATIVE_FILES[@]}"
488
+ elif [ "$ROUTE_ACTION" = "route-to-sub-repo" ]; then
489
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "${commit_message}" --push --repo-cwd "$ROUTE_REPO" --files "${RELATIVE_FILES[@]}"
490
+ else
491
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "${commit_message}" --push --files "${RELATIVE_FILES[@]}"
492
+ fi
493
+ ```
494
+
495
+ Get the short hash (from the routed staging directory):
496
+ ```bash
497
+ git -C "${STAGE_DIR}" rev-parse --short HEAD
217
498
  ```
218
499
 
219
500
  Store as `$COMMIT_HASH`.
@@ -260,17 +541,26 @@ If archival occurred (result contains `"archived": true`), `quick/HISTORY.md` wa
260
541
 
261
542
  **F6c. Commit tracking (fast path only)**
262
543
 
263
- Commit STATE.md and HISTORY.md together so archival data is persisted:
544
+ Commit STATE.md and HISTORY.md together so archival data is persisted. Uses `dgs-tools quick finalize --fast` — a single CLI call that stages both files (HISTORY.md optional) and commits with message `docs(quick-${quick_id}): track fast task`.
264
545
 
265
546
  ```bash
266
- FILE_LIST="${state_path}"
267
- if [ -f "${project_root}/quick/HISTORY.md" ]; then
268
- FILE_LIST="${FILE_LIST} ${project_root}/quick/HISTORY.md"
547
+ if [ -n "$QUICK_REPO_CWD" ]; then
548
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" quick finalize ${quick_id} \
549
+ --quick-dir "${quick_dir}" \
550
+ --state-path "${state_path}" \
551
+ --fast \
552
+ --push \
553
+ --repo-cwd "$QUICK_REPO_CWD" 2>/dev/null || true
554
+ else
555
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" quick finalize ${quick_id} \
556
+ --quick-dir "${quick_dir}" \
557
+ --state-path "${state_path}" \
558
+ --fast \
559
+ --push 2>/dev/null || true
269
560
  fi
270
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(quick-${quick_id}): track fast task" --push --files ${FILE_LIST} 2>/dev/null || true
271
561
  ```
272
562
 
273
- The `|| true` handles the case where nothing changed (e.g., STATE.md wasn't modified).
563
+ The `|| true` handles the case where nothing changed (e.g., STATE.md wasn't modified) — `quick finalize` returns `commit_reason: 'nothing_to_commit'` cleanly in that scenario.
274
564
 
275
565
  **F7. Output**
276
566
 
@@ -301,10 +591,10 @@ mkdir -p "${task_dir}"
301
591
 
302
592
  **Step 4: Create quick task directory**
303
593
 
304
- Create the directory for this quick task:
594
+ Use `task_dir` from init output do NOT build the path manually:
305
595
 
306
596
  ```bash
307
- QUICK_DIR="${project_root}/quick/${quick_id}-${slug}"
597
+ QUICK_DIR="${task_dir}"
308
598
  mkdir -p "$QUICK_DIR"
309
599
  ```
310
600
 
@@ -616,6 +906,12 @@ Task(
616
906
  prompt="
617
907
  Execute quick task ${quick_id}.
618
908
 
909
+ ${QUICK_CONTEXT === 'product' && QUICK_REPOS && Object.keys(QUICK_REPOS).length > 0 ? `
910
+ <worktree_context>
911
+ This quick task is executing in a git worktree. Work in these directories — do NOT use the main checkout paths:
912
+ ${Object.entries(QUICK_REPOS).map(([name, dir]) => '- ' + name + ': ' + dir).join('\n')}
913
+ </worktree_context>
914
+ ` : ''}
619
915
  <files_to_read>
620
916
  - ${QUICK_DIR}/${quick_id}-PLAN.md (Plan)
621
917
  - ${state_path} (Project state)
@@ -751,6 +1047,10 @@ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" state archive-quick
751
1047
 
752
1048
  If archival occurred, `quick/HISTORY.md` was created or updated. Include it in Step 8's commit file list.
753
1049
 
1050
+ **7c3. Milestone-context quick tracking**
1051
+
1052
+ If `$QUICK_CONTEXT` is 'milestone-context', note this in the Directory column of the table row. Instead of a directory link, use: `milestone (${MILESTONE_SLUG})`.
1053
+
754
1054
  **7d. Update "Last activity" line:**
755
1055
 
756
1056
  Use `date` from init:
@@ -764,20 +1064,18 @@ Use Edit tool to make these changes atomically
764
1064
 
765
1065
  **Step 8: Final commit and completion**
766
1066
 
767
- Stage and commit quick task artifacts:
768
-
769
- Build file list:
770
- - `${QUICK_DIR}/${quick_id}-PLAN.md`
771
- - `${QUICK_DIR}/${quick_id}-SUMMARY.md`
772
- - `${state_path}`
773
- - `${project_root}/quick/HISTORY.md` (if it exists — may have been created by archival)
774
- - If `$DISCUSS_MODE` and context file exists: `${QUICK_DIR}/${quick_id}-CONTEXT.md`
775
- - If `$FULL_MODE` and verification file exists: `${QUICK_DIR}/${quick_id}-VERIFICATION.md`
1067
+ Commit all quick task artifacts atomically via `dgs-tools quick finalize`. This single CLI call stages and commits PLAN, SUMMARY, STATE, and any optional artifacts present on disk (CONTEXT, VERIFICATION, HISTORY) in one commit no file-list assembly needed.
776
1068
 
777
1069
  ```bash
778
- node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(quick-${quick_id}): ${DESCRIPTION}" --push --files ${file_list}
1070
+ node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" quick finalize ${quick_id} \
1071
+ --quick-dir "${quick_dir}" \
1072
+ --state-path "${state_path}" \
1073
+ --description "${DESCRIPTION}" \
1074
+ --push
779
1075
  ```
780
1076
 
1077
+ Missing optional artifacts are skipped gracefully (no error if CONTEXT.md, VERIFICATION.md, or HISTORY.md do not exist).
1078
+
781
1079
  Get final commit hash:
782
1080
  ```bash
783
1081
  commit_hash=$(git rev-parse --short HEAD)
@@ -841,4 +1139,8 @@ Ready for next task: /dgs:quick
841
1139
  - [ ] (--fast) Scope warning shown when >3 files or >30 lines affected
842
1140
  - [ ] (--fast) (--dry-run) Changes shown as diff, user asked to apply or discard
843
1141
  - [ ] (--fast) Minimal output: "Done: {message} [{hash}]"
1142
+ - [ ] (--fast) F5 commit passes `--files` with the exact list of paths edited during F2 (no fallback to `cmdCommit`'s `['.']` default)
1143
+ - [ ] (--fast) Product-context fast rejects edits targeting sibling repos registered in `config.local.json` worktrees or `REPOS.md`, with an actionable error before F2 begins
1144
+ - [ ] (--fast) F1.5-pre pre-edit dirt check runs BEFORE F1.5; pre-existing dirt fails with `pre-existing-dirt` exit-code label in non-interactive mode (REL-06)
1145
+ - [ ] (--fast) F5 commit routes via fast-route decision: single-sub-repo dirty → `--repo-cwd <sub>`; multi-dirty → fails with `multi-repo-dirt` exit-code label; submodule warnings surface but don't block (REL-05)
844
1146
  </success_criteria>
@@ -125,7 +125,7 @@ Context is used to inform the conversation -- for example, when discussing imple
125
125
 
126
126
  3. Load source idea docs:
127
127
  Read the spec's frontmatter to find `source_ideas` (array of idea filenames). For each source idea:
128
- a. Derive the idea docs path (same pattern as write-spec: strip prefix/suffix for slug, check `${project_root}/ideas/pending/{slug}/docs/` or done/rejected paths)
128
+ a. Derive the idea docs path: strip prefix/suffix for slug, check `${project_root}/docs/ideas/{slug}/`
129
129
  b. If docs/ directory exists, read all files using the same pattern above
130
130
  c. Idea docs are loaded first (source material), then spec docs (refinements). If too many, cap spec docs.
131
131