@fission-ai/openspec 1.13.1 → 1.14.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 (85) hide show
  1. package/README.md +15 -3
  2. package/dist/cli/index.js +39 -1
  3. package/dist/commands/spec.js +1 -0
  4. package/dist/commands/workflow/instructions.js +66 -18
  5. package/dist/commands/workflow/shared.d.ts +7 -0
  6. package/dist/commands/workflow/status.js +15 -2
  7. package/dist/core/archive.js +258 -78
  8. package/dist/core/artifact-graph/instruction-loader.d.ts +7 -0
  9. package/dist/core/artifact-graph/instruction-loader.js +18 -1
  10. package/dist/core/artifact-graph/outputs.d.ts +1 -1
  11. package/dist/core/artifact-graph/outputs.js +38 -8
  12. package/dist/core/change-metadata/schema.d.ts +3 -0
  13. package/dist/core/change-metadata/schema.js +10 -0
  14. package/dist/core/change-status-policy.d.ts +8 -0
  15. package/dist/core/change-status-policy.js +33 -2
  16. package/dist/core/command-generation/adapters/atomcode.d.ts +24 -0
  17. package/dist/core/command-generation/adapters/atomcode.js +46 -0
  18. package/dist/core/command-generation/adapters/codestudio.d.ts +13 -0
  19. package/dist/core/command-generation/adapters/codestudio.js +27 -0
  20. package/dist/core/command-generation/adapters/continue.js +4 -0
  21. package/dist/core/command-generation/adapters/easycode.d.ts +17 -0
  22. package/dist/core/command-generation/adapters/easycode.js +28 -0
  23. package/dist/core/command-generation/adapters/gemini.js +1 -35
  24. package/dist/core/command-generation/adapters/gigacode.d.ts +17 -0
  25. package/dist/core/command-generation/adapters/gigacode.js +31 -0
  26. package/dist/core/command-generation/adapters/index.d.ts +4 -0
  27. package/dist/core/command-generation/adapters/index.js +4 -0
  28. package/dist/core/command-generation/adapters/kilocode.d.ts +1 -1
  29. package/dist/core/command-generation/adapters/kilocode.js +2 -2
  30. package/dist/core/command-generation/registry.js +8 -0
  31. package/dist/core/command-generation/toml.d.ts +19 -0
  32. package/dist/core/command-generation/toml.js +39 -0
  33. package/dist/core/command-surface.js +1 -1
  34. package/dist/core/completions/command-registry.js +19 -0
  35. package/dist/core/completions/installers/zsh-installer.js +4 -2
  36. package/dist/core/config-prompts.js +6 -6
  37. package/dist/core/config.js +11 -1
  38. package/dist/core/init.js +44 -14
  39. package/dist/core/legacy-cleanup.d.ts +1 -1
  40. package/dist/core/legacy-cleanup.js +40 -11
  41. package/dist/core/list.d.ts +2 -0
  42. package/dist/core/list.js +49 -23
  43. package/dist/core/parsers/markdown-parser.js +5 -0
  44. package/dist/core/parsers/requirement-blocks.d.ts +40 -3
  45. package/dist/core/parsers/requirement-blocks.js +74 -25
  46. package/dist/core/project-config.js +45 -1
  47. package/dist/core/references.js +3 -1
  48. package/dist/core/root-selection.d.ts +6 -0
  49. package/dist/core/root-selection.js +16 -0
  50. package/dist/core/schemas/base.schema.d.ts +3 -0
  51. package/dist/core/schemas/base.schema.js +6 -0
  52. package/dist/core/schemas/change.schema.d.ts +8 -0
  53. package/dist/core/schemas/spec.schema.d.ts +2 -0
  54. package/dist/core/specs-apply.d.ts +20 -0
  55. package/dist/core/specs-apply.js +19 -6
  56. package/dist/core/templates/workflows/apply-change.js +5 -2
  57. package/dist/core/templates/workflows/archive-change.js +56 -20
  58. package/dist/core/templates/workflows/bulk-archive-change.js +34 -16
  59. package/dist/core/templates/workflows/continue-change.js +0 -2
  60. package/dist/core/templates/workflows/explore.js +2 -2
  61. package/dist/core/templates/workflows/ff-change.js +2 -2
  62. package/dist/core/templates/workflows/onboard.js +9 -4
  63. package/dist/core/templates/workflows/update-change.js +21 -9
  64. package/dist/core/templates/workflows/verify-change.js +115 -52
  65. package/dist/core/update.js +20 -7
  66. package/dist/core/validation/constants.d.ts +1 -1
  67. package/dist/core/validation/constants.js +1 -1
  68. package/dist/core/validation/purpose-placeholder.js +24 -9
  69. package/dist/core/validation/validator.js +15 -6
  70. package/dist/core/version-check.d.ts +23 -1
  71. package/dist/core/version-check.js +112 -26
  72. package/dist/core/view.d.ts +2 -0
  73. package/dist/core/view.js +62 -4
  74. package/dist/utils/change-metadata.d.ts +20 -1
  75. package/dist/utils/change-metadata.js +57 -1
  76. package/dist/utils/command-references.d.ts +1 -1
  77. package/dist/utils/command-references.js +2 -2
  78. package/dist/utils/file-system.js +20 -3
  79. package/dist/utils/index.d.ts +1 -1
  80. package/dist/utils/index.js +1 -1
  81. package/dist/utils/line-endings.d.ts +34 -0
  82. package/dist/utils/line-endings.js +46 -0
  83. package/package.json +2 -2
  84. package/schemas/spec-driven/schema.yaml +10 -1
  85. package/schemas/spec-driven/templates/proposal.md +6 -3
@@ -415,7 +415,7 @@ Save to the \`resolvedOutputPath\` from \`openspec instructions design --change
415
415
 
416
416
  Finally, we break the work into implementation tasks—checkboxes that drive the apply phase.
417
417
 
418
- These should be small, clear, and in logical order.
418
+ These should be small, clear, and in logical order. Each group carries the tests and documentation for its own work - the last group is only for integration checks.
419
419
  \`\`\`
420
420
 
421
421
  **DO:** Generate tasks based on specs and design:
@@ -438,12 +438,17 @@ Here are the implementation tasks:
438
438
 
439
439
  ---
440
440
 
441
- Each checkbox becomes a unit of work in the apply phase. Ready to implement?
441
+ Each checkbox becomes a unit of work in the apply phase. Does this task breakdown look right?
442
442
  \`\`\`
443
443
 
444
- **PAUSE** - Wait for user to confirm they're ready to implement.
444
+ **PAUSE** - Wait for user approval/feedback.
445
+
446
+ After approval, save to the \`resolvedOutputPath\` from \`openspec instructions tasks --change "<name>" --json\`.
447
+
448
+ Then ask:
449
+ > "Tasks are saved. Ready to implement?"
445
450
 
446
- Save to the \`resolvedOutputPath\` from \`openspec instructions tasks --change "<name>" --json\`.
451
+ **PAUSE** - Wait for user to confirm before implementation.
447
452
 
448
453
  ---
449
454
 
@@ -10,7 +10,7 @@ import { PROJECT_ROOT_GUARD } from './project-root.js';
10
10
  const CONTINUE_SCOPE_NOTE = optionalWorkflow('continue', 'This workflow revises artifacts that already exist; `/opsx:continue` is what creates the ones that do not.', 'This workflow revises artifacts that already exist; it never creates missing ones. When an artifact is missing, `openspec status --change "<name>" --json` names the next one and `openspec instructions "<artifact-id>" --change "<name>" --json` explains how to write it.');
11
11
  const CONTINUE_CREATE_THEM = optionalWorkflow('continue', 'point the user to `/opsx:continue` to create them', 'point the user to `openspec instructions "<artifact-id>" --change "<name>" --json` for how to create them');
12
12
  const CONTINUE_NEXT_STEP = optionalWorkflow('continue', 'suggest `/opsx:continue` to create them', 'run `openspec status --change "<name>" --json` for the next artifact and point the user to `openspec instructions "<artifact-id>" --change "<name>" --json` for how to create it');
13
- const CONTINUE_DEFERRED = optionalWorkflow('continue', 'Anything deferred to `/opsx:continue` (not-yet-created artifacts or files)', 'Anything deferred because it does not exist yet (not-yet-created artifacts or files)');
13
+ const CONTINUE_DEFERRED = optionalWorkflow('continue', 'Anything deferred to `/opsx:continue` (artifacts with no files yet and status `ready` or `blocked`, never `skipped` artifacts)', 'Anything deferred because it does not exist yet (artifacts with no files and status `ready` or `blocked`, never `skipped` artifacts)');
14
14
  const CONTINUE_FRONTIER = optionalWorkflow('continue', "that is `/opsx:continue`'s job", 'creating them is a separate step, outside this workflow');
15
15
  /**
16
16
  * `apply` and `archive` are in the `core` profile but not guaranteed in a
@@ -45,7 +45,6 @@ ${CONTINUE_SCOPE_NOTE}
45
45
 
46
46
  When prompting, present the top 3-4 most recently modified changes as options, showing:
47
47
  - Change name
48
- - Schema (from \`schema\` field if present, otherwise "spec-driven")
49
48
  - Status (e.g., "0/5 tasks", "complete", "no tasks")
50
49
  - How recently it was modified (from \`lastModified\` field)
51
50
 
@@ -75,7 +74,13 @@ ${CONTINUE_SCOPE_NOTE}
75
74
  - Read the artifact(s) the request touches and the change's other existing artifacts.
76
75
  - Draft the requested edit in the conversation, not in files. Work out exactly what it changes; step 5 owns every write. Then check every other existing artifact against the drafted edit - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
77
76
  - Note everything that is now inconsistent, missing, or contradictory.
78
- - Propose revisions only to files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and ${CONTINUE_CREATE_THEM}.
77
+ - Propose revisions to files that already exist (\`existingOutputPaths\`). If an artifact has no existing output files and status \`ready\` or \`blocked\`, note it and ${CONTINUE_CREATE_THEM}. Leave \`skipped\` artifacts untouched; do not treat them as missing or defer them to the continue workflow.
78
+ - A glob artifact (e.g. \`specs/**/*.md\`) is marked \`done\` after at least one file matches, and the continue workflow only handles \`ready\` artifacts. When reconciliation identifies a missing file for a glob artifact whose \`existingOutputPaths\` is non-empty:
79
+ 1. Run \`openspec instructions "<artifact-id>" --change "<name>" --json\` and use its \`instruction\` and \`template\`. Treat \`context\` and \`rules\` as constraints; do not copy them into the file. If instructions report \`skipped: true\`, do not create the file. Read current dependency files from disk; if a required non-skipped dependency is missing, stop and ask the user to restore it first.
80
+ 2. Choose a concrete path inside \`changeRoot\` that matches \`artifactPaths.<id>.outputPath\` and does not already exist. Verify it remains inside \`changeRoot\` after resolving any symlinked parent directories. The glob \`resolvedOutputPath\` is not a valid target.
81
+ 3. Include the new file in step 5's proposed revisions and create it only after the user confirms.
82
+ 4. After confirmation, immediately before creation, refresh status and instructions. Verify the artifact is still in scope, not skipped, and partially populated; repeat the concrete-path checks above.
83
+ 5. Use a create operation that fails if the target already exists. If \`instruction\` delegates creation to another skill or command, invoke it only if it can honor the confirmed path and these guardrails; otherwise stop. If any check fails or the confirmed draft is no longer valid, stop and reconcile with the user rather than replacing existing content or choosing a different path.
79
84
  - If the change is already coherent, say so and propose no revisions.
80
85
 
81
86
  5. **Confirm and apply, one artifact at a time**
@@ -88,7 +93,7 @@ ${CONTINUE_SCOPE_NOTE}
88
93
  \`\`\`
89
94
 
90
95
  6. **Point to the next step (guidance only - NEVER act on it)**
91
- - Artifacts still missing -> ${CONTINUE_NEXT_STEP}.
96
+ - Artifacts with empty \`existingOutputPaths\` and status \`ready\` or \`blocked\` -> ${CONTINUE_NEXT_STEP}.
92
97
  - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; ${APPLY_DELTA_HANDOFF}.
93
98
  - Everything done and implemented -> ${ARCHIVE_HANDOFF}.
94
99
 
@@ -96,6 +101,7 @@ ${CONTINUE_SCOPE_NOTE}
96
101
 
97
102
  After each invocation, show:
98
103
  - Which artifacts were revised (and which proposed revisions were rejected)
104
+ - Any file created under a glob artifact that was already partially populated
99
105
  - ${CONTINUE_DEFERRED}
100
106
  - Where the change stands and the recommended next command
101
107
 
@@ -103,7 +109,7 @@ After each invocation, show:
103
109
  - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, ${APPLY_GUARDRAIL}.
104
110
  - Use the artifact ids and paths reported by \`openspec status\`; never branch on hardcoded artifact names.
105
111
  - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
106
- - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - ${CONTINUE_FRONTIER}.
112
+ - Do not advance the build frontier: if an artifact has empty \`existingOutputPaths\` and status \`ready\` or \`blocked\`, ${CONTINUE_FRONTIER}. Leave \`skipped\` artifacts untouched. The only new-file scope is a confirmed concrete path under a glob artifact whose \`existingOutputPaths\` is non-empty.
107
113
  - Confirm every edit with the user before writing.
108
114
  - If the request changes the change's *intent* rather than refining it, ${INTENT_CHANGE_GUARDRAIL}.`,
109
115
  license: 'MIT',
@@ -138,7 +144,6 @@ ${CONTINUE_SCOPE_NOTE}
138
144
 
139
145
  When prompting, present the top 3-4 most recently modified changes as options, showing:
140
146
  - Change name
141
- - Schema (from \`schema\` field if present, otherwise "spec-driven")
142
147
  - Status (e.g., "0/5 tasks", "complete", "no tasks")
143
148
  - How recently it was modified (from \`lastModified\` field)
144
149
 
@@ -168,7 +173,13 @@ ${CONTINUE_SCOPE_NOTE}
168
173
  - Read the artifact(s) the request touches and the change's other existing artifacts.
169
174
  - Draft the requested edit in the conversation, not in files. Work out exactly what it changes; step 5 owns every write. Then check every other existing artifact against the drafted edit - in ANY direction: an edit to a later artifact may require revising an earlier one, not only the other way around. Build order is a useful reading order, not a constraint on which artifacts may be revised.
170
175
  - Note everything that is now inconsistent, missing, or contradictory.
171
- - Propose revisions only to files that already exist (\`existingOutputPaths\`). Do NOT create artifacts that don't exist yet, and do NOT invent new files under a glob artifact - note them and ${CONTINUE_CREATE_THEM}.
176
+ - Propose revisions to files that already exist (\`existingOutputPaths\`). If an artifact has no existing output files and status \`ready\` or \`blocked\`, note it and ${CONTINUE_CREATE_THEM}. Leave \`skipped\` artifacts untouched; do not treat them as missing or defer them to the continue workflow.
177
+ - A glob artifact (e.g. \`specs/**/*.md\`) is marked \`done\` after at least one file matches, and the continue workflow only handles \`ready\` artifacts. When reconciliation identifies a missing file for a glob artifact whose \`existingOutputPaths\` is non-empty:
178
+ 1. Run \`openspec instructions "<artifact-id>" --change "<name>" --json\` and use its \`instruction\` and \`template\`. Treat \`context\` and \`rules\` as constraints; do not copy them into the file. If instructions report \`skipped: true\`, do not create the file. Read current dependency files from disk; if a required non-skipped dependency is missing, stop and ask the user to restore it first.
179
+ 2. Choose a concrete path inside \`changeRoot\` that matches \`artifactPaths.<id>.outputPath\` and does not already exist. Verify it remains inside \`changeRoot\` after resolving any symlinked parent directories. The glob \`resolvedOutputPath\` is not a valid target.
180
+ 3. Include the new file in step 5's proposed revisions and create it only after the user confirms.
181
+ 4. After confirmation, immediately before creation, refresh status and instructions. Verify the artifact is still in scope, not skipped, and partially populated; repeat the concrete-path checks above.
182
+ 5. Use a create operation that fails if the target already exists. If \`instruction\` delegates creation to another skill or command, invoke it only if it can honor the confirmed path and these guardrails; otherwise stop. If any check fails or the confirmed draft is no longer valid, stop and reconcile with the user rather than replacing existing content or choosing a different path.
172
183
  - If the change is already coherent, say so and propose no revisions.
173
184
 
174
185
  5. **Confirm and apply, one artifact at a time**
@@ -181,7 +192,7 @@ ${CONTINUE_SCOPE_NOTE}
181
192
  \`\`\`
182
193
 
183
194
  6. **Point to the next step (guidance only - NEVER act on it)**
184
- - Artifacts still missing -> ${CONTINUE_NEXT_STEP}.
195
+ - Artifacts with empty \`existingOutputPaths\` and status \`ready\` or \`blocked\` -> ${CONTINUE_NEXT_STEP}.
185
196
  - Change already implemented (tasks checked off / already applied) -> the code may no longer match the revised plan; ${APPLY_DELTA_HANDOFF}.
186
197
  - Everything done and implemented -> ${ARCHIVE_HANDOFF}.
187
198
 
@@ -189,6 +200,7 @@ ${CONTINUE_SCOPE_NOTE}
189
200
 
190
201
  After each invocation, show:
191
202
  - Which artifacts were revised (and which proposed revisions were rejected)
203
+ - Any file created under a glob artifact that was already partially populated
192
204
  - ${CONTINUE_DEFERRED}
193
205
  - Where the change stands and the recommended next command
194
206
 
@@ -196,7 +208,7 @@ After each invocation, show:
196
208
  - Planning artifacts only - NEVER edit implementation code. If the revised plan implies code changes, ${APPLY_GUARDRAIL}.
197
209
  - Use the artifact ids and paths reported by \`openspec status\`; never branch on hardcoded artifact names.
198
210
  - Edit only the concrete files in \`existingOutputPaths\`; never write to a glob \`resolvedOutputPath\`.
199
- - Do not advance the build frontier: no new artifacts, no new files under glob artifacts - ${CONTINUE_FRONTIER}.
211
+ - Do not advance the build frontier: if an artifact has empty \`existingOutputPaths\` and status \`ready\` or \`blocked\`, ${CONTINUE_FRONTIER}. Leave \`skipped\` artifacts untouched. The only new-file scope is a confirmed concrete path under a glob artifact whose \`existingOutputPaths\` is non-empty.
200
212
  - Confirm every edit with the user before writing.
201
213
  - If the request changes the change's *intent* rather than refining it, ${INTENT_CHANGE_GUARDRAIL}.`
202
214
  };
@@ -21,7 +21,7 @@ ${PROJECT_ROOT_GUARD}
21
21
  - Auto-select if only one active change exists
22
22
  - If ambiguous, run \`openspec list --json\` to get available changes and ask the user to select one
23
23
 
24
- When prompting, show changes that have implementation tasks (tasks artifact exists).
24
+ When prompting, show all active changes returned by the list, including changes with \`status: "no-tasks"\`.
25
25
  Include the schema used for each change if available.
26
26
  Mark changes with incomplete tasks as "(In Progress)".
27
27
 
@@ -42,7 +42,9 @@ ${PROJECT_ROOT_GUARD}
42
42
  openspec instructions apply --change "<name>" --json
43
43
  \`\`\`
44
44
 
45
- This returns the change directory and \`contextFiles\` (artifact ID -> array of concrete file paths). Read all available artifacts from \`contextFiles\`.
45
+ This returns the change directory, \`contextFiles\` (artifact ID -> array of concrete file paths), \`taskTrackingConfigured\`, and top-level \`tasks\` and \`progress\` aggregated from every concrete file matched by the schema's \`apply.tracks\` configuration that could be read. Read all available artifacts from \`contextFiles\`.
46
+
47
+ Treat apply \`state\` and \`instruction\` as context, not a verification verdict. Do not implement tasks or archive the change during verification.
46
48
 
47
49
  4. **Initialize verification report structure**
48
50
 
@@ -53,32 +55,59 @@ ${PROJECT_ROOT_GUARD}
53
55
 
54
56
  Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
55
57
 
58
+ Verification is advisory. Respect intentional omissions such as \`skip_specs: true\`, optional design documents, and schemas without task tracking. Do not require or invent optional or intentionally omitted artifacts to obtain a clean report. \`Not verified\` describes a limit of this report, not a new archive prerequisite. Archive retains its own checks and user-confirmation behavior.
59
+
60
+ Mark checks the schema does not define, or artifacts the status reports as intentionally skipped, as **Not applicable**. The correctness checks of a change whose readable delta specs contain REMOVED or RENAMED requirements but no ADDED or MODIFIED requirements are also **Not applicable** (see step 6). Exclude them from skipped-check counts and the archive-readiness assessment. Reserve **Not verified** for applicable checks whose evidence is missing or unusable.
61
+
62
+ If only task evidence is available for applicable checks, verify task completion only and mark the remaining applicable checks, including **Code Pattern Consistency**, as not verified with the reason "Only task evidence available".
63
+
64
+ If artifacts cannot be read or contain no usable requirements, scenarios, or design decisions, mark the affected checks as not verified with the specific reason. Continue checks supported by the remaining evidence, but a partially checked input set is not a fully verified check. Missing requirements affect Spec Coverage and Requirement Implementation Mapping; missing scenarios affect Scenario Coverage; missing design decisions affect Design Adherence.
65
+
56
66
  5. **Verify Completeness**
57
67
 
58
68
  **Task Completion**:
59
- - If \`contextFiles.tasks\` exists, read every file path in it
60
- - Parse checkboxes: complete means the box holds only \`x\`/\`X\`, ignoring
61
- spacing (\`- [ x]\` is complete); every other marker is incomplete
62
- (\`- [ ]\`, \`- []\`, and unfamiliar ones such as \`- [~]\` or \`- [-]\`)
63
- - Count complete vs total tasks
64
- - If incomplete tasks exist:
65
- - Add CRITICAL issue for each incomplete task
69
+ - If \`taskTrackingConfigured\` is false, report **Task Completion** as not applicable. Do not treat empty \`tasks\` as missing evidence.
70
+ - Otherwise, use the top-level \`tasks\` and \`progress\` fields. They already aggregate every readable concrete file matched by \`apply.tracks\`, regardless of the tracked artifact's ID; do not infer tracking from a \`contextFiles\` key.
71
+ - If \`unavailableTrackingFiles\` is nonempty, mark **Task Completion** as not verified and include every unavailable path and reason. Continue using any readable task evidence, but do not infer completion from the partial \`tasks\` and \`progress\` fields.
72
+ - If \`taskTrackingConfigured\` is true and \`tasks\` is empty, mark **Task Completion** as not verified and record the reason from apply \`state\` and \`instruction\`. Nonzero totals alone do not establish evaluable task descriptions.
73
+ - Report complete vs total tasks from \`progress\`.
74
+ - If \`progress.remaining\` is greater than 0:
75
+ - Add CRITICAL issue for each listed incomplete task. If the remaining count exceeds the listed incomplete tasks, also report the incomplete checkboxes without descriptions and recommend adding descriptions and completing them. Do not infer completion from the listed tasks alone.
66
76
  - Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
67
77
 
68
78
  **Spec Coverage**:
79
+ - If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact, report the spec-dependent checks as not applicable.
80
+ - Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema. If \`contextFiles.specs\` is absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean.
69
81
  - If delta specs exist in \`contextFiles.specs\`:
70
- - Extract all requirements (marked with "### Requirement:")
71
- - For each requirement:
82
+ - Extract all requirements (marked with "### Requirement:", or listed as \`FROM:\`/\`TO:\` pairs under \`## RENAMED Requirements\`) and note the delta section each one sits under: \`## ADDED\`, \`## MODIFIED\`, \`## REMOVED\`, or \`## RENAMED Requirements\`. The section decides what the check looks for.
83
+ - For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording):
72
84
  - Search codebase for keywords related to the requirement
73
85
  - Assess if implementation likely exists
74
- - If requirements appear unimplemented:
86
+ - If ADDED or MODIFIED requirements appear unimplemented:
75
87
  - Add CRITICAL issue: "Requirement not found: <requirement name>"
76
88
  - Recommendation: "Implement requirement X: <description>"
89
+ - For each REMOVED requirement, the change asks for the behavior to be gone, so invert the check:
90
+ - Search codebase for the removed behavior. Matches in \`openspec/\` artifacts or docs, or in code that serves only the Migration note or an ADDED requirement, are not evidence by themselves. Report any code path that still delivers the removed behavior, including one shared with an ADDED requirement.
91
+ - Finding no implementation is the expected result. Never report a REMOVED requirement as "Requirement not found" or recommend implementing it.
92
+ - If the behavior is still present:
93
+ - Add CRITICAL issue: "Removed requirement still implemented: <requirement name>"
94
+ - Recommendation: "Remove the remaining implementation at <file>:<lines>, following the requirement's Migration note if it has one"
95
+ - For each RENAMED entry (\`FROM:\`/\`TO:\`), the name changes but the behavior stays, so check the TO requirement for that unchanged behavior:
96
+ - Do not report the FROM name as missing, and do not require code symbols, identifiers, or file names to be renamed.
97
+ - If the TO name also appears under MODIFIED, its behavior is checked there against the MODIFIED text; skip it here.
98
+ - Otherwise, read the baseline requirement in the main spec at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\`, using the same capability path as the delta spec: the requirement under the FROM name, or under the TO name only when the FROM name is absent because the main spec is already synced. Its body and scenarios are the evidence for the behavior the TO requirement keeps.
99
+ - Search codebase for that behavior and assess if it is still implemented.
100
+ - If it appears unimplemented:
101
+ - Add CRITICAL issue: "Renamed requirement not found: <TO name>"
102
+ - Recommendation: "Restore the behavior of <TO name> (renamed from <FROM name>); a rename must not change behavior"
103
+ - If the baseline requirement cannot be found or read, mark **Spec Coverage** as not verified for that entry with the reason. Never count an unchecked rename as passing.
77
104
 
78
105
  6. **Verify Correctness**
79
106
 
107
+ If the delta specs are readable and contain at least one REMOVED or RENAMED requirement but no ADDED or MODIFIED requirements (the change only removes or renames requirements), report **Requirement Implementation Mapping** and **Scenario Coverage** as **Not applicable**. The REMOVED and RENAMED checks under Spec Coverage are the evidence for such a change (each RENAMED entry is checked there against its baseline behavior), so do not mark these two checks as not verified. A delta spec with no parseable requirements at all is unusable evidence, not a removal-only change: mark these checks as not verified.
108
+
80
109
  **Requirement Implementation Mapping**:
81
- - For each requirement from delta specs:
110
+ - For each ADDED or MODIFIED requirement from delta specs (REMOVED entries, and RENAMED entries without a MODIFIED block, were settled under Spec Coverage):
82
111
  - Search codebase for implementation evidence
83
112
  - If found, note file paths and line ranges
84
113
  - Assess if implementation matches requirement intent
@@ -87,26 +116,29 @@ ${PROJECT_ROOT_GUARD}
87
116
  - Recommendation: "Review <file>:<lines> against requirement X"
88
117
 
89
118
  **Scenario Coverage**:
90
- - For each scenario in delta specs (marked with "#### Scenario:"):
119
+ - For each scenario under an ADDED or MODIFIED requirement in delta specs (marked with "#### Scenario:"):
91
120
  - Check if conditions are handled in code
92
121
  - Check if tests exist covering the scenario
93
122
  - If scenario appears uncovered:
94
123
  - Add WARNING: "Scenario not covered: <scenario name>"
95
124
  - Recommendation: "Add test or implementation for scenario: <description>"
125
+ - Skip scenarios under a REMOVED requirement; that behavior is meant to be gone.
96
126
 
97
127
  7. **Verify Coherence**
98
128
 
99
129
  **Design Adherence**:
130
+ - If the schema defines no design artifact, report **Design Adherence** as not applicable.
100
131
  - If \`contextFiles.design\` exists:
101
132
  - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
102
133
  - Verify implementation follows those decisions
103
134
  - If contradiction detected:
104
135
  - Add WARNING: "Design decision not followed: <decision>"
105
136
  - Recommendation: "Update implementation or revise design.md to match reality"
106
- - If no design.md: Skip design adherence check, note "No design.md to verify against"
137
+ - Otherwise, if \`contextFiles.design\` is absent or empty: mark **Design Adherence** as not verified. With other supporting artifacts, **Code Pattern Consistency** still runs; the task-only case remains limited to task completion.
107
138
 
108
139
  **Code Pattern Consistency**:
109
- - Review new code for consistency with project patterns
140
+ - If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence.
141
+ - Otherwise, review new code for consistency with project patterns
110
142
  - Check file naming, directory structure, coding style
111
143
  - If significant deviations found:
112
144
  - Add SUGGESTION: "Code pattern deviation: <details>"
@@ -126,11 +158,15 @@ ${PROJECT_ROOT_GUARD}
126
158
  | Coherence | Followed/Issues |
127
159
  \`\`\`
128
160
 
161
+ In each Status cell, report the results of checks that ran and \`Not verified (<reason>)\` for every skipped check. If all checks in a dimension were skipped, start the cell with \`Not verified\`. Never score a skipped check as passing. Treat every not verified or partially verified check as skipped in the final assessment. Count only ADDED and MODIFIED requirements in N, and report REMOVED and RENAMED requirements separately (for example, "1 removal confirmed, 1 rename verified"). For a change that only removes or renames requirements, the Correctness cell reads \`Not applicable (no ADDED or MODIFIED requirements)\`.
162
+
129
163
  **Issues by Priority**:
130
164
 
131
165
  1. **CRITICAL** (Must fix before archive):
132
166
  - Incomplete tasks
133
167
  - Missing requirement implementations
168
+ - Removed requirements still implemented
169
+ - Renamed requirements whose behavior is no longer implemented
134
170
  - Each with specific, actionable recommendation
135
171
 
136
172
  2. **WARNING** (Should fix):
@@ -144,9 +180,12 @@ ${PROJECT_ROOT_GUARD}
144
180
  - Each with specific recommendation
145
181
 
146
182
  **Final Assessment**:
147
- - If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
148
- - If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
149
- - If all clear: "All checks passed. Ready for archive."
183
+ - If CRITICAL issues: "X critical issue(s) found. Fix before archiving." If any check was skipped, also name every skipped check and its reason.
184
+ - If no CRITICAL issues, one or more warnings, and no checks were skipped: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
185
+ - If only suggestions and no checks were skipped: "No critical issues or warnings. Z suggestion(s) to consider. Ready for archive (with noted improvements)."
186
+ - If no issues and no checks were skipped: "All checks passed. Ready for archive."
187
+ - If any check was skipped and there are no CRITICAL issues: do not claim readiness. Say "No critical issues found in the checks that ran. <check(s)> not verified: <reason>." Include the warning count when nonzero.
188
+ - Include the suggestion count when nonzero in every final assessment.
150
189
 
151
190
  **Verification Heuristics**
152
191
 
@@ -156,13 +195,6 @@ ${PROJECT_ROOT_GUARD}
156
195
  - **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
157
196
  - **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
158
197
 
159
- **Graceful Degradation**
160
-
161
- - If only tasks.md exists: verify task completion only, skip spec/design checks
162
- - If tasks + specs exist: verify completeness and correctness, skip design
163
- - If full artifacts: verify all three dimensions
164
- - Always note which checks were skipped and why
165
-
166
198
  **Output Format**
167
199
 
168
200
  Use clear markdown with:
@@ -199,7 +231,7 @@ ${PROJECT_ROOT_GUARD}
199
231
  - Auto-select if only one active change exists
200
232
  - If ambiguous, run \`openspec list --json\` to get available changes and ask the user to select one
201
233
 
202
- When prompting, show changes that have implementation tasks (tasks artifact exists).
234
+ When prompting, show all active changes returned by the list, including changes with \`status: "no-tasks"\`.
203
235
  Include the schema used for each change if available.
204
236
  Mark changes with incomplete tasks as "(In Progress)".
205
237
 
@@ -220,7 +252,9 @@ ${PROJECT_ROOT_GUARD}
220
252
  openspec instructions apply --change "<name>" --json
221
253
  \`\`\`
222
254
 
223
- This returns the change directory and \`contextFiles\` (artifact ID -> array of concrete file paths). Read all available artifacts from \`contextFiles\`.
255
+ This returns the change directory, \`contextFiles\` (artifact ID -> array of concrete file paths), \`taskTrackingConfigured\`, and top-level \`tasks\` and \`progress\` aggregated from every concrete file matched by the schema's \`apply.tracks\` configuration that could be read. Read all available artifacts from \`contextFiles\`.
256
+
257
+ Treat apply \`state\` and \`instruction\` as context, not a verification verdict. Do not implement tasks or archive the change during verification.
224
258
 
225
259
  4. **Initialize verification report structure**
226
260
 
@@ -231,32 +265,58 @@ ${PROJECT_ROOT_GUARD}
231
265
 
232
266
  Each dimension can have CRITICAL, WARNING, or SUGGESTION issues.
233
267
 
268
+ Verification is advisory. Respect intentional omissions such as \`skip_specs: true\`, optional design documents, and schemas without task tracking. Do not require or invent optional or intentionally omitted artifacts to obtain a clean report. \`Not verified\` describes a limit of this report, not a new archive prerequisite. Archive retains its own checks and user-confirmation behavior.
269
+ Mark checks the schema does not define, or artifacts the status reports as intentionally skipped, as **Not applicable**. The correctness checks of a change whose readable delta specs contain REMOVED or RENAMED requirements but no ADDED or MODIFIED requirements are also **Not applicable** (see step 6). Exclude them from skipped-check counts and the archive-readiness assessment. Reserve **Not verified** for applicable checks whose evidence is missing or unusable.
270
+
271
+ If only task evidence is available for applicable checks, verify task completion only and mark the remaining applicable checks, including **Code Pattern Consistency**, as not verified with the reason "Only task evidence available".
272
+
273
+ If artifacts cannot be read or contain no usable requirements, scenarios, or design decisions, mark the affected checks as not verified with the specific reason. Continue checks supported by the remaining evidence, but a partially checked input set is not a fully verified check. Missing requirements affect Spec Coverage and Requirement Implementation Mapping; missing scenarios affect Scenario Coverage; missing design decisions affect Design Adherence.
274
+
234
275
  5. **Verify Completeness**
235
276
 
236
277
  **Task Completion**:
237
- - If \`contextFiles.tasks\` exists, read every file path in it
238
- - Parse checkboxes: complete means the box holds only \`x\`/\`X\`, ignoring
239
- spacing (\`- [ x]\` is complete); every other marker is incomplete
240
- (\`- [ ]\`, \`- []\`, and unfamiliar ones such as \`- [~]\` or \`- [-]\`)
241
- - Count complete vs total tasks
242
- - If incomplete tasks exist:
243
- - Add CRITICAL issue for each incomplete task
278
+ - If \`taskTrackingConfigured\` is false, report **Task Completion** as not applicable. Do not treat empty \`tasks\` as missing evidence.
279
+ - Otherwise, use the top-level \`tasks\` and \`progress\` fields. They already aggregate every readable concrete file matched by \`apply.tracks\`, regardless of the tracked artifact's ID; do not infer tracking from a \`contextFiles\` key.
280
+ - If \`unavailableTrackingFiles\` is nonempty, mark **Task Completion** as not verified and include every unavailable path and reason. Continue using any readable task evidence, but do not infer completion from the partial \`tasks\` and \`progress\` fields.
281
+ - If \`taskTrackingConfigured\` is true and \`tasks\` is empty, mark **Task Completion** as not verified and record the reason from apply \`state\` and \`instruction\`. Nonzero totals alone do not establish evaluable task descriptions.
282
+ - Report complete vs total tasks from \`progress\`.
283
+ - If \`progress.remaining\` is greater than 0:
284
+ - Add CRITICAL issue for each listed incomplete task. If the remaining count exceeds the listed incomplete tasks, also report the incomplete checkboxes without descriptions and recommend adding descriptions and completing them. Do not infer completion from the listed tasks alone.
244
285
  - Recommendation: "Complete task: <description>" or "Mark as done if already implemented"
245
286
 
246
287
  **Spec Coverage**:
288
+ - If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact, report the spec-dependent checks as not applicable.
289
+ - Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema. If \`contextFiles.specs\` is absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean.
247
290
  - If delta specs exist in \`contextFiles.specs\`:
248
- - Extract all requirements (marked with "### Requirement:")
249
- - For each requirement:
291
+ - Extract all requirements (marked with "### Requirement:", or listed as \`FROM:\`/\`TO:\` pairs under \`## RENAMED Requirements\`) and note the delta section each one sits under: \`## ADDED\`, \`## MODIFIED\`, \`## REMOVED\`, or \`## RENAMED Requirements\`. The section decides what the check looks for.
292
+ - For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording):
250
293
  - Search codebase for keywords related to the requirement
251
294
  - Assess if implementation likely exists
252
- - If requirements appear unimplemented:
295
+ - If ADDED or MODIFIED requirements appear unimplemented:
253
296
  - Add CRITICAL issue: "Requirement not found: <requirement name>"
254
297
  - Recommendation: "Implement requirement X: <description>"
298
+ - For each REMOVED requirement, the change asks for the behavior to be gone, so invert the check:
299
+ - Search codebase for the removed behavior. Matches in \`openspec/\` artifacts or docs, or in code that serves only the Migration note or an ADDED requirement, are not evidence by themselves. Report any code path that still delivers the removed behavior, including one shared with an ADDED requirement.
300
+ - Finding no implementation is the expected result. Never report a REMOVED requirement as "Requirement not found" or recommend implementing it.
301
+ - If the behavior is still present:
302
+ - Add CRITICAL issue: "Removed requirement still implemented: <requirement name>"
303
+ - Recommendation: "Remove the remaining implementation at <file>:<lines>, following the requirement's Migration note if it has one"
304
+ - For each RENAMED entry (\`FROM:\`/\`TO:\`), the name changes but the behavior stays, so check the TO requirement for that unchanged behavior:
305
+ - Do not report the FROM name as missing, and do not require code symbols, identifiers, or file names to be renamed.
306
+ - If the TO name also appears under MODIFIED, its behavior is checked there against the MODIFIED text; skip it here.
307
+ - Otherwise, read the baseline requirement in the main spec at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\`, using the same capability path as the delta spec: the requirement under the FROM name, or under the TO name only when the FROM name is absent because the main spec is already synced. Its body and scenarios are the evidence for the behavior the TO requirement keeps.
308
+ - Search codebase for that behavior and assess if it is still implemented.
309
+ - If it appears unimplemented:
310
+ - Add CRITICAL issue: "Renamed requirement not found: <TO name>"
311
+ - Recommendation: "Restore the behavior of <TO name> (renamed from <FROM name>); a rename must not change behavior"
312
+ - If the baseline requirement cannot be found or read, mark **Spec Coverage** as not verified for that entry with the reason. Never count an unchecked rename as passing.
255
313
 
256
314
  6. **Verify Correctness**
257
315
 
316
+ If the delta specs are readable and contain at least one REMOVED or RENAMED requirement but no ADDED or MODIFIED requirements (the change only removes or renames requirements), report **Requirement Implementation Mapping** and **Scenario Coverage** as **Not applicable**. The REMOVED and RENAMED checks under Spec Coverage are the evidence for such a change (each RENAMED entry is checked there against its baseline behavior), so do not mark these two checks as not verified. A delta spec with no parseable requirements at all is unusable evidence, not a removal-only change: mark these checks as not verified.
317
+
258
318
  **Requirement Implementation Mapping**:
259
- - For each requirement from delta specs:
319
+ - For each ADDED or MODIFIED requirement from delta specs (REMOVED entries, and RENAMED entries without a MODIFIED block, were settled under Spec Coverage):
260
320
  - Search codebase for implementation evidence
261
321
  - If found, note file paths and line ranges
262
322
  - Assess if implementation matches requirement intent
@@ -265,26 +325,29 @@ ${PROJECT_ROOT_GUARD}
265
325
  - Recommendation: "Review <file>:<lines> against requirement X"
266
326
 
267
327
  **Scenario Coverage**:
268
- - For each scenario in delta specs (marked with "#### Scenario:"):
328
+ - For each scenario under an ADDED or MODIFIED requirement in delta specs (marked with "#### Scenario:"):
269
329
  - Check if conditions are handled in code
270
330
  - Check if tests exist covering the scenario
271
331
  - If scenario appears uncovered:
272
332
  - Add WARNING: "Scenario not covered: <scenario name>"
273
333
  - Recommendation: "Add test or implementation for scenario: <description>"
334
+ - Skip scenarios under a REMOVED requirement; that behavior is meant to be gone.
274
335
 
275
336
  7. **Verify Coherence**
276
337
 
277
338
  **Design Adherence**:
339
+ - If the schema defines no design artifact, report **Design Adherence** as not applicable.
278
340
  - If \`contextFiles.design\` exists:
279
341
  - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:")
280
342
  - Verify implementation follows those decisions
281
343
  - If contradiction detected:
282
344
  - Add WARNING: "Design decision not followed: <decision>"
283
345
  - Recommendation: "Update implementation or revise design.md to match reality"
284
- - If no design.md: Skip design adherence check, note "No design.md to verify against"
346
+ - Otherwise, if \`contextFiles.design\` is absent or empty: mark **Design Adherence** as not verified. With other supporting artifacts, **Code Pattern Consistency** still runs; the task-only case remains limited to task completion.
285
347
 
286
348
  **Code Pattern Consistency**:
287
- - Review new code for consistency with project patterns
349
+ - If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence.
350
+ - Otherwise, review new code for consistency with project patterns
288
351
  - Check file naming, directory structure, coding style
289
352
  - If significant deviations found:
290
353
  - Add SUGGESTION: "Code pattern deviation: <details>"
@@ -304,11 +367,15 @@ ${PROJECT_ROOT_GUARD}
304
367
  | Coherence | Followed/Issues |
305
368
  \`\`\`
306
369
 
370
+ In each Status cell, report the results of checks that ran and \`Not verified (<reason>)\` for every skipped check. If all checks in a dimension were skipped, start the cell with \`Not verified\`. Never score a skipped check as passing. Treat every not verified or partially verified check as skipped in the final assessment. Count only ADDED and MODIFIED requirements in N, and report REMOVED and RENAMED requirements separately (for example, "1 removal confirmed, 1 rename verified"). For a change that only removes or renames requirements, the Correctness cell reads \`Not applicable (no ADDED or MODIFIED requirements)\`.
371
+
307
372
  **Issues by Priority**:
308
373
 
309
374
  1. **CRITICAL** (Must fix before archive):
310
375
  - Incomplete tasks
311
376
  - Missing requirement implementations
377
+ - Removed requirements still implemented
378
+ - Renamed requirements whose behavior is no longer implemented
312
379
  - Each with specific, actionable recommendation
313
380
 
314
381
  2. **WARNING** (Should fix):
@@ -322,9 +389,12 @@ ${PROJECT_ROOT_GUARD}
322
389
  - Each with specific recommendation
323
390
 
324
391
  **Final Assessment**:
325
- - If CRITICAL issues: "X critical issue(s) found. Fix before archiving."
326
- - If only warnings: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
327
- - If all clear: "All checks passed. Ready for archive."
392
+ - If CRITICAL issues: "X critical issue(s) found. Fix before archiving." If any check was skipped, also name every skipped check and its reason.
393
+ - If no CRITICAL issues, one or more warnings, and no checks were skipped: "No critical issues. Y warning(s) to consider. Ready for archive (with noted improvements)."
394
+ - If only suggestions and no checks were skipped: "No critical issues or warnings. Z suggestion(s) to consider. Ready for archive (with noted improvements)."
395
+ - If no issues and no checks were skipped: "All checks passed. Ready for archive."
396
+ - If any check was skipped and there are no CRITICAL issues: do not claim readiness. Say "No critical issues found in the checks that ran. <check(s)> not verified: <reason>." Include the warning count when nonzero.
397
+ - Include the suggestion count when nonzero in every final assessment.
328
398
 
329
399
  **Verification Heuristics**
330
400
 
@@ -334,13 +404,6 @@ ${PROJECT_ROOT_GUARD}
334
404
  - **False Positives**: When uncertain, prefer SUGGESTION over WARNING, WARNING over CRITICAL
335
405
  - **Actionability**: Every issue must have a specific recommendation with file/line references where applicable
336
406
 
337
- **Graceful Degradation**
338
-
339
- - If only tasks.md exists: verify task completion only, skip spec/design checks
340
- - If tasks + specs exist: verify completeness and correctness, skip design
341
- - If full artifacts: verify all three dimensions
342
- - Always note which checks were skipped and why
343
-
344
407
  **Output Format**
345
408
 
346
409
  Use clear markdown with:
@@ -27,6 +27,11 @@ import { resolveSharedSkillWriters, writeSharedSkillTarget, } from './shared-ski
27
27
  import { includesGitHubCopilot, writeCopilotCloudFiles, removeCopilotCloudFiles, isCopilotCloudEnabled, readCopilotCloudOptIn, findUnmanagedCloudFiles } from './github-copilot/cloud-agent.js';
28
28
  const require = createRequire(import.meta.url);
29
29
  const { version: OPENSPEC_VERSION } = require('../../package.json');
30
+ function throwIfUpdateFailed(failedTools) {
31
+ if (failedTools.length > 0) {
32
+ throw new Error(`OpenSpec update failed for: ${failedTools.map((tool) => tool.name).join(', ')}`);
33
+ }
34
+ }
30
35
  /**
31
36
  * Checkout artifacts that are not real content drift: a UTF-8 BOM and the CRLF
32
37
  * line endings a Windows clone with `core.autocrlf` reintroduces on every
@@ -87,7 +92,7 @@ export class UpdateCommand {
87
92
  const desiredWorkflows = profileWorkflows.filter((workflow) => ALL_WORKFLOWS.includes(workflow));
88
93
  // 4. Detect and handle legacy artifacts + upgrade legacy tools using effective config
89
94
  const legacyUpgrade = await this.handleLegacyCleanup(resolvedProjectPath, desiredWorkflows, delivery);
90
- const { newlyConfiguredTools, workflowOverrides: legacyWorkflowOverrides, deferredGlobalCleanup, } = legacyUpgrade;
95
+ const { newlyConfiguredTools, workflowOverrides: legacyWorkflowOverrides, deferredGlobalCleanup, failedTools: legacyUpgradeFailures = [], } = legacyUpgrade;
91
96
  // 5. Find configured tools
92
97
  const configuredTools = getConfiguredToolsForProfileSync(resolvedProjectPath);
93
98
  const configuredAndNewTools = [...new Set([...configuredTools, ...newlyConfiguredTools])];
@@ -95,6 +100,7 @@ export class UpdateCommand {
95
100
  if (deferredGlobalCleanup) {
96
101
  await this.performDeferredGlobalPromptCleanup(resolvedProjectPath, deferredGlobalCleanup);
97
102
  }
103
+ throwIfUpdateFailed(legacyUpgradeFailures);
98
104
  if (declinedMigrations.length > 0) {
99
105
  // Not an unconfigured project — a configured one the user chose to
100
106
  // leave in its former directory. Saying "run init" would be wrong.
@@ -146,6 +152,7 @@ export class UpdateCommand {
146
152
  this.detectNewTools(resolvedProjectPath, configuredTools);
147
153
  this.displayProfileNotes(resolvedProjectPath, configuredTools, desiredWorkflows, profile, delivery);
148
154
  this.displaySetupNotes(configuredTools);
155
+ throwIfUpdateFailed(legacyUpgradeFailures);
149
156
  return;
150
157
  }
151
158
  // 8. Display update plan
@@ -168,7 +175,7 @@ export class UpdateCommand {
168
175
  .filter((tool) => tool !== undefined));
169
176
  const updatedTools = [];
170
177
  const updatedToolIds = [];
171
- const failedTools = [];
178
+ const failedTools = [...legacyUpgradeFailures];
172
179
  const skillsInvocableCommandSkips = [];
173
180
  const zeroArtifactTools = [];
174
181
  let removedCommandCount = 0;
@@ -339,9 +346,7 @@ export class UpdateCommand {
339
346
  if (restartHint) {
340
347
  console.log(chalk.dim(restartHint));
341
348
  }
342
- if (failedTools.length > 0) {
343
- throw new Error(`OpenSpec update failed for: ${failedTools.map((tool) => tool.name).join(', ')}`);
344
- }
349
+ throwIfUpdateFailed(failedTools);
345
350
  }
346
351
  async syncCopilotCloudFiles(projectPath, configuredTools) {
347
352
  try {
@@ -901,6 +906,7 @@ export class UpdateCommand {
901
906
  // Create skills/commands for selected tools using effective profile+delivery.
902
907
  const newlyConfigured = [];
903
908
  const skippedSharedSkillTools = [];
909
+ const failedTools = [];
904
910
  const workflowOverrides = {};
905
911
  const arbitrationTools = [...new Set([...configuredTools, ...selectedTools])]
906
912
  .map((toolId) => AI_TOOLS.find((tool) => tool.value === toolId))
@@ -974,13 +980,20 @@ export class UpdateCommand {
974
980
  }
975
981
  catch (error) {
976
982
  spinner.fail(`Failed to set up ${tool.name}`);
977
- console.log(chalk.red(` ${error instanceof Error ? error.message : String(error)}`));
983
+ const message = error instanceof Error ? error.message : String(error);
984
+ console.log(chalk.red(` ${message}`));
985
+ failedTools.push({ name: tool.name, error: message });
978
986
  }
979
987
  }
980
988
  if (newlyConfigured.length > 0) {
981
989
  console.log();
982
990
  }
983
- return { newlyConfiguredTools: newlyConfigured, workflowOverrides, skippedSharedSkillTools };
991
+ return {
992
+ newlyConfiguredTools: newlyConfigured,
993
+ workflowOverrides,
994
+ skippedSharedSkillTools,
995
+ failedTools,
996
+ };
984
997
  }
985
998
  }
986
999
  //# sourceMappingURL=update.js.map
@@ -29,7 +29,7 @@ export declare const VALIDATION_MESSAGES: {
29
29
  readonly DELTA_DESCRIPTION_EMPTY: "Delta description cannot be empty";
30
30
  readonly PURPOSE_TOO_BRIEF: "Purpose section is too brief (less than 50 characters)";
31
31
  readonly PURPOSE_IS_PLACEHOLDER: string;
32
- readonly REQUIREMENT_TOO_LONG: "Requirement text is very long (>500 characters). Consider breaking it down.";
32
+ readonly REQUIREMENT_TOO_LONG: "Requirement text is very long (>500 characters). Move examples and edge cases into scenarios, or split it into separate requirements that each state one behavior.";
33
33
  readonly DELTA_DESCRIPTION_TOO_BRIEF: "Delta description is too brief";
34
34
  readonly DELTA_MISSING_REQUIREMENTS: "Delta should include requirements";
35
35
  readonly GUIDE_NO_DELTAS: "No deltas found. Ensure your change has a specs/ directory with capability folders (e.g. specs/http-server/spec.md) containing .md files that use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each requirement includes at least one \"#### Scenario:\" block. If this change intentionally modifies no specs (pure refactor, tooling, docs), set \"skip_specs: true\" in the change's .openspec.yaml instead. Tip: run \"openspec change show <change-id> --json --deltas-only\" to inspect parsed deltas.";
@@ -43,7 +43,7 @@ export const VALIDATION_MESSAGES = {
43
43
  'writes for a new capability, or a `TBD`/`TODO` marker left in its place). Replace it with what this ' +
44
44
  'capability is for, editing the main spec directly: a `## Purpose` in a delta is read only when the ' +
45
45
  'capability is created, so it cannot replace this one.',
46
- REQUIREMENT_TOO_LONG: `Requirement text is very long (>${MAX_REQUIREMENT_TEXT_LENGTH} characters). Consider breaking it down.`,
46
+ REQUIREMENT_TOO_LONG: `Requirement text is very long (>${MAX_REQUIREMENT_TEXT_LENGTH} characters). Move examples and edge cases into scenarios, or split it into separate requirements that each state one behavior.`,
47
47
  DELTA_DESCRIPTION_TOO_BRIEF: 'Delta description is too brief',
48
48
  DELTA_MISSING_REQUIREMENTS: 'Delta should include requirements',
49
49
  // Guidance snippets (appended to primary messages for remediation)