diff --git a/docs/cli.md b/docs/cli.md index b624c8667..e064e9dac 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -527,7 +527,7 @@ openspec templates [options] openspec templates # Show templates for custom schema -openspec templates --schema tdd +openspec templates --schema my-workflow # JSON for programmatic use openspec templates --json @@ -576,10 +576,6 @@ Available schemas: The default spec-driven development workflow Flow: proposal → specs → design → tasks - tdd (package) - Test-driven development workflow - Flow: spec → tests → implementation → docs - my-custom (project) Custom workflow for this project Flow: research → proposal → tasks @@ -623,9 +619,9 @@ openspec schema init [options] openspec schema init research-first # Non-interactive with specific artifacts -openspec schema init tdd-lite \ - --description "Lightweight TDD workflow" \ - --artifacts "spec,tests,implementation" \ +openspec schema init rapid \ + --description "Rapid iteration workflow" \ + --artifacts "proposal,tasks" \ --default ``` diff --git a/docs/commands.md b/docs/commands.md index 1311bdb79..6974aaa97 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -115,16 +115,6 @@ AI: Created openspec/changes/add-dark-mode/ Use /opsx:continue to create it, or /opsx:ff to create all artifacts. ``` -**Example with schema:** -``` -You: /opsx:new write-tests --schema tdd - -AI: Created openspec/changes/write-tests/ - Schema: tdd - - Ready to create: spec -``` - **Tips:** - Use descriptive names: `add-feature`, `fix-bug`, `refactor-module` - Avoid generic names like `update`, `changes`, `wip` diff --git a/docs/concepts.md b/docs/concepts.md index 4972ff2b4..2ec1772d4 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -420,16 +420,6 @@ proposal → specs → design → tasks → implement Best for: Most feature work where you want to agree on specs before implementation. -**tdd** - -Test-driven development workflow: - -``` -spec → tests → implementation → docs -``` - -Best for: Teams practicing TDD who write tests before implementation. - ### Custom Schemas Create custom schemas for your team's workflow: diff --git a/docs/customization.md b/docs/customization.md index a99dbb424..ee4596e5b 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -84,7 +84,7 @@ Tech stack: TypeScript, React, Node.js, PostgreSQL When OpenSpec needs a schema, it checks in this order: -1. CLI flag: `--schema tdd` +1. CLI flag: `--schema ` 2. Change metadata (`.openspec.yaml` in the change folder) 3. Project config (`openspec/config.yaml`) 4. Default (`spec-driven`) @@ -140,9 +140,9 @@ For a completely fresh workflow: openspec schema init research-first # Non-interactive -openspec schema init tdd-lite \ - --description "Lightweight TDD workflow" \ - --artifacts "spec,tests,impl" \ +openspec schema init rapid \ + --description "Rapid iteration workflow" \ + --artifacts "proposal,tasks" \ --default ``` @@ -275,33 +275,35 @@ Path: /path/to/project/openspec/schemas/my-workflow ## Examples -### Minimal TDD Workflow +### Rapid Iteration Workflow + +A minimal workflow for quick iterations: ```yaml -# openspec/schemas/tdd-minimal/schema.yaml -name: tdd-minimal +# openspec/schemas/rapid/schema.yaml +name: rapid version: 1 -description: Write tests first, then implement +description: Fast iteration with minimal overhead artifacts: - - id: tests - generates: tests.md - description: Test cases to implement - template: tests.md + - id: proposal + generates: proposal.md + description: Quick proposal + template: proposal.md instruction: | - Define test cases for this feature. - Each test should be a clear Given/When/Then scenario. + Create a brief proposal for this change. + Focus on what and why, skip detailed specs. requires: [] - - id: impl - generates: implementation.md - description: Implementation notes - template: impl.md - requires: [tests] + - id: tasks + generates: tasks.md + description: Implementation checklist + template: tasks.md + requires: [proposal] apply: - requires: [impl] - tracks: implementation.md + requires: [tasks] + tracks: tasks.md ``` ### Adding a Review Artifact diff --git a/docs/migration-guide.md b/docs/migration-guide.md index 075261385..6e5e3354a 100644 --- a/docs/migration-guide.md +++ b/docs/migration-guide.md @@ -452,7 +452,7 @@ rules: When determining which schema to use, OPSX checks in order: -1. **CLI flag**: `--schema tdd` (highest priority) +1. **CLI flag**: `--schema ` (highest priority) 2. **Change metadata**: `.openspec.yaml` in the change directory 3. **Project config**: `openspec/config.yaml` 4. **Default**: `spec-driven` @@ -462,7 +462,6 @@ When determining which schema to use, OPSX checks in order: | Schema | Artifacts | Best For | |--------|-----------|----------| | `spec-driven` | proposal → specs → design → tasks | Most projects | -| `tdd` | spec → tests → implementation → docs | Test-first development | List all available schemas: @@ -507,7 +506,6 @@ Restart your IDE. Skills are detected at startup. Check that your `rules:` keys match your schema's artifact IDs: - **spec-driven**: `proposal`, `specs`, `design`, `tasks` -- **tdd**: `spec`, `tests`, `implementation`, `docs` Run this to see valid artifact IDs: diff --git a/docs/opsx.md b/docs/opsx.md index 10aaaca9e..779163423 100644 --- a/docs/opsx.md +++ b/docs/opsx.md @@ -100,14 +100,14 @@ rules: | Field | Type | Description | |-------|------|-------------| -| `schema` | string | Default schema for new changes (e.g., `spec-driven`, `tdd`) | +| `schema` | string | Default schema for new changes (e.g., `spec-driven`) | | `context` | string | Project context injected into all artifact instructions | | `rules` | object | Per-artifact rules, keyed by artifact ID | ### How It Works **Schema precedence** (highest to lowest): -1. CLI flag (`--schema tdd`) +1. CLI flag (`--schema `) 2. Change metadata (`.openspec.yaml` in change directory) 3. Project config (`openspec/config.yaml`) 4. Default (`spec-driven`) @@ -130,12 +130,6 @@ rules: - `design` — Technical design - `tasks` — Implementation tasks -**tdd**: -- `spec` — Feature specification -- `tests` — Test file -- `implementation` — Implementation code -- `docs` — Documentation - ### Config Validation - Unknown artifact IDs in `rules` generate warnings @@ -618,7 +612,6 @@ artifacts: Schemas define what artifacts exist and their dependencies. Currently available: - **spec-driven** (default): proposal → specs → design → tasks -- **tdd**: tests → implementation → docs ```bash # List available schemas diff --git a/schemas/tdd/schema.yaml b/schemas/tdd/schema.yaml deleted file mode 100644 index dd9b21d77..000000000 --- a/schemas/tdd/schema.yaml +++ /dev/null @@ -1,213 +0,0 @@ -name: tdd -version: 1 -description: Test-driven development workflow - tests → implementation → docs -artifacts: - - id: spec - generates: spec.md - description: Feature specification defining requirements - template: spec.md - instruction: | - Create the feature specification that defines WHAT to build. - - Sections: - - **Feature**: Name and high-level description of the feature's purpose and user value - - **Requirements**: List of specific requirements. Use SHALL/MUST for normative language. - - **Acceptance Criteria**: Testable criteria in WHEN/THEN format - - Format requirements: - - Each requirement should be specific and testable - - Use `#### Scenario: ` with WHEN/THEN format for acceptance criteria - - Define edge cases and error scenarios explicitly - - Every requirement MUST have at least one scenario - - Example: - ``` - ## Feature: User Authentication - - Users can securely log into the application. - - ## Requirements - - ### Requirement: Password validation - The system SHALL validate passwords meet minimum security requirements. - - #### Scenario: Valid password accepted - - **WHEN** password has 8+ chars, uppercase, lowercase, and number - - **THEN** password is accepted - - #### Scenario: Weak password rejected - - **WHEN** password is less than 8 characters - - **THEN** system displays "Password too short" error - ``` - - This spec drives test creation - each scenario becomes a test case. - requires: [] - - - id: tests - generates: "tests/*.test.ts" - description: Test files written before implementation - template: test.md - instruction: | - Write tests BEFORE implementation (TDD red phase). - - File naming: - - Create test files as `tests/.test.ts` - - One test file per feature/capability - - Use descriptive names matching the spec - - Test structure: - - Use Given/When/Then format matching spec scenarios - - Group related tests with `describe()` blocks - - Each scenario from spec becomes at least one `it()` test - - Coverage requirements: - - Cover each requirement from the spec - - Include happy path (success cases) - - Include edge cases (boundary conditions) - - Include error scenarios (invalid input, failures) - - Tests should fail initially (no implementation yet) - - Example: - ```typescript - describe('Password validation', () => { - it('accepts valid password with all requirements', () => { - // GIVEN a password meeting all requirements - const password = 'SecurePass1'; - // WHEN validating - const result = validatePassword(password); - // THEN it should be accepted - expect(result.valid).toBe(true); - }); - - it('rejects password shorter than 8 characters', () => { - // GIVEN a short password - const password = 'Short1'; - // WHEN validating - const result = validatePassword(password); - // THEN it should be rejected with message - expect(result.valid).toBe(false); - expect(result.error).toBe('Password too short'); - }); - }); - ``` - - Follow the spec requirements exactly - tests verify the spec. - requires: - - spec - - - id: implementation - generates: "src/*.ts" - description: Implementation code to pass the tests - template: implementation.md - instruction: | - Implement the feature to make tests pass (TDD green phase). - - TDD workflow: - 1. Run tests - confirm they fail (red) - 2. Write minimal code to pass ONE test - 3. Run tests - confirm that test passes (green) - 4. Refactor if needed while keeping tests green - 5. Repeat for next failing test - - Implementation guidelines: - - Write minimal code to pass each test - no more, no less - - Run tests frequently to verify progress - - Keep functions small and focused - - Use clear, descriptive names - - Code organization: - - Create source files in `src/.ts` - - Export public API clearly - - Keep implementation details private - - Add JSDoc comments for public functions - - Example structure: - ```typescript - /** - * Validates a password meets security requirements. - * @param password - The password to validate - * @returns Validation result with valid flag and optional error - */ - export function validatePassword(password: string): ValidationResult { - if (password.length < 8) { - return { valid: false, error: 'Password too short' }; - } - // ... additional checks - return { valid: true }; - } - ``` - - Don't over-engineer - implement only what tests require. - requires: - - tests - - - id: docs - generates: "docs/*.md" - description: Documentation for the implemented feature - template: docs.md - instruction: | - Document the implemented feature. - - Sections: - - **Overview**: What the feature does and why it exists (1-2 paragraphs) - - **Getting Started**: Quick start guide to use the feature immediately - - **Examples**: Code examples showing common use cases - - **Reference**: Detailed API documentation, configuration options - - Guidelines: - - Write for the user, not the developer - - Start with the most common use case - - Include copy-pasteable code examples - - Document all configuration options with defaults - - Note any limitations, edge cases, or gotchas - - Link to related features or specs - - Example structure: - ```markdown - ## Overview - - Password validation ensures user passwords meet security requirements - before account creation or password changes. - - ## Getting Started - - Import and use the validation function: - - ```typescript - import { validatePassword } from './password'; - - const result = validatePassword('MySecurePass1'); - if (!result.valid) { - console.error(result.error); - } - ``` - - ## Examples - - ### Basic validation - ... - - ### Custom error handling - ... - - ## Reference - - ### validatePassword(password) - - | Parameter | Type | Description | - |-----------|------|-------------| - | password | string | The password to validate | - - **Returns**: `{ valid: boolean, error?: string }` - ``` - - Reference the spec for requirements, implementation for details. - requires: - - implementation - -apply: - requires: [tests] - tracks: null - instruction: | - Run tests to see failures. Implement minimal code to pass each test. - Refactor while keeping tests green. diff --git a/schemas/tdd/templates/docs.md b/schemas/tdd/templates/docs.md deleted file mode 100644 index fae40a6b8..000000000 --- a/schemas/tdd/templates/docs.md +++ /dev/null @@ -1,15 +0,0 @@ -## Overview - - - -## Getting Started - - - -## Examples - - - -## Reference - - diff --git a/schemas/tdd/templates/implementation.md b/schemas/tdd/templates/implementation.md deleted file mode 100644 index fac9db930..000000000 --- a/schemas/tdd/templates/implementation.md +++ /dev/null @@ -1,11 +0,0 @@ -## Implementation Notes - - - -## API - - - -## Usage - - diff --git a/schemas/tdd/templates/spec.md b/schemas/tdd/templates/spec.md deleted file mode 100644 index 232e783de..000000000 --- a/schemas/tdd/templates/spec.md +++ /dev/null @@ -1,11 +0,0 @@ -## Feature: - - - -## Requirements - - - -## Acceptance Criteria - - diff --git a/schemas/tdd/templates/test.md b/schemas/tdd/templates/test.md deleted file mode 100644 index cfa1a11b6..000000000 --- a/schemas/tdd/templates/test.md +++ /dev/null @@ -1,11 +0,0 @@ -## Test Plan - - - -## Test Cases - -### - -- **Given:** -- **When:** -- **Then:** diff --git a/src/commands/workflow/instructions.ts b/src/commands/workflow/instructions.ts index f2d343e05..0d501afec 100644 --- a/src/commands/workflow/instructions.ts +++ b/src/commands/workflow/instructions.ts @@ -378,7 +378,7 @@ export async function generateApplyInstructions( state = 'all_done'; instruction = 'All tasks are complete! This change is ready to be archived.\nConsider running tests and reviewing the changes before archiving.'; } else if (!tracksFile) { - // No tracking file (e.g., TDD schema) - ready to apply + // No tracking file configured in schema - ready to apply state = 'ready'; instruction = schemaInstruction?.trim() ?? 'All required artifacts complete. Proceed with implementation.'; } else { diff --git a/src/core/project-config.ts b/src/core/project-config.ts index 457488206..6c1ea04a5 100644 --- a/src/core/project-config.ts +++ b/src/core/project-config.ts @@ -17,11 +17,11 @@ import { z } from 'zod'; * - Consistent with other OpenSpec schemas */ export const ProjectConfigSchema = z.object({ - // Required: which schema to use (e.g., "spec-driven", "tdd", or project-local schema name) + // Required: which schema to use (e.g., "spec-driven", or project-local schema name) schema: z .string() .min(1) - .describe('The workflow schema to use (e.g., "spec-driven", "tdd")'), + .describe('The workflow schema to use (e.g., "spec-driven")'), // Optional: project context (injected into all artifact instructions) // Max size: 50KB (enforced during parsing) diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts index 524755a2f..dcb479307 100644 --- a/src/core/templates/skill-templates.ts +++ b/src/core/templates/skill-templates.ts @@ -338,7 +338,6 @@ export function getNewChangeSkillTemplate(): SkillTemplate { Use the default schema (omit \`--schema\`) unless the user explicitly requests a different workflow. **Use a different schema only if the user mentions:** - - "tdd" or "test-driven" → use \`--schema tdd\` - A specific schema name → use \`--schema \` - "show workflows" or "what workflows" → run \`openspec schemas --json\` and let them choose @@ -358,7 +357,7 @@ export function getNewChangeSkillTemplate(): SkillTemplate { This shows which artifacts need to be created and which are ready (dependencies satisfied). 5. **Get instructions for the first artifact** - The first artifact depends on the schema (e.g., \`proposal\` for spec-driven, \`spec\` for tdd). + The first artifact depends on the schema (e.g., \`proposal\` for spec-driven). Check the status output to find the first artifact with status "ready". \`\`\`bash openspec instructions --change "" @@ -421,7 +420,7 @@ export function getContinueChangeSkillTemplate(): SkillTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand current state. The response includes: - - \`schemaName\`: The workflow schema being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow schema being used (e.g., "spec-driven") - \`artifacts\`: Array of artifacts with their status ("done", "ready", "blocked") - \`isComplete\`: Boolean indicating if all artifacts are complete @@ -491,12 +490,6 @@ Common artifact patterns: - **design.md**: Document technical decisions, architecture, and implementation approach. - **tasks.md**: Break down implementation into checkboxed tasks. -**tdd schema** (spec → tests → implementation → docs): -- **spec.md**: Feature specification defining what to build. -- **tests/*.test.ts**: Write tests BEFORE implementation (TDD red phase). -- **src/*.ts**: Implement to make tests pass (TDD green phase). -- **docs/*.md**: Document the implemented feature. - For other schemas, follow the \`instruction\` field from the CLI output. **Guardrails** @@ -543,7 +536,7 @@ export function getApplyChangeSkillTemplate(): SkillTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand: - - \`schemaName\`: The workflow being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow being used (e.g., "spec-driven") - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -568,7 +561,6 @@ export function getApplyChangeSkillTemplate(): SkillTemplate { Read the files listed in \`contextFiles\` from the apply instructions output. The files depend on the schema being used: - **spec-driven**: proposal, specs, design, tasks - - **tdd**: spec, tests, implementation, docs - Other schemas: follow the contextFiles from CLI output 5. **Show current progress** @@ -1680,7 +1672,6 @@ export function getOpsxNewCommandTemplate(): CommandTemplate { Use the default schema (omit \`--schema\`) unless the user explicitly requests a different workflow. **Use a different schema only if the user mentions:** - - "tdd" or "test-driven" → use \`--schema tdd\` - A specific schema name → use \`--schema \` - "show workflows" or "what workflows" → run \`openspec schemas --json\` and let them choose @@ -1760,7 +1751,7 @@ export function getOpsxContinueCommandTemplate(): CommandTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand current state. The response includes: - - \`schemaName\`: The workflow schema being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow schema being used (e.g., "spec-driven") - \`artifacts\`: Array of artifacts with their status ("done", "ready", "blocked") - \`isComplete\`: Boolean indicating if all artifacts are complete @@ -1830,12 +1821,6 @@ Common artifact patterns: - **design.md**: Document technical decisions, architecture, and implementation approach. - **tasks.md**: Break down implementation into checkboxed tasks. -**tdd schema** (spec → tests → implementation → docs): -- **spec.md**: Feature specification defining what to build. -- **tests/*.test.ts**: Write tests BEFORE implementation (TDD red phase). -- **src/*.ts**: Implement to make tests pass (TDD green phase). -- **docs/*.md**: Document the implemented feature. - For other schemas, follow the \`instruction\` field from the CLI output. **Guardrails** @@ -1880,7 +1865,7 @@ export function getOpsxApplyCommandTemplate(): CommandTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand: - - \`schemaName\`: The workflow being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow being used (e.g., "spec-driven") - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) 3. **Get apply instructions** @@ -1905,7 +1890,6 @@ export function getOpsxApplyCommandTemplate(): CommandTemplate { Read the files listed in \`contextFiles\` from the apply instructions output. The files depend on the schema being used: - **spec-driven**: proposal, specs, design, tasks - - **tdd**: spec, tests, implementation, docs - Other schemas: follow the contextFiles from CLI output 5. **Show current progress** @@ -2643,7 +2627,7 @@ export function getVerifyChangeSkillTemplate(): SkillTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand: - - \`schemaName\`: The workflow being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow being used (e.g., "spec-driven") - Which artifacts exist for this change 3. **Get the change directory and load artifacts** @@ -3238,7 +3222,7 @@ export function getOpsxVerifyCommandTemplate(): CommandTemplate { openspec status --change "" --json \`\`\` Parse the JSON to understand: - - \`schemaName\`: The workflow being used (e.g., "spec-driven", "tdd") + - \`schemaName\`: The workflow being used (e.g., "spec-driven") - Which artifacts exist for this change 3. **Get the change directory and load artifacts** diff --git a/src/utils/change-utils.ts b/src/utils/change-utils.ts index 44178b00e..671a92b79 100644 --- a/src/utils/change-utils.ts +++ b/src/utils/change-utils.ts @@ -105,9 +105,9 @@ export function validateChangeName(name: string): ValidationResult { * console.log(result.schema) // 'spec-driven' or value from config * * @example - * // Creates openspec/changes/add-auth/ with TDD schema - * const result = await createChange('/path/to/project', 'add-auth', { schema: 'tdd' }) - * console.log(result.schema) // 'tdd' + * // Creates openspec/changes/add-auth/ with custom schema + * const result = await createChange('/path/to/project', 'add-auth', { schema: 'my-workflow' }) + * console.log(result.schema) // 'my-workflow' */ export async function createChange( projectRoot: string, diff --git a/test/commands/artifact-workflow.test.ts b/test/commands/artifact-workflow.test.ts index b1224128c..181629940 100644 --- a/test/commands/artifact-workflow.test.ts +++ b/test/commands/artifact-workflow.test.ts @@ -152,13 +152,13 @@ describe('artifact-workflow CLI commands', () => { }); it('supports --schema option', async () => { - await createTestChange('tdd-change'); + await createTestChange('schema-change'); - const result = await runCLI(['status', '--change', 'tdd-change', '--schema', 'tdd'], { + const result = await runCLI(['status', '--change', 'schema-change', '--schema', 'spec-driven'], { cwd: tempDir, }); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('tdd'); + expect(result.stdout).toContain('spec-driven'); }); it('errors for unknown schema', async () => { @@ -282,12 +282,12 @@ describe('artifact-workflow CLI commands', () => { expect(result.stdout).toContain('tasks:'); }); - it('shows template paths for custom schema', async () => { - const result = await runCLI(['templates', '--schema', 'tdd'], { cwd: tempDir }); + it('shows template paths for specified schema', async () => { + const result = await runCLI(['templates', '--schema', 'spec-driven'], { cwd: tempDir }); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('Schema: tdd'); - expect(result.stdout).toContain('spec:'); - expect(result.stdout).toContain('tests:'); + expect(result.stdout).toContain('Schema: spec-driven'); + expect(result.stdout).toContain('proposal:'); + expect(result.stdout).toContain('design:'); }); it('outputs JSON mapping of templates', async () => { @@ -430,23 +430,16 @@ describe('artifact-workflow CLI commands', () => { expect(result.stdout).toContain('ready to be archived'); }); - it('uses tdd schema apply configuration', async () => { - // Create a TDD-style change with spec and tests - const changeDir = path.join(changesDir, 'tdd-apply'); - await fs.mkdir(changeDir, { recursive: true }); - await fs.writeFile(path.join(changeDir, 'spec.md'), '## Feature\nTest spec.'); - const testsDir = path.join(changeDir, 'tests'); - await fs.mkdir(testsDir, { recursive: true }); - await fs.writeFile(path.join(testsDir, 'test.test.ts'), 'test("works", () => {})'); + it('uses spec-driven schema apply configuration', async () => { + // Create a spec-driven style change with all artifacts + await createTestChange('apply-schema-test', ['proposal', 'design', 'specs', 'tasks']); const result = await runCLI( - ['instructions', 'apply', '--change', 'tdd-apply', '--schema', 'tdd'], + ['instructions', 'apply', '--change', 'apply-schema-test', '--schema', 'spec-driven'], { cwd: tempDir } ); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('Schema: tdd'); - // TDD schema has no task tracking, so should show schema instruction - expect(result.stdout).toContain('Run tests to see failures'); + expect(result.stdout).toContain('Schema: spec-driven'); }); it('spec-driven schema uses apply block configuration', async () => { @@ -665,29 +658,29 @@ artifacts: describe('project config integration', () => { describe('new change uses config schema', () => { it('creates change with schema from project config', async () => { - // Create project config with tdd schema + // Create project config with spec-driven schema // Note: changesDir is already at tempDir/openspec/changes (created in beforeEach) await fs.writeFile( path.join(tempDir, 'openspec', 'config.yaml'), - 'schema: tdd\n' + 'schema: spec-driven\n' ); // Create a new change without specifying schema const result = await runCLI(['new', 'change', 'test-change'], { cwd: tempDir, timeoutMs: 30000 }); expect(result.exitCode).toBe(0); - // Verify the change was created with tdd schema + // Verify the change was created with spec-driven schema const metadataPath = path.join(changesDir, 'test-change', '.openspec.yaml'); const metadata = await fs.readFile(metadataPath, 'utf-8'); - expect(metadata).toContain('schema: tdd'); + expect(metadata).toContain('schema: spec-driven'); }, 60000); it('CLI schema overrides config schema', async () => { - // Create project config with tdd schema + // Create project config with spec-driven schema // Note: openspec directory already exists (from changesDir creation in beforeEach) await fs.writeFile( path.join(tempDir, 'openspec', 'config.yaml'), - 'schema: tdd\n' + 'schema: spec-driven\n' ); // Create change with explicit schema @@ -795,7 +788,7 @@ rules: const changeDir = await createTestChange('metadata-only-change'); await fs.writeFile( path.join(changeDir, '.openspec.yaml'), - 'schema: tdd\ncreated: "2025-01-05"\n' + 'schema: spec-driven\ncreated: "2025-01-05"\n' ); // Status should use schema from metadata @@ -804,7 +797,7 @@ rules: { cwd: tempDir, timeoutMs: 30000 } ); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('tdd'); + expect(result.stdout).toContain('spec-driven'); }, 60000); }); diff --git a/test/core/artifact-graph/instruction-loader.test.ts b/test/core/artifact-graph/instruction-loader.test.ts index bc9a67cc3..9d8f612cd 100644 --- a/test/core/artifact-graph/instruction-loader.test.ts +++ b/test/core/artifact-graph/instruction-loader.test.ts @@ -63,11 +63,11 @@ describe('instruction-loader', () => { expect(context.completed.size).toBe(0); }); - it('should load context with custom schema', () => { - const context = loadChangeContext(tempDir, 'my-change', 'tdd'); + it('should load context with explicit schema', () => { + const context = loadChangeContext(tempDir, 'my-change', 'spec-driven'); - expect(context.schemaName).toBe('tdd'); - expect(context.graph.getName()).toBe('tdd'); + expect(context.schemaName).toBe('spec-driven'); + expect(context.graph.getName()).toBe('spec-driven'); }); it('should detect completed artifacts', () => { @@ -91,20 +91,20 @@ describe('instruction-loader', () => { // Create change directory with metadata file const changeDir = path.join(tempDir, 'openspec', 'changes', 'my-change'); fs.mkdirSync(changeDir, { recursive: true }); - fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: tdd\ncreated: "2025-01-05"\n'); + fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: spec-driven\ncreated: "2025-01-05"\n'); // Load without explicit schema - should detect from metadata const context = loadChangeContext(tempDir, 'my-change'); - expect(context.schemaName).toBe('tdd'); - expect(context.graph.getName()).toBe('tdd'); + expect(context.schemaName).toBe('spec-driven'); + expect(context.graph.getName()).toBe('spec-driven'); }); it('should use explicit schema over metadata schema', () => { - // Create change directory with metadata file using tdd + // Create change directory with metadata file using spec-driven const changeDir = path.join(tempDir, 'openspec', 'changes', 'my-change'); fs.mkdirSync(changeDir, { recursive: true }); - fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: tdd\n'); + fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: spec-driven\n'); // Load with explicit schema - should override metadata const context = loadChangeContext(tempDir, 'my-change', 'spec-driven'); diff --git a/test/core/artifact-graph/resolver.test.ts b/test/core/artifact-graph/resolver.test.ts index 8c5f19f2c..484cc3b40 100644 --- a/test/core/artifact-graph/resolver.test.ts +++ b/test/core/artifact-graph/resolver.test.ts @@ -80,14 +80,6 @@ describe('artifact-graph/resolver', () => { expect(schema.artifacts.length).toBeGreaterThan(0); }); - it('should return built-in tdd schema', () => { - const schema = resolveSchema('tdd'); - - expect(schema.name).toBe('tdd'); - expect(schema.version).toBe(1); - expect(schema.artifacts.length).toBeGreaterThan(0); - }); - it('should strip .yaml extension from name', () => { const schema1 = resolveSchema('spec-driven'); const schema2 = resolveSchema('spec-driven.yaml'); @@ -261,7 +253,6 @@ version: [[[invalid yaml } catch (e) { const error = e as Error; expect(error.message).toContain('spec-driven'); - expect(error.message).toContain('tdd'); } }); }); @@ -271,7 +262,6 @@ version: [[[invalid yaml const schemas = listSchemas(); expect(schemas).toContain('spec-driven'); - expect(schemas).toContain('tdd'); }); it('should include user override schemas', () => { diff --git a/test/core/artifact-graph/workflow.integration.test.ts b/test/core/artifact-graph/workflow.integration.test.ts index 337c76aad..64dd6fa66 100644 --- a/test/core/artifact-graph/workflow.integration.test.ts +++ b/test/core/artifact-graph/workflow.integration.test.ts @@ -131,46 +131,6 @@ describe('artifact-graph workflow integration', () => { }); }); - describe('tdd workflow', () => { - it('should progress through complete workflow', () => { - const schema = resolveSchema('tdd'); - const graph = ArtifactGraph.fromSchema(schema); - - expect(graph.getName()).toBe('tdd'); - expect(graph.getBuildOrder()).toEqual(['spec', 'tests', 'implementation', 'docs']); - - // Initial state - let completed = detectCompleted(graph, tempDir); - expect(graph.getNextArtifacts(completed)).toEqual(['spec']); - - // Create spec - fs.writeFileSync(path.join(tempDir, 'spec.md'), '# Feature Spec'); - completed = detectCompleted(graph, tempDir); - expect(graph.getNextArtifacts(completed)).toEqual(['tests']); - - // Create tests directory with test file - const testsDir = path.join(tempDir, 'tests'); - fs.mkdirSync(testsDir, { recursive: true }); - fs.writeFileSync(path.join(testsDir, 'feature.test.ts'), 'describe("feature", () => {});'); - completed = detectCompleted(graph, tempDir); - expect(graph.getNextArtifacts(completed)).toEqual(['implementation']); - - // Create src directory with implementation - const srcDir = path.join(tempDir, 'src'); - fs.mkdirSync(srcDir, { recursive: true }); - fs.writeFileSync(path.join(srcDir, 'feature.ts'), 'export function feature() {}'); - completed = detectCompleted(graph, tempDir); - expect(graph.getNextArtifacts(completed)).toEqual(['docs']); - - // Create docs - const docsDir = path.join(tempDir, 'docs'); - fs.mkdirSync(docsDir, { recursive: true }); - fs.writeFileSync(path.join(docsDir, 'feature.md'), '# Feature Documentation'); - completed = detectCompleted(graph, tempDir); - expect(graph.isComplete(completed)).toBe(true); - }); - }); - describe('build order consistency', () => { it('should return consistent build order across multiple calls', () => { const schema = resolveSchema('spec-driven'); diff --git a/test/core/project-config.test.ts b/test/core/project-config.test.ts index abfd2a38e..88944659d 100644 --- a/test/core/project-config.test.ts +++ b/test/core/project-config.test.ts @@ -374,7 +374,7 @@ context: | ); fs.writeFileSync( path.join(configDir, 'config.yml'), - 'schema: tdd\ncontext: from yml\n' + 'schema: custom-schema\ncontext: from yml\n' ); const config = readProjectConfig(tempDir); @@ -388,12 +388,12 @@ context: | fs.mkdirSync(configDir, { recursive: true }); fs.writeFileSync( path.join(configDir, 'config.yml'), - 'schema: tdd\ncontext: from yml\n' + 'schema: custom-schema\ncontext: from yml\n' ); const config = readProjectConfig(tempDir); - expect(config?.schema).toBe('tdd'); + expect(config?.schema).toBe('custom-schema'); expect(config?.context).toBe('from yml'); }); @@ -538,7 +538,6 @@ rules: describe('suggestSchemas', () => { const availableSchemas = [ { name: 'spec-driven', isBuiltIn: true }, - { name: 'tdd', isBuiltIn: true }, { name: 'custom-workflow', isBuiltIn: false }, { name: 'team-process', isBuiltIn: false }, ]; @@ -551,29 +550,28 @@ rules: expect(message).toContain('spec-driven (built-in)'); }); - it('should suggest tdd for tdd typo', () => { - const message = suggestSchemas('td', availableSchemas); + it('should suggest custom-workflow for workflow typo', () => { + const message = suggestSchemas('custom-workflo', availableSchemas); expect(message).toContain('Did you mean one of these?'); - expect(message).toContain('tdd (built-in)'); + expect(message).toContain('custom-workflow'); }); it('should list all available schemas', () => { const message = suggestSchemas('nonexistent', availableSchemas); expect(message).toContain('Available schemas:'); - expect(message).toContain('Built-in: spec-driven, tdd'); + expect(message).toContain('Built-in: spec-driven'); expect(message).toContain('Project-local: custom-workflow, team-process'); }); it('should handle case when no project-local schemas exist', () => { const builtInOnly = [ { name: 'spec-driven', isBuiltIn: true }, - { name: 'tdd', isBuiltIn: true }, ]; const message = suggestSchemas('invalid', builtInOnly); - expect(message).toContain('Built-in: spec-driven, tdd'); + expect(message).toContain('Built-in: spec-driven'); expect(message).toContain('Project-local: (none found)'); }); diff --git a/test/utils/change-metadata.test.ts b/test/utils/change-metadata.test.ts index 2102c98ea..a8c123836 100644 --- a/test/utils/change-metadata.test.ts +++ b/test/utils/change-metadata.test.ts @@ -28,11 +28,11 @@ describe('ChangeMetadataSchema', () => { it('should accept valid schema without created date', () => { const result = ChangeMetadataSchema.safeParse({ - schema: 'tdd', + schema: 'custom-schema', }); expect(result.success).toBe(true); if (result.success) { - expect(result.data.schema).toBe('tdd'); + expect(result.data.schema).toBe('custom-schema'); expect(result.data.created).toBeUndefined(); } }); @@ -183,8 +183,8 @@ describe('resolveSchemaForChange', () => { const metaPath = path.join(changeDir, '.openspec.yaml'); await fs.writeFile(metaPath, 'schema: spec-driven\n', 'utf-8'); - const result = resolveSchemaForChange(changeDir, 'tdd'); - expect(result).toBe('tdd'); + const result = resolveSchemaForChange(changeDir, 'custom-schema'); + expect(result).toBe('custom-schema'); }); it('should return schema from metadata when no explicit schema', async () => { @@ -216,12 +216,12 @@ describe('resolveSchemaForChange', () => { await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( path.join(configDir, 'config.yaml'), - 'schema: tdd\n', + 'schema: custom-schema\n', 'utf-8' ); const result = resolveSchemaForChange(changeDir); - expect(result).toBe('tdd'); + expect(result).toBe('custom-schema'); }); it('should prefer change metadata over project config', async () => { @@ -230,7 +230,7 @@ describe('resolveSchemaForChange', () => { await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( path.join(configDir, 'config.yaml'), - 'schema: tdd\n', + 'schema: custom-schema\n', 'utf-8' ); @@ -248,7 +248,7 @@ describe('resolveSchemaForChange', () => { await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( path.join(configDir, 'config.yaml'), - 'schema: tdd\n', + 'schema: custom-schema\n', 'utf-8' ); @@ -257,8 +257,8 @@ describe('resolveSchemaForChange', () => { await fs.writeFile(metaPath, 'schema: spec-driven\n', 'utf-8'); // Explicit schema should win - const result = resolveSchemaForChange(changeDir, 'tdd'); - expect(result).toBe('tdd'); + const result = resolveSchemaForChange(changeDir, 'custom-schema'); + expect(result).toBe('custom-schema'); }); it('should test full precedence order: CLI > metadata > config > default', async () => { @@ -267,7 +267,7 @@ describe('resolveSchemaForChange', () => { await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( path.join(configDir, 'config.yaml'), - 'schema: tdd\n', + 'schema: custom-schema\n', 'utf-8' ); @@ -275,12 +275,12 @@ describe('resolveSchemaForChange', () => { await fs.writeFile(metaPath, 'schema: spec-driven\n', 'utf-8'); // Test each level - expect(resolveSchemaForChange(changeDir, 'tdd')).toBe('tdd'); // CLI wins + expect(resolveSchemaForChange(changeDir, 'custom-schema')).toBe('custom-schema'); // CLI wins expect(resolveSchemaForChange(changeDir)).toBe('spec-driven'); // Metadata wins when no CLI // Remove metadata, config should win await fs.unlink(metaPath); - expect(resolveSchemaForChange(changeDir)).toBe('tdd'); // Config wins + expect(resolveSchemaForChange(changeDir)).toBe('custom-schema'); // Config wins // Remove config, default should win await fs.unlink(path.join(configDir, 'config.yaml')); diff --git a/test/utils/change-utils.test.ts b/test/utils/change-utils.test.ts index 8e94260fa..090b21b24 100644 --- a/test/utils/change-utils.test.ts +++ b/test/utils/change-utils.test.ts @@ -139,11 +139,11 @@ describe('createChange', () => { }); it('should create .openspec.yaml with custom schema', async () => { - await createChange(testDir, 'add-auth', { schema: 'tdd' }); + await createChange(testDir, 'add-auth', { schema: 'spec-driven' }); const metaPath = path.join(testDir, 'openspec', 'changes', 'add-auth', '.openspec.yaml'); const content = await fs.readFile(metaPath, 'utf-8'); - expect(content).toContain('schema: tdd'); + expect(content).toContain('schema: spec-driven'); }); });