@opengsd/gsd-core 1.19.0 → 1.20.1

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 (131) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.compact.md +5 -5
  4. package/agents/gsd-code-fixer.md +9 -4
  5. package/agents/gsd-code-reviewer.compact.md +49 -8
  6. package/agents/gsd-code-reviewer.md +53 -14
  7. package/agents/gsd-executor.md +8 -4
  8. package/bin/install.js +36 -40
  9. package/commands/gsd/new-milestone.md +2 -2
  10. package/commands/gsd/new-project.md +2 -2
  11. package/commands/gsd/update.md +5 -2
  12. package/gsd-core/bin/gsd-tools.cjs +177 -93
  13. package/gsd-core/bin/lib/capability-lifecycle.cjs +1 -12
  14. package/gsd-core/bin/lib/capability-registry.cjs +284 -93
  15. package/gsd-core/bin/lib/capability-validator.cjs +15 -0
  16. package/gsd-core/bin/lib/commands.cjs +46 -17
  17. package/gsd-core/bin/lib/config-loader.cjs +3 -3
  18. package/gsd-core/bin/lib/core-utils.cjs +11 -0
  19. package/gsd-core/bin/lib/frontmatter.cjs +21 -3
  20. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +2 -2
  21. package/gsd-core/bin/lib/gate-context-drift.cjs +1 -1
  22. package/gsd-core/bin/lib/gate-phase-context.cjs +7 -8
  23. package/gsd-core/bin/lib/gate-schema-drift.cjs +1 -1
  24. package/gsd-core/bin/lib/git-info-exclude.cjs +1 -6
  25. package/gsd-core/bin/lib/gsd-tool-dir.cjs +134 -0
  26. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +13 -9
  27. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +9 -7
  28. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +3 -3
  29. package/gsd-core/bin/lib/init.cjs +181 -68
  30. package/gsd-core/bin/lib/install-engine.cjs +9 -9
  31. package/gsd-core/bin/lib/install-manifest-record.cjs +86 -0
  32. package/gsd-core/bin/lib/install-profiles.cjs +4 -2
  33. package/gsd-core/bin/lib/io.cjs +6 -0
  34. package/gsd-core/bin/lib/markdown-sectionizer.cjs +34 -1
  35. package/gsd-core/bin/lib/markdown-table.cjs +23 -0
  36. package/gsd-core/bin/lib/mcp-server.cjs +8 -5
  37. package/gsd-core/bin/lib/milestone.cjs +18 -50
  38. package/gsd-core/bin/lib/phase-entry-grammar.cjs +119 -0
  39. package/gsd-core/bin/lib/phase-id-display.cjs +2 -0
  40. package/gsd-core/bin/lib/phase-id.cjs +627 -36
  41. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -74
  42. package/gsd-core/bin/lib/phase-locator.cjs +328 -19
  43. package/gsd-core/bin/lib/phase.cjs +3039 -666
  44. package/gsd-core/bin/lib/planning-document.cjs +26 -5
  45. package/gsd-core/bin/lib/planning-inspect.cjs +27 -35
  46. package/gsd-core/bin/lib/planning-snapshot.cjs +12 -7
  47. package/gsd-core/bin/lib/planning-workspace.cjs +3 -3
  48. package/gsd-core/bin/lib/read-only-git-env.cjs +23 -2
  49. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +2 -2
  50. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -0
  51. package/gsd-core/bin/lib/review-lane-invocation.cjs +125 -18
  52. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +11 -9
  53. package/gsd-core/bin/lib/roadmap-parser.cjs +759 -144
  54. package/gsd-core/bin/lib/roadmap-progress.cjs +136 -0
  55. package/gsd-core/bin/lib/roadmap-upgrade.cjs +8 -5
  56. package/gsd-core/bin/lib/roadmap.cjs +358 -106
  57. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -130
  58. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +6 -0
  59. package/gsd-core/bin/lib/shell-command-projection.cjs +36 -9
  60. package/gsd-core/bin/lib/smart-entry.cjs +22 -11
  61. package/gsd-core/bin/lib/state-contract.cjs +11 -7
  62. package/gsd-core/bin/lib/state-document.cjs +332 -23
  63. package/gsd-core/bin/lib/state-transition.cjs +51 -15
  64. package/gsd-core/bin/lib/state.cjs +499 -180
  65. package/gsd-core/bin/lib/template.cjs +2 -2
  66. package/gsd-core/bin/lib/validate.cjs +3 -2
  67. package/gsd-core/bin/lib/vendor/re2js.cjs +863 -577
  68. package/gsd-core/bin/lib/vendor/re2js.d.cts +284 -219
  69. package/gsd-core/bin/lib/verify.cjs +2 -2
  70. package/gsd-core/bin/lib/workstream-inventory.cjs +27 -21
  71. package/gsd-core/bin/lib/worktree-base-ref.cjs +32 -2
  72. package/gsd-core/bin/verify-reapply-patches.cjs +411 -10
  73. package/gsd-core/references/cicd-review-patterns.md +45 -0
  74. package/gsd-core/references/necessity-review.md +48 -0
  75. package/gsd-core/workflows/code-review-fix.md +46 -5
  76. package/gsd-core/workflows/code-review.md +3 -0
  77. package/gsd-core/workflows/execute-phase.md +1 -1
  78. package/gsd-core/workflows/execute-plan.md +1 -1
  79. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +13 -9
  80. package/gsd-core/workflows/plan-phase.md +1 -1
  81. package/gsd-core/workflows/pr-branch.md +2 -0
  82. package/gsd-core/workflows/reapply-patches.md +104 -0
  83. package/gsd-core/workflows/review.md +54 -141
  84. package/gsd-core/workflows/secure-phase.md +1 -1
  85. package/gsd-core/workflows/settings-advanced.md +57 -9
  86. package/gsd-core/workflows/ship.md +12 -0
  87. package/hooks/dist/gsd-agent-isolation-guard.js +1 -1
  88. package/hooks/dist/gsd-cursor-subagent-start.js +1 -1
  89. package/hooks/dist/gsd-graphify-update.sh +6 -0
  90. package/hooks/dist/gsd-statusline.js +3 -2
  91. package/hooks/dist/gsd-windsurf-pre-write.js +4 -4
  92. package/hooks/dist/gsd-workflow-guard.js +2 -1
  93. package/hooks/dist/gsd-worktree-path-guard.js +4 -4
  94. package/hooks/dist/lib/git-probe.js +16 -0
  95. package/hooks/dist/lib/isolation-sentinel.js +77 -2
  96. package/hooks/gsd-agent-isolation-guard.js +1 -1
  97. package/hooks/gsd-cursor-subagent-start.js +1 -1
  98. package/hooks/gsd-graphify-update.sh +6 -0
  99. package/hooks/gsd-statusline.js +3 -2
  100. package/hooks/gsd-windsurf-pre-write.js +4 -4
  101. package/hooks/gsd-workflow-guard.js +2 -1
  102. package/hooks/gsd-worktree-path-guard.js +4 -4
  103. package/hooks/lib/git-probe.js +16 -0
  104. package/hooks/lib/isolation-sentinel.js +77 -2
  105. package/package.json +3 -3
  106. package/pi/package-agents/gsd-code-fixer.md +9 -4
  107. package/pi/package-agents/gsd-code-reviewer.md +53 -14
  108. package/pi/package-agents/gsd-executor.md +8 -4
  109. package/pi/package-agents/manifest.json +3 -3
  110. package/pi/package-skills/gsd-new-milestone/SKILL.md +1 -1
  111. package/pi/package-skills/gsd-new-project/SKILL.md +1 -1
  112. package/pi/package-skills/gsd-update/SKILL.md +4 -1
  113. package/scripts/changeset/lint.cjs +28 -3
  114. package/scripts/ci-next-health.cjs +246 -23
  115. package/scripts/docs-guard-registry.cjs +2 -0
  116. package/scripts/gen-features.cjs +14 -2
  117. package/scripts/lib/drift-scan.cjs +27 -0
  118. package/scripts/lib/macos-conformance-tier.generated.cjs +10 -0
  119. package/scripts/lib/platform-conformance-tier.generated.cjs +15 -0
  120. package/scripts/lint-phase-enumeration-drift.cjs +8 -4
  121. package/scripts/lint-roadmap-progress-drift.cjs +421 -0
  122. package/scripts/merge-commit-pr.cjs +186 -0
  123. package/scripts/mutation-matrix.cjs +23 -1
  124. package/scripts/release-ancestry.cjs +86 -0
  125. package/scripts/release-pipeline-pr.cjs +92 -0
  126. package/scripts/require-issue-link-policy.cjs +18 -9
  127. package/scripts/sync-next-version.cjs +48 -7
  128. package/skills/gsd-new-milestone/SKILL.md +1 -1
  129. package/skills/gsd-new-project/SKILL.md +1 -1
  130. package/skills/gsd-update/SKILL.md +5 -2
  131. package/vscode/package.json +1 -1
@@ -163,6 +163,7 @@ const DOCS_GUARD_TESTS = {
163
163
  'docs/COMMANDS.md',
164
164
  'docs/how-to/run-phases-autonomously.md',
165
165
  ],
166
+ 'tests/adr-612-bracket-new-project-config.test.cjs': ['docs/CONFIGURATION.md'],
166
167
  // Walks docs/adr/ as a directory (builds/reads docs/adr/README.md and
167
168
  // fixture ADRs throughout) and separately reads docs/contributor-standards.md.
168
169
  'tests/adr-index-gate.test.cjs': ['docs/adr/', 'docs/contributor-standards.md'],
@@ -319,6 +320,7 @@ const DOCS_GUARD_TESTS = {
319
320
  'tests/host-integration-descriptors.test.cjs': [
320
321
  'docs/reference/host-integration-capability-matrix.md',
321
322
  ],
323
+ 'tests/inline-plan-threshold-default.test.cjs': ['docs/CONFIGURATION.md', 'docs/zh-CN/CONFIGURATION.md', 'docs/pt-BR/CONFIGURATION.md'],
322
324
  'tests/install.test.cjs': ['docs/reference/agents.md', 'docs/INVENTORY.md', 'docs/INVENTORY-MANIFEST.json'],
323
325
  // SOURCE_DIRS includes 'docs' and walks it recursively for every .md file
324
326
  // (intel.test.cjs:1223-1228) — a generic tree walk.
@@ -666,6 +666,17 @@ function describeViolation(v) {
666
666
  }
667
667
  }
668
668
 
669
+ /**
670
+ * Fragment bodies live in `docs/features/` and are emitted into `docs/FEATURES.md`, one
671
+ * directory up, so a relative markdown link target written for the fragment must lose
672
+ * `depth` leading `../` to resolve from the index (1 for a section; 2 for a group note from
673
+ * `docs/features/_groups/`). Only relative targets are touched:
674
+ * `http(s):`, `#anchor` and absolute `/` targets (and anything not starting `../`) pass through.
675
+ */
676
+ function rewriteRelativeLinks(text, depth = 1) {
677
+ return text.replace(new RegExp(`\\]\\((?:\\.\\./){${depth}}`, 'g'), '](');
678
+ }
679
+
669
680
  /** Render the generated region: the table of contents, then every section. */
670
681
  function renderFeatures(corpus) {
671
682
  const out = [START_MARKER, '', '## Table of Contents', ''];
@@ -677,10 +688,10 @@ function renderFeatures(corpus) {
677
688
 
678
689
  for (const g of corpus.groups) {
679
690
  out.push('', '---', '', `## ${g.title}`, '');
680
- if (g.note) out.push(g.note, '');
691
+ if (g.note) out.push(rewriteRelativeLinks(g.note, 2), '');
681
692
  g.sections.forEach((s, i) => {
682
693
  if (i > 0) out.push('---', '');
683
- out.push(`### ${s.id}. ${s.title}`, '', s.body, '');
694
+ out.push(`### ${s.id}. ${s.title}`, '', rewriteRelativeLinks(s.body), '');
684
695
  });
685
696
  }
686
697
 
@@ -836,6 +847,7 @@ module.exports = {
836
847
  checkInboundAnchors,
837
848
  buildCorpus,
838
849
  renderFeatures,
850
+ rewriteRelativeLinks,
839
851
  spliceIntoFeatures,
840
852
  describeViolation,
841
853
  };
@@ -294,12 +294,39 @@ function sanitizeForReport(text) {
294
294
  .replace(/[\u200B-\u200F\u2028\u2029\u202A-\u202E\u2066-\u2069]/g, (c) => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'));
295
295
  }
296
296
 
297
+ /**
298
+ * Read the quoted or backtick-delimited string literal starting at `line[start]`
299
+ * (which must be `'`, `"`, or a backtick). Returns `{ text, end }` (`text`
300
+ * includes both delimiters, `end` is the index one past the literal) or null when
301
+ * no close quote is found within MAX_REGEX_LITERAL_LEN characters. Same single
302
+ * left-to-right, no-backtracking, escape-aware pass as `readRegexLiteralAt` (a
303
+ * `\x` escape consumes both characters, so an escaped quote never ends the
304
+ * literal early). A literal cannot span lines in a per-line scan. The older drift
305
+ * guards each carry their own byte-identical copy; new guards import this one.
306
+ */
307
+ function readStringLiteralAt(line, start) {
308
+ const quote = line[start];
309
+ if (quote !== "'" && quote !== '"' && quote !== '`') return null;
310
+ const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
311
+ for (let i = start + 1; i < limit; i++) {
312
+ const ch = line[i];
313
+ if (ch === '\\') {
314
+ i++;
315
+ continue;
316
+ }
317
+ if (ch === '\r' || ch === '\n') return null;
318
+ if (ch === quote) return { text: line.slice(start, i + 1), end: i + 1 };
319
+ }
320
+ return null;
321
+ }
322
+
297
323
  module.exports = {
298
324
  SKIP_DIR_NAMES,
299
325
  isInsideRoot,
300
326
  isUnderSkippedDir,
301
327
  walk,
302
328
  readRegexLiteralAt,
329
+ readStringLiteralAt,
303
330
  MAX_REGEX_LITERAL_LEN,
304
331
  sanitizeForReport,
305
332
  scanTree,
@@ -9,6 +9,8 @@ module.exports = {
9
9
  "tests/5100-win32-bare-bash-sentinel.property.test.cjs",
10
10
  "tests/active-workstream-store.unit.test.cjs",
11
11
  "tests/adr-612-bracket-phase-counting.test.cjs",
12
+ "tests/adr-612-bracket-phase-remove.test.cjs",
13
+ "tests/adr-612-bracket-write-path.test.cjs",
12
14
  "tests/adr-index-gate.test.cjs",
13
15
  "tests/adr-parser.property.test.cjs",
14
16
  "tests/adr-parser.unit.test.cjs",
@@ -32,6 +34,7 @@ module.exports = {
32
34
  "tests/capability-source.test.cjs",
33
35
  "tests/capability-state.test.cjs",
34
36
  "tests/capability-trust.test.cjs",
37
+ "tests/changeset-lint.test.cjs",
35
38
  "tests/changeset-parse.test.cjs",
36
39
  "tests/check-contract-drift.test.cjs",
37
40
  "tests/check-predicate.test.cjs",
@@ -63,6 +66,7 @@ module.exports = {
63
66
  "tests/contributor-standards.test.cjs",
64
67
  "tests/core-utils.test.cjs",
65
68
  "tests/cursor-subagent-isolation.test.cjs",
69
+ "tests/custom-phase-readers.test.cjs",
66
70
  "tests/debugger-semantic-recall.test.cjs",
67
71
  "tests/default-flip-documentation-lint.test.cjs",
68
72
  "tests/discuss-phase-power.test.cjs",
@@ -94,6 +98,7 @@ module.exports = {
94
98
  "tests/gen-context-index.test.cjs",
95
99
  "tests/gen-section-manifest.test.cjs",
96
100
  "tests/git-base-branch.test.cjs",
101
+ "tests/git-location-env-scrub.test.cjs",
97
102
  "tests/graphify-query.test.cjs",
98
103
  "tests/graphify-visualization.test.cjs",
99
104
  "tests/gsd-agent-isolation-guard.test.cjs",
@@ -101,6 +106,7 @@ module.exports = {
101
106
  "tests/gsd-secret-read-guard.test.cjs",
102
107
  "tests/gsd-settings-advanced.test.cjs",
103
108
  "tests/gsd-statusline.test.cjs",
109
+ "tests/gsd-tool-dir.platform.test.cjs",
104
110
  "tests/gsd-tools-path-refs.test.cjs",
105
111
  "tests/gsd-validate-commit-crash-policy.test.cjs",
106
112
  "tests/gsd-validate-commit-sigpipe.test.cjs",
@@ -138,6 +144,7 @@ module.exports = {
138
144
  "tests/markdown-sectionizer-xml-tags.property.test.cjs",
139
145
  "tests/markdown-sectionizer.test.cjs",
140
146
  "tests/mcp-catalog.test.cjs",
147
+ "tests/merge-commit-pr.test.cjs",
141
148
  "tests/milestone-archive.test.cjs",
142
149
  "tests/milestone-release-tags.test.cjs",
143
150
  "tests/milestone-window-single-owner.test.cjs",
@@ -197,11 +204,13 @@ module.exports = {
197
204
  "tests/quick-research.test.cjs",
198
205
  "tests/reapply-verify-hunks.test.cjs",
199
206
  "tests/refactor-1390-t3-characterization.test.cjs",
207
+ "tests/release-pipeline-pr.test.cjs",
200
208
  "tests/require-issue-link-policy.test.cjs",
201
209
  "tests/response-language-coverage.test.cjs",
202
210
  "tests/retired-artifact-cleanup.test.cjs",
203
211
  "tests/review-build-prompt-optional-sections.test.cjs",
204
212
  "tests/review-lane-invocation.test.cjs",
213
+ "tests/review-lane-prompt-cap.test.cjs",
205
214
  "tests/review-lane-runner.test.cjs",
206
215
  "tests/review-lane-windows-spawn-resolution.test.cjs",
207
216
  "tests/review-parallel-lanes.test.cjs",
@@ -229,6 +238,7 @@ module.exports = {
229
238
  "tests/shell-command-projection-md-normalize.test.cjs",
230
239
  "tests/shipped-reference-cites.test.cjs",
231
240
  "tests/skill-manifest.test.cjs",
241
+ "tests/smart-entry.unit.test.cjs",
232
242
  "tests/spawn-liveness-banner.test.cjs",
233
243
  "tests/state-document.test.cjs",
234
244
  "tests/state-transition.test.cjs",
@@ -4,6 +4,9 @@
4
4
  module.exports = {
5
5
  CONFORMANCE_TIER_FILES: [
6
6
  "tests/5100-win32-bare-bash-sentinel.property.test.cjs",
7
+ "tests/adr-612-bracket-new-project-config.test.cjs",
8
+ "tests/adr-612-bracket-phase-remove.test.cjs",
9
+ "tests/adr-612-bracket-write-path.test.cjs",
7
10
  "tests/adr-index-gate.test.cjs",
8
11
  "tests/adr857-core-without-capabilities.test.cjs",
9
12
  "tests/agent-install-check.test.cjs",
@@ -52,7 +55,9 @@ module.exports = {
52
55
  "tests/claude-md.test.cjs",
53
56
  "tests/cline-install.test.cjs",
54
57
  "tests/close-phase-todos-padded-resolves.test.cjs",
58
+ "tests/code-review-cicd.test.cjs",
55
59
  "tests/code-review-fix-pipeline-regression.test.cjs",
60
+ "tests/code-review-necessity.test.cjs",
56
61
  "tests/code-review-pipeline-regression.test.cjs",
57
62
  "tests/code-review-tier3-files-override-scoping.test.cjs",
58
63
  "tests/code-review.test.cjs",
@@ -86,6 +91,7 @@ module.exports = {
86
91
  "tests/cursor-hook-workspace-roots.test.cjs",
87
92
  "tests/cursor-hooks.test.cjs",
88
93
  "tests/cursor-subagent-isolation.test.cjs",
94
+ "tests/custom-phase-readers.test.cjs",
89
95
  "tests/debug-session-management.test.cjs",
90
96
  "tests/defaults-json-fallback.test.cjs",
91
97
  "tests/diagnose-windows-spawn-watcher.test.cjs",
@@ -96,6 +102,7 @@ module.exports = {
96
102
  "tests/effort-local-install.test.cjs",
97
103
  "tests/effort-surface-axis.test.cjs",
98
104
  "tests/effort-sync-installed-runtime.test.cjs",
105
+ "tests/effort-sync-manifest.test.cjs",
99
106
  "tests/emitted-ack-trailer.test.cjs",
100
107
  "tests/emitted-attribution.test.cjs",
101
108
  "tests/emitted-provenance.test.cjs",
@@ -134,6 +141,7 @@ module.exports = {
134
141
  "tests/gen-health-docs.test.cjs",
135
142
  "tests/gen-section-manifest.test.cjs",
136
143
  "tests/git-base-branch.test.cjs",
144
+ "tests/git-location-env-scrub.test.cjs",
137
145
  "tests/git-optional-locks-parity.test.cjs",
138
146
  "tests/golden-install-tree.test.cjs",
139
147
  "tests/graphify-graph-path.test.cjs",
@@ -143,8 +151,10 @@ module.exports = {
143
151
  "tests/gsd-check-update-worker-atomic-cache.test.cjs",
144
152
  "tests/gsd-check-update-worker-platform-gate.test.cjs",
145
153
  "tests/gsd-mcp-server-bin.test.cjs",
154
+ "tests/gsd-mcp-server.test.cjs",
146
155
  "tests/gsd-path-export-hook.test.cjs",
147
156
  "tests/gsd-statusline.test.cjs",
157
+ "tests/gsd-tool-dir.platform.test.cjs",
148
158
  "tests/gsd-validate-commit-crash-policy.test.cjs",
149
159
  "tests/gsd-validate-commit-sigpipe.test.cjs",
150
160
  "tests/gsd-write-guard.test.cjs",
@@ -268,6 +278,7 @@ module.exports = {
268
278
  "tests/process-seam.test.cjs",
269
279
  "tests/profile-output.test.cjs",
270
280
  "tests/profile-pipeline.test.cjs",
281
+ "tests/progress-drift-guard.test.cjs",
271
282
  "tests/prohibition-enforcement.test.cjs",
272
283
  "tests/project-root.test.cjs",
273
284
  "tests/quick-batch-command-router.stdin.test.cjs",
@@ -278,6 +289,8 @@ module.exports = {
278
289
  "tests/quick-review-scope-tip-bound.test.cjs",
279
290
  "tests/read-guard.test.cjs",
280
291
  "tests/reapply-verify-hunks.test.cjs",
292
+ "tests/release-ancestry.test.cjs",
293
+ "tests/release-backmerge-invariants.test.cjs",
281
294
  "tests/repo-layout.test.cjs",
282
295
  "tests/representative-corpus.test.cjs",
283
296
  "tests/require-fs-op-fallback.rule.test.cjs",
@@ -290,6 +303,7 @@ module.exports = {
290
303
  "tests/review-lane-availability.test.cjs",
291
304
  "tests/review-lane-invocation.test.cjs",
292
305
  "tests/review-lane-no-redirect-5433.test.cjs",
306
+ "tests/review-lane-prompt-cap.test.cjs",
293
307
  "tests/review-lane-runner.test.cjs",
294
308
  "tests/review-lane-windows-spawn-resolution.test.cjs",
295
309
  "tests/review-model-config.test.cjs",
@@ -327,6 +341,7 @@ module.exports = {
327
341
  "tests/shipped-reference-cites.test.cjs",
328
342
  "tests/skill-manifest.test.cjs",
329
343
  "tests/slug-derivation-drift-guard.test.cjs",
344
+ "tests/smart-entry.unit.test.cjs",
330
345
  "tests/state-todos-render.test.cjs",
331
346
  "tests/state.platform.test.cjs",
332
347
  "tests/subject-first-line.platform.test.cjs",
@@ -191,6 +191,10 @@
191
191
  * WHOLE ROADMAP (not milestone-scoped) for existing `2.N` ids — an id
192
192
  * collision it must avoid can come from any milestone, so it needs the
193
193
  * physical set, matching the CREATE-adjacent exemption category.
194
+ * - `src/phase.cts` `collectPhaseDirNums` (#5528): the allocators' one on-disk scan,
195
+ * run over the cwd's phases dir (cmdPhaseAdd/cmdPhaseAddBatch) and a sibling worktree's
196
+ * (collectSiblingWorktreePhaseNums). It builds the set of USED phase numbers across
197
+ * checkouts, not a milestone-scoped list, so listMilestonePhaseDirs cannot serve it.
194
198
  * - `src/phase.cts` `cmdPhasePlanIndex`: resolves ONE caller-supplied
195
199
  * `phase` id to its directory — a single-phase LOCATION lookup, not an
196
200
  * enumeration of the current milestone's phase set.
@@ -316,10 +320,10 @@ const FUNCTION_SCOPED_EXEMPTIONS = new Map([
316
320
  [path.join('src', 'gate-phase-context.cts'), new Set(['resolvePhaseDirByToken'])],
317
321
  [path.join('src', 'init.cts'), new Set(['detectHasPriorPhases', 'detectUiPhaseActive'])],
318
322
  [path.join('src', 'milestone.cts'), new Set(['archivePhaseDirectories', 'cmdMilestoneComplete', 'cmdPhasesClear'])],
319
- // #3849: collectSiblingWorktreePhaseNums reads a SIBLING worktree's phases dir —
320
- // a different checkout listMilestonePhaseDirs (cwd-scoped) cannot serve; the
321
- // allocators' own on-disk scans stay unexempted.
322
- [path.join('src', 'phase.cts'), new Set(['cmdPhasesList', 'cmdPhaseNextDecimal', 'cmdPhasePlanIndex', 'cmdPhaseInsert', 'renameDecimalPhases', 'renameIntegerPhases', 'collectSiblingWorktreePhaseNums'])],
323
+ // #3849/#5528: collectPhaseDirNums is the allocators' one on-disk scan (the cwd's phases dir for
324
+ // cmdPhaseAdd/cmdPhaseAddBatch, a sibling worktree's for collectSiblingWorktreePhaseNums). It is a
325
+ // used-NUMBER roster across checkouts, not the milestone-scoped list listMilestonePhaseDirs serves.
326
+ [path.join('src', 'phase.cts'), new Set(['cmdPhasesList', 'cmdPhaseNextDecimal', 'cmdPhasePlanIndex', 'cmdPhaseInsert', 'renameDecimalPhases', 'renameIntegerPhases', 'collectPhaseDirNums'])],
323
327
  [path.join('src', 'audit.cts'), new Set(['listAuditPhaseTargets'])],
324
328
  [path.join('src', 'commands.cts'), new Set(['cmdHistoryDigest'])],
325
329
  [path.join('src', 'state.cts'), new Set(['cmdStateValidate', 'cmdStateSync', 'cmdStateRebuild', 'countRoadmapPhaseHeadings'])],