@@ -444,6 +444,112 @@ describe('artifact-workflow CLI commands', () => {
444444 const changeDir = path . join ( changesDir , 'my-new-feature' ) ;
445445 const stat = await fs . stat ( changeDir ) ;
446446 expect ( stat . isDirectory ( ) ) . toBe ( true ) ;
447+
448+ const metadata = await fs . readFile ( path . join ( changeDir , '.openspec.yaml' ) , 'utf-8' ) ;
449+ expect ( metadata ) . not . toContain ( 'skip_specs' ) ;
450+ } ) ;
451+
452+ it ( 'marks changes as skip_specs when their schema cannot generate specs' , async ( ) => {
453+ const schemaDir = path . join ( tempDir , 'openspec' , 'schemas' , 'no-specs' ) ;
454+ await fs . mkdir ( path . join ( schemaDir , 'templates' ) , { recursive : true } ) ;
455+ await fs . writeFile (
456+ path . join ( schemaDir , 'schema.yaml' ) ,
457+ `name: no-specs
458+ version: 1
459+ artifacts:
460+ - id: proposal
461+ generates: proposal.md
462+ description: Proposal
463+ template: proposal.md
464+ requires: []
465+ - id: tasks
466+ generates: tasks.md
467+ description: Tasks
468+ template: tasks.md
469+ requires: [proposal]
470+ apply:
471+ requires: [tasks]
472+ tracks: tasks.md
473+ `
474+ ) ;
475+ await fs . writeFile ( path . join ( schemaDir , 'templates' , 'proposal.md' ) , '# Proposal\n' ) ;
476+ await fs . writeFile ( path . join ( schemaDir , 'templates' , 'tasks.md' ) , '# Tasks\n' ) ;
477+ await fs . writeFile (
478+ path . join ( tempDir , 'openspec' , 'config.yaml' ) ,
479+ 'schema: no-specs\n'
480+ ) ;
481+
482+ const result = await runCLI ( [ 'new' , 'change' , 'no-spec-change' ] , { cwd : tempDir } ) ;
483+ expect ( result . exitCode ) . toBe ( 0 ) ;
484+
485+ const metadata = await fs . readFile (
486+ path . join ( changesDir , 'no-spec-change' , '.openspec.yaml' ) ,
487+ 'utf-8'
488+ ) ;
489+ expect ( metadata ) . toContain ( 'skip_specs: true' ) ;
490+
491+ const validation = await runCLI (
492+ [ 'validate' , 'no-spec-change' , '--type' , 'change' ] ,
493+ { cwd : tempDir }
494+ ) ;
495+ expect ( validation . exitCode ) . toBe ( 0 ) ;
496+ } ) ;
497+
498+ it ( 'does not mark spec-producing schemas that use Windows separators' , async ( ) => {
499+ const schemaName = 'windows-specs' ;
500+ const generates = String . raw `specs\**\*.md` ;
501+ const schemaDir = path . join ( tempDir , 'openspec' , 'schemas' , schemaName ) ;
502+ await fs . mkdir ( path . join ( schemaDir , 'templates' ) , { recursive : true } ) ;
503+ await fs . writeFile (
504+ path . join ( schemaDir , 'schema.yaml' ) ,
505+ `name: ${ schemaName }
506+ version: 1
507+ artifacts:
508+ - id: specs
509+ generates: '${ generates } '
510+ description: Specs
511+ template: spec.md
512+ requires: []
513+ `
514+ ) ;
515+ await fs . writeFile ( path . join ( schemaDir , 'templates' , 'spec.md' ) , '# Spec\n' ) ;
516+ await fs . writeFile (
517+ path . join ( tempDir , 'openspec' , 'config.yaml' ) ,
518+ `schema: ${ schemaName } \n`
519+ ) ;
520+
521+ const changeName = `${ schemaName } -change` ;
522+ const result = await runCLI ( [ 'new' , 'change' , changeName ] , { cwd : tempDir } ) ;
523+ expect ( result . exitCode ) . toBe ( 0 ) ;
524+
525+ const changeDir = path . join ( changesDir , changeName ) ;
526+ const metadata = await fs . readFile ( path . join ( changeDir , '.openspec.yaml' ) , 'utf-8' ) ;
527+ expect ( metadata ) . not . toContain ( 'skip_specs' ) ;
528+
529+ const specDir = path . join ( changeDir , 'specs' , 'example' ) ;
530+ await fs . mkdir ( specDir , { recursive : true } ) ;
531+ await fs . writeFile (
532+ path . join ( specDir , 'spec.md' ) ,
533+ `## ADDED Requirements
534+ ### Requirement: Example behavior
535+ The system SHALL support the example behavior.
536+
537+ #### Scenario: Example succeeds
538+ - **WHEN** the example runs
539+ - **THEN** it succeeds
540+ `
541+ ) ;
542+
543+ const status = await runCLI ( [ 'status' , '--change' , changeName , '--json' ] , {
544+ cwd : tempDir ,
545+ } ) ;
546+ expect ( status . exitCode ) . toBe ( 0 ) ;
547+ expect ( JSON . parse ( status . stdout ) . artifacts [ 0 ] . status ) . toBe ( 'done' ) ;
548+
549+ const validation = await runCLI ( [ 'validate' , changeName , '--type' , 'change' ] , {
550+ cwd : tempDir ,
551+ } ) ;
552+ expect ( validation . exitCode ) . toBe ( 0 ) ;
447553 } ) ;
448554
449555 it ( 'rejects --initiative and writes no change' , async ( ) => {
0 commit comments