@namewta/speculo 0.7.3 → 0.7.5

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 (199) hide show
  1. package/README.md +2 -2
  2. package/dist/src/migrations.js +190 -39
  3. package/dist/src/migrations.js.map +1 -1
  4. package/package.json +1 -1
  5. package/template/canonical/README.md +208 -63
  6. package/template/canonical/canonical-person-steelman-deliberation.md +518 -0
  7. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +51 -15
  8. package/template/canonical/canonical-specdev-goal-plan.md +183 -116
  9. package/template/canonical/canonical-specdev-grill-with-docs.md +51 -15
  10. package/template/canonical/canonical-specdev-spec.md +61 -21
  11. package/template/canonical/canonical-specdev-tickets.md +83 -43
  12. package/template/canonical/canonical-specdev-wayfinder.md +51 -15
  13. package/template/skills/engineering-standards-builder/README.md +43 -0
  14. package/template/skills/engineering-standards-builder/SKILL.md +233 -0
  15. package/template/skills/engineering-standards-builder/examples/README.md +15 -0
  16. package/template/skills/engineering-standards-builder/examples/fallback/kotlin-gradle/build.gradle.kts +5 -0
  17. package/template/skills/engineering-standards-builder/examples/fallback/kotlin-gradle/expected.json +12 -0
  18. package/template/skills/engineering-standards-builder/examples/fallback/kotlin-gradle/src/main/kotlin/example/App.kt +2 -0
  19. package/template/skills/engineering-standards-builder/examples/go/service/.golangci.yml +3 -0
  20. package/template/skills/engineering-standards-builder/examples/go/service/cmd/api/main.go +3 -0
  21. package/template/skills/engineering-standards-builder/examples/go/service/expected.json +23 -0
  22. package/template/skills/engineering-standards-builder/examples/go/service/go.mod +3 -0
  23. package/template/skills/engineering-standards-builder/examples/go/service/internal/service/service.go +2 -0
  24. package/template/skills/engineering-standards-builder/examples/go/service/internal/service/service_test.go +3 -0
  25. package/template/skills/engineering-standards-builder/examples/java/spring-boot-maven/expected.json +22 -0
  26. package/template/skills/engineering-standards-builder/examples/java/spring-boot-maven/pom.xml +12 -0
  27. package/template/skills/engineering-standards-builder/examples/java/spring-boot-maven/src/main/java/dev/speculo/orders/OrdersApplication.java +7 -0
  28. package/template/skills/engineering-standards-builder/examples/java/spring-boot-maven/src/test/java/dev/speculo/orders/OrdersApplicationTest.java +3 -0
  29. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/.github/workflows/ci.yml +11 -0
  30. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/apps/web/package.json +11 -0
  31. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/apps/web/src/App.vue +2 -0
  32. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/apps/web/tsconfig.json +8 -0
  33. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/expected.json +22 -0
  34. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/package.json +11 -0
  35. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/pnpm-workspace.yaml +2 -0
  36. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/services/orders/pom.xml +12 -0
  37. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/services/orders/src/main/java/dev/speculo/orders/OrdersApplication.java +7 -0
  38. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/services/worker/go.mod +3 -0
  39. package/template/skills/engineering-standards-builder/examples/polyglot/monorepo/services/worker/main.go +2 -0
  40. package/template/skills/engineering-standards-builder/examples/rust/workspace/Cargo.toml +7 -0
  41. package/template/skills/engineering-standards-builder/examples/rust/workspace/crates/cli/Cargo.toml +8 -0
  42. package/template/skills/engineering-standards-builder/examples/rust/workspace/crates/cli/src/main.rs +1 -0
  43. package/template/skills/engineering-standards-builder/examples/rust/workspace/crates/core/Cargo.toml +5 -0
  44. package/template/skills/engineering-standards-builder/examples/rust/workspace/crates/core/src/lib.rs +3 -0
  45. package/template/skills/engineering-standards-builder/examples/rust/workspace/expected.json +14 -0
  46. package/template/skills/engineering-standards-builder/examples/rust/workspace/rust-toolchain.toml +3 -0
  47. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/expected.json +21 -0
  48. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/package.json +20 -0
  49. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/src/App.test.tsx +2 -0
  50. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/src/App.tsx +1 -0
  51. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/src/main.tsx +3 -0
  52. package/template/skills/engineering-standards-builder/examples/typescript/react-vite/tsconfig.json +10 -0
  53. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/expected.json +22 -0
  54. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/package.json +21 -0
  55. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/src/App.test.ts +2 -0
  56. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/src/App.vue +7 -0
  57. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/src/main.ts +4 -0
  58. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/tsconfig.json +11 -0
  59. package/template/skills/engineering-standards-builder/examples/typescript/vue-vite/vite.config.ts +2 -0
  60. package/template/skills/engineering-standards-builder/manifest.txt +112 -0
  61. package/template/skills/engineering-standards-builder/references/go/00-detection-and-scope.md +37 -0
  62. package/template/skills/engineering-standards-builder/references/go/01-language-and-idioms.md +34 -0
  63. package/template/skills/engineering-standards-builder/references/go/02-modules-packages-and-layout.md +34 -0
  64. package/template/skills/engineering-standards-builder/references/go/03-errors-context-and-concurrency.md +38 -0
  65. package/template/skills/engineering-standards-builder/references/go/04-testing-tooling-quality-gates.md +46 -0
  66. package/template/skills/engineering-standards-builder/references/go/README.md +9 -0
  67. package/template/skills/engineering-standards-builder/references/java/00-detection-and-scope.md +40 -0
  68. package/template/skills/engineering-standards-builder/references/java/01-language-packages-and-api.md +35 -0
  69. package/template/skills/engineering-standards-builder/references/java/02-build-modules-and-dependencies.md +39 -0
  70. package/template/skills/engineering-standards-builder/references/java/03-errors-nullability-resources-concurrency.md +36 -0
  71. package/template/skills/engineering-standards-builder/references/java/04-testing-tooling-quality-gates.md +36 -0
  72. package/template/skills/engineering-standards-builder/references/java/README.md +10 -0
  73. package/template/skills/engineering-standards-builder/references/java/frameworks/spring-boot.md +74 -0
  74. package/template/skills/engineering-standards-builder/references/rules/00-governance-and-precedence.md +52 -0
  75. package/template/skills/engineering-standards-builder/references/rules/01-project-discovery.md +79 -0
  76. package/template/skills/engineering-standards-builder/references/rules/02-evidence-topology-and-scope.md +87 -0
  77. package/template/skills/engineering-standards-builder/references/rules/03-interview-and-decisions.md +77 -0
  78. package/template/skills/engineering-standards-builder/references/rules/04-architecture-and-dependency-boundaries.md +58 -0
  79. package/template/skills/engineering-standards-builder/references/rules/05-files-directories-and-naming.md +53 -0
  80. package/template/skills/engineering-standards-builder/references/rules/06-apis-errors-resources-and-concurrency.md +53 -0
  81. package/template/skills/engineering-standards-builder/references/rules/07-documentation-and-comments.md +46 -0
  82. package/template/skills/engineering-standards-builder/references/rules/08-testing-strategy.md +45 -0
  83. package/template/skills/engineering-standards-builder/references/rules/09-security-configuration-and-data.md +44 -0
  84. package/template/skills/engineering-standards-builder/references/rules/10-performance-observability-and-i18n.md +36 -0
  85. package/template/skills/engineering-standards-builder/references/rules/11-tooling-quality-gates-and-ci.md +69 -0
  86. package/template/skills/engineering-standards-builder/references/rules/12-git-review-and-delivery.md +46 -0
  87. package/template/skills/engineering-standards-builder/references/rules/13-adoption-exceptions-and-ratchets.md +60 -0
  88. package/template/skills/engineering-standards-builder/references/rules/14-generation-contract.md +105 -0
  89. package/template/skills/engineering-standards-builder/references/rules/15-validation-contract.md +65 -0
  90. package/template/skills/engineering-standards-builder/references/rules/16-language-adapter-contract.md +55 -0
  91. package/template/skills/engineering-standards-builder/references/rules/README.md +23 -0
  92. package/template/skills/engineering-standards-builder/references/rust/00-detection-and-scope.md +38 -0
  93. package/template/skills/engineering-standards-builder/references/rust/01-language-api-and-safety.md +35 -0
  94. package/template/skills/engineering-standards-builder/references/rust/02-crates-workspaces-and-layout.md +36 -0
  95. package/template/skills/engineering-standards-builder/references/rust/03-errors-ownership-and-concurrency.md +37 -0
  96. package/template/skills/engineering-standards-builder/references/rust/04-testing-tooling-quality-gates.md +44 -0
  97. package/template/skills/engineering-standards-builder/references/rust/README.md +9 -0
  98. package/template/skills/engineering-standards-builder/references/typescript/00-detection-and-scope.md +58 -0
  99. package/template/skills/engineering-standards-builder/references/typescript/01-language-and-type-system.md +49 -0
  100. package/template/skills/engineering-standards-builder/references/typescript/02-modules-packages-and-runtime-boundaries.md +49 -0
  101. package/template/skills/engineering-standards-builder/references/typescript/03-functions-async-errors-resources.md +42 -0
  102. package/template/skills/engineering-standards-builder/references/typescript/04-testing-tooling-quality-gates.md +51 -0
  103. package/template/skills/engineering-standards-builder/references/typescript/README.md +27 -0
  104. package/template/skills/engineering-standards-builder/references/typescript/app-types/cli.md +11 -0
  105. package/template/skills/engineering-standards-builder/references/typescript/app-types/library.md +11 -0
  106. package/template/skills/engineering-standards-builder/references/typescript/frameworks/react.md +71 -0
  107. package/template/skills/engineering-standards-builder/references/typescript/frameworks/vue.md +131 -0
  108. package/template/skills/engineering-standards-builder/references/typescript/runtimes/browser.md +15 -0
  109. package/template/skills/engineering-standards-builder/references/typescript/runtimes/electron.md +25 -0
  110. package/template/skills/engineering-standards-builder/references/typescript/runtimes/node.md +13 -0
  111. package/template/skills/engineering-standards-builder/scripts/discover-project.mjs +957 -0
  112. package/template/skills/engineering-standards-builder/scripts/self-test.mjs +203 -0
  113. package/template/skills/engineering-standards-builder/scripts/sync-manifest.mjs +105 -0
  114. package/template/skills/engineering-standards-builder/scripts/validate-builder.mjs +255 -0
  115. package/template/skills/engineering-standards-builder/scripts/validate-generated-skill.mjs +286 -0
  116. package/template/skills/engineering-standards-builder/templates/README.md +18 -0
  117. package/template/skills/engineering-standards-builder/templates/compatibility/agents-typescript--standards.md +6 -0
  118. package/template/skills/engineering-standards-builder/templates/compatibility/agents-typescript-standards.md +6 -0
  119. package/template/skills/engineering-standards-builder/templates/compatibility/claude-engineering-standards.md +6 -0
  120. package/template/skills/engineering-standards-builder/templates/compatibility/claude-typescript-standards.md +6 -0
  121. package/template/skills/engineering-standards-builder/templates/project-skill/SKILL.md.template +26 -0
  122. package/template/skills/engineering-standards-builder/templates/project-skill/references/project/00-project-profile.md.template +26 -0
  123. package/template/skills/engineering-standards-builder/templates/project-skill/references/project/01-module-map.md.template +27 -0
  124. package/template/skills/engineering-standards-builder/templates/project-skill/references/project/02-decisions-and-exceptions.md.template +31 -0
  125. package/template/skills/engineering-standards-builder/templates/project-skill/references/project/review-checklist.md.template +14 -0
  126. package/template/skills/migrate-runtime-state/references/migration-contract.md +3 -3
  127. package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +94 -12
  128. package/template/skills/source-code-zip-skill/SKILL.md +343 -0
  129. package/template/skills/source-code-zip-skill/scripts/zip_source_code.py +638 -0
  130. package/template/workflows/person/INDEX.md +1 -0
  131. package/template/workflows/person/S-steelman-deliberation/S-steelman-deliberation.md +218 -0
  132. package/template/workflows/person/S-steelman-deliberation/_templates/decision-template.md +51 -0
  133. package/template/workflows/person/S-steelman-deliberation/_templates/steelman-dossier-template.md +96 -0
  134. package/template/workflows/person/S-steelman-deliberation/deliberate.md +127 -0
  135. package/template/workflows/person/S-steelman-deliberation/evidence-gate.md +37 -0
  136. package/template/workflows/person/S-steelman-deliberation/judge.md +69 -0
  137. package/template/workflows/person/S-steelman-deliberation/tools/validate-steelman-change.mjs +697 -0
  138. package/template/workflows/specdev/I-implement/I-implement.md +27 -26
  139. package/template/workflows/specdev/I-implement/evidence-template.md +18 -12
  140. package/template/workflows/specdev/I-implement/execution-preflight.md +11 -9
  141. package/template/workflows/specdev/I-init-setup/I-init-setup.md +2 -2
  142. package/template/workflows/specdev/I-init-setup/change-status-template.json +3 -3
  143. package/template/workflows/specdev/I-init-setup/config-template.json +5 -2
  144. package/template/workflows/specdev/INDEX.md +6 -6
  145. package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +16 -16
  146. package/template/workflows/specdev/P-goal-plan/completion-control.md +8 -8
  147. package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +20 -14
  148. package/template/workflows/specdev/P-goal-plan/lead-orchestration.md +5 -5
  149. package/template/workflows/specdev/P-goal-plan/orchestration-protocol.md +13 -13
  150. package/template/workflows/specdev/P-goal-plan/planning-modes.md +27 -15
  151. package/template/workflows/specdev/P-prototype/ui-prototype.md +1 -1
  152. package/template/workflows/specdev/T-tickets/T-tickets.md +4 -4
  153. package/template/workflows/specdev/T-tickets/ticket-readiness.md +3 -3
  154. package/template/workflows/specdev/T-tickets/ticket-template.md +6 -6
  155. package/template/workflows/specdev/T-tickets/tickets-map-template.md +2 -2
  156. package/template/workflows/specdev/common/README.md +1 -1
  157. package/template/workflows/specdev/common/rules/change-completion.md +2 -2
  158. package/template/workflows/specdev/common/rules/evidence-and-verification.md +10 -6
  159. package/template/workflows/specdev/common/rules/path-ownership.md +4 -4
  160. package/template/workflows/specdev/common/schemas/change-status.schema.json +31 -4
  161. package/template/workflows/specdev/common/schemas/config.schema.json +12 -6
  162. package/template/workflows/specdev/common/schemas/goal-plan.schema.json +15 -6
  163. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +3 -3
  164. package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +1 -1
  165. package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +4 -4
  166. package/template/workflows/specdev/common/skills/subagent-delivery/references/external-web-subagent.md +1 -1
  167. package/template/workflows/specdev/common/skills/subagent-delivery/references/native-subagent.md +4 -4
  168. package/template/workflows/specdev/common/tools/README.md +2 -1
  169. package/template/workflows/specdev/common/tools/validate-specdev.mjs +261 -66
  170. package/template/skills/typescript-standards-builder/README.md +0 -53
  171. package/template/skills/typescript-standards-builder/SKILL.md +0 -245
  172. package/template/skills/typescript-standards-builder/examples/sample-generated-tree.md +0 -30
  173. package/template/skills/typescript-standards-builder/examples/sample-interview-decisions.md +0 -26
  174. package/template/skills/typescript-standards-builder/manifest.txt +0 -29
  175. package/template/skills/typescript-standards-builder/references/00-governance-and-fixed-defaults.md +0 -77
  176. package/template/skills/typescript-standards-builder/references/01-project-discovery.md +0 -100
  177. package/template/skills/typescript-standards-builder/references/02-interview-workflow.md +0 -129
  178. package/template/skills/typescript-standards-builder/references/03-project-architecture-and-directory-layout.md +0 -84
  179. package/template/skills/typescript-standards-builder/references/04-file-directory-and-symbol-naming.md +0 -92
  180. package/template/skills/typescript-standards-builder/references/05-modules-imports-exports-and-dependencies.md +0 -63
  181. package/template/skills/typescript-standards-builder/references/06-typescript-type-system.md +0 -64
  182. package/template/skills/typescript-standards-builder/references/07-functions-async-errors-and-resources.md +0 -42
  183. package/template/skills/typescript-standards-builder/references/08-comments-jsdoc-and-documentation.md +0 -51
  184. package/template/skills/typescript-standards-builder/references/09-testing-strategy.md +0 -58
  185. package/template/skills/typescript-standards-builder/references/10-react-and-frontend.md +0 -39
  186. package/template/skills/typescript-standards-builder/references/11-node-cli-and-cross-platform.md +0 -31
  187. package/template/skills/typescript-standards-builder/references/12-formatting-lint-and-complexity.md +0 -58
  188. package/template/skills/typescript-standards-builder/references/13-configuration-dependencies-and-ci.md +0 -71
  189. package/template/skills/typescript-standards-builder/references/14-security-performance-and-i18n.md +0 -32
  190. package/template/skills/typescript-standards-builder/references/15-git-review-and-delivery.md +0 -28
  191. package/template/skills/typescript-standards-builder/references/16-adoption-exceptions-and-migration.md +0 -61
  192. package/template/skills/typescript-standards-builder/references/17-generation-contract.md +0 -104
  193. package/template/skills/typescript-standards-builder/references/README.md +0 -37
  194. package/template/skills/typescript-standards-builder/templates/agents-compat-skill/SKILL.md +0 -1
  195. package/template/skills/typescript-standards-builder/templates/claude-skill/SKILL.md +0 -1
  196. package/template/skills/typescript-standards-builder/templates/project-skill/SKILL.md.template +0 -34
  197. package/template/skills/typescript-standards-builder/templates/project-skill/references/00-project-profile.md.template +0 -17
  198. package/template/skills/typescript-standards-builder/templates/project-skill/references/10-review-checklist.md +0 -23
  199. package/template/skills/typescript-standards-builder/templates/project-skill/references/11-decisions-and-exceptions.md.template +0 -19
package/README.md CHANGED
@@ -60,7 +60,7 @@ After initialization, the target project gains the following AI agent-callable a
60
60
  | `migrate-runtime-state` | Validate backups, lock source/target fingerprints, and apply runtime migration plans with rollback |
61
61
  | `optimize-codex-config` | Audit and optimize local Codex configuration, custom Responses providers, permissions, and compaction failures |
62
62
  | `speculo-retro` | Retrospective analysis |
63
- | `typescript-standards-builder` | Interview-driven generator that produces a project-specific TypeScript/JS/React/Node standards skill |
63
+ | `engineering-standards-builder` | Interview-driven generator that produces a project-specific TypeScript/JS/React/Node standards skill |
64
64
  | `writing-great-skills` | Authoring guidance for agent skills |
65
65
 
66
66
  ### 2 Workflow Packages
@@ -68,7 +68,7 @@ After initialization, the target project gains the following AI agent-callable a
68
68
  | Workflow | Work Entries | Description |
69
69
  |---|---:|---|
70
70
  | **specdev** | 14 | Local-first specification-driven development: archive, code review, diagnosis, mentoring, grilling, implementation, setup, goal planning, prototyping, architecture review, specs, tickets, triage, and wayfinding |
71
- | **person** | 1 | Persona-methodology-based consulting workflow (Mao Zedong Cognitive OS) |
71
+ | **person** | 2 | Persona-methodology and rigorous deliberation workflows (Mao Zedong Cognitive OS; Bidirectional Steelman Deliberation) |
72
72
 
73
73
  Every workflow ships an `INDEX.md` as its auto-generated work catalog. Work entries follow `<Letter>-<work_name>/<Letter>-<work_name>.md` naming with progressive-disclosure sub-files, and resolve runtime paths via `<Path>{roots.xxx}/...</Path>` pointers in `workspace.json`.
74
74
 
@@ -6,6 +6,9 @@ const BACKUP_RELATIVE = ".speculo/back";
6
6
  const INSTALL_RELATIVE = ".speculo/install.json";
7
7
  const MIGRATION_RELATIVE = ".speculo/migration.json";
8
8
  const SNAPSHOT_DIR = ".migration-snapshot";
9
+ const CONFIG_SCHEMA_VERSION = 5;
10
+ const GOAL_PLAN_SCHEMA_VERSION = 6;
11
+ const CHANGE_STATUS_SCHEMA_VERSION = 6;
9
12
  const MANAGED_STATE_ENTRIES = new Set([
10
13
  "README.md",
11
14
  "workspace.json",
@@ -191,7 +194,7 @@ function hasCompleteV4Integration(integration, worktreeStatus, sourceCheckpoint,
191
194
  return false;
192
195
  if (!new Set(["pending", "candidate", "passed", "failed", "stale"]).has(String(integration.status)))
193
196
  return false;
194
- if (![null, "fast-forward", "merge-commit"].includes(integration.method))
197
+ if (![null, "direct-parent", "fast-forward", "merge-commit"].includes(integration.method))
195
198
  return false;
196
199
  if (!new Set(["pending", "passed", "failed"]).has(String(integration.verification)))
197
200
  return false;
@@ -224,15 +227,18 @@ function hasCompleteV4Integration(integration, worktreeStatus, sourceCheckpoint,
224
227
  return false;
225
228
  if (e2e.required === true && e2e.status === "passed" && !isNonEmptyString(e2e.evidence))
226
229
  return false;
230
+ const currentWorkspace = integration.method === "direct-parent";
227
231
  const lifecycleNeedsCandidate = new Set(["integrating", "integrated", "removed"]).has(String(worktreeStatus));
228
232
  if (lifecycleNeedsCandidate) {
229
233
  if (!isNonEmptyString(integration.parent_before_sha) ||
230
234
  !isNonEmptyString(integration.source_sha) ||
231
235
  integration.source_sha !== sourceCheckpoint ||
232
- !isNonEmptyString(integration.candidate_sha) ||
233
- integration.candidate_branch !== `speculo/integration/${change}/${ticketId}` ||
234
- integration.candidate_workspace_ref !== `specdev-worktree/.integration/${ticketId}` ||
235
- !new Set(["fast-forward", "merge-commit"]).has(String(integration.method)) ||
236
+ (currentWorkspace
237
+ ? integration.candidate_sha !== null || integration.candidate_branch !== null || integration.candidate_workspace_ref !== null || integration.method !== "direct-parent"
238
+ : !isNonEmptyString(integration.candidate_sha) ||
239
+ integration.candidate_branch !== `speculo/integration/${change}/${ticketId}` ||
240
+ integration.candidate_workspace_ref !== `specdev-worktree/.integration/${ticketId}` ||
241
+ !new Set(["fast-forward", "merge-commit"]).has(String(integration.method))) ||
236
242
  !Number.isInteger(integration.attempts) ||
237
243
  Number(integration.attempts) < 1)
238
244
  return false;
@@ -243,7 +249,7 @@ function hasCompleteV4Integration(integration, worktreeStatus, sourceCheckpoint,
243
249
  if (integration.status !== "passed" ||
244
250
  integration.verification !== "passed" ||
245
251
  !isNonEmptyString(integration.result_sha) ||
246
- integration.result_sha !== integration.candidate_sha ||
252
+ integration.result_sha !== (currentWorkspace ? integration.source_sha : integration.candidate_sha) ||
247
253
  !new Set(["not-required", "passed"]).has(String(e2e.status)))
248
254
  return false;
249
255
  if (integration.method === "fast-forward" &&
@@ -327,16 +333,17 @@ function hasCompleteV4ChangeStatus(status) {
327
333
  if (!isNonEmptyString(entry[key]))
328
334
  return false;
329
335
  }
330
- if (entry.parent_branch === entry.branch)
336
+ const integration = isJsonObject(entry.integration) ? entry.integration : {};
337
+ const currentWorkspace = entry.workspace_ref === "current" || integration.method === "direct-parent";
338
+ if (currentWorkspace ? entry.parent_branch !== entry.branch : entry.parent_branch === entry.branch)
331
339
  return false;
332
- if (entry.workspace_ref !== `specdev-worktree/${entry.ticket_id}`)
340
+ if (!currentWorkspace && entry.workspace_ref !== `specdev-worktree/${entry.ticket_id}`)
333
341
  return false;
334
342
  if (!new Set(["planned", "active", "review", "integrating", "integrated", "removed", "blocked"]).has(String(entry.status)))
335
343
  return false;
336
344
  const sourceRequired = new Set(["review", "integrating", "integrated", "removed"]).has(String(entry.status));
337
345
  if (sourceRequired ? !isNonEmptyString(entry.source_checkpoint) : !isStringOrNull(entry.source_checkpoint))
338
346
  return false;
339
- const integration = entry.integration;
340
347
  return isJsonObject(integration) && hasCompleteV4Integration(integration, entry.status, entry.source_checkpoint, String(status.change), entry.ticket_id);
341
348
  });
342
349
  }
@@ -357,7 +364,7 @@ function hasCompleteV4SpecdevConfig(config) {
357
364
  if (!hasExactKeys(config.execution, ["max_implementation_agents", "deep_ticket_human_approval", "shared_path_owner"]))
358
365
  return false;
359
366
  const limit = config.execution.max_implementation_agents;
360
- if (!Number.isInteger(limit) || Number(limit) < 1 || Number(limit) > 3 ||
367
+ if (!Number.isInteger(limit) || Number(limit) < 1 ||
361
368
  typeof config.execution.deep_ticket_human_approval !== "boolean" ||
362
369
  !isNonEmptyString(config.execution.shared_path_owner))
363
370
  return false;
@@ -369,6 +376,30 @@ function hasCompleteV4SpecdevConfig(config) {
369
376
  typeof config.planning.require_ready_gate === "boolean" &&
370
377
  typeof config.planning.require_evidence === "boolean";
371
378
  }
379
+ function hasCompleteV5SpecdevConfig(config) {
380
+ const rootKeys = ["schema_version", "interaction_language", "artifact_language", "git", "execution", "verification", "planning"];
381
+ if (config.schema_version !== CONFIG_SCHEMA_VERSION || !hasExactKeys(config, rootKeys) ||
382
+ !isNonEmptyString(config.interaction_language) || !isNonEmptyString(config.artifact_language) ||
383
+ !isJsonObject(config.git) || !isJsonObject(config.execution) || !isJsonObject(config.verification) || !isJsonObject(config.planning))
384
+ return false;
385
+ if (!hasExactKeys(config.git, ["default_branch"]) || !(config.git.default_branch === null || typeof config.git.default_branch === "string"))
386
+ return false;
387
+ if (!hasExactKeys(config.execution, ["max_implementation_agents", "max_integration_attempts", "deep_ticket_human_approval", "shared_path_owner"]))
388
+ return false;
389
+ if (!Number.isInteger(config.execution.max_implementation_agents) || Number(config.execution.max_implementation_agents) < 1 ||
390
+ !Number.isInteger(config.execution.max_integration_attempts) || Number(config.execution.max_integration_attempts) < 1 ||
391
+ typeof config.execution.deep_ticket_human_approval !== "boolean" || !isNonEmptyString(config.execution.shared_path_owner))
392
+ return false;
393
+ for (const key of ["test", "typecheck", "lint", "build"]) {
394
+ if (!(key in config.verification) || !isStringOrNull(config.verification[key]))
395
+ return false;
396
+ }
397
+ return new Set(["lite", "standard", "deep"]).has(String(config.planning.default_depth)) &&
398
+ typeof config.planning.require_ready_gate === "boolean" &&
399
+ typeof config.planning.require_evidence === "boolean" &&
400
+ Number.isInteger(config.planning.ui_prototype_default_variants) && Number(config.planning.ui_prototype_default_variants) >= 1 &&
401
+ Number.isInteger(config.planning.ui_prototype_max_variants) && Number(config.planning.ui_prototype_max_variants) >= Number(config.planning.ui_prototype_default_variants);
402
+ }
372
403
  function parseGoalPlanFrontmatter(text) {
373
404
  const lines = text.split(/\r?\n/);
374
405
  if (lines[0]?.trim() !== "---")
@@ -431,12 +462,35 @@ function hasCompleteV5GoalPlan(meta, change) {
431
462
  return (new Set(["ready", "in_progress"]).has(status) && meta.ready_for_execution === true) ||
432
463
  (new Set(["draft", "blocked", "completed"]).has(status) && meta.ready_for_execution === false);
433
464
  }
465
+ function hasCompleteV6GoalPlan(meta, change) {
466
+ const required = [
467
+ "schema_version", "artifact", "change", "status", "modes", "orchestration", "lead",
468
+ "implementation_agent_limit", "integration_attempt_limit", "ticket_workspace_policy", "integration_gate", "ready_for_execution",
469
+ ];
470
+ if (!hasExactKeys(meta, required) || meta.schema_version !== GOAL_PLAN_SCHEMA_VERSION)
471
+ return false;
472
+ const { integration_attempt_limit: integrationAttemptLimit, ...previous } = meta;
473
+ return hasCompleteV5GoalPlan({ ...previous, schema_version: 5 }, change) &&
474
+ Number.isInteger(integrationAttemptLimit) && Number(integrationAttemptLimit) >= 1;
475
+ }
434
476
  function normalizeGoalPlanV5(text) {
435
477
  const meta = parseGoalPlanFrontmatter(text);
436
478
  if (meta === null || !hasCompleteV4GoalPlan(meta, String(meta.change)))
437
479
  return text;
438
480
  return text.replace(/^schema_version:\s*4\s*$/m, "schema_version: 5");
439
481
  }
482
+ function normalizeGoalPlanV6(text, config) {
483
+ const meta = parseGoalPlanFrontmatter(text);
484
+ if (meta === null || meta.schema_version !== 5 || !hasCompleteV5GoalPlan(meta, String(meta.change)))
485
+ return text;
486
+ const execution = isJsonObject(config.execution) ? config.execution : {};
487
+ const attempts = Number.isInteger(execution.max_integration_attempts) && Number(execution.max_integration_attempts) >= 1
488
+ ? Number(execution.max_integration_attempts)
489
+ : 3;
490
+ return text
491
+ .replace(/^schema_version:\s*5\s*$/m, "schema_version: 6")
492
+ .replace(/^(implementation_agent_limit:\s*[^\n]+)$/m, `$1\nintegration_attempt_limit: ${attempts}`);
493
+ }
440
494
  function v5Authorization(scope) {
441
495
  return { status: "not-authorized", source: null, granted_at: null, scope };
442
496
  }
@@ -452,12 +506,21 @@ function normalizeChangeStatusV5(previous, globalEntry) {
452
506
  const sourceCheckpoint = isStringOrNull(entry.source_checkpoint) ? entry.source_checkpoint : null;
453
507
  return {
454
508
  ...entry,
455
- workspace_ref: `specdev-worktree/${change}/${ticketId}`,
509
+ workspace_ref: entry.workspace_ref === "current" || integration.method === "direct-parent"
510
+ ? "current"
511
+ : `specdev-worktree/${change}/${ticketId}`,
512
+ branch: entry.workspace_ref === "current" || integration.method === "direct-parent"
513
+ ? entry.parent_branch
514
+ : entry.branch,
456
515
  integration: {
457
516
  ...integration,
458
517
  parent_ref: typeof entry.parent_branch === "string" ? entry.parent_branch : null,
459
- candidate_tree_sha: integration.candidate_sha ?? null,
460
- candidate_workspace_ref: integration.candidate_workspace_ref === null ? null : `specdev-worktree/.integration/${change}/${ticketId}`,
518
+ candidate_sha: entry.workspace_ref === "current" || integration.method === "direct-parent" ? null : integration.candidate_sha ?? null,
519
+ candidate_tree_sha: entry.workspace_ref === "current" || integration.method === "direct-parent" ? null : integration.candidate_sha ?? null,
520
+ candidate_branch: entry.workspace_ref === "current" || integration.method === "direct-parent" ? null : integration.candidate_branch ?? null,
521
+ candidate_workspace_ref: entry.workspace_ref === "current" || integration.method === "direct-parent"
522
+ ? null
523
+ : integration.candidate_workspace_ref === null ? null : `specdev-worktree/.integration/${change}/${ticketId}`,
461
524
  full_suite: { required: true, status: "pending", reason: null, evidence: null },
462
525
  promotion_status: integration.status === "passed" ? "applied" : "pending",
463
526
  source_sha: integration.source_sha ?? sourceCheckpoint,
@@ -474,8 +537,8 @@ function normalizeChangeStatusV5(previous, globalEntry) {
474
537
  id: String(claim.id ?? ""), owner: String(claim.owner ?? ""), session: typeof claim.session === "string" ? claim.session : null, claimed_at: String(claim.claimed_at ?? ""),
475
538
  } : claim) : [],
476
539
  execution_authorization: {
477
- implementation_commit: v5Authorization("Ticket source commits"),
478
- local_candidate_integration: v5Authorization("Lead-owned local parent candidate integration and parent update"),
540
+ implementation_commit: v5Authorization("Ticket implementation commits"),
541
+ local_candidate_integration: v5Authorization("Lead-owned local direct-parent or candidate integration and parent update"),
479
542
  source_cleanup: v5Authorization("Source worktree and branch cleanup"),
480
543
  },
481
544
  leadership: { current: "unassigned", epoch: 1, assigned_at: String(previous.updated_at), history: [] },
@@ -502,8 +565,61 @@ function hasCompleteV5ChangeStatus(status) {
502
565
  return false;
503
566
  }
504
567
  const leadership = status.leadership;
505
- return isNonEmptyString(leadership.current) && Number.isInteger(leadership.epoch) && Number(leadership.epoch) >= 1 &&
506
- isNonEmptyString(leadership.assigned_at) && Array.isArray(leadership.history);
568
+ if (!isNonEmptyString(leadership.current) || !Number.isInteger(leadership.epoch) || Number(leadership.epoch) < 1 ||
569
+ !isNonEmptyString(leadership.assigned_at) || !Array.isArray(leadership.history) || !Array.isArray(status.worktrees))
570
+ return false;
571
+ const change = String(status.change);
572
+ const worktreeKeys = [
573
+ "ticket_id", "owner", "implementation_owner", "integration_owner", "provider", "base_sha",
574
+ "parent_branch", "branch", "workspace_ref", "source_checkpoint", "integration", "status", "updated_at",
575
+ ];
576
+ const integrationKeys = [
577
+ "status", "parent_ref", "parent_before_sha", "source_sha", "candidate_sha", "candidate_tree_sha",
578
+ "candidate_branch", "candidate_workspace_ref", "result_sha", "method", "conflict_paths", "verification",
579
+ "full_suite", "e2e", "evidence", "attempts", "promotion_status",
580
+ ];
581
+ return status.worktrees.every((entry) => {
582
+ if (!isJsonObject(entry) || !hasExactKeys(entry, worktreeKeys) || entry.provider !== "git" ||
583
+ typeof entry.ticket_id !== "string" || !/^T-[0-9]{2,}$/.test(entry.ticket_id) || !isJsonObject(entry.integration))
584
+ return false;
585
+ const current = entry.workspace_ref === "current";
586
+ if (current ? entry.branch !== entry.parent_branch : entry.workspace_ref !== `specdev-worktree/${change}/${entry.ticket_id}` || entry.branch === entry.parent_branch)
587
+ return false;
588
+ const integration = entry.integration;
589
+ if (!hasExactKeys(integration, integrationKeys) || !Number.isInteger(integration.attempts) || Number(integration.attempts) < 0 ||
590
+ !isStringArray(integration.conflict_paths) || !isNonEmptyString(integration.evidence))
591
+ return false;
592
+ for (const key of ["full_suite", "e2e"]) {
593
+ const suite = integration[key];
594
+ if (!isJsonObject(suite) || !hasExactKeys(suite, ["required", "status", "reason", "evidence"]) || typeof suite.required !== "boolean")
595
+ return false;
596
+ }
597
+ return true;
598
+ });
599
+ }
600
+ function hasCompleteV6ChangeStatus(status) {
601
+ if (status.schema_version !== CHANGE_STATUS_SCHEMA_VERSION)
602
+ return false;
603
+ const previous = { ...status, schema_version: 5 };
604
+ if (!hasCompleteV5ChangeStatus(previous) || !Array.isArray(status.worktrees))
605
+ return false;
606
+ return status.worktrees.every((entry) => {
607
+ if (!isJsonObject(entry) || !isJsonObject(entry.integration))
608
+ return false;
609
+ const current = entry.workspace_ref === "current";
610
+ if (current && entry.parent_branch !== entry.branch)
611
+ return false;
612
+ if (!current && entry.parent_branch === entry.branch)
613
+ return false;
614
+ const integration = entry.integration;
615
+ if (current && ["candidate_sha", "candidate_tree_sha", "candidate_branch", "candidate_workspace_ref"].some((key) => integration[key] !== null))
616
+ return false;
617
+ if (current && integration.method !== null && integration.method !== "direct-parent")
618
+ return false;
619
+ if (!current && integration.method === "direct-parent")
620
+ return false;
621
+ return true;
622
+ });
507
623
  }
508
624
  function hasCompleteV4GoalPlan(meta, change) {
509
625
  const required = [
@@ -520,9 +636,10 @@ function hasCompleteV4GoalPlan(meta, change) {
520
636
  !isNonEmptyString(meta.lead) ||
521
637
  !Number.isInteger(meta.implementation_agent_limit) ||
522
638
  Number(meta.implementation_agent_limit) < 1 ||
523
- Number(meta.implementation_agent_limit) > 3 ||
524
- meta.ticket_workspace_policy !== "required" ||
525
- meta.integration_gate !== "candidate-merge" ||
639
+ !new Set(["current", "required"]).has(String(meta.ticket_workspace_policy)) ||
640
+ !new Set(["direct-parent", "candidate-merge"]).has(String(meta.integration_gate)) ||
641
+ (meta.ticket_workspace_policy === "current" && meta.integration_gate !== "direct-parent") ||
642
+ (meta.ticket_workspace_policy === "required" && meta.integration_gate !== "candidate-merge") ||
526
643
  typeof meta.ready_for_execution !== "boolean" ||
527
644
  !Array.isArray(meta.modes))
528
645
  return false;
@@ -535,12 +652,12 @@ async function inspectGoalPlanVersion(stateRoot, change, blockers) {
535
652
  if (!(await pathExists(path)))
536
653
  return;
537
654
  const frontmatter = parseGoalPlanFrontmatter(await readFile(path, "utf8"));
538
- const currentContract = frontmatter !== null && hasCompleteV5GoalPlan(frontmatter, change);
655
+ const currentContract = frontmatter !== null && (hasCompleteV6GoalPlan(frontmatter, change) || hasCompleteV5GoalPlan(frontmatter, change));
539
656
  if (!currentContract) {
540
657
  blockers.push({
541
658
  code: "unsupported-goal-plan-contract",
542
659
  path: `.speculo/specdev/changes/${change}/goal-plan.md`,
543
- message: "Goal Plan must contain the complete fixed Lead and candidate-integration v5 frontmatter contract",
660
+ message: "Goal Plan must contain the complete Lead and workspace/integration v6 frontmatter contract",
544
661
  });
545
662
  }
546
663
  }
@@ -582,11 +699,11 @@ async function inspectSpecdevState(stateRoot) {
582
699
  else {
583
700
  try {
584
701
  const changeStatus = await readJson(changeStatusPath);
585
- if (!new Set([3, 4, 5]).has(Number(changeStatus.schema_version)) ||
702
+ if (!new Set([3, 4, 5, 6]).has(Number(changeStatus.schema_version)) ||
586
703
  changeStatus.artifact !== "change-status" ||
587
704
  changeStatus.change !== name ||
588
705
  !new Set(["active", "blocked", "completed"]).has(String(changeStatus.change_status))) {
589
- blockers.push({ code: "unsupported-change-status", path: `.speculo/specdev/changes/${name}/.status.json`, message: "active change state must use schema v3/v4 and match its index entry" });
706
+ blockers.push({ code: "unsupported-change-status", path: `.speculo/specdev/changes/${name}/.status.json`, message: "active change state must use schema v3/v4/v5/v6 and match its index entry" });
590
707
  }
591
708
  else if (hasLegacyWorktreeState(changeStatus)) {
592
709
  blockers.push({
@@ -616,6 +733,9 @@ async function inspectSpecdevState(stateRoot) {
616
733
  message: "change-status v5 is missing required runtime authority fields",
617
734
  });
618
735
  }
736
+ else if (changeStatus.schema_version === 6 && !hasCompleteV6ChangeStatus(changeStatus)) {
737
+ blockers.push({ code: "invalid-change-status-v6", path: `.speculo/specdev/changes/${name}/.status.json`, message: "change-status v6 has inconsistent current/required workspace fields" });
738
+ }
619
739
  await inspectGoalPlanVersion(stateRoot, name, blockers);
620
740
  }
621
741
  catch {
@@ -646,7 +766,7 @@ async function inspectSpecdevState(stateRoot) {
646
766
  else {
647
767
  try {
648
768
  const archivedStatus = await readJson(archivedStatusPath);
649
- if (!new Set([3, 4]).has(Number(archivedStatus.schema_version)) ||
769
+ if (!new Set([3, 4, 5, 6]).has(Number(archivedStatus.schema_version)) ||
650
770
  archivedStatus.artifact !== "change-status" ||
651
771
  archivedStatus.change !== item ||
652
772
  archivedStatus.change_status !== "archived") {
@@ -673,6 +793,12 @@ async function inspectSpecdevState(stateRoot) {
673
793
  message: "archived change-status v4 is incomplete",
674
794
  });
675
795
  }
796
+ else if (archivedStatus.schema_version === 5 && !hasCompleteV5ChangeStatus(archivedStatus)) {
797
+ blockers.push({ code: "invalid-archived-status-v5", path: `.speculo/specdev/archive/${month}/${item}/.status.json`, message: "archived change-status v5 is incomplete" });
798
+ }
799
+ else if (archivedStatus.schema_version === 6 && !hasCompleteV6ChangeStatus(archivedStatus)) {
800
+ blockers.push({ code: "invalid-archived-status-v6", path: `.speculo/specdev/archive/${month}/${item}/.status.json`, message: "archived change-status v6 has inconsistent current/required workspace fields" });
801
+ }
676
802
  }
677
803
  catch {
678
804
  // The JSON tree check reports the parse failure with the precise path.
@@ -716,8 +842,8 @@ async function inspectSpecdevState(stateRoot) {
716
842
  if (await pathExists(configPath)) {
717
843
  try {
718
844
  const config = await readJson(configPath);
719
- if (!new Set([3, 4]).has(Number(config.schema_version))) {
720
- blockers.push({ code: "unsupported-specdev-config", path: ".speculo/specdev/config.json", message: "automatic migration supports SpecDev config schema v3/v4 only" });
845
+ if (!new Set([3, 4, 5]).has(Number(config.schema_version))) {
846
+ blockers.push({ code: "unsupported-specdev-config", path: ".speculo/specdev/config.json", message: "automatic migration supports SpecDev config schema v3/v4/v5 only" });
721
847
  }
722
848
  else if (hasUnsupportedV3SpecdevConfigFields(config)) {
723
849
  blockers.push({ code: "unmapped-specdev-config-fields", path: ".speculo/specdev/config.json", message: "SpecDev config v3 contains additional fields that require an explicit migration decision" });
@@ -725,6 +851,9 @@ async function inspectSpecdevState(stateRoot) {
725
851
  else if (config.schema_version === 4 && !hasCompleteV4SpecdevConfig(config)) {
726
852
  blockers.push({ code: "invalid-specdev-config-v4", path: ".speculo/specdev/config.json", message: "SpecDev config v4 is incomplete or contains legacy execution fields" });
727
853
  }
854
+ else if (config.schema_version === 5 && !hasCompleteV5SpecdevConfig(config)) {
855
+ blockers.push({ code: "invalid-specdev-config-v5", path: ".speculo/specdev/config.json", message: "SpecDev config v5 is incomplete or contains invalid execution limits" });
856
+ }
728
857
  }
729
858
  catch {
730
859
  // The JSON tree check reports the parse failure with the precise path.
@@ -838,19 +967,24 @@ function mergeDefaults(defaults, previous) {
838
967
  }
839
968
  return previous;
840
969
  }
841
- function normalizeSpecdevConfigV4(previous, defaults) {
842
- if (previous.schema_version === 4)
970
+ function normalizeSpecdevConfigV5(previous, defaults) {
971
+ if (previous.schema_version === CONFIG_SCHEMA_VERSION)
843
972
  return previous;
844
973
  const previousGit = isJsonObject(previous.git) ? previous.git : {};
845
974
  const previousExecution = isJsonObject(previous.execution) ? previous.execution : {};
846
975
  const defaultGit = isJsonObject(defaults.git) ? defaults.git : {};
847
976
  const defaultExecution = isJsonObject(defaults.execution) ? defaults.execution : {};
977
+ const configuredLimit = Number(previousExecution.max_implementation_agents);
848
978
  const legacyLimit = Number(previousExecution.max_parallel);
849
- const maxImplementationAgents = Number.isInteger(legacyLimit)
850
- ? Math.max(1, Math.min(3, legacyLimit))
851
- : Number(defaultExecution.max_implementation_agents ?? 3);
979
+ const maxImplementationAgents = Number.isInteger(configuredLimit) && configuredLimit >= 1
980
+ ? configuredLimit
981
+ : Number.isInteger(legacyLimit) && legacyLimit >= 1
982
+ ? legacyLimit
983
+ : Number(defaultExecution.max_implementation_agents ?? 3);
984
+ const merged = mergeDefaults(defaults, previous);
852
985
  return {
853
- schema_version: 4,
986
+ ...merged,
987
+ schema_version: CONFIG_SCHEMA_VERSION,
854
988
  interaction_language: typeof previous.interaction_language === "string"
855
989
  ? previous.interaction_language
856
990
  : defaults.interaction_language,
@@ -864,6 +998,9 @@ function normalizeSpecdevConfigV4(previous, defaults) {
864
998
  },
865
999
  execution: {
866
1000
  max_implementation_agents: maxImplementationAgents,
1001
+ max_integration_attempts: Number.isInteger(previousExecution.max_integration_attempts) && Number(previousExecution.max_integration_attempts) >= 1
1002
+ ? previousExecution.max_integration_attempts
1003
+ : Number(defaultExecution.max_integration_attempts ?? 3),
867
1004
  deep_ticket_human_approval: typeof previousExecution.deep_ticket_human_approval === "boolean"
868
1005
  ? previousExecution.deep_ticket_human_approval
869
1006
  : defaultExecution.deep_ticket_human_approval,
@@ -917,9 +1054,9 @@ async function upgradeSpecdevRuntimeV5(stagedRoot) {
917
1054
  const configPath = join(stateRoot, "config.json");
918
1055
  if (await pathExists(configPath)) {
919
1056
  const previous = await readJson(configPath);
920
- if (previous.schema_version === 3) {
921
- const defaults = await readJson(join(stagedRoot, "workflows", "specdev", "I-init-setup", "config-template.json"));
922
- await writeFile(configPath, JSON.stringify(normalizeSpecdevConfigV4(previous, defaults), null, 2) + "\n", "utf8");
1057
+ const defaults = await readJson(join(stagedRoot, "workflows", "specdev", "I-init-setup", "config-template.json"));
1058
+ if (previous.schema_version !== CONFIG_SCHEMA_VERSION) {
1059
+ await writeFile(configPath, JSON.stringify(normalizeSpecdevConfigV5(previous, defaults), null, 2) + "\n", "utf8");
923
1060
  }
924
1061
  }
925
1062
  const statusPath = join(stateRoot, "status.json");
@@ -942,10 +1079,24 @@ async function upgradeSpecdevRuntimeV5(stagedRoot) {
942
1079
  const previous = await readJson(path);
943
1080
  if (previous.schema_version === 3) {
944
1081
  await writeFile(path, JSON.stringify(normalizeChangeStatusV4(previous), null, 2) + "\n", "utf8");
945
- continue;
946
1082
  }
947
- if (previous.schema_version === 4) {
948
- await writeFile(path, JSON.stringify(normalizeChangeStatusV5(previous, entry), null, 2) + "\n", "utf8");
1083
+ let current = await readJson(path);
1084
+ if (current.schema_version === 4) {
1085
+ await writeFile(path, JSON.stringify(normalizeChangeStatusV5(current, entry), null, 2) + "\n", "utf8");
1086
+ }
1087
+ current = await readJson(path);
1088
+ if (current.schema_version === 5) {
1089
+ await writeFile(path, JSON.stringify({ ...current, schema_version: CHANGE_STATUS_SCHEMA_VERSION }, null, 2) + "\n", "utf8");
1090
+ }
1091
+ }
1092
+ const config = await pathExists(configPath) ? await readJson(configPath) : {};
1093
+ for (const { path } of changeStatusPaths) {
1094
+ const goalPlanPath = join(dirname(path), "goal-plan.md");
1095
+ if (!(await pathExists(goalPlanPath)))
1096
+ continue;
1097
+ const goalPlan = await readFile(goalPlanPath, "utf8");
1098
+ if (parseGoalPlanFrontmatter(goalPlan)?.schema_version === 5) {
1099
+ await writeFile(goalPlanPath, normalizeGoalPlanV6(goalPlan, config), "utf8");
949
1100
  }
950
1101
  }
951
1102
  if (status.schema_version === 4) {