@opengsd/gsd-core 1.9.1 → 1.11.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +27 -3
  5. package/agents/gsd-debug-session-manager.md +11 -0
  6. package/agents/gsd-debugger.md +12 -246
  7. package/agents/gsd-doc-synthesizer.md +2 -4
  8. package/agents/gsd-executor.md +12 -10
  9. package/agents/gsd-integration-checker.md +3 -0
  10. package/agents/gsd-mempalace-curator.md +5 -2
  11. package/agents/gsd-phase-researcher.md +20 -1
  12. package/agents/gsd-plan-checker.md +46 -0
  13. package/agents/gsd-planner.md +49 -54
  14. package/agents/gsd-roadmapper.md +21 -3
  15. package/agents/gsd-user-profiler.md +3 -0
  16. package/agents/gsd-verifier.md +26 -73
  17. package/bin/install.js +1272 -1238
  18. package/bin/lib/ui-safety-gate.cjs +2 -0
  19. package/commands/gsd/code-review.md +1 -1
  20. package/commands/gsd/execute-phase.md +1 -1
  21. package/commands/gsd/map-codebase.md +1 -1
  22. package/commands/gsd/mempalace-capture.md +2 -2
  23. package/commands/gsd/mempalace-recall.md +1 -1
  24. package/commands/gsd/new-milestone.md +2 -2
  25. package/commands/gsd/plan-phase.md +1 -1
  26. package/commands/gsd/quick.md +1 -1
  27. package/commands/gsd/review-backlog.md +2 -1
  28. package/commands/gsd/verify-work.md +1 -1
  29. package/gsd-core/bin/gsd-tools.cjs +1009 -115
  30. package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
  31. package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
  32. package/gsd-core/bin/lib/api-coverage.cjs +123 -5
  33. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  34. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  35. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  36. package/gsd-core/bin/lib/audit.cjs +926 -202
  37. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  38. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  39. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  40. package/gsd-core/bin/lib/capability-registry.cjs +608 -148
  41. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  42. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  43. package/gsd-core/bin/lib/capability-validator.cjs +507 -24
  44. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  45. package/gsd-core/bin/lib/check-command-router.cjs +114 -38
  46. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  47. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  48. package/gsd-core/bin/lib/command-aliases.cjs +94 -0
  49. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  50. package/gsd-core/bin/lib/commands.cjs +665 -99
  51. package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
  52. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  53. package/gsd-core/bin/lib/config-loader.cjs +76 -0
  54. package/gsd-core/bin/lib/config.cjs +22 -2
  55. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  56. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  57. package/gsd-core/bin/lib/core-utils.cjs +217 -40
  58. package/gsd-core/bin/lib/decisions.cjs +23 -0
  59. package/gsd-core/bin/lib/docs.cjs +3 -2
  60. package/gsd-core/bin/lib/external-job.cjs +19 -4
  61. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  62. package/gsd-core/bin/lib/frontmatter.cjs +239 -32
  63. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  64. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  65. package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
  66. package/gsd-core/bin/lib/graphify.cjs +142 -27
  67. package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
  68. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  69. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  72. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  73. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  74. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  75. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  76. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  77. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  78. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  79. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  80. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  81. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  82. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  83. package/gsd-core/bin/lib/init.cjs +1325 -169
  84. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  85. package/gsd-core/bin/lib/install-engine.cjs +805 -264
  86. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  87. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  88. package/gsd-core/bin/lib/install-profiles.cjs +160 -57
  89. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  90. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  91. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  92. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  93. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  94. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  95. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  96. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  97. package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
  98. package/gsd-core/bin/lib/io.cjs +38 -3
  99. package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
  100. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  101. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  102. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  103. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  104. package/gsd-core/bin/lib/milestone.cjs +821 -109
  105. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  106. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  107. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  108. package/gsd-core/bin/lib/pattern.cjs +122 -0
  109. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  110. package/gsd-core/bin/lib/phase-id.cjs +507 -36
  111. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  112. package/gsd-core/bin/lib/phase-locator.cjs +258 -58
  113. package/gsd-core/bin/lib/phase.cjs +891 -156
  114. package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
  115. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  116. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  117. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  118. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  119. package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
  120. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  121. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  122. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  123. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  124. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
  125. package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
  126. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  127. package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
  128. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  129. package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
  130. package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
  131. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  132. package/gsd-core/bin/lib/roadmap.cjs +405 -84
  133. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
  134. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  135. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
  136. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  137. package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
  138. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
  139. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  140. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  141. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  142. package/gsd-core/bin/lib/security.cjs +104 -5
  143. package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
  144. package/gsd-core/bin/lib/smart-entry.cjs +154 -22
  145. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  146. package/gsd-core/bin/lib/state-document.cjs +152 -8
  147. package/gsd-core/bin/lib/state-transition.cjs +424 -105
  148. package/gsd-core/bin/lib/state.cjs +1927 -401
  149. package/gsd-core/bin/lib/surface.cjs +35 -10
  150. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  151. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  152. package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
  153. package/gsd-core/bin/lib/uat.cjs +706 -64
  154. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  155. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  156. package/gsd-core/bin/lib/unusable-input.cjs +33 -0
  157. package/gsd-core/bin/lib/update-context.cjs +8 -2
  158. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  159. package/gsd-core/bin/lib/validate.cjs +20 -6
  160. package/gsd-core/bin/lib/vendor/README.md +37 -0
  161. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  162. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  163. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  164. package/gsd-core/bin/lib/verification.cjs +287 -20
  165. package/gsd-core/bin/lib/verify.cjs +368 -880
  166. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  167. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
  169. package/gsd-core/bin/lib/workstream.cjs +8 -2
  170. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  171. package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
  172. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  173. package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
  174. package/gsd-core/references/agent-contracts.md +43 -26
  175. package/gsd-core/references/artifact-types.md +10 -3
  176. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  177. package/gsd-core/references/checkpoints.md +2 -2
  178. package/gsd-core/references/context-budget.md +1 -1
  179. package/gsd-core/references/debugger-techniques.md +255 -0
  180. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  181. package/gsd-core/references/doc-conflict-engine.md +1 -1
  182. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  184. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  185. package/gsd-core/references/execute-phase-response-language.md +1 -1
  186. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  187. package/gsd-core/references/gate-prompts.md +1 -1
  188. package/gsd-core/references/git-planning-commit.md +2 -1
  189. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  190. package/gsd-core/references/model-profiles.md +12 -4
  191. package/gsd-core/references/mvp-concepts.md +9 -9
  192. package/gsd-core/references/planner-guidance.md +3 -9
  193. package/gsd-core/references/planner-preconditions.md +1 -1
  194. package/gsd-core/references/planner-reviews.md +1 -1
  195. package/gsd-core/references/planning-config.md +8 -6
  196. package/gsd-core/references/research-documentation-lookup.md +5 -3
  197. package/gsd-core/references/revision-loop.md +1 -1
  198. package/gsd-core/references/specless-probe-fallback.md +8 -7
  199. package/gsd-core/references/universal-anti-patterns.md +3 -3
  200. package/gsd-core/references/verifier-phase-gates.md +192 -0
  201. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  202. package/gsd-core/references/verify-mvp-mode.md +1 -1
  203. package/gsd-core/references/workstream-flag.md +22 -6
  204. package/gsd-core/references/worktree-branch-check.md +2 -2
  205. package/gsd-core/templates/discussion-log.md +1 -1
  206. package/gsd-core/templates/phase-prompt.md +2 -4
  207. package/gsd-core/templates/state.md +4 -4
  208. package/gsd-core/templates/summary-complex.md +2 -0
  209. package/gsd-core/templates/summary-minimal.md +2 -0
  210. package/gsd-core/templates/summary-standard.md +2 -0
  211. package/gsd-core/templates/summary.md +2 -0
  212. package/gsd-core/templates/verification-report.md +9 -1
  213. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  214. package/gsd-core/workflows/audit-milestone.md +3 -0
  215. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  216. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  217. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  218. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  219. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  220. package/gsd-core/workflows/autonomous.md +33 -70
  221. package/gsd-core/workflows/cleanup.md +62 -3
  222. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  223. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
  224. package/gsd-core/workflows/code-review-fix.md +37 -10
  225. package/gsd-core/workflows/code-review.md +74 -166
  226. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  227. package/gsd-core/workflows/complete-milestone.md +160 -95
  228. package/gsd-core/workflows/debug.md +16 -17
  229. package/gsd-core/workflows/diagnose-issues.md +56 -8
  230. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  231. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  232. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  233. package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
  234. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  235. package/gsd-core/workflows/docs-update.md +8 -51
  236. package/gsd-core/workflows/edit-phase.md +26 -1
  237. package/gsd-core/workflows/eval-review.md +3 -5
  238. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
  239. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  240. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  241. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  242. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
  243. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  245. package/gsd-core/workflows/execute-phase.md +103 -187
  246. package/gsd-core/workflows/execute-plan.md +36 -4
  247. package/gsd-core/workflows/explore.md +131 -4
  248. package/gsd-core/workflows/fast.md +10 -2
  249. package/gsd-core/workflows/health.md +73 -4
  250. package/gsd-core/workflows/help/modes/full.md +6 -1
  251. package/gsd-core/workflows/import.md +4 -4
  252. package/gsd-core/workflows/ingest-docs.md +7 -6
  253. package/gsd-core/workflows/mvp-phase.md +6 -3
  254. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  255. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  256. package/gsd-core/workflows/new-milestone.md +35 -47
  257. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  258. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  259. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  260. package/gsd-core/workflows/new-project.md +27 -240
  261. package/gsd-core/workflows/next.md +12 -0
  262. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  263. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  264. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  265. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  266. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  267. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  268. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  269. package/gsd-core/workflows/plan-phase.md +89 -209
  270. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  271. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  272. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  273. package/gsd-core/workflows/progress.md +45 -159
  274. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  275. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  276. package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
  277. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  278. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  279. package/gsd-core/workflows/quick.md +55 -405
  280. package/gsd-core/workflows/resume-project.md +3 -0
  281. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  282. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  283. package/gsd-core/workflows/review.md +41 -13
  284. package/gsd-core/workflows/section-manifest.json +219 -0
  285. package/gsd-core/workflows/secure-phase.md +1 -1
  286. package/gsd-core/workflows/session-report.md +2 -1
  287. package/gsd-core/workflows/settings.md +66 -2
  288. package/gsd-core/workflows/ship.md +104 -44
  289. package/gsd-core/workflows/sketch.md +1 -1
  290. package/gsd-core/workflows/spec-phase.md +41 -20
  291. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  292. package/gsd-core/workflows/spike.md +50 -16
  293. package/gsd-core/workflows/sync-skills.md +106 -13
  294. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  295. package/gsd-core/workflows/transition.md +53 -31
  296. package/gsd-core/workflows/ui-phase.md +13 -12
  297. package/gsd-core/workflows/ui-review.md +2 -2
  298. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  299. package/gsd-core/workflows/update.md +19 -8
  300. package/gsd-core/workflows/validate-phase.md +1 -1
  301. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  302. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  303. package/gsd-core/workflows/verify-work.md +17 -65
  304. package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
  305. package/hooks/dist/gsd-check-update-worker.js +64 -12
  306. package/hooks/dist/gsd-check-update.js +19 -1
  307. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  308. package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
  309. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  310. package/hooks/dist/gsd-prompt-guard.js +21 -20
  311. package/hooks/dist/gsd-read-injection-scanner.js +45 -24
  312. package/hooks/dist/gsd-statusline.js +90 -6
  313. package/hooks/dist/gsd-update-banner.js +22 -1
  314. package/hooks/dist/gsd-workflow-guard.js +134 -36
  315. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  316. package/hooks/dist/gsd-write-guard.js +359 -0
  317. package/hooks/dist/lib/git-cmd.js +92 -59
  318. package/hooks/dist/lib/injection-patterns.js +45 -0
  319. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  320. package/hooks/dist/lib/isolation-sentinel.js +277 -0
  321. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  322. package/hooks/gsd-agent-isolation-guard.js +517 -0
  323. package/hooks/gsd-check-update-worker.js +64 -12
  324. package/hooks/gsd-check-update.js +19 -1
  325. package/hooks/gsd-cursor-pre-tool.js +0 -3
  326. package/hooks/gsd-cursor-subagent-start.js +607 -26
  327. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  328. package/hooks/gsd-prompt-guard.js +21 -20
  329. package/hooks/gsd-read-injection-scanner.js +45 -24
  330. package/hooks/gsd-statusline.js +90 -6
  331. package/hooks/gsd-update-banner.js +22 -1
  332. package/hooks/gsd-workflow-guard.js +134 -36
  333. package/hooks/gsd-worktree-path-guard.js +2 -1
  334. package/hooks/gsd-write-guard.js +359 -0
  335. package/hooks/hooks.json +12 -0
  336. package/hooks/lib/git-cmd.js +92 -59
  337. package/hooks/lib/injection-patterns.js +45 -0
  338. package/hooks/lib/isolation-deny-reason.js +39 -0
  339. package/hooks/lib/isolation-sentinel.js +277 -0
  340. package/hooks/managed-hooks-registry.cjs +2 -0
  341. package/package.json +31 -10
  342. package/pi/gsd.cjs +71 -12
  343. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  344. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  345. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  346. package/scripts/build-hooks.js +9 -0
  347. package/scripts/changeset/lint.cjs +68 -6
  348. package/scripts/changeset/serialize.cjs +5 -1
  349. package/scripts/check-alias-drift.cjs +7 -43
  350. package/scripts/check-contract-drift.cjs +297 -0
  351. package/scripts/ci-test-scope.cjs +19 -2
  352. package/scripts/command-contract-helpers.cjs +903 -1
  353. package/scripts/gen-adr-index.cjs +728 -38
  354. package/scripts/gen-capability-matrix.cjs +1 -1
  355. package/scripts/gen-capability-registry.cjs +3 -15
  356. package/scripts/gen-context-index.cjs +439 -0
  357. package/scripts/gen-health-docs.cjs +390 -0
  358. package/scripts/gen-inventory-manifest.cjs +150 -4
  359. package/scripts/gen-loop-host-contract.cjs +4 -24
  360. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  361. package/scripts/gen-registry.cjs +3 -14
  362. package/scripts/gen-section-manifest.cjs +638 -0
  363. package/scripts/generate-package-identity.cjs +4 -2
  364. package/scripts/lib/alias-drift-families.cjs +46 -0
  365. package/scripts/lib/drift-scan.cjs +278 -0
  366. package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
  367. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  368. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  369. package/scripts/lint-canary-version-leak.cjs +73 -0
  370. package/scripts/lint-command-contract.cjs +96 -13
  371. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  372. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  373. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  374. package/scripts/lint-default-flip-documentation.cjs +193 -0
  375. package/scripts/lint-docs-command-form.cjs +195 -0
  376. package/scripts/lint-docs-required.cjs +9 -1
  377. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  378. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  379. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  380. package/scripts/lint-example-parser-parity.cjs +395 -0
  381. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  382. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  383. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  384. package/scripts/lint-milestone-window-drift.cjs +468 -0
  385. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  386. package/scripts/lint-plan-count-drift.cjs +318 -0
  387. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  388. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  389. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  390. package/scripts/lint-regression-test-names.cjs +15 -13
  391. package/scripts/lint-removed-but-needed.cjs +320 -0
  392. package/scripts/lint-state-field-drift.cjs +805 -0
  393. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  394. package/scripts/lint-test-file-count.allowlist.json +40 -3
  395. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  396. package/scripts/lint-vendored-deps.cjs +124 -0
  397. package/scripts/mutation-matrix.cjs +13 -0
  398. package/scripts/pr-changed-files.cjs +63 -0
  399. package/scripts/pr-template-policy.cjs +14 -4
  400. package/scripts/prompt-injection-scan.sh +52 -6
  401. package/scripts/require-issue-link-policy.cjs +192 -0
  402. package/scripts/state-write-path-drift-baseline.json +19 -0
  403. package/scripts/sync-runtime-launcher.cjs +2 -4
  404. package/skills/gsd-autonomous/SKILL.md +0 -1
  405. package/skills/gsd-code-review/SKILL.md +1 -1
  406. package/skills/gsd-execute-phase/SKILL.md +1 -2
  407. package/skills/gsd-map-codebase/SKILL.md +1 -1
  408. package/skills/gsd-mempalace-capture/SKILL.md +2 -2
  409. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  410. package/skills/gsd-new-milestone/SKILL.md +2 -2
  411. package/skills/gsd-next/SKILL.md +0 -1
  412. package/skills/gsd-plan-phase/SKILL.md +1 -2
  413. package/skills/gsd-progress/SKILL.md +0 -1
  414. package/skills/gsd-quick/SKILL.md +1 -1
  415. package/skills/gsd-review-backlog/SKILL.md +2 -1
  416. package/skills/gsd-stats/SKILL.md +0 -1
  417. package/skills/gsd-verify-work/SKILL.md +1 -1
  418. package/vscode/package.json +1 -1
  419. package/gsd-core/workflows/discovery-phase.md +0 -298
  420. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  421. package/gsd-core/workflows/verify-phase.md +0 -577
  422. package/scripts/affected-tests-lib.cjs +0 -554
  423. package/scripts/gen-emitted-baseline.cjs +0 -145
  424. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  425. package/scripts/run-affected-tests.cjs +0 -7
  426. package/scripts/run-tests.cjs +0 -1050
@@ -12,13 +12,62 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.pickRollupWinners = pickRollupWinners;
15
16
  exports.isCompletedInventory = isCompletedInventory;
16
17
  exports.buildWorkstreamInventory = buildWorkstreamInventory;
17
18
  const node_path_1 = __importDefault(require("node:path"));
19
+ const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
18
20
  // Internal helpers
19
21
  function toPosixPath(p) {
20
22
  return p.split('\\').join('/');
21
23
  }
24
+ // #2562/#2645's FAILING_VERIFICATION_STATUSES set (the verdicts that used to
25
+ // disqualify a phase from `complete` when combined with a local
26
+ // summary-count-meets-plan-count check) was removed by ADR-3180 §7.4
27
+ // (#3186): `complete` is now the single canonical owner's verdict
28
+ // (`PhaseFilesCount.complete`, computed via `isPhaseComplete` by the
29
+ // I/O-capable caller — see the loop below), which already requires
30
+ // `verification.status === 'passed'` unconditionally. Disk-strict (#2957)
31
+ // deliberately DROPS the prior "verifier-disabled projects fall back to
32
+ // summaries-met" tolerance that set existed to preserve — a phase with no
33
+ // `*-VERIFICATION.md` (`missing`) is no longer treated as complete just
34
+ // because its summaries meet its plan count. Disclosed in this phase's
35
+ // changeset.
36
+ /**
37
+ * #2562 / Bug #2445 / #2645 review: pick ONE winning item per key from a
38
+ * PRE-SORTED list — newest `mtimeMs` wins; on an exact tie the incumbent
39
+ * (first-in-sort-order) wins, since only a STRICTLY greater mtime replaces
40
+ * it. `includeItem` lets a caller exclude items before comparison (e.g.
41
+ * out-of-milestone directories) — critically, the filter runs BEFORE the
42
+ * mtime comparison, so an excluded item can never win a tie or a comparison
43
+ * against an included one.
44
+ *
45
+ * Extracted as the SINGLE shared implementation after a #2645 review found
46
+ * two independently-written copies of this exact rule had silently
47
+ * diverged: `workstream-inventory.cts`'s ledger-winner selection compared
48
+ * raw mtimes with no scoping filter, while this module's own `rollupDirByKey`
49
+ * (below) filtered out-of-milestone directories first. A stale out-of-
50
+ * milestone directory with a newer mtime than the live in-milestone one
51
+ * (plausible after a checkout/rebase resets mtimes) could then win the
52
+ * LEDGER's selection while losing the BUILDER's — reopening #2645's own
53
+ * hole for the phase that actually counts toward `completed_phases`,
54
+ * reachable with a plain `rm` and no ledger tampering. A comment asserting
55
+ * two hand-written copies "use the same rule" is not a guarantee they do;
56
+ * one shared function is.
57
+ */
58
+ function pickRollupWinners(sortedItems, keyOf, mtimeOf, includeItem = () => true) {
59
+ const winners = new Map();
60
+ for (const item of sortedItems) {
61
+ if (!includeItem(item))
62
+ continue;
63
+ const key = keyOf(item);
64
+ const incumbent = winners.get(key);
65
+ if (incumbent === undefined || mtimeOf(item) > mtimeOf(incumbent)) {
66
+ winners.set(key, item);
67
+ }
68
+ }
69
+ return winners;
70
+ }
22
71
  function isCompletedInventory(status) {
23
72
  const s = (typeof status === 'string'
24
73
  ? status
@@ -28,42 +77,153 @@ function isCompletedInventory(status) {
28
77
  return /\bmilestone\s+complete\b/.test(s) || /\barchived\b/.test(s);
29
78
  }
30
79
  function buildWorkstreamInventory(inputs) {
31
- const { name, projectDir, workstreamDir, phaseDirNames, activeWorkstreamName, phaseFilesCounts, roadmapPhaseCount, stateProjection, filesExist, milestoneShipped, } = inputs;
80
+ const { name, projectDir, workstreamDir, phaseDirNames, activeWorkstreamName, phaseFilesCounts, roadmapPhaseCount, stateProjection, filesExist, milestoneShipped, milestoneShippedSignal, currentMilestonePhaseCount = 0, milestoneScoped, } = inputs;
81
+ // A caller that passes only the legacy boolean states THAT a signal fired but
82
+ // not which one. Treat it as `legacy` — the ungated strength — so pre-review
83
+ // callers keep their exact behavior rather than silently acquiring a new gate.
84
+ const shippedSignal = milestoneShippedSignal !== undefined ? milestoneShippedSignal : (milestoneShipped ? 'legacy' : null);
85
+ const milestoneShippedResolved = shippedSignal !== null;
86
+ // #2562: when scoping is active, prior-milestone phase directories are
87
+ // excluded from the completion rollup and the denominator. The caller states
88
+ // this; the count-derived default is the pre-#2562 fallback for callers that
89
+ // do not, and cannot represent a scoped-but-empty current milestone.
90
+ const scoped = milestoneScoped ?? currentMilestonePhaseCount > 0;
32
91
  // Index counts by directory for O(1) lookup during sort/iteration
33
92
  const countsMap = new Map();
34
93
  for (const entry of phaseFilesCounts) {
35
- countsMap.set(entry.directory, { planCount: entry.planCount, summaryCount: entry.summaryCount });
94
+ countsMap.set(entry.directory, entry);
36
95
  }
96
+ // #2562 / Bug #2445: pick ONE directory per phase key for the rollup. Stale
97
+ // same-numbered directories left over from a prior milestone would otherwise
98
+ // each add to the numerator while the denominator counts distinct phases —
99
+ // pushing completed_phases past it, where the old `Math.min` cap silently
100
+ // rounded the result up to 100% and hid an unstarted phase. Newest-on-disk
101
+ // wins, mirroring state.cts's #2445 de-duplication. `pickRollupWinners` is
102
+ // the SHARED implementation `workstream-inventory.cts`'s ledger-winner
103
+ // selection also calls, so the two can never independently diverge again
104
+ // (#2645 review).
105
+ const rollupDirByKey = pickRollupWinners([...phaseDirNames].sort(), (dir) => countsMap.get(dir)?.phaseKey ?? dir, (dir) => countsMap.get(dir)?.mtimeMs ?? 0, (dir) => !(scoped && countsMap.get(dir)?.inMilestone === false));
106
+ const rollupDirs = new Set(rollupDirByKey.values());
37
107
  const phases = [];
38
108
  let completedPhases = 0;
39
109
  let totalPlans = 0;
40
110
  let completedPlans = 0;
111
+ // #2562 review: in-milestone phase directories still present under `phases/`,
112
+ // whatever their status. A CLEAN archive has none — `milestone complete` moves
113
+ // them all out — so this counts exactly the phases that outlived the archive,
114
+ // which is what distinguishes "archived" from "archived, then reopened".
115
+ // Deliberately NOT "…and unfinished": a complete live dir beside a declared
116
+ // but never-scaffolded phase is a dirty archive too, and the dirless phase has
117
+ // no directory to inspect.
118
+ let liveInMilestonePhases = 0;
41
119
  for (const dir of [...phaseDirNames].sort()) {
42
- const counts = countsMap.get(dir) ?? { planCount: 0, summaryCount: 0 };
43
- const status = counts.summaryCount >= counts.planCount && counts.planCount > 0
120
+ const counts = countsMap.get(dir);
121
+ const planCount = counts?.planCount ?? 0;
122
+ const summaryCount = counts?.summaryCount ?? 0;
123
+ // ADR-3180 §7.4 (issue #3186): routed through the single canonical owner
124
+ // (`isPhaseComplete`, src/verification.cts) — via `PhaseFilesCount.complete`,
125
+ // which the I/O-capable CALLER computes (this module is a PURE, I/O-free
126
+ // projection — see the module header: "No I/O. No async." — and cannot
127
+ // call the owner itself). The prior local derivation
128
+ // (`summaryCount >= planCount && planCount > 0` combined with a
129
+ // caller-supplied verification status) was this module's OWN completion
130
+ // verdict computed from raw counts — the exact "post-process a canonical
131
+ // result locally" bypass §7.4 rules out, and it reproduced the disk-strict
132
+ // headline case (#3168): a zero-plan phase with a passing verification
133
+ // read `pending` instead of `complete`. `complete` defaults to `false`
134
+ // when absent so a caller that has not been updated to pass it never
135
+ // silently reads as complete.
136
+ const status = (counts?.complete ?? false)
44
137
  ? 'complete'
45
- : counts.planCount > 0
138
+ : planCount > 0
46
139
  ? 'in_progress'
47
140
  : 'pending';
48
- totalPlans += counts.planCount;
49
- completedPlans += Math.min(counts.summaryCount, counts.planCount);
50
- if (status === 'complete')
51
- completedPhases++;
141
+ // #2562: only current-milestone phases feed the rollup when scoping is on,
142
+ // and only one directory per phase key (see rollupDirs above).
143
+ const countsTowardMilestone = (!scoped || counts?.inMilestone !== false) && rollupDirs.has(dir);
144
+ if (countsTowardMilestone) {
145
+ totalPlans += planCount;
146
+ completedPlans += Math.min(summaryCount, planCount);
147
+ if (status === 'complete')
148
+ completedPhases++;
149
+ liveInMilestonePhases++;
150
+ }
52
151
  phases.push({
53
152
  directory: dir,
54
153
  status,
55
- plan_count: counts.planCount,
56
- summary_count: counts.summaryCount,
154
+ plan_count: planCount,
155
+ summary_count: summaryCount,
57
156
  });
58
157
  }
158
+ // #2562: the denominator is the current milestone's declared phase count when
159
+ // scoping is active (catches phases declared but never scaffolded), else the
160
+ // legacy whole-roadmap heading count.
161
+ const effectivePhaseCount = scoped ? currentMilestonePhaseCount : roadmapPhaseCount;
162
+ // #2562 invariant: the numerator counts de-duplicated in-milestone phase keys
163
+ // and the denominator counts the union of those keys with the roadmap's own
164
+ // declarations, so the numerator can never exceed it. Raising the numerator
165
+ // above the denominator means the two sides were derived in different key
166
+ // spaces — the defect class this issue is about. The old `Math.min(100, …)`
167
+ // capped that away and reported 100%; this makes it fail loudly instead.
168
+ if (scoped && completedPhases > effectivePhaseCount) {
169
+ throw new Error(`workstream inventory invariant violated for "${name}": completed_phases (${completedPhases}) ` +
170
+ `exceeds the current-milestone denominator (${effectivePhaseCount}). The completion numerator and ` +
171
+ `denominator were derived in different phase-key spaces.`);
172
+ }
59
173
  // #1913: derive status from authoritative shipped signals rather than trusting
60
174
  // the mutable STATE.md `Status` field. When a shipped signal is present, the
61
175
  // workstream is "milestone complete" regardless of a stale field value.
176
+ //
177
+ // #2562 review: a shipped signal is a CLAIM, and a claim its own milestone's
178
+ // artifacts contradict must not be echoed as fact — the defect class this issue
179
+ // is about reaches `status`, not just `progress_percent`. The two signals need
180
+ // DIFFERENT cross-checks; one check for both regresses the commonest shape:
181
+ //
182
+ // - `heading` — operator-typed marker in the LIVE roadmap. Nothing has been
183
+ // archived, so every phase the milestone declares should be on disk and
184
+ // complete. Gate on the full ratio, which also catches the
185
+ // declared-but-never-scaffolded phases that have no directory to inspect.
186
+ // - `snapshot` — `milestones/<version>-ROADMAP.md`. The `milestone complete`
187
+ // run that writes it also MOVES the milestone's phase directories into
188
+ // `milestones/<version>-phases/` (milestone.cts:783-790) while COPYING —
189
+ // never truncating — the live ROADMAP (:700-702), so its Progress rows
190
+ // survive. A CLEAN archive therefore reads 0/N by construction, and gating
191
+ // it on the ratio alone would strip `milestone complete` from every
192
+ // archived milestone. But a live in-milestone directory means the archive
193
+ // is NOT clean — a phase was added or reopened after it, reachable because
194
+ // `milestone complete` does not advance STATE's `milestone:` field
195
+ // (state-transition.cts:83, :1335); only `/gsd-new-milestone` does (:1224).
196
+ // Once any in-milestone directory is live the ratio IS meaningful again, so
197
+ // the check is the conjunction. Requiring the live directory to itself be
198
+ // unfinished was too narrow: it let a complete live dir alongside a
199
+ // declared-but-unscaffolded phase reproduce the reported symptom, since a
200
+ // dirless phase has nothing to inspect.
201
+ //
202
+ // The whole cross-check is scoped-only, and NOT because of the signal: when
203
+ // scoping is off, `effectivePhaseCount` is the whole-roadmap count and
204
+ // membership is everything, so there is no current-milestone artifact set to
205
+ // check a current-milestone claim against. `legacy` is additionally ungated by
206
+ // signal — it is the fallback for an unknown milestone version, which is
207
+ // exactly when scoping cannot engage either.
62
208
  const fieldStatus = stateProjection.status;
63
- const useDerived = milestoneShipped;
64
- const status = useDerived ? 'milestone complete' : fieldStatus;
65
- const status_source = useDerived ? 'derived' : 'field';
66
- const status_conflict = useDerived && !isCompletedInventory(fieldStatus);
209
+ const shippedContradicted = scoped && (shippedSignal === 'heading'
210
+ ? completedPhases < effectivePhaseCount
211
+ : shippedSignal === 'snapshot'
212
+ ? liveInMilestonePhases > 0 && completedPhases < effectivePhaseCount
213
+ : false);
214
+ const useDerived = milestoneShippedResolved && !shippedContradicted;
215
+ // Refusing the claim does not make the STATE field a safe fallback: it is
216
+ // operator-written and in this window it commonly ALSO reads "milestone
217
+ // complete", which would re-report the refused claim through the other door.
218
+ // Against contradicting artifacts, NEITHER source may assert completion.
219
+ const artifactOverride = shippedContradicted && isCompletedInventory(fieldStatus);
220
+ const status = useDerived
221
+ ? 'milestone complete'
222
+ : artifactOverride
223
+ ? 'in_progress'
224
+ : fieldStatus;
225
+ const status_source = useDerived || artifactOverride ? 'derived' : 'field';
226
+ const status_conflict = (useDerived && !isCompletedInventory(fieldStatus)) || artifactOverride;
67
227
  return {
68
228
  name,
69
229
  path: toPosixPath(node_path_1.default.relative(projectDir, workstreamDir)),
@@ -76,16 +236,40 @@ function buildWorkstreamInventory(inputs) {
76
236
  status,
77
237
  status_source,
78
238
  status_conflict,
239
+ milestone_shipped_unverified: shippedContradicted,
79
240
  current_phase: stateProjection.current_phase,
80
241
  last_activity: stateProjection.last_activity,
81
242
  phases,
82
243
  phase_count: phases.length,
83
244
  completed_phases: completedPhases,
84
- roadmap_phase_count: roadmapPhaseCount,
245
+ roadmap_phase_count: effectivePhaseCount,
85
246
  total_plans: totalPlans,
86
247
  completed_plans: completedPlans,
87
- progress_percent: roadmapPhaseCount > 0
88
- ? Math.min(100, Math.round((completedPhases / roadmapPhaseCount) * 100))
89
- : 0,
248
+ // `clampPercent`'s 100 ceiling is unreachable under milestone scoping (the
249
+ // invariant above throws first) and matters only for the legacy unscoped
250
+ // path, where the denominator is a roadmap heading count that a caller
251
+ // cannot guarantee bounds the numerator.
252
+ //
253
+ // #3217 (ADR-3180 §7.6 rule 4) — WRITTEN REASON this site is NOT migrated
254
+ // onto the `SCOPE` enum this phase: `buildWorkstreamInventory` is a pure
255
+ // projection (no I/O — see the module header) fed `BuildWorkstreamInventoryInputs`
256
+ // by `workstream-inventory.cts`. Its own `milestoneScoped` is a pre-ADR-3180
257
+ // bespoke boolean, not a `SCOPE` value, and its caller does not currently
258
+ // thread a real `listMilestonePhaseDirs` scope into these inputs. Doing
259
+ // this honestly requires ONE of: (a) widening `BuildWorkstreamInventoryInputs`
260
+ // with a `Scope` field and `WorkstreamInventory.progress_percent`'s type
261
+ // from `number` to `number | null` — the exact "re-architecting
262
+ // StateProjection/WorkstreamInventory return types" the design phase
263
+ // (`.gsd/phase/refactor-3217-completion-ratio-scoping/40-design.md`,
264
+ // "Known limits") states is OUT of this phase's scope; or (b) silently
265
+ // reusing `milestoneScoped` as a `Scope` stand-in, which would be exactly
266
+ // the kind of proxy-for-a-data-flow-property this same phase's guard
267
+ // section explicitly rejects (a `boolean` cannot distinguish TRUNCATED
268
+ // from UNSCOPED from UNREADABLE, so a caller could not tell which
269
+ // non-answer it got). Left un-migrated rather than done dishonestly;
270
+ // `workstream inventory`'s `progress_percent` can still render a number
271
+ // derived from an under-scoped set (A8 in the phase's test matrix is
272
+ // NOT covered here for that reason — see this phase's PR description).
273
+ progress_percent: (0, phase_lifecycle_cjs_1.clampPercent)(completedPhases, effectivePhaseCount),
90
274
  };
91
275
  }