From 98429366947165e2f3f67afe32eab67fd730bbe8 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 12 Mar 2026 00:14:19 +0100 Subject: [PATCH 1/2] Realign code import ownership surface --- README.md | 2 +- docs/examples/brownfield-data-pipeline.md | 4 +- .../brownfield-django-modernization.md | 2 +- docs/examples/brownfield-flask-api.md | 2 +- docs/examples/dogfooding-specfact-cli.md | 4 +- .../integration-showcases-testing-guide.md | 6 +- docs/examples/quick-examples.md | 36 +++--- docs/getting-started/installation.md | 2 +- .../tutorial-openspec-speckit.md | 4 +- docs/guides/ai-ide-workflow.md | 6 +- docs/guides/brownfield-engineer.md | 14 +- docs/guides/brownfield-faq.md | 2 +- docs/guides/brownfield-journey.md | 4 +- docs/guides/brownfield-roi.md | 4 +- docs/guides/command-chains.md | 4 +- docs/guides/common-tasks.md | 6 +- docs/guides/competitive-analysis.md | 6 +- docs/guides/copilot-mode.md | 2 +- docs/guides/dual-stack-enrichment.md | 4 +- docs/guides/ide-integration.md | 2 +- docs/guides/import-features.md | 10 +- docs/guides/migration-cli-reorganization.md | 2 +- docs/guides/openspec-journey.md | 2 +- docs/guides/speckit-journey.md | 2 +- docs/guides/specmatic-integration.md | 6 +- docs/guides/testing-terminal-output.md | 4 +- docs/guides/troubleshooting.md | 26 ++-- docs/guides/use-cases.md | 4 +- docs/guides/ux-features.md | 16 +-- docs/guides/workflows.md | 16 +-- docs/prompts/README.md | 2 +- docs/reference/README.md | 2 +- docs/reference/command-syntax-policy.md | 4 +- docs/reference/commands.md | 2 +- docs/reference/directory-structure.md | 10 +- docs/reference/feature-keys.md | 6 +- docs/reference/modes.md | 4 +- docs/reference/telemetry.md | 2 +- docs/technical/code2spec-analysis-logic.md | 4 +- openspec/CHANGE_ORDER.md | 1 + .../proposal.md | 2 +- .../bundle-command-surface-alignment/spec.md | 2 +- .../OWNERSHIP_MATRIX.md | 66 ++++++++++ .../TDD_EVIDENCE.md | 85 +++++++++++++ .../design.md | 120 ++++++++++++++++++ .../proposal.md | 53 ++++++++ .../specs/project-codebase-ownership/spec.md | 44 +++++++ .../tasks.md | 32 +++++ resources/prompts/shared/cli-enforcement.md | 2 +- resources/prompts/specfact.03-review.md | 2 +- src/specfact_cli/agents/analyze_agent.py | 6 +- src/specfact_cli/commands/import_cmd.py | 4 +- src/specfact_cli/groups/codebase_group.py | 6 +- src/specfact_cli/groups/project_group.py | 3 +- src/specfact_cli/utils/structure.py | 2 +- src/specfact_cli/utils/suggestions.py | 10 +- src/specfact_cli/validation/command_audit.py | 31 ++++- tests/e2e/test_complete_workflow.py | 2 +- .../analyzers/test_analyze_command.py | 2 +- ...test_command_package_runtime_validation.py | 9 ++ tests/unit/groups/test_codebase_group.py | 2 +- tests/unit/groups/test_project_group.py | 38 ++++++ tests/unit/prompts/test_prompt_validation.py | 2 +- tests/unit/validation/test_command_audit.py | 2 +- tools/validate_prompts.py | 4 +- 65 files changed, 624 insertions(+), 148 deletions(-) create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/OWNERSHIP_MATRIX.md create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/TDD_EVIDENCE.md create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/design.md create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/proposal.md create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/specs/project-codebase-ownership/spec.md create mode 100644 openspec/changes/module-migration-11-project-codebase-ownership-realignment/tasks.md create mode 100644 tests/unit/groups/test_project_group.py diff --git a/README.md b/README.md index 576f8118..68de2ed7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ specfact init ide --ide vscode ```bash # Analyze an existing codebase -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Validate external code without modifying source specfact code validate sidecar init my-project /path/to/repo diff --git a/docs/examples/brownfield-data-pipeline.md b/docs/examples/brownfield-data-pipeline.md index 998fd289..bc5320e7 100644 --- a/docs/examples/brownfield-data-pipeline.md +++ b/docs/examples/brownfield-data-pipeline.md @@ -29,7 +29,7 @@ You inherited a 5-year-old Python data pipeline with: ```bash # Analyze the legacy data pipeline -specfact project import from-code customer-etl \ +specfact code import customer-etl \ --repo ./legacy-etl-pipeline \ --language python @@ -338,7 +338,7 @@ def transform_order(raw_order: Dict[str, Any]) -> Dict[str, Any]: **Solution:** -1. Ran `specfact project import from-code` → 47 features extracted in 12 seconds +1. Ran `specfact code import` → 47 features extracted in 12 seconds 2. Added contracts to 23 critical data transformation functions 3. CrossHair discovered 6 edge cases in legacy validation logic 4. Enforced contracts during migration, blocked 11 regressions diff --git a/docs/examples/brownfield-django-modernization.md b/docs/examples/brownfield-django-modernization.md index 70fabb0b..00c74c21 100644 --- a/docs/examples/brownfield-django-modernization.md +++ b/docs/examples/brownfield-django-modernization.md @@ -29,7 +29,7 @@ You inherited a 3-year-old Django app with: ```bash # Analyze the legacy Django app -specfact project import from-code customer-portal \ +specfact code import customer-portal \ --repo ./legacy-django-app \ --language python diff --git a/docs/examples/brownfield-flask-api.md b/docs/examples/brownfield-flask-api.md index 601d143a..adaafaa1 100644 --- a/docs/examples/brownfield-flask-api.md +++ b/docs/examples/brownfield-flask-api.md @@ -27,7 +27,7 @@ You inherited a 2-year-old Flask REST API with: ```bash # Analyze the legacy Flask API -specfact project import from-code customer-api \ +specfact code import customer-api \ --repo ./legacy-flask-api \ --language python diff --git a/docs/examples/dogfooding-specfact-cli.md b/docs/examples/dogfooding-specfact-cli.md index 264995f5..8c2ace14 100644 --- a/docs/examples/dogfooding-specfact-cli.md +++ b/docs/examples/dogfooding-specfact-cli.md @@ -25,7 +25,7 @@ We built SpecFact CLI and wanted to validate that it actually works in the real First, we analyzed the existing codebase to see what features it discovered: ```bash -specfact project import from-code specfact-cli --repo . --confidence 0.5 +specfact code import specfact-cli --repo . --confidence 0.5 ``` **Output**: @@ -546,7 +546,7 @@ These are **actual questions** that need answers, not false positives! ```bash # 1. Analyze existing codebase (3 seconds) -specfact project import from-code specfact-cli --repo . --confidence 0.5 +specfact code import specfact-cli --repo . --confidence 0.5 # ✅ Discovers 19 features, 49 stories # 2. Set quality gates (1 second) diff --git a/docs/examples/integration-showcases/integration-showcases-testing-guide.md b/docs/examples/integration-showcases/integration-showcases-testing-guide.md index 1109b214..c6227ed4 100644 --- a/docs/examples/integration-showcases/integration-showcases-testing-guide.md +++ b/docs/examples/integration-showcases/integration-showcases-testing-guide.md @@ -159,7 +159,7 @@ def process_payment(request): - **Suggested plan name for Example 1**: `Payment Processing` or `Legacy Payment View` 3. **CLI Execution**: The AI will: - Sanitize the name (lowercase, remove spaces/special chars) - - Run `specfact project import from-code --repo --confidence 0.5` + - Run `specfact code import --repo --confidence 0.5` - Capture CLI output and create a project bundle 4. **CLI Output Summary**: The AI will present a summary showing: - Bundle name used @@ -193,7 +193,7 @@ def process_payment(request): 3. **Apply Enrichment**: The AI will run: ```bash - specfact project import from-code --repo --enrichment .specfact/projects//reports/enrichment/-.enrichment.md --confidence 0.5 + specfact code import --repo --enrichment .specfact/projects//reports/enrichment/-.enrichment.md --confidence 0.5 ``` 4. **Enriched Project Bundle**: The CLI will update: @@ -238,7 +238,7 @@ uvx specfact-cli@latest --no-banner import from-code --repo . --output-format ya **CLI vs Interactive Mode**: -- **CLI-only** (`uvx specfact-cli@latest import from-code` or `specfact project import from-code`): Uses AST-based analyzer (CI/CD mode) +- **CLI-only** (`uvx specfact-cli@latest import from-code` or `specfact code import`): Uses AST-based analyzer (CI/CD mode) - May show "0 features" for minimal test cases - Limited to AST pattern matching - Works but may not detect all features in simple examples diff --git a/docs/examples/quick-examples.md b/docs/examples/quick-examples.md index a92c2936..093027be 100644 --- a/docs/examples/quick-examples.md +++ b/docs/examples/quick-examples.md @@ -33,7 +33,7 @@ pip install specfact-cli specfact project plan init my-project --interactive # Have existing code? -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Using GitHub Spec-Kit? specfact project import from-bridge --adapter speckit --repo ./my-project --dry-run @@ -55,30 +55,30 @@ specfact project import from-bridge --adapter speckit --repo ./spec-kit-project ```bash # Basic import (bundle name as positional argument) -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # With confidence threshold -specfact project import from-code my-project --repo . --confidence 0.7 +specfact code import my-project --repo . --confidence 0.7 # Shadow mode (observe only) -specfact project import from-code my-project --repo . --shadow-only +specfact code import my-project --repo . --shadow-only # CoPilot mode (enhanced prompts) specfact --mode copilot import from-code my-project --repo . --confidence 0.7 # Re-validate existing features (force re-analysis) -specfact project import from-code my-project --repo . --revalidate-features +specfact code import my-project --repo . --revalidate-features # Resume interrupted import (features saved early as checkpoint) # If import is cancelled, just run the same command again -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Partial analysis (analyze specific subdirectory only) -specfact project import from-code my-project --repo . --entry-point src/core +specfact code import my-project --repo . --entry-point src/core # Large codebase with progress reporting # Progress bars show: feature analysis, source linking, contract extraction -specfact project import from-code large-project --repo . --confidence 0.5 +specfact code import large-project --repo . --confidence 0.5 ``` @@ -223,7 +223,7 @@ specfact init ide --ide cursor --force ```bash # Auto-detect mode (default) -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Force CI/CD mode specfact --mode cicd import from-code my-project --repo . @@ -233,7 +233,7 @@ specfact --mode copilot import from-code my-project --repo . # Set via environment variable export SPECFACT_MODE=copilot -specfact project import from-code my-project --repo . +specfact code import my-project --repo . ``` ## Common Workflows @@ -258,7 +258,7 @@ specfact project plan compare --repo . ```bash # Step 1: Extract specs from legacy code -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Step 2: Create hard SDD manifest specfact project plan harden my-project @@ -302,7 +302,7 @@ specfact govern enforce stage --preset minimal ```bash # Step 1: Analyze code -specfact project import from-code my-project --repo . --confidence 0.7 +specfact code import my-project --repo . --confidence 0.7 # Step 2: Review plan using CLI commands specfact project plan review my-project @@ -320,14 +320,14 @@ specfact project sync repository --repo . --watch --interval 5 ```bash # Bundle name is a positional argument (not --name option) -specfact project import from-code my-project --repo . +specfact code import my-project --repo . ``` ### Custom Report ```bash -specfact project import from-code \ +specfact code import \ --repo . \ --report analysis-report.md @@ -341,10 +341,10 @@ specfact project plan compare \ ```bash # Classname format (default for auto-derived) -specfact project import from-code my-project --repo . --key-format classname +specfact code import my-project --repo . --key-format classname # Sequential format (for manual plans) -specfact project import from-code my-project --repo . --key-format sequential +specfact code import my-project --repo . --key-format sequential ``` @@ -352,10 +352,10 @@ specfact project import from-code my-project --repo . --key-format sequential ```bash # Lower threshold (more features, lower confidence) -specfact project import from-code my-project --repo . --confidence 0.3 +specfact code import my-project --repo . --confidence 0.3 # Higher threshold (fewer features, higher confidence) -specfact project import from-code my-project --repo . --confidence 0.8 +specfact code import my-project --repo . --confidence 0.8 ``` ## Integration Examples diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 4021581e..d741b498 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -341,7 +341,7 @@ specfact init ```bash # Analyze repository (CI/CD mode - fast) -specfact project import from-code my-project \ +specfact code import my-project \ --repo ./my-project \ --shadow-only \ --report analysis.md diff --git a/docs/getting-started/tutorial-openspec-speckit.md b/docs/getting-started/tutorial-openspec-speckit.md index b7075e6e..a38d82a4 100644 --- a/docs/getting-started/tutorial-openspec-speckit.md +++ b/docs/getting-started/tutorial-openspec-speckit.md @@ -122,7 +122,7 @@ openspec init ```bash # Analyze legacy codebase cd /path/to/your-openspec-project -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . # Expected output: # 🔍 Analyzing codebase... @@ -143,7 +143,7 @@ specfact project import from-code legacy-api --repo . **Note**: If using `hatch run specfact`, run from the specfact-cli directory: ```bash cd /path/to/specfact-cli -hatch run specfact project import from-code legacy-api --repo /path/to/your-openspec-project +hatch run specfact code import legacy-api --repo /path/to/your-openspec-project ``` ### Step 4: Create an OpenSpec Change Proposal diff --git a/docs/guides/ai-ide-workflow.md b/docs/guides/ai-ide-workflow.md index 4f9702e0..2a6328f4 100644 --- a/docs/guides/ai-ide-workflow.md +++ b/docs/guides/ai-ide-workflow.md @@ -62,7 +62,7 @@ Once initialized, the following slash commands are available in your IDE: | Slash Command | Purpose | Equivalent CLI Command | |---------------|---------|------------------------| -| `/specfact.01-import` | Import from codebase | `specfact project import from-code` | +| `/specfact.01-import` | Import from codebase | `specfact code import` | | `/specfact.02-plan` | Plan management | `specfact project plan init/add-feature/add-story` | | `/specfact.03-review` | Review plan | `specfact project plan review` | | `/specfact.04-sdd` | Create SDD manifest | `specfact govern enforce sdd` | @@ -104,7 +104,7 @@ graph TD ```bash # Import from codebase -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Run validation to find gaps specfact code repro --verbose @@ -193,7 +193,7 @@ The AI IDE workflow integrates with several command chains: ```bash # 1. Analyze codebase -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . # 2. Find gaps specfact code repro --verbose diff --git a/docs/guides/brownfield-engineer.md b/docs/guides/brownfield-engineer.md index 146daf06..c1dd38d6 100644 --- a/docs/guides/brownfield-engineer.md +++ b/docs/guides/brownfield-engineer.md @@ -43,11 +43,11 @@ SpecFact CLI is designed specifically for your situation. It provides: ```bash # Analyze your legacy codebase -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app # For large codebases or multi-project repos, analyze specific modules: -specfact project import from-code core-module --repo ./legacy-app --entry-point src/core -specfact project import from-code api-module --repo ./legacy-app --entry-point src/api +specfact code import core-module --repo ./legacy-app --entry-point src/core +specfact code import api-module --repo ./legacy-app --entry-point src/api ``` **What you get:** @@ -81,10 +81,10 @@ For large codebases or monorepos with multiple projects, you can analyze specifi ```bash # Analyze only the core module -specfact project import from-code core-module --repo . --entry-point src/core +specfact code import core-module --repo . --entry-point src/core # Analyze only the API service -specfact project import from-code api-service --repo . --entry-point projects/api-service +specfact code import api-service --repo . --entry-point projects/api-service ``` This enables: @@ -227,7 +227,7 @@ You inherited a 3-year-old Django app with: ```bash # Step 1: Extract specs -specfact project import from-code customer-portal --repo ./legacy-django-app +specfact code import customer-portal --repo ./legacy-django-app # Output: ✅ Analyzed 47 Python files @@ -289,7 +289,7 @@ SpecFact CLI integrates seamlessly with your existing tools: Begin in shadow mode to observe without blocking: ```bash -specfact project import from-code legacy-api --repo . --shadow-only +specfact code import legacy-api --repo . --shadow-only ``` ### 2. Add Contracts Incrementally diff --git a/docs/guides/brownfield-faq.md b/docs/guides/brownfield-faq.md index 77870b5f..fc6b7c47 100644 --- a/docs/guides/brownfield-faq.md +++ b/docs/guides/brownfield-faq.md @@ -164,7 +164,7 @@ For large codebases, run CrossHair on critical functions first, then expand. **Recommended workflow:** -1. **Extract specs** (`specfact project import from-code`) +1. **Extract specs** (`specfact code import`) 2. **Add contracts** to 3-5 critical functions 3. **Run CrossHair** to discover edge cases 4. **Refactor incrementally** (one function at a time) diff --git a/docs/guides/brownfield-journey.md b/docs/guides/brownfield-journey.md index 46534d4f..61a32cad 100644 --- a/docs/guides/brownfield-journey.md +++ b/docs/guides/brownfield-journey.md @@ -35,7 +35,7 @@ This guide walks you through the complete brownfield modernization journey: ```bash # Analyze your legacy codebase -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app ``` **What happens:** @@ -328,7 +328,7 @@ Legacy Django app: #### Week 1: Understand -- Ran `specfact project import from-code legacy-api --repo .` → 23 features extracted in 8 seconds +- Ran `specfact code import legacy-api --repo .` → 23 features extracted in 8 seconds - Reviewed extracted plan → Identified 5 critical features - Time: 2 hours (vs. 60 hours manual) diff --git a/docs/guides/brownfield-roi.md b/docs/guides/brownfield-roi.md index 9ad8b8f2..70e2845f 100644 --- a/docs/guides/brownfield-roi.md +++ b/docs/guides/brownfield-roi.md @@ -150,7 +150,7 @@ SpecFact's code2spec provides similar automation: **Solution:** -1. Ran `specfact project import from-code` → 47 features extracted in 12 seconds +1. Ran `specfact code import` → 47 features extracted in 12 seconds 2. Added contracts to 23 critical data transformation functions 3. CrossHair discovered 6 edge cases in legacy validation logic 4. Enforced contracts during migration, blocked 11 regressions @@ -199,7 +199,7 @@ Calculate your ROI: 1. **Run code2spec** on your legacy codebase: ```bash - specfact project import from-code legacy-api --repo ./your-legacy-app + specfact code import legacy-api --repo ./your-legacy-app ``` 2. **Time the extraction** (typically < 10 seconds) diff --git a/docs/guides/command-chains.md b/docs/guides/command-chains.md index 815b17b7..a51a7284 100644 --- a/docs/guides/command-chains.md +++ b/docs/guides/command-chains.md @@ -83,7 +83,7 @@ Start: What do you want to accomplish? ```bash # Step 1: Extract specifications from legacy code -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . # Step 2: Review the extracted plan specfact project plan review legacy-api @@ -444,7 +444,7 @@ graph LR ```bash # Step 1: Import current code state -specfact project import from-code current-state --repo . +specfact code import current-state --repo . # Step 2: Compare code against plan specfact project plan compare --bundle --code-vs-plan diff --git a/docs/guides/common-tasks.md b/docs/guides/common-tasks.md index 22d97534..b49da3bc 100644 --- a/docs/guides/common-tasks.md +++ b/docs/guides/common-tasks.md @@ -29,7 +29,7 @@ This guide maps common user goals to recommended SpecFact CLI commands or comman **Quick Example**: ```bash -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . ``` **Detailed Guide**: [Brownfield Engineer Guide](brownfield-engineer.md) @@ -80,7 +80,7 @@ specfact project sync bridge --adapter speckit --bundle --bidirect **Quick Example**: ```bash -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app ``` **Detailed Guide**: [Brownfield Engineer Guide](brownfield-engineer.md#step-1-understand-what-you-have) @@ -111,7 +111,7 @@ specfact project plan update-feature --bundle legacy-api --feature **Quick Example**: ```bash -specfact project import from-code current-state --repo . +specfact code import current-state --repo . specfact project plan compare --bundle --code-vs-plan specfact code drift detect --bundle ``` diff --git a/docs/guides/competitive-analysis.md b/docs/guides/competitive-analysis.md index 76c0d5e4..fa24ea0b 100644 --- a/docs/guides/competitive-analysis.md +++ b/docs/guides/competitive-analysis.md @@ -222,7 +222,7 @@ specfact code repro --budget 120 --report evidence.md ```bash # Primary use case: Analyze legacy code -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app # Extract specs from existing code in < 10 seconds # Then enforce contracts to prevent regressions @@ -307,7 +307,7 @@ uvx specfact-cli@latest plan init --interactive ```bash # Primary use case: Analyze legacy codebase -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app ``` See [Use Cases: Brownfield Modernization](use-cases.md#use-case-1-brownfield-code-modernization-primary) ⭐ @@ -327,7 +327,7 @@ See [Use Cases: Spec-Kit Migration](use-cases.md#use-case-2-github-spec-kit-migr **Add validation layer**: 1. Let AI generate code as usual -2. Run `specfact project import from-code --repo .` (auto-detects CoPilot mode) +2. Run `specfact code import --repo .` (auto-detects CoPilot mode) 3. Review auto-generated plan 4. Enable `specfact govern enforce stage --preset balanced` diff --git a/docs/guides/copilot-mode.md b/docs/guides/copilot-mode.md index 32ae0c99..db545729 100644 --- a/docs/guides/copilot-mode.md +++ b/docs/guides/copilot-mode.md @@ -31,7 +31,7 @@ Mode is auto-detected based on environment, or you can explicitly set it with `- specfact --mode copilot import from-code legacy-api --repo . --confidence 0.7 # Mode is auto-detected based on environment (IDE integration, CoPilot API availability) -specfact project import from-code legacy-api --repo . --confidence 0.7 # Auto-detects CoPilot if available +specfact code import legacy-api --repo . --confidence 0.7 # Auto-detects CoPilot if available ``` ### What You Get with CoPilot Mode diff --git a/docs/guides/dual-stack-enrichment.md b/docs/guides/dual-stack-enrichment.md index 2f83e8eb..66c0db12 100644 --- a/docs/guides/dual-stack-enrichment.md +++ b/docs/guides/dual-stack-enrichment.md @@ -190,7 +190,7 @@ The enrichment parser expects a specific Markdown format. Follow this structure ```bash # Use enrichment to update plan via CLI -specfact project import from-code [] --repo --enrichment --no-interactive +specfact code import [] --repo --enrichment --no-interactive ``` **Result**: Final artifacts are CLI-generated with validated enrichments @@ -327,7 +327,7 @@ specfact spec generate contracts-apply enhanced_login.py --original src/auth/log - `specfact project plan init ` - Initialize project bundle - `specfact project plan select ` - Set active plan (used as default for other commands) -- `specfact project import from-code [] --repo ` - Import from codebase (uses active plan if bundle not specified) +- `specfact code import [] --repo ` - Import from codebase (uses active plan if bundle not specified) - `specfact project plan review []` - Review plan (uses active plan if bundle not specified) - `specfact project plan harden []` - Create SDD manifest (uses active plan if bundle not specified) - `specfact govern enforce sdd []` - Validate SDD (uses active plan if bundle not specified) diff --git a/docs/guides/ide-integration.md b/docs/guides/ide-integration.md index c3530acf..2c19a9fd 100644 --- a/docs/guides/ide-integration.md +++ b/docs/guides/ide-integration.md @@ -161,7 +161,7 @@ Detailed instructions for the AI assistant... | Command | Description | CLI Equivalent | |---------|-------------|----------------| -| `/specfact.01-import` | Import codebase into plan bundle | `specfact project import from-code ` | +| `/specfact.01-import` | Import codebase into plan bundle | `specfact code import ` | | `/specfact.02-plan` | Plan management (init, add-feature, add-story, update-idea, update-feature, update-story) | `specfact project plan ` | | `/specfact.03-review` | Review plan and promote through stages | `specfact project plan review `, `specfact project plan promote ` | | `/specfact.04-sdd` | Create SDD manifest from plan | `specfact project plan harden ` | diff --git a/docs/guides/import-features.md b/docs/guides/import-features.md index b74d1e1a..f858135d 100644 --- a/docs/guides/import-features.md +++ b/docs/guides/import-features.md @@ -64,10 +64,10 @@ When you restart an import on an existing bundle, the command automatically vali ```bash # First import -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Later, restart import (validates existing features automatically) -specfact project import from-code my-project --repo . +specfact code import my-project --repo . ``` ### Validation Results @@ -116,7 +116,7 @@ Features are saved immediately after the initial codebase analysis, before expen ```bash # Start import -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # Output shows: # ✓ Found 3156 features @@ -124,7 +124,7 @@ specfact project import from-code my-project --repo . # ✓ Features saved (can resume if interrupted) # If you press Ctrl+C during source linking, you can restart: -specfact project import from-code my-project --repo . +specfact code import my-project --repo . # The command will detect existing features and resume from checkpoint ``` @@ -169,7 +169,7 @@ Use `--revalidate-features` to force re-analysis even if source files haven't ch ```bash # Re-analyze all features even if files unchanged -specfact project import from-code my-project --repo . --revalidate-features +specfact code import my-project --repo . --revalidate-features # Output shows: # ⚠ --revalidate-features enabled: Will re-analyze features even if files unchanged diff --git a/docs/guides/migration-cli-reorganization.md b/docs/guides/migration-cli-reorganization.md index afd77acb..aa758d7f 100644 --- a/docs/guides/migration-cli-reorganization.md +++ b/docs/guides/migration-cli-reorganization.md @@ -197,7 +197,7 @@ Example: 'specfact constitution bootstrap' → 'specfact sdd constitution bootst ### Brownfield Import Workflow ```bash -specfact import from-code legacy-api --repo . +specfact code import legacy-api --repo . specfact sdd constitution bootstrap --repo . specfact project sync bridge --adapter speckit ``` diff --git a/docs/guides/openspec-journey.md b/docs/guides/openspec-journey.md index 7cf64125..1c327f7c 100644 --- a/docs/guides/openspec-journey.md +++ b/docs/guides/openspec-journey.md @@ -312,7 +312,7 @@ Here's how to use both tools together for legacy code modernization: ```bash # Step 1: Analyze legacy code with SpecFact -specfact project import from-code legacy-api --repo ./legacy-app +specfact code import legacy-api --repo ./legacy-app # → Extracts features from existing code # → Creates SpecFact bundle: .specfact/projects/legacy-api/ diff --git a/docs/guides/speckit-journey.md b/docs/guides/speckit-journey.md index 4d3244d8..7e8d6794 100644 --- a/docs/guides/speckit-journey.md +++ b/docs/guides/speckit-journey.md @@ -79,7 +79,7 @@ When modernizing legacy code, you can use **both tools together** for maximum va ```bash # Step 1: Use SpecFact to extract specs from legacy code -specfact project import from-code customer-portal --repo ./legacy-app +specfact code import customer-portal --repo ./legacy-app # Output: Auto-generated project bundle from existing code # ✅ Analyzed 47 Python files diff --git a/docs/guides/specmatic-integration.md b/docs/guides/specmatic-integration.md index d49d7d8f..65114f0e 100644 --- a/docs/guides/specmatic-integration.md +++ b/docs/guides/specmatic-integration.md @@ -248,7 +248,7 @@ Here's a full workflow from contract to tested implementation: ```bash # 1. Import existing code and extract contracts -specfact project import from-code user-api --repo . +specfact code import user-api --repo . # 2. Validate contracts are correct specfact spec validate --bundle user-api @@ -422,7 +422,7 @@ When importing code, SpecFact auto-detects and validates OpenAPI/AsyncAPI specs: ```bash # Import with bundle (uses active plan if --bundle not specified) -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . # Automatically validates: # - Repo-level OpenAPI/AsyncAPI specs (openapi.yaml, asyncapi.yaml) @@ -500,7 +500,7 @@ SpecFact calls Specmatic via subprocess: ```bash # Project has openapi.yaml -specfact project import from-code api-service --repo . +specfact code import api-service --repo . # Output: # ✓ Import complete! diff --git a/docs/guides/testing-terminal-output.md b/docs/guides/testing-terminal-output.md index e68b7cb4..21b7bfd5 100644 --- a/docs/guides/testing-terminal-output.md +++ b/docs/guides/testing-terminal-output.md @@ -20,7 +20,7 @@ NO_COLOR=1 specfact --help # Or export for the entire session export NO_COLOR=1 -specfact project import from-code my-bundle +specfact code import my-bundle unset NO_COLOR # Re-enable colors ``` @@ -33,7 +33,7 @@ Simulate a CI/CD pipeline (BASIC mode): CI=true specfact --help # Or simulate GitHub Actions -GITHUB_ACTIONS=true specfact project import from-code my-bundle +GITHUB_ACTIONS=true specfact code import my-bundle ``` ### Method 3: Use Dumb Terminal Type diff --git a/docs/guides/troubleshooting.md b/docs/guides/troubleshooting.md index 6c48399d..00d30bc8 100644 --- a/docs/guides/troubleshooting.md +++ b/docs/guides/troubleshooting.md @@ -115,13 +115,13 @@ specfact project plan select --last 5 1. **Check repository path**: ```bash - specfact project import from-code legacy-api --repo . --verbose + specfact code import legacy-api --repo . --verbose ``` 2. **Lower confidence threshold** (for legacy code with less structure): ```bash - specfact project import from-code legacy-api --repo . --confidence 0.3 + specfact code import legacy-api --repo . --confidence 0.3 ``` 3. **Check file structure**: @@ -139,7 +139,7 @@ specfact project plan select --last 5 5. **For legacy codebases**, start with minimal confidence and review extracted features: ```bash - specfact project import from-code legacy-api --repo . --confidence 0.2 + specfact code import legacy-api --repo . --confidence 0.2 ``` --- @@ -254,7 +254,7 @@ specfact project plan select --last 5 2. **Adjust confidence threshold**: ```bash - specfact project import from-code legacy-api --repo . --confidence 0.7 + specfact code import legacy-api --repo . --confidence 0.7 ``` 3. **Check enforcement rules** (use CLI commands): @@ -374,7 +374,7 @@ specfact project plan select --last 5 3. **Generate auto-derived plan first**: ```bash - specfact project import from-code legacy-api --repo . + specfact code import legacy-api --repo . ``` ### No Deviations Found (Expected Some) @@ -481,7 +481,7 @@ specfact project plan select --last 5 ```bash export SPECFACT_MODE=copilot - specfact project import from-code legacy-api --repo . + specfact code import legacy-api --repo . ``` 4. **See [Operational Modes](../reference/modes.md)** for details @@ -505,14 +505,14 @@ specfact project plan select --last 5 2. **Increase confidence threshold** (fewer features): ```bash - specfact project import from-code legacy-api --repo . --confidence 0.8 + specfact code import legacy-api --repo . --confidence 0.8 ``` 3. **Exclude directories**: ```bash # Use .gitignore or exclude patterns - specfact project import from-code legacy-api --repo . --exclude "tests/" + specfact code import legacy-api --repo . --exclude "tests/" ``` ### Watch Mode High CPU @@ -588,17 +588,17 @@ You can override auto-detection using standard environment variables: ```bash # Auto-detection (default behavior) -specfact project import from-code my-bundle +specfact code import my-bundle # → Automatically detects terminal and uses appropriate mode # Manual override: Disable colors -NO_COLOR=1 specfact project import from-code my-bundle +NO_COLOR=1 specfact code import my-bundle # Manual override: Force colors in CI/CD FORCE_COLOR=1 specfact project sync bridge # Manual override: Explicit CI/CD mode -CI=true specfact project import from-code my-bundle +CI=true specfact code import my-bundle ``` ### No Progress Visible in Embedded Terminals @@ -631,7 +631,7 @@ CI=true specfact project import from-code my-bundle ```bash # Force basic mode - CI=true specfact project import from-code my-bundle + CI=true specfact code import my-bundle ``` ### Colors Not Working in CI/CD @@ -643,7 +643,7 @@ CI=true specfact project import from-code my-bundle **Solution**: This is expected behavior. CI/CD logs are more readable without colors. To force colors: ```bash -FORCE_COLOR=1 specfact project import from-code my-bundle +FORCE_COLOR=1 specfact code import my-bundle ``` --- diff --git a/docs/guides/use-cases.md b/docs/guides/use-cases.md index b2db5bd7..19226ac6 100644 --- a/docs/guides/use-cases.md +++ b/docs/guides/use-cases.md @@ -29,14 +29,14 @@ Detailed use cases and examples for SpecFact CLI. ```bash # CI/CD mode (fast, deterministic) - Full repository -specfact project import from-code \ +specfact code import \ --repo . \ --shadow-only \ --confidence 0.7 \ --report analysis.md # Partial analysis (large codebases or monorepos) -specfact project import from-code \ +specfact code import \ --repo . \ --entry-point src/core \ --confidence 0.7 \ diff --git a/docs/guides/ux-features.md b/docs/guides/ux-features.md index 5544dc2a..33898e2d 100644 --- a/docs/guides/ux-features.md +++ b/docs/guides/ux-features.md @@ -17,7 +17,7 @@ SpecFact CLI uses progressive disclosure to show the most important options firs By default, `--help` shows only the most commonly used options: ```bash -specfact project import from-code --help +specfact code import --help ``` This displays: @@ -32,7 +32,7 @@ This displays: To see all options including advanced configuration, use `--help-advanced` (alias: `-ha`): ```bash -specfact project import from-code --help-advanced +specfact code import --help-advanced ``` This reveals: @@ -88,10 +88,10 @@ The following options are hidden by default across commands: ```bash # This works even though --confidence is hidden in regular help: -specfact project import from-code my-bundle --confidence 0.7 --key-format sequential +specfact code import my-bundle --confidence 0.7 --key-format sequential # To see all options in help: -specfact project import from-code --help-advanced # or -ha +specfact code import --help-advanced # or -ha ``` ## Context Detection @@ -126,7 +126,7 @@ You can also explicitly check your project context: ```bash # Context detection is automatic, but you can verify -specfact project import from-code my-bundle --repo . +specfact code import my-bundle --repo . # CLI automatically detects Python, FastAPI, existing specs, etc. ``` @@ -139,7 +139,7 @@ SpecFact provides context-aware suggestions to guide your workflow. After running commands, SpecFact suggests logical next steps: ```bash -$ specfact project import from-code legacy-api +$ specfact code import legacy-api ✓ Import complete 💡 Suggested next steps: @@ -158,7 +158,7 @@ $ specfact code analyze --bundle missing-bundle 💡 Suggested fixes: • specfact project plan select # Select an active plan bundle - • specfact project import from-code missing-bundle # Create a new bundle + • specfact code import missing-bundle # Create a new bundle ``` ### Improvements @@ -171,7 +171,7 @@ $ specfact code analyze --bundle legacy-api 💡 Suggested improvements: • specfact code analyze --bundle legacy-api # Identify missing contracts - • specfact project import from-code legacy-api # Extract contracts from code + • specfact code import legacy-api # Extract contracts from code ``` ## Template-Driven Quality diff --git a/docs/guides/workflows.md b/docs/guides/workflows.md index b2b95d9c..c30629e2 100644 --- a/docs/guides/workflows.md +++ b/docs/guides/workflows.md @@ -29,11 +29,11 @@ Reverse engineer existing code and enforce contracts incrementally. ```bash # Full repository analysis -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . # For large codebases, analyze specific modules: -specfact project import from-code core-module --repo . --entry-point src/core -specfact project import from-code api-module --repo . --entry-point src/api +specfact code import core-module --repo . --entry-point src/core +specfact code import api-module --repo . --entry-point src/api ``` ### Step 2: Review Extracted Specs @@ -63,13 +63,13 @@ For large codebases or monorepos with multiple projects, use `--entry-point` to ```bash # Analyze individual projects in a monorepo -specfact project import from-code api-service --repo . --entry-point projects/api-service -specfact project import from-code web-app --repo . --entry-point projects/web-app -specfact project import from-code mobile-app --repo . --entry-point projects/mobile-app +specfact code import api-service --repo . --entry-point projects/api-service +specfact code import web-app --repo . --entry-point projects/web-app +specfact code import mobile-app --repo . --entry-point projects/mobile-app # Analyze specific modules for incremental modernization -specfact project import from-code core-module --repo . --entry-point src/core -specfact project import from-code integrations-module --repo . --entry-point src/integrations +specfact code import core-module --repo . --entry-point src/core +specfact code import integrations-module --repo . --entry-point src/integrations ``` **Benefits:** diff --git a/docs/prompts/README.md b/docs/prompts/README.md index 8f874108..fe7f8315 100644 --- a/docs/prompts/README.md +++ b/docs/prompts/README.md @@ -34,7 +34,7 @@ SpecFact CLI provides slash commands that work with AI-assisted IDEs (Cursor, VS **Purpose**: Import from codebase (brownfield modernization) -**Equivalent CLI**: `specfact project import from-code` +**Equivalent CLI**: `specfact code import` **Example**: diff --git a/docs/reference/README.md b/docs/reference/README.md index 237ce21d..41d965d4 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -31,7 +31,7 @@ Complete technical reference for SpecFact CLI. ### Commands - `specfact project import from-bridge --adapter speckit` - Import from external tools via bridge adapter -- `specfact project import from-code ` - Reverse-engineer plans from code +- `specfact code import ` - Reverse-engineer plans from code - `specfact project plan init ` - Initialize new development plan - `specfact project plan compare` - Compare manual vs auto plans - `specfact govern enforce stage` - Configure quality gates diff --git a/docs/reference/command-syntax-policy.md b/docs/reference/command-syntax-policy.md index a75796d9..8e9e9659 100644 --- a/docs/reference/command-syntax-policy.md +++ b/docs/reference/command-syntax-policy.md @@ -19,7 +19,7 @@ Always document commands exactly as implemented by `specfact --help` i ## Bundle Argument Conventions (v0.30.x baseline) - Positional bundle argument: - - `specfact project import from-code [BUNDLE]` + - `specfact code import [BUNDLE]` - `specfact project plan init BUNDLE` - `specfact project plan review [BUNDLE]` - `--bundle` option: @@ -43,7 +43,7 @@ Before merging command docs updates: ## Quick Verification Commands ```bash -hatch run specfact project import from-code --help +hatch run specfact code import --help hatch run specfact project plan init --help hatch run specfact project plan review --help hatch run specfact project plan add-feature --help diff --git a/docs/reference/commands.md b/docs/reference/commands.md index 951e30f6..aadc08be 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -76,7 +76,7 @@ specfact init --profile solo-developer specfact module install nold-ai/specfact-backlog # Project workflow examples -specfact project import from-code legacy-api --repo . +specfact code import legacy-api --repo . specfact project plan review legacy-api # Code workflow examples diff --git a/docs/reference/directory-structure.md b/docs/reference/directory-structure.md index 8997137d..785ccb2c 100644 --- a/docs/reference/directory-structure.md +++ b/docs/reference/directory-structure.md @@ -388,13 +388,13 @@ See [`plan upgrade`](../reference/commands.md#plan-upgrade) for details. ## Default Command Paths -### `specfact project import from-code` ⭐ PRIMARY +### `specfact code import` ⭐ PRIMARY **Primary use case**: Reverse-engineer existing codebases into project bundles. ```bash # Command syntax -specfact project import from-code --repo . [OPTIONS] +specfact code import --repo . [OPTIONS] # Creates modular bundle at: .specfact/projects// @@ -415,7 +415,7 @@ specfact project import from-code --repo . [OPTIONS] ```bash # Analyze legacy codebase -specfact project import from-code legacy-api --repo . --confidence 0.7 +specfact code import legacy-api --repo . --confidence 0.7 # Creates: # - .specfact/projects/legacy-api/bundle.manifest.yaml (versioned) @@ -746,7 +746,7 @@ SpecFact supports multiple plan bundles for: ```bash # Step 1: Reverse-engineer legacy codebase -specfact project import from-code legacy-api \ +specfact code import legacy-api \ --repo src/legacy-api \ --confidence 0.7 @@ -756,7 +756,7 @@ specfact project plan compare \ --auto .specfact/projects/modernized-api # Step 3: Analyze specific legacy component -specfact project import from-code legacy-payment \ +specfact code import legacy-payment \ --repo src/legacy-payment \ --confidence 0.7 ``` diff --git a/docs/reference/feature-keys.md b/docs/reference/feature-keys.md index 21d3aeeb..382ec6c7 100644 --- a/docs/reference/feature-keys.md +++ b/docs/reference/feature-keys.md @@ -19,7 +19,7 @@ SpecFact CLI supports multiple feature key formats to accommodate different use **Generation**: ```bash -specfact project import from-code --key-format classname +specfact code import --key-format classname ``` ### 2. Sequential Format @@ -33,7 +33,7 @@ specfact project import from-code --key-format classname **Generation**: ```bash -specfact project import from-code --key-format sequential +specfact code import --key-format sequential ``` **Manual creation**: When creating plans interactively, use `FEATURE-001` format: @@ -171,7 +171,7 @@ specfact project plan init When analyzing existing codebases: ```bash -specfact project import from-code --key-format classname # ← Default, explicit for clarity +specfact code import --key-format classname # ← Default, explicit for clarity ``` **Why**: Classname format directly maps to codebase structure, making it easy to trace features back to classes. diff --git a/docs/reference/modes.md b/docs/reference/modes.md index 945105db..36a1528f 100644 --- a/docs/reference/modes.md +++ b/docs/reference/modes.md @@ -223,7 +223,7 @@ print(f'Execution mode: {result.execution_mode}') # In GitHub Actions or CI/CD # No environment variables set # Should auto-detect CI/CD mode (bundle name as positional argument) -hatch run specfact project import from-code my-project --repo . --confidence 0.7 +hatch run specfact code import my-project --repo . --confidence 0.7 # Expected: Mode: CI/CD (direct execution) ``` @@ -234,7 +234,7 @@ hatch run specfact project import from-code my-project --repo . --confidence 0.7 # Developer running in VS Code/Cursor with CoPilot enabled # IDE environment variables automatically set # Should auto-detect CoPilot mode (bundle name as positional argument) -hatch run specfact project import from-code my-project --repo . --confidence 0.7 +hatch run specfact code import my-project --repo . --confidence 0.7 # Expected: Mode: CoPilot (agent routing) ``` diff --git a/docs/reference/telemetry.md b/docs/reference/telemetry.md index 4306c17f..f325641b 100644 --- a/docs/reference/telemetry.md +++ b/docs/reference/telemetry.md @@ -488,7 +488,7 @@ Only if you explicitly opt in. We recommend enabling telemetry in CI/CD to track **How do I verify telemetry is working?** 1. Enable debug mode: `export SPECFACT_TELEMETRY_DEBUG=true` -2. Run a command: `specfact project import from-code --repo .` +2. Run a command: `specfact code import --repo .` 3. Check local log: `tail -f ~/.specfact/telemetry.log` 4. Verify events appear in your OTLP collector (if configured) diff --git a/docs/technical/code2spec-analysis-logic.md b/docs/technical/code2spec-analysis-logic.md index d6716f1c..2760d924 100644 --- a/docs/technical/code2spec-analysis-logic.md +++ b/docs/technical/code2spec-analysis-logic.md @@ -15,7 +15,7 @@ Uses **AI IDE's native LLM** for semantic understanding via pragmatic integratio **Workflow**: 1. **AI IDE's LLM** understands codebase semantically (via slash command prompt) -2. **AI calls SpecFact CLI** (`specfact project import from-code `) for structured analysis +2. **AI calls SpecFact CLI** (`specfact code import `) for structured analysis 3. **AI enhances results** with semantic understanding (priorities, constraints, unknowns) 4. **CLI handles structured work** (file I/O, YAML generation, validation) @@ -66,7 +66,7 @@ Uses **Python's AST + Semgrep pattern matching** for comprehensive structural an ```mermaid flowchart TD - A["code2spec Command
specfact project import from-code my-project --repo . --confidence 0.5"] --> B{Operational Mode} + A["code2spec Command
specfact code import my-project --repo . --confidence 0.5"] --> B{Operational Mode} B -->|CoPilot Mode| C["AnalyzeAgent (AI-First)
• LLM semantic understanding
• Multi-language support
• Semantic extraction (priorities, constraints, unknowns)
• High-quality Spec-Kit artifacts"] diff --git a/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md index f560248e..16ff5b72 100644 --- a/openspec/CHANGE_ORDER.md +++ b/openspec/CHANGE_ORDER.md @@ -104,6 +104,7 @@ These are derived extensions of the same 2026-02-15 plan and are required to ope | module-migration | 08 | module-migration-08-release-suite-stabilization | TBD | module-migration-03/04/06/07 merged; residual release-suite regressions after migration merge | | module-migration | 09 | backlog-module-ownership-cleanup | TBD | module-migration-06; backlog-core-07; cli-val-07 findings | | module-migration | 10 | module-migration-10-bundle-command-surface-alignment | [#385](https://github.com/nold-ai/specfact-cli/issues/385) | module-migration-02 ✅; module-migration-06/07 baseline; cli-val-07 findings | +| module-migration | 11 | module-migration-11-project-codebase-ownership-realignment | [#408](https://github.com/nold-ai/specfact-cli/issues/408) | module-migration-06 baseline; backlog-module-ownership-cleanup precedent; blocks final canonical import-path decisions in module-migration-10 | | init-ide | 01 | init-ide-prompt-source-selection | TBD | backlog-module-ownership-cleanup | | backlog-auth | 01 | backlog-auth-01-backlog-auth-commands | TBD | module-migration-03 (central auth interface in core; auth removed from core) | diff --git a/openspec/changes/module-migration-10-bundle-command-surface-alignment/proposal.md b/openspec/changes/module-migration-10-bundle-command-surface-alignment/proposal.md index 597ae843..78705711 100644 --- a/openspec/changes/module-migration-10-bundle-command-surface-alignment/proposal.md +++ b/openspec/changes/module-migration-10-bundle-command-surface-alignment/proposal.md @@ -22,7 +22,7 @@ This must be treated as a product/runtime alignment issue first, not just a docs - `bundle-command-surface-alignment`: Official bundle command trees match the documented grouped CLI surface for shipped releases. ## Acceptance Criteria -- Installed official bundles expose documented grouped commands such as `specfact project import from-code`, `specfact project plan ...`, and `specfact spec generate ...` when those commands are intended to be public in `v0.40.x`. +- Installed official bundles expose documented grouped commands such as `specfact code import`, `specfact project plan ...`, and `specfact spec generate ...` when those commands are intended to be public in `v0.40.x`. - If a command path is intentionally not part of the shipped runtime surface, README/docs/release content no longer describe it as available. - Runtime validation fails when a documented grouped command path is missing from the installed official bundle command tree. - Release-content examples no longer rely on slash-command-only fallbacks to paper over missing CLI registration. diff --git a/openspec/changes/module-migration-10-bundle-command-surface-alignment/specs/bundle-command-surface-alignment/spec.md b/openspec/changes/module-migration-10-bundle-command-surface-alignment/specs/bundle-command-surface-alignment/spec.md index 292e5ffe..f01e022d 100644 --- a/openspec/changes/module-migration-10-bundle-command-surface-alignment/specs/bundle-command-surface-alignment/spec.md +++ b/openspec/changes/module-migration-10-bundle-command-surface-alignment/specs/bundle-command-surface-alignment/spec.md @@ -7,7 +7,7 @@ The system SHALL ensure that grouped CLI commands documented for a shipped relea #### Scenario: Documented project subgroup commands resolve - **GIVEN** the official `nold-ai/specfact-project` bundle is installed -- **WHEN** the user runs documented grouped command paths such as `specfact project import from-code --help` or `specfact project plan review --help` +- **WHEN** the user runs documented grouped command paths such as `specfact code import --help` or `specfact project plan review --help` - **THEN** the command path resolves successfully from the installed bundle runtime - **AND** the help output reflects the mounted subgroup command rather than `No such command`. diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/OWNERSHIP_MATRIX.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/OWNERSHIP_MATRIX.md new file mode 100644 index 00000000..fafcf8dd --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/OWNERSHIP_MATRIX.md @@ -0,0 +1,66 @@ +# Project vs Codebase Ownership Matrix + +## Current Runtime Surface + +### Core CLI group mounting + +| Surface | Current owner | Evidence | Notes | +|---|---|---|---| +| `specfact project ...` | `specfact-project` bundle | `src/specfact_cli/groups/project_group.py` | Mounts `project`, `plan`, `import`, `sync`, `migrate` | +| `specfact code ...` | `specfact-codebase` bundle | `src/specfact_cli/groups/codebase_group.py` | Mounts only `analyze`, `drift`, `validate`, `repro` | + +### Brownfield import path + +| Concern | Current owner | Evidence | Problem | +|---|---|---|---| +| Public grouped path | `project` | `docs/reference/commands.md`, `README.md`, `module-migration-10` active spec | Code-first workflow is exposed as project-owned | +| Actual command implementation | `specfact_project.import_cmd` | `packages/specfact-project/src/specfact_project/import_cmd/commands.py` | Canonical implementation lives under project bundle | +| `code` aggregate bundle app | `specfact-codebase.code` | `packages/specfact-codebase/src/specfact_codebase/code/commands.py` | No `import` subtree exists today | + +## Contradictory Archived Ownership Records + +| Subsystem / path | Archived source | Recorded owner | +|---|---|---| +| `import_cmd` | `module-migration-01`, `module-grouping` spec, `bundle-extraction` spec | `specfact-project` | +| `analyzers` | `IMPORT_DEPENDENCY_ANALYSIS.md`, `MIGRATION_REMOVAL_PLAN.md` | `specfact-codebase` | +| `comparators` | `IMPORT_DEPENDENCY_ANALYSIS.md`, `MIGRATION_REMOVAL_PLAN.md` | `specfact-codebase` | +| brownfield-oriented `parsers` | `IMPORT_DEPENDENCY_ANALYSIS.md`, `MIGRATION_REMOVAL_PLAN.md` | `specfact-codebase` | +| migrated local package placement | `module-migration-05-modules-repo-quality/tasks.md` section 19.2 | copied into `specfact_project` | + +## Current Helper / Subsystem Placement + +### In `specfact-project` + +- `import_cmd` +- `agents` +- `analyzers` +- `comparators` +- `parsers` +- `sync_runtime` +- project-bundle artifact lifecycle commands (`project`, `plan`, `sync`, `migrate`) + +### In `specfact-codebase` + +- `code` aggregate app +- `analyze` +- `drift` +- `validate` +- `repro` +- `validators.sidecar` +- `validators.repro_checker` +- `sync.drift_detector` + +## Pending Active Changes That Must Align + +| Change | Why alignment is required | +|---|---| +| `module-migration-10-bundle-command-surface-alignment` | Currently treats `specfact project import from-code` as the documented grouped contract | +| `init-ide-prompt-source-selection` | Prompt source ownership must not re-assert obsolete import paths | +| docs/prompt updates under current release branch | README, prompt validation, suggestions, and docs all reference the import path users are told to run | + +## Target Rule From This Change + +- `code` owns commands whose primary input is source code or runtime code evidence +- `project` owns SpecFact project bundle/workspace artifact lifecycle +- `specfact code import` is canonical in the target state +- temporary aliases such as `project import from-code` are acceptable only as compatibility behavior during transition diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/TDD_EVIDENCE.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/TDD_EVIDENCE.md new file mode 100644 index 00000000..22de509a --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/TDD_EVIDENCE.md @@ -0,0 +1,85 @@ +# TDD Evidence: module-migration-11-project-codebase-ownership-realignment + +## Pre-Implementation Failing Evidence + +### Core Ownership And Audit Coverage + +Command: + +```bash +hatch run pytest tests/unit/groups/test_codebase_group.py tests/unit/groups/test_project_group.py tests/unit/validation/test_command_audit.py -q +``` + +Result: failed + +Key failures: + +- `tests/unit/groups/test_codebase_group.py` + - expected `import` under the `code` group + - actual subcommands: `['analyze', 'drift', 'validate', 'repro']` +- `tests/unit/groups/test_project_group.py` + - expected `import` to be absent from the `project` group + - actual subcommands: `['project', 'plan', 'import', 'sync', 'migrate']` +- `tests/unit/validation/test_command_audit.py` + - expected audit coverage for `code import` + - actual command audit paths did not include `code import` + +### Modules Codebase Command App Coverage + +Command: + +```bash +hatch run pytest tests/integration/specfact_codebase/test_command_apps.py -q +``` + +Result: failed + +Key failures: + +- `specfact_codebase.import_cmd.commands` does not exist yet +- existing codebase command modules also fail to import in the worktree test env because `specfact-cli` dev dependencies have not been synced into the local Hatch environment yet (`ModuleNotFoundError: specfact_cli`, `ModuleNotFoundError: beartype`) + +Interpretation: + +- the canonical `specfact code import` surface is not implemented yet +- the project-owned import surface is still present +- the modules worktree needs `dev-deps` synchronized before post-implementation verification can be trusted + +## Post-Implementation Passing Evidence + +### Core Ownership And Command Audit Coverage + +Command: + +```bash +SPECFACT_MODULES_REPO=/home/dom/git/nold-ai/specfact-cli-modules-worktrees/bugfix/module-migration-11-project-codebase-ownership-realignment hatch run pytest tests/unit/groups/test_codebase_group.py tests/unit/groups/test_project_group.py tests/unit/validation/test_command_audit.py -q +``` + +Result: passed + +Verified: + +- `code` group now exposes `import` +- category-level `project` group no longer mounts brownfield import as a top-level group member +- command audit inventory now includes `code import` + +### Modules Codebase Command App Coverage + +Command: + +```bash +PYTHONPATH=/home/dom/git/nold-ai/specfact-cli-worktrees/bugfix/module-migration-11-project-codebase-ownership-realignment/src:/home/dom/.local/lib/python3.11/site-packages:/usr/lib/python3/dist-packages hatch run pytest tests/integration/specfact_codebase/test_command_apps.py tests/e2e/specfact_codebase/test_help_smoke.py -q +``` + +Result: passed + +Verified: + +- `specfact_codebase.import_cmd.commands` exists and exports a Typer app +- `specfact_codebase.code.commands` mounts the new import surface +- `code import --help` renders cleanly at the module-app level + +### Notes + +- The implementation intentionally uses temporary delegation from `specfact_codebase.import_cmd` into the existing brownfield import logic in `specfact_project.import_cmd.commands` while ownership is realigned. +- A broader temp-home marketplace install/runtime audit was started in the core worktree, but it did not complete in a timely way during this turn, so the passing evidence above is the recorded verification baseline. diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/design.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/design.md new file mode 100644 index 00000000..7d697624 --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/design.md @@ -0,0 +1,120 @@ +# Design: Project And Codebase Ownership Realignment + +## Context + +The migration wave established five grouped bundle families: + +- `project` +- `backlog` +- `code` +- `spec` +- `govern` + +But the `project` family inherited two different meanings: + +1. the old plan/bundle artifact workflow +2. the brownfield code-ingestion entrypoint currently exposed as `import from-code` + +That mix became unstable during follow-up migration work. Archived artifacts disagree about where the brownfield analysis internals belong: + +- migration-01 and migration-02 put `import_cmd` in `specfact-project` +- migration-02 dependency analysis mapped `analyzers`, `comparators`, and `parsers` to `specfact-codebase` +- migration-05 later copied those subsystems into `specfact_project` +- migration-06 removal planning still describes those subsystems as `specfact-codebase` targets + +So the current system has a command path and code layout that are internally consistent enough to run, but not conceptually coherent enough to guide future work. + +## Goals + +- Define a stable rule for `project` versus `codebase` ownership that is easy to apply in code, docs, prompts, and future migrations. +- Make command ownership follow the command's primary domain, not just the artifact it happens to emit. +- Reduce the chance that pending changes keep reinforcing the wrong bundle boundary. + +## Non-Goals + +- Revisit the full five-bundle architecture. +- Fold backlog, spec, or govern ownership cleanup into this change. +- Reintroduce flat top-level command shims. + +## Design Decisions + +### 1. Ownership is based on primary input domain + +Command ownership SHALL follow the command's primary domain of analysis or manipulation: + +- If the command primarily inspects or derives behavior from source code, tests, or runtime codebase evidence, it belongs to `code`. +- If the command primarily manipulates an existing SpecFact project bundle, its files, or its editable artifacts, it belongs to `project`. + +This rule is more stable than deciding ownership from the output artifact. Many code-first commands emit project-bundle state, but that does not make them project-lifecycle commands. + +### 2. `specfact code import` is codebase-owned in the target state + +The brownfield import workflow is fundamentally code-analysis-driven: + +- primary input: repository source tree +- core work: analyze code, derive features/contracts/relationships, compare inferred structure +- output: a SpecFact project bundle + +The command therefore belongs to `specfact code ...` in the target state. + +Target public path: + +```text +specfact code import --repo . +``` + +Compatibility transition: + +- `specfact project import from-code ...` MAY remain temporarily as a deprecation alias during the migration window +- `specfact code import from-code ...` MAY exist temporarily as an internal compatibility shim if needed during rename rollout, but SHALL NOT be documented as canonical +- docs, prompts, and validation inventory SHALL treat `specfact code import ...` as the canonical path once this change lands +- mode distinctions such as bridge-driven import, shadow-only runs, enrichment, or future source-type variants SHALL be expressed as options or explicit alternate subcommands only when they represent materially different workflows + +### 3. `project` is narrowed to bundle/workspace artifact lifecycle + +`specfact project ...` SHALL mean: + +- commands that manage SpecFact project bundles/workspaces directly +- plan/project artifact review and editing flows +- import/export/migrate/select/list operations whose primary subject is the bundle itself, not the external codebase + +This keeps `project` aligned with the renamed successor of the original plan bundle lifecycle instead of turning it into a generic catch-all for anything that eventually writes bundle files. + +### 4. Brownfield analysis internals move with the codebase owner + +The following subsystem families SHALL be treated as codebase-owned unless a narrower exception is documented: + +- `analyzers` +- `comparators` +- brownfield-oriented `parsers` +- code-analysis-specific agents/helpers used by the brownfield import workflow + +Project-owned helpers remain in `specfact-project` only when they are about bundle transformation, editable artifact generation, or project lifecycle orchestration rather than codebase inspection. + +### 5. Pending changes must not finalize conflicting import paths + +Until this ownership change is resolved, other active changes must not hard-code contradictory assumptions: + +- `module-migration-10-bundle-command-surface-alignment` must not treat `specfact project import from-code` or `specfact code import from-code` as the final public command contract without referencing this decision +- docs/prompt alignment fixes must avoid re-asserting the old project-owned path as canonical +- future decoupling or cleanup work must use the canonical owner defined here when moving internals + +## Implementation Outline + +1. Create an ownership matrix for current `project` and `codebase` commands, prompts, tests, helpers, and docs references. +2. Add spec deltas defining the canonical ownership rule and target command topology. +3. Add failing runtime/docs validation for the target canonical import path and ownership boundaries. +4. Move brownfield import command ownership from `project` to `code`, including internal subsystem ownership updates. +5. Introduce a temporary compatibility alias only if needed for release transition. +6. Update active pending changes and validation inventories so they point at the canonical owner. + +## Risks + +- Reclassifying the public import path can affect docs, tests, IDE prompts, and existing user habits at the same time. +- A temporary alias may require a short-lived dependency edge or compatibility layer between `project` and `codebase`. +- Some helpers currently living under `specfact_project` may be mixed-purpose and need explicit triage instead of bulk movement. + +## Open Questions + +- Which existing `project` subcommands, if any, should remain nested under `project import ...` for bundle-artifact import/export cases unrelated to code analysis? +- Whether the transition should ship a deprecation alias for one release line or switch directly if the grouped path is still pre-stable. diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/proposal.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/proposal.md new file mode 100644 index 00000000..4f13c2cc --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/proposal.md @@ -0,0 +1,53 @@ +# Change: Project And Codebase Ownership Realignment + +## Why + +The post-migration bundle model leaves a fuzzy boundary between `specfact-project` and `specfact-codebase`. + +Archived migration changes explicitly classified `import_cmd` under the `project` category, but later migration work also copied major code-analysis subsystems into `specfact_project` even though earlier dependency analysis and later removal-planning documents still treated those subsystems as `specfact-codebase` ownership. The result is an ambiguous runtime and design model: + +- `specfact project import from-code` remained the public path even though the command's primary input is a source codebase +- brownfield analysis internals (`analyzers`, `comparators`, `parsers`, related agents/helpers) are not consistently owned across migration documents +- active follow-up changes can accidentally reinforce the wrong bundle boundary because the ownership decision is not explicit + +This is not just a docs problem. The product needs a durable ownership rule for what belongs in `project` versus `code`, otherwise future bundle-surface fixes, prompt updates, dependency cleanup, and docs work will continue to drift. + +## What Changes + +- Define the canonical ownership boundary between the `project` and `codebase` categories after the plan-to-project rename. +- Reclassify code-first brownfield analysis behavior under `specfact code ...`, with `import` treated as codebase-owned rather than project-owned. +- Define `specfact project ...` as the owner of SpecFact bundle/workspace artifact lifecycle commands rather than generic code-ingestion behavior. +- Realign internal subsystem ownership so code-analysis internals live with `specfact-codebase` instead of remaining implicitly attached to `specfact-project`. +- Add a transition plan and validation coverage so pending changes and release docs do not reintroduce contradictory command ownership assumptions. + +## Capabilities +### New Capabilities + +- `project-codebase-ownership`: Explicit, testable ownership rules for `project` versus `codebase` command families and internal subsystems. + +## Acceptance Criteria + +- The spec and design explicitly define ownership by primary domain: + - `specfact code ...` owns commands whose primary input is source code or runtime codebase behavior + - `specfact project ...` owns commands whose primary subject is the SpecFact project bundle/workspace and its editable artifacts +- `specfact code import` is defined as the canonical codebase-owned command path in the target state, with a documented compatibility plan for any temporary legacy alias that remains during migration. +- Brownfield analysis internals currently split or ambiguously owned across migration documents are assigned to a single canonical bundle owner and the expected bundle boundaries are documented. +- Pending changes that touch command surface, docs, prompts, or migration cleanup reference the new ownership decision instead of encoding conflicting assumptions. +- Validation coverage is planned to fail if runtime command ownership and documented ownership diverge again. + +## Dependencies + +- `module-migration-06-core-decoupling-cleanup` documented the residual migrated subsystem inventory and still references code-analysis ownership boundaries that need resolution. +- `module-migration-10-bundle-command-surface-alignment` must align with the ownership decision in this change before finalizing public import command paths. +- `backlog-module-ownership-cleanup` is the architectural precedent for fixing post-migration ownership drift after the initial extraction wave. + + +--- + +## Source Tracking + + +- **GitHub Issue**: #408 +- **Issue URL**: +- **Last Synced Status**: proposed +- **Sanitized**: false diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/specs/project-codebase-ownership/spec.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/specs/project-codebase-ownership/spec.md new file mode 100644 index 00000000..bddabccc --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/specs/project-codebase-ownership/spec.md @@ -0,0 +1,44 @@ +## ADDED Requirements + +### Requirement: Codebase Commands Own Code-First Brownfield Workflows + +The system SHALL treat commands whose primary input is a source codebase or runtime code evidence as `code` category commands. + +#### Scenario: Brownfield import is code-owned +- **WHEN** the user runs the canonical code-first brownfield import workflow +- **THEN** the workflow resolves from the `specfact code ...` command surface +- **AND** `specfact code import` is treated as the canonical codebase-owned entrypoint rather than a project-owned path in the target command model. + +#### Scenario: Compatibility alias is transitional only +- **GIVEN** a temporary compatibility alias exists for a pre-realignment path such as `specfact project import from-code` +- **WHEN** the command is invoked during the migration window +- **THEN** the system routes to the code-owned implementation +- **AND** the alias is documented as compatibility behavior rather than the canonical ownership model. + +### Requirement: Project Commands Own SpecFact Bundle Artifact Lifecycle + +The system SHALL reserve the `project` category for commands whose primary subject is the SpecFact project bundle/workspace and its editable artifacts. + +#### Scenario: Project surface manages bundle artifacts +- **WHEN** a command primarily selects, reviews, edits, imports, exports, migrates, or otherwise manages SpecFact project bundle artifacts +- **THEN** that command belongs to the `specfact project ...` surface +- **AND** the command is not classified as codebase-owned solely because the artifact may later be synchronized with source code. + +### Requirement: Brownfield Analysis Internals Have A Single Canonical Owner + +Subsystems that implement code-first brownfield analysis SHALL have one documented canonical bundle owner. + +#### Scenario: Analysis subsystems align with codebase ownership +- **WHEN** bundle ownership is resolved for brownfield analysis internals +- **THEN** `analyzers`, `comparators`, brownfield-oriented `parsers`, and related import-analysis helpers are assigned to the codebase owner unless an explicit documented exception exists +- **AND** migration plans, runtime registration, and docs do not describe contradictory owners for the same subsystem family. + +### Requirement: Pending Changes Must Align With The Ownership Decision + +Pending OpenSpec changes that touch command surface, docs, prompts, or migration cleanup SHALL align with the canonical `project` versus `codebase` ownership model. + +#### Scenario: Active change does not finalize conflicting import ownership +- **GIVEN** an active pending change updates grouped command paths or release-facing docs +- **WHEN** that change references brownfield import ownership +- **THEN** it references the canonical owner defined by this change +- **AND** it does not re-establish a conflicting public command path or subsystem owner by implication. diff --git a/openspec/changes/module-migration-11-project-codebase-ownership-realignment/tasks.md b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/tasks.md new file mode 100644 index 00000000..08c0a502 --- /dev/null +++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/tasks.md @@ -0,0 +1,32 @@ +## 1. Inventory And Decision Baseline + +- [x] 1.1 Freeze the current `project` versus `codebase` ownership matrix for commands, prompts, docs, tests, and helper subsystems. +- [x] 1.2 Record the contradictory archived references that currently place brownfield analysis internals in both `specfact-project` and `specfact-codebase`. +- [x] 1.3 Identify active pending changes that must align with this ownership decision (`module-migration-10` minimum, plus any docs/prompt follow-ups that reference import command paths). + +## 2. Spec And Design First + +- [x] 2.1 Add spec deltas for canonical `project` and `codebase` ownership boundaries. +- [x] 2.2 Define the target public command path for code-first brownfield import and any temporary compatibility alias policy. +- [x] 2.3 Update `openspec/CHANGE_ORDER.md` dependency notes so pending changes do not finalize conflicting import ownership assumptions. + +## 3. Test-First Realignment + +- [x] 3.1 Add failing regression coverage proving code-first import is owned by the `code` surface in the target model. +- [x] 3.2 Add failing regression coverage proving `project` is limited to project-bundle/workspace lifecycle behavior rather than code-analysis ownership. +- [x] 3.3 Add failing validation coverage for docs/runtime ownership drift so future changes cannot silently reintroduce contradictory public paths. +- [x] 3.4 Record the failing evidence in `TDD_EVIDENCE.md`. + +## 4. Runtime And Bundle Ownership Refactor + +- [x] 4.1 Move brownfield import runtime ownership from `specfact-project` to `specfact-codebase`, making `specfact code import` canonical (with a bounded compatibility alias only where needed during transition). +- [x] 4.2 Move or reclassify brownfield analysis internals (`analyzers`, `comparators`, relevant `parsers`, and related helpers/agents) to the canonical codebase owner. +- [x] 4.3 Keep only true bundle/project artifact lifecycle behavior in `specfact-project`. +- [x] 4.4 Update package dependencies, command registration, and validation inventories to match the new ownership boundary. + +## 5. Alignment And Validation + +- [x] 5.1 Update active pending change artifacts that currently assume the pre-realignment import ownership model. +- [x] 5.2 Update release-facing docs, prompts, and suggestion text to the canonical command path and ownership wording. +- [x] 5.3 Re-run targeted runtime validation and ownership tests; record passing evidence in `TDD_EVIDENCE.md`. +- [x] 5.4 Run `openspec validate module-migration-11-project-codebase-ownership-realignment --strict`. diff --git a/resources/prompts/shared/cli-enforcement.md b/resources/prompts/shared/cli-enforcement.md index c2952dbd..b8aab9aa 100644 --- a/resources/prompts/shared/cli-enforcement.md +++ b/resources/prompts/shared/cli-enforcement.md @@ -109,7 +109,7 @@ When generating or enhancing code via LLM, **ALWAYS** follow this pattern: - `specfact plan init ` - Initialize project bundle - `specfact plan select ` - Set active plan (used as default for other commands) -- `specfact import from-code [] --repo ` - Import from codebase (uses active plan if bundle not specified) +- `specfact code import [] --repo ` - Import from codebase (uses active plan if bundle not specified) - `specfact plan review []` - Review plan (uses active plan if bundle not specified) - `specfact plan harden []` - Create SDD manifest (uses active plan if bundle not specified) - `specfact enforce sdd []` - Validate SDD (uses active plan if bundle not specified) diff --git a/resources/prompts/specfact.03-review.md b/resources/prompts/specfact.03-review.md index 35ddc85d..a66a6fed 100644 --- a/resources/prompts/specfact.03-review.md +++ b/resources/prompts/specfact.03-review.md @@ -318,7 +318,7 @@ specfact plan update-idea --bundle [] --value-hypothesis "..." --na #### Option C: Apply enrichment via import (only if bundle needs regeneration) ```bash -specfact import from-code [] --repo . --enrichment enrichment-report.md +specfact code import [] --repo . --enrichment enrichment-report.md ``` **Note:** diff --git a/src/specfact_cli/agents/analyze_agent.py b/src/specfact_cli/agents/analyze_agent.py index dae8f3d5..e1a55755 100644 --- a/src/specfact_cli/agents/analyze_agent.py +++ b/src/specfact_cli/agents/analyze_agent.py @@ -57,7 +57,7 @@ def generate_prompt(self, command: str, context: dict[str, Any] | None = None) - Examples: >>> agent = AnalyzeAgent() >>> prompt = agent.generate_prompt("import from-code", {"current_file": "src/main.py"}) - >>> "specfact import from-code" in prompt.lower() + >>> "specfact code import" in prompt.lower() True """ if context is None: @@ -316,7 +316,7 @@ def analyze_codebase(self, repo_path: Path, confidence: float = 0.5, plan_name: **Pragmatic Approach**: This method is designed for AI IDE integration (Cursor, CoPilot, etc.). The AI IDE's native LLM will: 1. Understand the codebase semantically (using the prompt from `generate_prompt()`) - 2. Call the SpecFact CLI (`specfact import from-code`) for structured analysis + 2. Call the SpecFact CLI (`specfact code import`) for structured analysis 3. Enhance results with semantic understanding This avoids the need for: @@ -356,7 +356,7 @@ def analyze_codebase(self, repo_path: Path, confidence: float = 0.5, plan_name: # In AI IDE mode, the AI will: # 1. Use the prompt to understand the codebase semantically - # 2. Call `specfact import from-code` with appropriate arguments + # 2. Call `specfact code import` with appropriate arguments # 3. Parse the CLI output and enhance with semantic understanding # 4. Present results to the user diff --git a/src/specfact_cli/commands/import_cmd.py b/src/specfact_cli/commands/import_cmd.py index 3eac86dd..b4e1d49a 100644 --- a/src/specfact_cli/commands/import_cmd.py +++ b/src/specfact_cli/commands/import_cmd.py @@ -1,4 +1,4 @@ -"""Backward-compatible app shim for project import command.""" +"""Backward-compatible app shim for code-owned import command.""" from typing import TYPE_CHECKING, Any @@ -11,7 +11,7 @@ def __getattr__(name: str) -> Any: if name == "app": - return load_bundle_app(__file__, "specfact_project.import_cmd.commands") + return load_bundle_app(__file__, "specfact_codebase.import_cmd.commands") raise AttributeError(name) diff --git a/src/specfact_cli/groups/codebase_group.py b/src/specfact_cli/groups/codebase_group.py index 1390c6ca..afe11a58 100644 --- a/src/specfact_cli/groups/codebase_group.py +++ b/src/specfact_cli/groups/codebase_group.py @@ -1,4 +1,4 @@ -"""Codebase quality category group (analyze, drift, validate, repro).""" +"""Codebase category group (import, analyze, drift, validate, repro).""" from __future__ import annotations @@ -9,7 +9,7 @@ from specfact_cli.registry.registry import CommandRegistry -_MEMBERS = ("analyze", "drift", "validate", "repro") +_MEMBERS = ("import", "analyze", "drift", "validate", "repro") @require(lambda app: app is not None) @@ -30,7 +30,7 @@ def build_app() -> typer.Typer: """Build the code group Typer with members (lazy; registry must be populated).""" app = typer.Typer( name="code", - help="Codebase quality commands: analyze, drift, validate, repro.", + help="Codebase commands: import, analyze, drift, validate, repro.", no_args_is_help=True, ) _register_members(app) diff --git a/src/specfact_cli/groups/project_group.py b/src/specfact_cli/groups/project_group.py index b5ce3464..9c82e9d8 100644 --- a/src/specfact_cli/groups/project_group.py +++ b/src/specfact_cli/groups/project_group.py @@ -1,4 +1,4 @@ -"""Project lifecycle category group (project, plan, import, sync, migrate).""" +"""Project lifecycle category group (project, plan, sync, migrate).""" from __future__ import annotations @@ -12,7 +12,6 @@ _MEMBERS = [ ("project", "project"), ("plan", "plan"), - ("import", "import"), ("sync", "sync"), ("migrate", "migrate"), ] diff --git a/src/specfact_cli/utils/structure.py b/src/specfact_cli/utils/structure.py index 8529bbbb..c37393ca 100644 --- a/src/specfact_cli/utils/structure.py +++ b/src/specfact_cli/utils/structure.py @@ -945,7 +945,7 @@ def create_readme(cls, base_path: Path | None = None) -> None: specfact plan init --interactive # Analyze existing code -specfact import from-code --repo . +specfact code import --repo . # Compare plans specfact plan compare --manual .specfact/plans/main.bundle.yaml --auto .specfact/plans/auto-derived-.bundle.yaml diff --git a/src/specfact_cli/utils/suggestions.py b/src/specfact_cli/utils/suggestions.py index edcb35ba..ed129416 100644 --- a/src/specfact_cli/utils/suggestions.py +++ b/src/specfact_cli/utils/suggestions.py @@ -38,14 +38,14 @@ def suggest_next_steps(repo_path: Path, context: ProjectContext | None = None) - # First-time setup suggestions if not context.has_plan and not context.has_config: - suggestions.append("specfact import from-code --bundle # Import your codebase") + suggestions.append("specfact code import --repo . # Import your codebase") suggestions.append("specfact init # Initialize SpecFact configuration") return suggestions # Analysis suggestions if context.has_plan and context.contract_coverage < 0.5: suggestions.append("specfact analyze --bundle # Analyze contract coverage") - suggestions.append("specfact import from-code --bundle # Update plan from code") + suggestions.append("specfact code import --repo . # Update the project bundle from code") # Specmatic integration suggestions if context.has_specmatic_config and not context.openapi_specs: @@ -81,7 +81,7 @@ def suggest_fixes(error_message: str, context: ProjectContext | None = None) -> # Bundle not found if "bundle" in error_lower and ("not found" in error_lower or "does not exist" in error_lower): suggestions.append("specfact plan select # Select an active plan bundle") - suggestions.append("specfact import from-code --bundle # Create a new bundle") + suggestions.append("specfact code import --repo . # Create a new bundle from code") # Contract validation errors if "contract" in error_lower and ("violation" in error_lower or "invalid" in error_lower): @@ -95,7 +95,7 @@ def suggest_fixes(error_message: str, context: ProjectContext | None = None) -> # Import errors if "import" in error_lower and "failed" in error_lower: - suggestions.append("specfact import from-code --bundle --repo . # Retry import") + suggestions.append("specfact code import --repo . # Retry import") return suggestions @@ -116,7 +116,7 @@ def suggest_improvements(context: ProjectContext) -> list[str]: # Low contract coverage if context.contract_coverage < 0.3: suggestions.append("specfact analyze --bundle # Identify missing contracts") - suggestions.append("specfact import from-code --bundle # Extract contracts from code") + suggestions.append("specfact code import --repo . # Extract contracts from code") # Missing OpenAPI specs if context.has_plan and not context.openapi_specs: diff --git a/src/specfact_cli/validation/command_audit.py b/src/specfact_cli/validation/command_audit.py index 848882aa..258f2512 100644 --- a/src/specfact_cli/validation/command_audit.py +++ b/src/specfact_cli/validation/command_audit.py @@ -32,6 +32,15 @@ def _resolve_modules_repo_root() -> Path | None: return candidate current = Path(__file__).resolve() + current_parts = current.parts + if "specfact-cli-worktrees" in current_parts: + idx = current_parts.index("specfact-cli-worktrees") + worktree_root = Path(*current_parts[:idx], "specfact-cli-modules-worktrees") + relative_tail = current.relative_to(Path(*current_parts[: idx + 1])) + candidate = worktree_root / relative_tail.parts[0] / relative_tail.parts[1] + if candidate.exists(): + return candidate.resolve() + for parent in current.parents: sibling = parent.parent / "specfact-cli-modules" if sibling.exists(): @@ -89,6 +98,19 @@ def _collect_typer_paths(app: object, prefix: str) -> set[str]: return paths +def _auditable_paths_for_prefix(app: object, prefix: str) -> set[str]: + """Return help-safe command paths for audit cases. + + `code import` is implemented as a callback-driven command surface with optional + positional bundle input plus compatibility subcommands. The canonical audited + public path is `code import` itself, not nested help cases under that prefix. + """ + paths = _collect_typer_paths(app, prefix) + if prefix == "code": + paths = {path for path in paths if not path.startswith("code import ")} + return paths + + def _import_typer(module_path: str, attr_name: str = "app") -> object: module = importlib.import_module(module_path) return getattr(module, attr_name) @@ -111,6 +133,13 @@ def _explicit_cases() -> list[CommandAuditCase]: CommandAuditCase("project", ("project", "--help"), "project", "help-only", "nold-ai/specfact-project"), CommandAuditCase("spec", ("spec", "--help"), "spec", "help-only", "nold-ai/specfact-spec"), CommandAuditCase("code", ("code", "--help"), "code", "help-only", "nold-ai/specfact-codebase"), + CommandAuditCase( + "code import", + ("code", "import", "--help"), + "code", + "help-only", + "nold-ai/specfact-codebase", + ), CommandAuditCase("backlog", ("backlog", "--help"), "backlog", "help-only", "nold-ai/specfact-backlog"), CommandAuditCase("govern", ("govern", "--help"), "govern", "help-only", "nold-ai/specfact-govern"), CommandAuditCase( @@ -149,7 +178,7 @@ def build_command_audit_cases() -> list[CommandAuditCase]: prefix, CommandAuditCase(prefix, (*tuple(prefix.split()), "--help"), phase, "help-only", owner), ) - for command_path in sorted(_collect_typer_paths(app, prefix)): + for command_path in sorted(_auditable_paths_for_prefix(app, prefix)): cases.setdefault( command_path, CommandAuditCase( diff --git a/tests/e2e/test_complete_workflow.py b/tests/e2e/test_complete_workflow.py index b1f7d084..f8d82294 100644 --- a/tests/e2e/test_complete_workflow.py +++ b/tests/e2e/test_complete_workflow.py @@ -2037,7 +2037,7 @@ def test_cli_analyze_code2spec_on_self(self): with tempfile.TemporaryDirectory() as tmpdir: report_path = Path(tmpdir) / "analysis-report.md" - print("🚀 Running: specfact project import from-code (scoped to analyzers)") + print("🚀 Running: specfact code import (scoped to analyzers)") bundle_name = "specfact-auto" # Remove existing bundle if it exists (from previous test runs) diff --git a/tests/integration/analyzers/test_analyze_command.py b/tests/integration/analyzers/test_analyze_command.py index 299889df..a6bf4b0f 100644 --- a/tests/integration/analyzers/test_analyze_command.py +++ b/tests/integration/analyzers/test_analyze_command.py @@ -21,7 +21,7 @@ class TestAnalyzeCommand: - """Integration tests for 'specfact project import from-code' command.""" + """Integration tests for 'specfact code import' command.""" def test_code2spec_basic_repository(self): """Test analyzing a basic Python repository.""" diff --git a/tests/integration/test_command_package_runtime_validation.py b/tests/integration/test_command_package_runtime_validation.py index fc62e124..39ae6413 100644 --- a/tests/integration/test_command_package_runtime_validation.py +++ b/tests/integration/test_command_package_runtime_validation.py @@ -19,6 +19,15 @@ def _resolve_modules_repo() -> Path: if configured: return Path(configured).expanduser() + root_parts = REPO_ROOT.resolve().parts + if "specfact-cli-worktrees" in root_parts: + idx = root_parts.index("specfact-cli-worktrees") + worktree_root = Path(*root_parts[:idx], "specfact-cli-modules-worktrees") + relative_tail = REPO_ROOT.resolve().relative_to(Path(*root_parts[: idx + 1])) + candidate = worktree_root / relative_tail.parts[0] / relative_tail.parts[1] + if candidate.exists(): + return candidate + candidates = [ REPO_ROOT / "specfact-cli-modules", REPO_ROOT.parent / "specfact-cli-modules", diff --git a/tests/unit/groups/test_codebase_group.py b/tests/unit/groups/test_codebase_group.py index 26d63e53..21f728af 100644 --- a/tests/unit/groups/test_codebase_group.py +++ b/tests/unit/groups/test_codebase_group.py @@ -28,5 +28,5 @@ def test_codebase_group_has_expected_subcommands() -> None: click_code = get_command(code_app) assert hasattr(click_code, "commands") code_subcommands = list(click_code.commands.keys()) - for expected in ("analyze", "drift", "validate", "repro"): + for expected in ("analyze", "drift", "validate", "repro", "import"): assert expected in code_subcommands, f"Expected sub-command {expected!r} in code group: {code_subcommands}" diff --git a/tests/unit/groups/test_project_group.py b/tests/unit/groups/test_project_group.py new file mode 100644 index 00000000..ddf28f16 --- /dev/null +++ b/tests/unit/groups/test_project_group.py @@ -0,0 +1,38 @@ +"""Tests for project category group app ownership boundaries.""" + +from __future__ import annotations + +from collections.abc import Generator +from unittest.mock import patch + +import pytest +import typer +from typer.main import get_command + +from specfact_cli.groups.project_group import build_app +from specfact_cli.registry import CommandRegistry + + +@pytest.fixture(autouse=True) +def _clear_registry() -> Generator[None, None, None]: + CommandRegistry._clear_for_testing() + yield + CommandRegistry._clear_for_testing() + + +def test_project_group_excludes_code_owned_import_subcommand() -> None: + """Project group keeps bundle lifecycle commands and excludes code-owned import.""" + member_app = typer.Typer() + with patch.object(CommandRegistry, "get_module_typer", return_value=member_app): + project_app = build_app() + click_project = get_command(project_app) + assert hasattr(click_project, "commands") + project_subcommands = list(click_project.commands.keys()) + for expected in ("plan", "sync", "migrate"): + assert expected in project_subcommands, ( + f"Expected sub-command {expected!r} in project group: {project_subcommands}" + ) + assert getattr(project_app, "_specfact_flatten_same_name", None) == "project" + assert "import" not in project_subcommands, ( + f"Code-first import should not remain on the project lifecycle surface: {project_subcommands}" + ) diff --git a/tests/unit/prompts/test_prompt_validation.py b/tests/unit/prompts/test_prompt_validation.py index 5293df0f..a95e36e1 100644 --- a/tests/unit/prompts/test_prompt_validation.py +++ b/tests/unit/prompts/test_prompt_validation.py @@ -87,7 +87,7 @@ def test_validate_cli_alignment(self, tmp_path: Path): ## ⚠️ CRITICAL: CLI Usage Enforcement -1. **ALWAYS execute CLI first**: Run `specfact project import from-code` before any analysis +1. **ALWAYS execute CLI first**: Run `specfact code import` before any analysis 2. **NEVER create YAML/JSON directly**: All artifacts must be CLI-generated 3. **NEVER bypass CLI validation**: CLI ensures schema compliance and metadata 4. **Use CLI output as grounding**: Parse CLI output, don't regenerate it diff --git a/tests/unit/validation/test_command_audit.py b/tests/unit/validation/test_command_audit.py index db0bb9f4..26fba628 100644 --- a/tests/unit/validation/test_command_audit.py +++ b/tests/unit/validation/test_command_audit.py @@ -33,13 +33,13 @@ def test_command_audit_cases_cover_core_and_bundle_surfaces() -> None: "project version", "project version check", "project sync bridge", - "project import", "spec", "spec validate", "spec backward-compat", "spec generate-tests", "spec mock", "code", + "code import", "code analyze contracts", "code drift detect", "code validate sidecar init", diff --git a/tools/validate_prompts.py b/tools/validate_prompts.py index 19ed91a4..b32eb483 100644 --- a/tools/validate_prompts.py +++ b/tools/validate_prompts.py @@ -32,7 +32,7 @@ # CLI commands that should be referenced (new slash command names) CLI_COMMANDS = { - "specfact.01-import": "specfact import from-code", + "specfact.01-import": "specfact code import", "specfact.02-plan": "specfact plan ", # init, add-feature, add-story, update-idea, update-feature, update-story "specfact.03-review": "specfact plan review", # Also handles promote "specfact.04-sdd": "specfact plan harden", @@ -59,7 +59,7 @@ ] # Commands that should have dual-stack workflow -DUAL_STACK_COMMANDS = ["specfact.01-import", "specfact-import-from-code"] # New and legacy names +DUAL_STACK_COMMANDS = ["specfact.01-import", "specfact-import-from-code"] # New and legacy prompt ids class PromptValidator: From db0b15edf3ed1eb1ec83805e68c7024a2b1b318d Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 12 Mar 2026 01:06:33 +0100 Subject: [PATCH 2/2] Harden temp registry command audit test --- ...test_command_package_runtime_validation.py | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_command_package_runtime_validation.py b/tests/integration/test_command_package_runtime_validation.py index 39ae6413..0dbd2201 100644 --- a/tests/integration/test_command_package_runtime_validation.py +++ b/tests/integration/test_command_package_runtime_validation.py @@ -1,12 +1,18 @@ from __future__ import annotations +import hashlib +import json import os +import shutil import subprocess import sys +import tarfile from pathlib import Path import pytest +import yaml +from specfact_cli.registry.module_installer import _module_artifact_payload_signed from specfact_cli.validation.command_audit import build_command_audit_cases, official_marketplace_module_ids @@ -40,7 +46,6 @@ def _resolve_modules_repo() -> Path: MODULES_REPO = _resolve_modules_repo() -REGISTRY_INDEX = MODULES_REPO / "registry" / "index.json" FORBIDDEN_OUTPUT = ( "Module compatibility check:", "Partially compliant modules:", @@ -50,6 +55,65 @@ def _resolve_modules_repo() -> Path: ) +def _build_local_registry(home_dir: Path) -> Path: + registry_root = home_dir / ".specfact-local-registry" + modules_dir = registry_root / "modules" + staging_dir = registry_root / ".staging" + modules_dir.mkdir(parents=True, exist_ok=True) + staging_dir.mkdir(parents=True, exist_ok=True) + + modules_payload: list[dict[str, object]] = [] + packages_root = MODULES_REPO / "packages" + + for module_id in official_marketplace_module_ids(): + bundle_name = module_id.split("/", 1)[1] + package_dir = packages_root / bundle_name + staged_package_dir = staging_dir / bundle_name + if staged_package_dir.exists(): + shutil.rmtree(staged_package_dir) + shutil.copytree(package_dir, staged_package_dir) + + staged_manifest_path = staged_package_dir / "module-package.yaml" + staged_manifest = yaml.safe_load(staged_manifest_path.read_text(encoding="utf-8")) + assert isinstance(staged_manifest, dict), f"Invalid manifest: {staged_manifest_path}" + staged_manifest["integrity"] = { + "checksum": f"sha256:{hashlib.sha256(_module_artifact_payload_signed(staged_package_dir)).hexdigest()}" + } + staged_manifest_path.write_text( + yaml.safe_dump(staged_manifest, sort_keys=False, allow_unicode=False), + encoding="utf-8", + ) + + manifest_path = package_dir / "module-package.yaml" + manifest = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) + assert isinstance(manifest, dict), f"Invalid manifest: {manifest_path}" + + version = str(manifest["version"]).strip() + archive_name = f"{bundle_name}-{version}.tar.gz" + archive_path = modules_dir / archive_name + + with tarfile.open(archive_path, "w:gz") as archive: + archive.add(staged_package_dir, arcname=bundle_name) + + checksum = hashlib.sha256(archive_path.read_bytes()).hexdigest() + modules_payload.append( + { + "id": module_id, + "latest_version": version, + "download_url": f"modules/{archive_name}", + "checksum_sha256": checksum, + "tier": manifest.get("tier", "official"), + "publisher": manifest.get("publisher", {}), + "bundle_dependencies": manifest.get("bundle_dependencies", []), + "description": manifest.get("description", ""), + } + ) + + index_path = registry_root / "index.json" + index_path.write_text(json.dumps({"modules": modules_payload}, indent=2), encoding="utf-8") + return index_path + + def _subprocess_env(home_dir: Path) -> dict[str, str]: env = os.environ.copy() pythonpath_parts = [str(SRC_ROOT), str(REPO_ROOT)] @@ -76,7 +140,7 @@ def _subprocess_env(home_dir: Path) -> dict[str, str]: env["HOME"] = str(home_dir) env["SPECFACT_REPO_ROOT"] = str(REPO_ROOT) env["SPECFACT_MODULES_REPO"] = str(MODULES_REPO.resolve()) - env["SPECFACT_REGISTRY_INDEX_URL"] = REGISTRY_INDEX.resolve().as_uri() + env["SPECFACT_REGISTRY_INDEX_URL"] = _build_local_registry(home_dir).resolve().as_uri() env["SPECFACT_ALLOW_UNSIGNED"] = "1" env["SPECFACT_REGISTRY_DIR"] = str(home_dir / ".specfact-test-registry") return env