From 349fb3b51aa3f4ba2f1ec91a9484df4e6cf52a99 Mon Sep 17 00:00:00 2001 From: drakeo338 Date: Fri, 2 Oct 2026 07:54:35 +0000 Subject: [PATCH 1/2] fix(verify): find spec and design artifacts by output path The verify workflow read contextFiles.specs and contextFiles.design, which only exist when the schema names its artifacts "specs" and "design". Find them by artifactPaths..outputPath instead: spec artifacts are those under specs/, the design artifact is design.md. Closes #2027 --- .changeset/verify-change-artifact-paths.md | 5 ++++ src/core/templates/workflows/verify-change.ts | 24 +++++++++---------- .../templates/skill-templates-parity.test.ts | 6 ++--- test/core/templates/verify-change.test.ts | 11 +++++++++ 4 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 .changeset/verify-change-artifact-paths.md diff --git a/.changeset/verify-change-artifact-paths.md b/.changeset/verify-change-artifact-paths.md new file mode 100644 index 0000000000..d5571310d8 --- /dev/null +++ b/.changeset/verify-change-artifact-paths.md @@ -0,0 +1,5 @@ +--- +"@fission-ai/openspec": patch +--- + +The verify workflow now finds a change's spec and design artifacts by their output path (`specs/` and `design.md`) instead of the hardcoded artifact ids `specs` and `design`, so it works with custom schemas whose artifacts use other ids. diff --git a/src/core/templates/workflows/verify-change.ts b/src/core/templates/workflows/verify-change.ts index 544e1da608..928cf3a75f 100644 --- a/src/core/templates/workflows/verify-change.ts +++ b/src/core/templates/workflows/verify-change.ts @@ -84,9 +84,9 @@ ${PROJECT_ROOT_GUARD} - Recommendation: "Complete task: " or "Mark as done if already implemented" **Spec Coverage**: - - 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. - - 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. - - If delta specs exist in \`contextFiles.specs\`: + - If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact (no artifact whose \`artifactPaths..outputPath\` is under \`specs/\`), report the spec-dependent checks as not applicable. + - Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema, so do not assume an id such as \`specs\`. The spec artifacts are those whose \`artifactPaths..outputPath\` is under \`specs/\`; read their files from \`contextFiles.\`. If those spec files are absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean. + - If delta specs exist in those spec files: - 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. - For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording): - Search codebase for keywords related to the requirement @@ -135,14 +135,14 @@ ${PROJECT_ROOT_GUARD} 7. **Verify Coherence** **Design Adherence**: - - If the schema defines no design artifact, report **Design Adherence** as not applicable. - - If \`contextFiles.design\` exists: + - If the schema defines no design artifact (no artifact whose \`artifactPaths..outputPath\` is \`design.md\`), report **Design Adherence** as not applicable. + - If the design artifact's \`contextFiles.\` file exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions - If contradiction detected: - Add WARNING: "Design decision not followed: " - Recommendation: "Update implementation or revise design.md to match reality" - - 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. + - Otherwise, if the design artifact's \`contextFiles.\` file 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. **Code Pattern Consistency**: - If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence. @@ -294,9 +294,9 @@ ${PROJECT_ROOT_GUARD} - Recommendation: "Complete task: " or "Mark as done if already implemented" **Spec Coverage**: - - 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. - - 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. - - If delta specs exist in \`contextFiles.specs\`: + - If status marks the spec artifact skipped by \`skip_specs: true\`, or the schema defines no spec artifact (no artifact whose \`artifactPaths..outputPath\` is under \`specs/\`), report the spec-dependent checks as not applicable. + - Otherwise, \`contextFiles\` is keyed by artifact id, and artifact ids come from the active schema, so do not assume an id such as \`specs\`. The spec artifacts are those whose \`artifactPaths..outputPath\` is under \`specs/\`; read their files from \`contextFiles.\`. If those spec files are absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean. + - If delta specs exist in those spec files: - 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. - For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording): - Search codebase for keywords related to the requirement @@ -345,14 +345,14 @@ ${PROJECT_ROOT_GUARD} 7. **Verify Coherence** **Design Adherence**: - - If the schema defines no design artifact, report **Design Adherence** as not applicable. - - If \`contextFiles.design\` exists: + - If the schema defines no design artifact (no artifact whose \`artifactPaths..outputPath\` is \`design.md\`), report **Design Adherence** as not applicable. + - If the design artifact's \`contextFiles.\` file exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions - If contradiction detected: - Add WARNING: "Design decision not followed: " - Recommendation: "Update implementation or revise design.md to match reality" - - 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. + - Otherwise, if the design artifact's \`contextFiles.\` file 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. **Code Pattern Consistency**: - If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence. diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index e3d1c48dc7..257b697556 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -91,11 +91,11 @@ const EXPECTED_FUNCTION_HASHES: Record = { getArchiveChangeSkillTemplate: '04a029782fc4137971fad6f54cfda3685d7e0b835b06565f9a509b4878093099', getBulkArchiveChangeSkillTemplate: '44dbd3c7a347e5f8339b2141393f2ac36017527cce251483fe70f2059c1e286e', getOpsxSyncCommandTemplate: '60550b7bb9829421656d6324a9e4c951bc912f48f88882d1a07ce7f78397a5e7', - getVerifyChangeSkillTemplate: 'eecb063792075191b613978dec45f9f2fee247d2ff3003f2ebf17d632e54352e', + getVerifyChangeSkillTemplate: 'f1133129941366b37d003c8304b373d1c4643078f2248566d434ec9d4f8e67e2', getOpsxArchiveCommandTemplate: '5d153490bf1ca24207f49856826720f793c8884a6ec15059104107b0e34ee345', getOpsxOnboardCommandTemplate: '0cf66e164c0e14c916c6d1ebb5d80ded07d7fb8e55d4eb34eba43e8ca9c28558', getOpsxBulkArchiveCommandTemplate: 'cb1d55d6ce53686bfe94be5e081c7a4d06a8e4d10b63019132df5bb3db7144cb', - getOpsxVerifyCommandTemplate: 'f47bc0c30cfa8e93b5e42026e9417636c5f15bd8505fb9138872e34af8906abb', + getOpsxVerifyCommandTemplate: '7b0b33975ff586ed8fdd121766926b69d6509ffff4f5e31e45b440ed1a5a158f', getOpsxProposeSkillTemplate: '1aa2f2eb9c8cbc4dcab9d777bf8832b92ca04f9ef91d0494f1224a566aefdfe8', getOpsxProposeCommandTemplate: '3b7090ce5e79e879ab9b5bdaf4ff2b52e3c02211f71188838772d36ac337f96c', getFeedbackSkillTemplate: 'dabeb5e825b9349abc8156c3e7b8608f27987912a6d9bf47ef29addde6138133', @@ -112,7 +112,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-sync-specs': '3909936a236a21a9a6d5bf495f90b396b3b68fc9220d7b2c1894668653beb2e4', 'openspec-archive-change': '5f0d131a885dcdcd9ba2172ea9a42bc6748125e24b8c4eecb7c86f1a4aea83af', 'openspec-bulk-archive-change': 'd2a258055ab2f0d8086c4348d37212ebc95a5adef2d5f524db959fb93490d5c8', - 'openspec-verify-change': '62c2d471a1ebc4be38df0d06393eb94d3d8b803719b6349b8a1d8e9231448275', + 'openspec-verify-change': 'd66e1de6436cae2ce246ae82614bc84013215d5619c652fd25d6fd551a48587d', 'openspec-onboard': '6993eff867d97d485e080078f9dfb80e968e242f3b17a924eeb077715fd548fa', 'openspec-propose': '66e3395adf9f2d93a09e8ef1d20e4efb010e5e8d4811f2d42a9316e4d1ca5a8b', 'openspec-update-change': '5f4ea19aa732b33d87a2120ec393ee34578e70678d97e8c3bb10f988c00cb4d3', diff --git a/test/core/templates/verify-change.test.ts b/test/core/templates/verify-change.test.ts index 05fa002949..dfc2d40c7d 100644 --- a/test/core/templates/verify-change.test.ts +++ b/test/core/templates/verify-change.test.ts @@ -14,6 +14,17 @@ const bodies: Array<[string, string]> = [ ]; describe('verify-change templates', () => { + it('finds spec and design artifacts by output path, not by hardcoded artifact id', () => { + for (const [label, body] of bodies) { + expect(body, label).not.toContain('`contextFiles.specs`'); + expect(body, label).not.toContain('`contextFiles.design`'); + expect(body, label).toContain('`artifactPaths..outputPath`'); + expect(body, label).toContain('under `specs/`'); + expect(body, label).toContain('`contextFiles.`'); + expect(body, label).toContain('`design.md`'); + } + }); + it('keeps active no-task changes eligible for ambiguous selection', () => { for (const [label, body] of bodies) { expect(body, label).toContain('show all active changes returned by the list'); From 250c490860102cf26e4ec111a82edf184ab2b8e7 Mon Sep 17 00:00:00 2001 From: drakeo338 Date: Fri, 2 Oct 2026 07:59:50 +0000 Subject: [PATCH 2/2] fix(verify): regenerate skills and match design artifact by id or path Regenerate skills/openspec-verify-change/SKILL.md so the skills.sh copy matches the template, and treat an artifact with id design, or an output path ending in design.md, as the design artifact. Signed-off-by: drakeo338 --- skills/openspec-verify-change/SKILL.md | 12 ++++++------ src/core/templates/workflows/verify-change.ts | 4 ++-- test/core/templates/skill-templates-parity.test.ts | 6 +++--- test/core/templates/verify-change.test.ts | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/skills/openspec-verify-change/SKILL.md b/skills/openspec-verify-change/SKILL.md index 41be312432..9cbfb35a25 100644 --- a/skills/openspec-verify-change/SKILL.md +++ b/skills/openspec-verify-change/SKILL.md @@ -90,9 +90,9 @@ In both branches, never create the root as a side effect: do not run `openspec i - Recommendation: "Complete task: " or "Mark as done if already implemented" **Spec Coverage**: - - 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. - - 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. - - If delta specs exist in `contextFiles.specs`: + - If status marks the spec artifact skipped by `skip_specs: true`, or the schema defines no spec artifact (no artifact whose `artifactPaths..outputPath` is under `specs/`), report the spec-dependent checks as not applicable. + - Otherwise, `contextFiles` is keyed by artifact id, and artifact ids come from the active schema, so do not assume an id such as `specs`. The spec artifacts are those whose `artifactPaths..outputPath` is under `specs/`; read their files from `contextFiles.`. If those spec files are absent or empty, mark **Spec Coverage**, **Requirement Implementation Mapping**, and **Scenario Coverage** as not verified; do not treat any of them as clean. + - If delta specs exist in those spec files: - 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. - For each ADDED or MODIFIED requirement (for MODIFIED, check the text in the delta, not the old wording): - Search codebase for keywords related to the requirement @@ -141,14 +141,14 @@ In both branches, never create the root as a side effect: do not run `openspec i 7. **Verify Coherence** **Design Adherence**: - - If the schema defines no design artifact, report **Design Adherence** as not applicable. - - If `contextFiles.design` exists: + - If the schema defines no design artifact (no artifact with id `design`, and none whose `artifactPaths..outputPath` is or ends in `design.md`), report **Design Adherence** as not applicable. + - If the design artifact's `contextFiles.` file exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions - If contradiction detected: - Add WARNING: "Design decision not followed: " - Recommendation: "Update implementation or revise design.md to match reality" - - 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. + - Otherwise, if the design artifact's `contextFiles.` file 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. **Code Pattern Consistency**: - If implementation changes cannot be identified, mark **Code Pattern Consistency** as not verified and explain the missing evidence. diff --git a/src/core/templates/workflows/verify-change.ts b/src/core/templates/workflows/verify-change.ts index 928cf3a75f..cd40f7e653 100644 --- a/src/core/templates/workflows/verify-change.ts +++ b/src/core/templates/workflows/verify-change.ts @@ -135,7 +135,7 @@ ${PROJECT_ROOT_GUARD} 7. **Verify Coherence** **Design Adherence**: - - If the schema defines no design artifact (no artifact whose \`artifactPaths..outputPath\` is \`design.md\`), report **Design Adherence** as not applicable. + - If the schema defines no design artifact (no artifact with id \`design\`, and none whose \`artifactPaths..outputPath\` is or ends in \`design.md\`), report **Design Adherence** as not applicable. - If the design artifact's \`contextFiles.\` file exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions @@ -345,7 +345,7 @@ ${PROJECT_ROOT_GUARD} 7. **Verify Coherence** **Design Adherence**: - - If the schema defines no design artifact (no artifact whose \`artifactPaths..outputPath\` is \`design.md\`), report **Design Adherence** as not applicable. + - If the schema defines no design artifact (no artifact with id \`design\`, and none whose \`artifactPaths..outputPath\` is or ends in \`design.md\`), report **Design Adherence** as not applicable. - If the design artifact's \`contextFiles.\` file exists: - Extract key decisions (look for sections like "Decision:", "Approach:", "Architecture:") - Verify implementation follows those decisions diff --git a/test/core/templates/skill-templates-parity.test.ts b/test/core/templates/skill-templates-parity.test.ts index 257b697556..b1f38b96ea 100644 --- a/test/core/templates/skill-templates-parity.test.ts +++ b/test/core/templates/skill-templates-parity.test.ts @@ -91,11 +91,11 @@ const EXPECTED_FUNCTION_HASHES: Record = { getArchiveChangeSkillTemplate: '04a029782fc4137971fad6f54cfda3685d7e0b835b06565f9a509b4878093099', getBulkArchiveChangeSkillTemplate: '44dbd3c7a347e5f8339b2141393f2ac36017527cce251483fe70f2059c1e286e', getOpsxSyncCommandTemplate: '60550b7bb9829421656d6324a9e4c951bc912f48f88882d1a07ce7f78397a5e7', - getVerifyChangeSkillTemplate: 'f1133129941366b37d003c8304b373d1c4643078f2248566d434ec9d4f8e67e2', + getVerifyChangeSkillTemplate: '9522cdf3fd638baee6098d480445c615b908b2f35d776b2a1eebeb6e2b208480', getOpsxArchiveCommandTemplate: '5d153490bf1ca24207f49856826720f793c8884a6ec15059104107b0e34ee345', getOpsxOnboardCommandTemplate: '0cf66e164c0e14c916c6d1ebb5d80ded07d7fb8e55d4eb34eba43e8ca9c28558', getOpsxBulkArchiveCommandTemplate: 'cb1d55d6ce53686bfe94be5e081c7a4d06a8e4d10b63019132df5bb3db7144cb', - getOpsxVerifyCommandTemplate: '7b0b33975ff586ed8fdd121766926b69d6509ffff4f5e31e45b440ed1a5a158f', + getOpsxVerifyCommandTemplate: '62ba027d789186416620f963341129bf8f7acf956c8f5b806f78945e1109d7ab', getOpsxProposeSkillTemplate: '1aa2f2eb9c8cbc4dcab9d777bf8832b92ca04f9ef91d0494f1224a566aefdfe8', getOpsxProposeCommandTemplate: '3b7090ce5e79e879ab9b5bdaf4ff2b52e3c02211f71188838772d36ac337f96c', getFeedbackSkillTemplate: 'dabeb5e825b9349abc8156c3e7b8608f27987912a6d9bf47ef29addde6138133', @@ -112,7 +112,7 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record = { 'openspec-sync-specs': '3909936a236a21a9a6d5bf495f90b396b3b68fc9220d7b2c1894668653beb2e4', 'openspec-archive-change': '5f0d131a885dcdcd9ba2172ea9a42bc6748125e24b8c4eecb7c86f1a4aea83af', 'openspec-bulk-archive-change': 'd2a258055ab2f0d8086c4348d37212ebc95a5adef2d5f524db959fb93490d5c8', - 'openspec-verify-change': 'd66e1de6436cae2ce246ae82614bc84013215d5619c652fd25d6fd551a48587d', + 'openspec-verify-change': 'ed7c3f0287ef246fc1c19665fd64c275259712950bfe95fb94971ddcc8fb64ac', 'openspec-onboard': '6993eff867d97d485e080078f9dfb80e968e242f3b17a924eeb077715fd548fa', 'openspec-propose': '66e3395adf9f2d93a09e8ef1d20e4efb010e5e8d4811f2d42a9316e4d1ca5a8b', 'openspec-update-change': '5f4ea19aa732b33d87a2120ec393ee34578e70678d97e8c3bb10f988c00cb4d3', diff --git a/test/core/templates/verify-change.test.ts b/test/core/templates/verify-change.test.ts index dfc2d40c7d..e2e2be7654 100644 --- a/test/core/templates/verify-change.test.ts +++ b/test/core/templates/verify-change.test.ts @@ -21,7 +21,7 @@ describe('verify-change templates', () => { expect(body, label).toContain('`artifactPaths..outputPath`'); expect(body, label).toContain('under `specs/`'); expect(body, label).toContain('`contextFiles.`'); - expect(body, label).toContain('`design.md`'); + expect(body, label).toContain('is or ends in `design.md`'); } });