From 323db2d665caac99d72e857339833796ef5a6bb6 Mon Sep 17 00:00:00 2001 From: defin85 Date: Wed, 24 Jun 2026 16:51:29 +0300 Subject: [PATCH] feat(workflows): add implementation review command --- .../add-review-impl-vs-plan-workflow.md | 5 + docs/commands.md | 26 ++++ docs/faq.md | 2 +- docs/glossary.md | 2 +- docs/how-commands-work.md | 2 +- docs/migration-guide.md | 1 + docs/opsx.md | 3 +- docs/supported-tools.md | 5 +- docs/workflows.md | 15 ++- openspec/specs/cli-init/spec.md | 6 +- src/commands/config.ts | 4 + src/core/profile-sync-drift.ts | 1 + src/core/profiles.ts | 1 + src/core/shared/skill-generation.ts | 4 + src/core/templates/skill-templates.ts | 1 + .../workflows/review-impl-vs-plan.ts | 116 ++++++++++++++++++ test/core/profiles.test.ts | 6 +- test/core/shared/skill-generation.test.ts | 14 ++- .../templates/skill-templates-parity.test.ts | 8 ++ 19 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 .changeset/add-review-impl-vs-plan-workflow.md create mode 100644 src/core/templates/workflows/review-impl-vs-plan.ts diff --git a/.changeset/add-review-impl-vs-plan-workflow.md b/.changeset/add-review-impl-vs-plan-workflow.md new file mode 100644 index 000000000..4b2bf418b --- /dev/null +++ b/.changeset/add-review-impl-vs-plan-workflow.md @@ -0,0 +1,5 @@ +--- +"@fission-ai/openspec": minor +--- + +Add an optional `/opsx:review` workflow for read-only implementation review against an OpenSpec change plan. diff --git a/docs/commands.md b/docs/commands.md index 5d52c056c..10b8e5ec6 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -24,6 +24,7 @@ For workflow patterns and when to use each command, see [Workflows](workflows.md | `/opsx:continue` | Create the next artifact based on dependencies | | `/opsx:ff` | Fast-forward: create all planning artifacts at once | | `/opsx:verify` | Validate implementation matches artifacts | +| `/opsx:review` | Read-only review of implementation against the change plan | | `/opsx:bulk-archive` | Archive multiple changes at once | | `/opsx:onboard` | Guided tutorial through the complete workflow | @@ -385,6 +386,31 @@ AI: Verifying add-dark-mode... --- +### `/opsx:review` + +Run a read-only implementation review against the OpenSpec change plan. This is stricter and more evidence-focused than `/opsx:verify`: it checks whether the default runtime path, producer/consumer wiring, tests, config, examples, and docs actually support the requirements and tasks. + +**Syntax:** +``` +/opsx:review [change-name] +``` + +**Arguments:** +| Argument | Required | Description | +|----------|----------|-------------| +| `change-name` | No | Which change to review (inferred from context if not provided) | + +**What it does:** +- Reads proposal, tasks, design, and delta specs +- Builds a requirement/task/design-to-code review matrix +- Inspects implementation, tests, runtime wiring, config, and docs +- Reports BLOCKER, WARNING, and NOTE findings +- Does not edit code or artifacts + +Use `/opsx:review` when you want a code-review style answer to "does the implementation really match the approved plan?" Use `/opsx:verify` when you want the lighter archive-readiness check. + +--- + ### `/opsx:sync` **Optional command.** Merge delta specs from a change into main specs. Archive will prompt to sync if needed, so you typically don't need to run this manually. diff --git a/docs/faq.md b/docs/faq.md index 9b9198fd3..256ea25f9 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -66,7 +66,7 @@ Explore to think it through, propose to draft the plan, apply to build it, archi ### What are `core` and expanded profiles? -A profile decides which slash commands get installed. **Core** (the default) gives you `propose`, `explore`, `apply`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `bulk-archive`, and `onboard` for finer control. Switch with `openspec config profile`, then apply with `openspec update`. +A profile decides which slash commands get installed. **Core** (the default) gives you `propose`, `explore`, `apply`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `review`, `bulk-archive`, and `onboard` for finer control. Switch with `openspec config profile`, then apply with `openspec update`. ### Do I need to run `/opsx:sync`? diff --git a/docs/glossary.md b/docs/glossary.md index 397cbe36d..9ac61a194 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -54,7 +54,7 @@ Terms are grouped by topic, then alphabetized within each group. **Command file.** A per-tool slash command file (`.../commands/opsx-*`). The older delivery mechanism, still supported alongside skills. You rarely touch these directly. -**Profile.** The set of slash commands installed in your project. **Core** (the default) is `propose`, `explore`, `apply`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`. Change it with `openspec config profile`. +**Profile.** The set of slash commands installed in your project. **Core** (the default) is `propose`, `explore`, `apply`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `review`, `bulk-archive`, `onboard`. Change it with `openspec config profile`. **Delivery.** Whether OpenSpec installs skills, command files, or both for your tools. Configured globally and applied with `openspec update`. diff --git a/docs/how-commands-work.md b/docs/how-commands-work.md index e60c9a761..7297b1244 100644 --- a/docs/how-commands-work.md +++ b/docs/how-commands-work.md @@ -118,7 +118,7 @@ By default, OpenSpec installs the **core** set of slash commands: A good default rhythm: `explore` when you're figuring out what to do, then `propose`, `apply`, `archive`. The [Explore First](explore.md) guide explains why that opening step pays off. -There's also an **expanded** set for people who want finer control (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`). You turn it on with `openspec config profile`, then apply it with `openspec update`. +There's also an **expanded** set for people who want finer control (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:review`, `/opsx:bulk-archive`, `/opsx:onboard`). You turn it on with `openspec config profile`, then apply it with `openspec update`. New to all of this? `/opsx:onboard` (in the expanded set) walks you through a complete change on your own codebase, narrating each step. It's the friendliest possible introduction. diff --git a/docs/migration-guide.md b/docs/migration-guide.md index d6355740f..4aa0db189 100644 --- a/docs/migration-guide.md +++ b/docs/migration-guide.md @@ -297,6 +297,7 @@ Command availability is profile-dependent: | `/opsx:continue` | Create the next artifact (one at a time) | | `/opsx:ff` | Fast-forward—create planning artifacts at once | | `/opsx:verify` | Validate implementation matches specs | +| `/opsx:review` | Read-only implementation review against the change plan | | `/opsx:sync` | Merge delta specs into main specs | | `/opsx:bulk-archive` | Archive multiple changes at once | | `/opsx:onboard` | Guided end-to-end onboarding workflow | diff --git a/docs/opsx.md b/docs/opsx.md index bebe0a51d..0a0caff94 100644 --- a/docs/opsx.md +++ b/docs/opsx.md @@ -65,7 +65,7 @@ openspec init This creates skills in `.claude/skills/` (or equivalent) that AI coding assistants auto-detect. -By default, OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `sync`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`. +By default, OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `sync`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `review`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`. During setup, you'll be prompted to create a **project config** (`openspec/config.yaml`). This is optional but recommended. @@ -164,6 +164,7 @@ rules: | `/opsx:ff` | Fast-forward planning artifacts (expanded workflow) | | `/opsx:apply` | Implement tasks, updating artifacts as needed | | `/opsx:verify` | Validate implementation against artifacts (expanded workflow) | +| `/opsx:review` | Read-only implementation review against the change plan (expanded workflow) | | `/opsx:sync` | Sync delta specs to main (default workflow, optional) | | `/opsx:archive` | Archive when done | | `/opsx:bulk-archive` | Archive multiple completed changes (expanded workflow) | diff --git a/docs/supported-tools.md b/docs/supported-tools.md index b2ee30fb4..dff789240 100644 --- a/docs/supported-tools.md +++ b/docs/supported-tools.md @@ -16,7 +16,7 @@ By default, OpenSpec uses the `core` profile, which includes: - `sync` - `archive` -You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`) via `openspec config profile`, then run `openspec update`. +You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `review`, `bulk-archive`, `onboard`) via `openspec config profile`, then run `openspec update`. ## Tool Directory Reference @@ -83,7 +83,7 @@ OpenSpec installs workflow artifacts based on selected workflows: - **Core profile (default):** `propose`, `explore`, `apply`, `sync`, `archive` - **Custom selection:** any subset of all workflow IDs: - `propose`, `explore`, `new`, `continue`, `apply`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `onboard` + `propose`, `explore`, `new`, `continue`, `apply`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `review`, `onboard` In other words, skill/command counts are profile-dependent and delivery-dependent, not fixed. @@ -101,6 +101,7 @@ When selected by profile/workflow config, OpenSpec generates these skills: - `openspec-archive-change` - `openspec-bulk-archive-change` - `openspec-verify-change` +- `openspec-review-impl-vs-plan` - `openspec-onboard` See [Commands](commands.md) for command behavior and [CLI](cli.md) for `init`/`update` options. diff --git a/docs/workflows.md b/docs/workflows.md index e333ca6ef..04bd1c0f1 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -74,7 +74,7 @@ Explore creates no artifacts and writes no code. It's a free, no-stakes conversa ### Expanded/Full Workflow (custom selection) -If you want explicit scaffold-and-build commands (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), enable them with: +If you want explicit scaffold-and-build commands (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:review`, `/opsx:bulk-archive`, `/opsx:onboard`), enable them with: ```bash openspec config profile @@ -303,6 +303,18 @@ AI: Verifying add-auth... Verify won't block archive, but it surfaces issues you might want to address first. +#### Review: Check the Implementation Against the Plan + +`/opsx:review` is a read-only, code-review style check. It reads the change artifacts, extracts requirements, tasks, scenarios, and design decisions, then inspects the actual implementation path: + +- enforcing code +- default runtime entry points +- producer/consumer wiring +- tests and smoke checks +- config, examples, and docs + +Use it when "tasks are checked" is not enough and you need evidence that the shipped behavior matches the approved plan. It reports blockers first and does not edit files. + #### Archive: Finalize the Change `/opsx:archive` completes the change and moves it to the archive: @@ -468,6 +480,7 @@ For full command details and options, see [Commands](commands.md). | `/opsx:ff` | Create all planning artifacts | Expanded mode, clear scope | | `/opsx:apply` | Implement tasks | Ready to write code | | `/opsx:verify` | Validate implementation | Expanded mode, before archiving | +| `/opsx:review` | Review implementation against plan | Expanded mode, before or after verify | | `/opsx:sync` | Merge delta specs | Expanded mode, optional | | `/opsx:archive` | Complete the change | All work finished | | `/opsx:bulk-archive` | Archive multiple changes | Expanded mode, parallel work | diff --git a/openspec/specs/cli-init/spec.md b/openspec/specs/cli-init/spec.md index f53a0580a..7ee9e2425 100644 --- a/openspec/specs/cli-init/spec.md +++ b/openspec/specs/cli-init/spec.md @@ -185,7 +185,7 @@ The command SHALL generate Agent Skills for selected AI tools. #### Scenario: Generating skills for a tool - **WHEN** a tool is selected during initialization -- **THEN** create 9 skill directories under `./skills/`: +- **THEN** create skill directories under `./skills/` for the selected workflows: - `openspec-explore/SKILL.md` - `openspec-new-change/SKILL.md` - `openspec-continue-change/SKILL.md` @@ -195,6 +195,7 @@ The command SHALL generate Agent Skills for selected AI tools. - `openspec-sync-specs/SKILL.md` - `openspec-archive-change/SKILL.md` - `openspec-bulk-archive-change/SKILL.md` + - `openspec-review-impl-vs-plan/SKILL.md` - **AND** each SKILL.md SHALL contain YAML frontmatter with name and description - **AND** each SKILL.md SHALL contain the skill instructions @@ -205,7 +206,7 @@ The command SHALL generate opsx slash commands only for selected tools that have #### Scenario: Generating slash commands for a tool with a registered adapter - **WHEN** a tool with a registered command adapter is selected during initialization -- **THEN** create 9 slash command files using the tool's command adapter: +- **THEN** create slash command files using the tool's command adapter for the selected workflows: - `/opsx:explore` - `/opsx:new` - `/opsx:continue` @@ -215,6 +216,7 @@ The command SHALL generate opsx slash commands only for selected tools that have - `/opsx:sync` - `/opsx:archive` - `/opsx:bulk-archive` + - `/opsx:review` - **AND** use tool-specific path conventions (e.g., `.claude/commands/opsx/` for Claude) - **AND** include tool-specific frontmatter format diff --git a/src/commands/config.ts b/src/commands/config.ts index 711ec5f9c..1c9b56be3 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -83,6 +83,10 @@ const WORKFLOW_PROMPT_META: Record = { name: 'Verify change', description: 'Run verification checks against a change', }, + review: { + name: 'Review implementation', + description: 'Read-only review of code against the change plan', + }, onboard: { name: 'Onboard', description: 'Guided onboarding flow for OpenSpec', diff --git a/src/core/profile-sync-drift.ts b/src/core/profile-sync-drift.ts index 782bdcc9f..220ed0d29 100644 --- a/src/core/profile-sync-drift.ts +++ b/src/core/profile-sync-drift.ts @@ -21,6 +21,7 @@ export const WORKFLOW_TO_SKILL_DIR: Record = { 'archive': 'openspec-archive-change', 'bulk-archive': 'openspec-bulk-archive-change', 'verify': 'openspec-verify-change', + 'review': 'openspec-review-impl-vs-plan', 'onboard': 'openspec-onboard', 'propose': 'openspec-propose', }; diff --git a/src/core/profiles.ts b/src/core/profiles.ts index 29d492746..411667f9c 100644 --- a/src/core/profiles.ts +++ b/src/core/profiles.ts @@ -27,6 +27,7 @@ export const ALL_WORKFLOWS = [ 'archive', 'bulk-archive', 'verify', + 'review', 'onboard', ] as const; diff --git a/src/core/shared/skill-generation.ts b/src/core/shared/skill-generation.ts index 898e7a25e..f8f9f70f7 100644 --- a/src/core/shared/skill-generation.ts +++ b/src/core/shared/skill-generation.ts @@ -14,6 +14,7 @@ import { getArchiveChangeSkillTemplate, getBulkArchiveChangeSkillTemplate, getVerifyChangeSkillTemplate, + getReviewImplVsPlanSkillTemplate, getOnboardSkillTemplate, getOpsxProposeSkillTemplate, getOpsxExploreCommandTemplate, @@ -25,6 +26,7 @@ import { getOpsxArchiveCommandTemplate, getOpsxBulkArchiveCommandTemplate, getOpsxVerifyCommandTemplate, + getOpsxReviewCommandTemplate, getOpsxOnboardCommandTemplate, getOpsxProposeCommandTemplate, type SkillTemplate, @@ -64,6 +66,7 @@ export function getSkillTemplates(workflowFilter?: readonly string[]): SkillTemp { template: getArchiveChangeSkillTemplate(), dirName: 'openspec-archive-change', workflowId: 'archive' }, { template: getBulkArchiveChangeSkillTemplate(), dirName: 'openspec-bulk-archive-change', workflowId: 'bulk-archive' }, { template: getVerifyChangeSkillTemplate(), dirName: 'openspec-verify-change', workflowId: 'verify' }, + { template: getReviewImplVsPlanSkillTemplate(), dirName: 'openspec-review-impl-vs-plan', workflowId: 'review' }, { template: getOnboardSkillTemplate(), dirName: 'openspec-onboard', workflowId: 'onboard' }, { template: getOpsxProposeSkillTemplate(), dirName: 'openspec-propose', workflowId: 'propose' }, ]; @@ -90,6 +93,7 @@ export function getCommandTemplates(workflowFilter?: readonly string[]): Command { template: getOpsxArchiveCommandTemplate(), id: 'archive' }, { template: getOpsxBulkArchiveCommandTemplate(), id: 'bulk-archive' }, { template: getOpsxVerifyCommandTemplate(), id: 'verify' }, + { template: getOpsxReviewCommandTemplate(), id: 'review' }, { template: getOpsxOnboardCommandTemplate(), id: 'onboard' }, { template: getOpsxProposeCommandTemplate(), id: 'propose' }, ]; diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts index ff687d900..bd2c44bd4 100644 --- a/src/core/templates/skill-templates.ts +++ b/src/core/templates/skill-templates.ts @@ -15,6 +15,7 @@ export { getSyncSpecsSkillTemplate, getOpsxSyncCommandTemplate } from './workflo export { getArchiveChangeSkillTemplate, getOpsxArchiveCommandTemplate } from './workflows/archive-change.js'; export { getBulkArchiveChangeSkillTemplate, getOpsxBulkArchiveCommandTemplate } from './workflows/bulk-archive-change.js'; export { getVerifyChangeSkillTemplate, getOpsxVerifyCommandTemplate } from './workflows/verify-change.js'; +export { getReviewImplVsPlanSkillTemplate, getOpsxReviewCommandTemplate } from './workflows/review-impl-vs-plan.js'; export { getOnboardSkillTemplate, getOpsxOnboardCommandTemplate } from './workflows/onboard.js'; export { getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate } from './workflows/propose.js'; export { getFeedbackSkillTemplate } from './workflows/feedback.js'; diff --git a/src/core/templates/workflows/review-impl-vs-plan.ts b/src/core/templates/workflows/review-impl-vs-plan.ts new file mode 100644 index 000000000..86c879d92 --- /dev/null +++ b/src/core/templates/workflows/review-impl-vs-plan.ts @@ -0,0 +1,116 @@ +/** + * Skill Template Workflow Modules + */ +import type { SkillTemplate, CommandTemplate } from '../types.js'; +import { STORE_SELECTION_GUIDANCE } from './store-selection.js'; + +const REVIEW_IMPL_VS_PLAN_INSTRUCTIONS = `Review real implementation against an OpenSpec change plan. This is a read-only review: inspect artifacts, code, tests, configuration, and documented runtime paths, then report gaps. Do not edit files. + +${STORE_SELECTION_GUIDANCE} + +**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Resolve the change** + + If a change name is provided, use it. Otherwise: + - Infer from conversation context if the user clearly mentioned one + - If ambiguous, run \`openspec list --json\` and ask the user to select + +2. **Check status to understand scope** + \`\`\`bash + openspec status --change "" --json + \`\`\` + Parse: + - \`schemaName\`: workflow schema + - \`planningHome\`, \`changeRoot\`, \`artifactPaths\`, and \`actionContext\`: path and scope context + - Existing artifacts and their concrete paths + +3. **Load the plan artifacts** + + Read every existing artifact path from the status JSON. For a spec-driven change this usually includes: + - \`proposal.md\` + - \`tasks.md\` + - \`design.md\`, if present + - \`specs/**/spec.md\` + +4. **Extract implementation claims** + + Build a review matrix from: + - Requirements and scenarios from delta specs + - Task checklist items + - Design decisions or constraints + - Proposal impact areas and named affected systems + +5. **Inspect implementation evidence** + + For each claim, inspect the actual codebase: + - enforcing code path + - default runtime or user-facing entry point + - producer/consumer wiring + - configuration, examples, and docs that users will actually follow + - tests or smoke checks proving the behavior + + Do not accept checklist state or generated contracts as proof by themselves. Verify that the default path is wired end to end. + +6. **Report blockers first** + + Classify findings: + - **BLOCKER**: shipped behavior is missing, incorrectly wired, unsafe, or contradicts required specs/tasks + - **WARNING**: likely drift, missing scenario coverage, weak test evidence, or docs/config mismatch + - **NOTE**: minor follow-up or assumption + +**Output Format** + +\`\`\`markdown +## Review: + +### Verdict + + +### Findings +- [BLOCKER] +- [WARNING] + +### Requirement -> Code -> Test +| Plan item | Code evidence | Test evidence | Status | +|-----------|---------------|---------------|--------| + +### Runtime Wiring + + +### Questions + +\`\`\` + +**Guardrails** +- Stay read-only. Do not edit artifacts or implementation. +- Prioritize concrete bugs, regressions, missing wiring, missing tests, and spec contradictions. +- Cite files and line numbers for findings whenever possible. +- If no issues are found, say that clearly and list any residual test gaps or assumptions. +- Keep summaries brief; findings and evidence are the main output.`; + +export function getReviewImplVsPlanSkillTemplate(): SkillTemplate { + return { + name: 'openspec-review-impl-vs-plan', + description: 'Review real implementation against an OpenSpec proposal, tasks, specs, and design. Use when the user wants a read-only check that shipped code matches the approved plan.', + instructions: REVIEW_IMPL_VS_PLAN_INSTRUCTIONS, + license: 'MIT', + compatibility: 'Requires openspec CLI.', + metadata: { author: 'openspec', version: '1.0' }, + }; +} + +export function getOpsxReviewCommandTemplate(): CommandTemplate { + return { + name: 'OPSX: Review', + description: 'Read-only review of implementation against an OpenSpec change plan', + category: 'Workflow', + tags: ['workflow', 'review', 'experimental'], + content: REVIEW_IMPL_VS_PLAN_INSTRUCTIONS.replace( + '**Input**: Optionally specify a change name.', + '**Input**: Optionally specify a change name after `/opsx:review` (e.g., `/opsx:review add-auth`).' + ), + }; +} diff --git a/test/core/profiles.test.ts b/test/core/profiles.test.ts index b46901fa2..2d77ac085 100644 --- a/test/core/profiles.test.ts +++ b/test/core/profiles.test.ts @@ -20,14 +20,14 @@ describe('profiles', () => { }); describe('ALL_WORKFLOWS', () => { - it('should contain all 11 workflows', () => { - expect(ALL_WORKFLOWS).toHaveLength(11); + it('should contain all 12 workflows', () => { + expect(ALL_WORKFLOWS).toHaveLength(12); }); it('should contain expected workflow IDs', () => { const expected = [ 'propose', 'explore', 'new', 'continue', 'apply', - 'ff', 'sync', 'archive', 'bulk-archive', 'verify', 'onboard', + 'ff', 'sync', 'archive', 'bulk-archive', 'verify', 'review', 'onboard', ]; expect([...ALL_WORKFLOWS]).toEqual(expected); }); diff --git a/test/core/shared/skill-generation.test.ts b/test/core/shared/skill-generation.test.ts index 6c755f51d..cd9ebf522 100644 --- a/test/core/shared/skill-generation.test.ts +++ b/test/core/shared/skill-generation.test.ts @@ -8,9 +8,9 @@ import { describe('skill-generation', () => { describe('getSkillTemplates', () => { - it('should return all 11 skill templates', () => { + it('should return all 12 skill templates', () => { const templates = getSkillTemplates(); - expect(templates).toHaveLength(11); + expect(templates).toHaveLength(12); }); it('should have unique directory names', () => { @@ -33,6 +33,7 @@ describe('skill-generation', () => { expect(dirNames).toContain('openspec-archive-change'); expect(dirNames).toContain('openspec-bulk-archive-change'); expect(dirNames).toContain('openspec-verify-change'); + expect(dirNames).toContain('openspec-review-impl-vs-plan'); expect(dirNames).toContain('openspec-onboard'); expect(dirNames).toContain('openspec-propose'); }); @@ -88,9 +89,9 @@ describe('skill-generation', () => { }); describe('getCommandTemplates', () => { - it('should return all 11 command templates', () => { + it('should return all 12 command templates', () => { const templates = getCommandTemplates(); - expect(templates).toHaveLength(11); + expect(templates).toHaveLength(12); }); it('should have unique IDs', () => { @@ -113,6 +114,7 @@ describe('skill-generation', () => { expect(ids).toContain('archive'); expect(ids).toContain('bulk-archive'); expect(ids).toContain('verify'); + expect(ids).toContain('review'); expect(ids).toContain('onboard'); expect(ids).toContain('propose'); }); @@ -142,9 +144,9 @@ describe('skill-generation', () => { }); describe('getCommandContents', () => { - it('should return all 11 command contents', () => { + it('should return all 12 command contents', () => { const contents = getCommandContents(); - expect(contents).toHaveLength(11); + expect(contents).toHaveLength(12); }); it('should have valid content structure', () => { diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index cc6ec7bc1..0ad07b342 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -26,6 +26,8 @@ import { getOpsxVerifyCommandTemplate, getSyncSpecsSkillTemplate, getVerifyChangeSkillTemplate, + getReviewImplVsPlanSkillTemplate, + getOpsxReviewCommandTemplate, } from '../../../src/core/templates/skill-templates.js'; import { generateSkillContent, @@ -51,10 +53,12 @@ const EXPECTED_FUNCTION_HASHES: Record = { getBulkArchiveChangeSkillTemplate: '0f635913757ae3d1609e111f4a8f699443ca47cbaaf8a1b21eb652f7b96a1d13', getOpsxSyncCommandTemplate: '86cf706886d0f18069e2cfa16948b7357028fd348210efb58588c88c416d8622', getVerifyChangeSkillTemplate: 'd718c79aad649223a73fdb11036c93fb3842ac5a780f4934d50bfa03c9692683', + getReviewImplVsPlanSkillTemplate: 'b510e001951b605d11ea97260a917f9b2f859add8a9182e9bb4dd2e8ec80ec9d', getOpsxArchiveCommandTemplate: '6985bddb310cb45b6b50350bfcebe31bf67146135ca0084c94930920280970a4', getOpsxOnboardCommandTemplate: '0673f34a0f81fd173bcfb8c3ac83e2b1c617f7b7564e24e5298d3bd5665a05a9', getOpsxBulkArchiveCommandTemplate: '9f444fc7b27a5b788077b5e3aa4f61af45aa8c8004ac8d899d204fa362ff89b7', getOpsxVerifyCommandTemplate: '011509480a20a60342c993906f0f9280c0e9ba5d019d335bdc1ef4d53213a5a8', + getOpsxReviewCommandTemplate: 'e1d7d34af9b5fe1a3468aadbba4ef9e4cc17dcaa9f82b37999828e9b9d20fa92', getOpsxProposeSkillTemplate: '8dfb5e9c719d5ba547aff0d3953c076dca6b33d7223be98cbffc396b8f1e0048', getOpsxProposeCommandTemplate: '7cd569beb32d99cdabd0b49615a8245160a8e152b6ea67a99fc4dd71e3f39f50', getFeedbackSkillTemplate: 'd7d83c5f7fc2b92fe8f4588a5bf2d9cb315e4c73ec19bcd5ef28270906319a0d', @@ -70,6 +74,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-archive-change': '833290ade47ddaed7f5e523d07437c7cef2497340021e944096bce449e290c22', 'openspec-bulk-archive-change': '244b195e53d3f010a99892c1922c800fd8f02e7745d0f34ec18b5fe9b5548706', 'openspec-verify-change': '97d1eed5b900788706c28339e27c1d2d9c548626316253f43ebd00d8d52d02d6', + 'openspec-review-impl-vs-plan': 'eac4a870bcc0f379c920e5a07eb064d9fe5e229d91dd148281637341e3b9d04c', 'openspec-onboard': 'd136b6ab7134d6bceeca73bc2f6037624506587e8df99059f77fe88874256ed1', 'openspec-propose': '5c350d80247722489374a49ec9853d5fda55a827f421fbb32b6b6a078fcb69ee', }; @@ -86,6 +91,7 @@ const GENERATED_SKILL_FACTORIES: Array<[string, () => SkillTemplate]> = [ ['openspec-archive-change', getArchiveChangeSkillTemplate], ['openspec-bulk-archive-change', getBulkArchiveChangeSkillTemplate], ['openspec-verify-change', getVerifyChangeSkillTemplate], + ['openspec-review-impl-vs-plan', getReviewImplVsPlanSkillTemplate], ['openspec-onboard', getOnboardSkillTemplate], ['openspec-propose', getOpsxProposeSkillTemplate], ]; @@ -129,10 +135,12 @@ describe('skill templates split parity', () => { getBulkArchiveChangeSkillTemplate, getOpsxSyncCommandTemplate, getVerifyChangeSkillTemplate, + getReviewImplVsPlanSkillTemplate, getOpsxArchiveCommandTemplate, getOpsxOnboardCommandTemplate, getOpsxBulkArchiveCommandTemplate, getOpsxVerifyCommandTemplate, + getOpsxReviewCommandTemplate, getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate, getFeedbackSkillTemplate,