diff --git a/CHANGELOG.md b/CHANGELOG.md
index e50229ef..959f5250 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,14 @@ All notable changes to this project will be documented in this file.
**Important:** Changes need to be documented below this block as this is the header section. Each section should be separated by a horizontal rule. Newer changelog entries need to be added on top of prior ones to keep the history chronological with most recent changes first.
+---
+
+## [0.41.0] - 2026-03-11
+
+### Added
+
+- Added the `nold-ai/specfact-code-review` module scaffold (SP-001): structured `ReviewFinding` / `ReviewReport` models, review scoring helpers, and the `specfact code review` command surface documentation.
+
---
## [0.40.4] - 2026-03-11
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/_layouts/default.html b/docs/_layouts/default.html
index dcd7258a..9356e70c 100644
--- a/docs/_layouts/default.html
+++ b/docs/_layouts/default.html
@@ -145,6 +145,7 @@
Installing Modules
Module Marketplace
Marketplace Bundles
+ Code Review Module
Command Chains
Agile/Scrum Workflows
Policy Engine Commands
@@ -192,7 +193,6 @@ ProjectBundle Schema
Module Contracts
Module Security
- Module Categories
Bridge Registry
Integrations Overview
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/index.md b/docs/index.md
index 17a608ab..8d4706a6 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -159,6 +159,7 @@ long-term bundle docs home is prepared in `nold-ai/specfact-cli-modules`:
- **[Installing Modules](guides/installing-modules.md)** - Install, list, uninstall, and upgrade modules
- **[Module Marketplace](guides/module-marketplace.md)** - Registry model, security checks, and discovery priority
- **[Marketplace Bundles](guides/marketplace.md)** - Official bundle ids, trust tiers, and dependency auto-install behavior
+- **[Code Review Module](modules/code-review.md)** - Install and use the `nold-ai/specfact-code-review` scaffold under `specfact code review`
- **[Module Signing and Key Rotation](guides/module-signing-and-key-rotation.md)** - Signing and key management runbook
Module lifecycle note: use `specfact module` (`init`, `install`, `list`, `show`, `search`, `enable`, `disable`, `uninstall`, `upgrade`) for module management.
diff --git a/docs/modules/code-review.md b/docs/modules/code-review.md
new file mode 100644
index 00000000..b4969eb0
--- /dev/null
+++ b/docs/modules/code-review.md
@@ -0,0 +1,101 @@
+---
+layout: default
+title: Code Review Module
+description: Install and use the official specfact-code-review module scaffold.
+permalink: /modules/code-review/
+---
+
+# Code Review Module
+
+The `nold-ai/specfact-code-review` module extends `specfact code` with a governed `review` subgroup for structured review execution, scoring, and reporting.
+
+## Install
+
+```bash
+specfact module install nold-ai/specfact-code-review
+```
+
+After installation, the grouped command surface becomes available under:
+
+```bash
+specfact code review --help
+```
+
+## Command Overview
+
+The scaffold adds these review entrypoints:
+
+- `specfact code review run`
+- `specfact code review ledger`
+- `specfact code review rules`
+
+This change delivers the command scaffold and the review data model foundation. Runtime review execution and ledger/rules behavior can be layered on in later changes.
+
+## Scoring Algorithm
+
+The module computes review scores from structured findings.
+
+```text
+base_score = 100
+
+deductions:
+- blocking error: -15
+- fixable error: -5
+- warning: -2
+- info: -1
+
+bonuses:
+- zero LOC violations: +5
+- zero complexity violations: +5
+- all APIs use icontract: +5
+- coverage >= 90%: +5
+- no new suppressions: +5
+
+score = clamp(0, 120)
+reward_delta = score - 80
+```
+
+Verdict mapping:
+
+- `PASS` for scores `>= 70`
+- `PASS_WITH_ADVISORY` for scores `>= 50` and `< 70`
+- `FAIL` for scores `< 50`
+- Any blocking error forces `FAIL` regardless of score
+
+## JSON Output Schema
+
+The scaffolded `ReviewReport` envelope carries these fields:
+
+```json
+{
+ "schema_version": "1.0",
+ "run_id": "run-001",
+ "timestamp": "2026-03-11T21:50:05Z",
+ "overall_verdict": "PASS",
+ "ci_exit_code": 0,
+ "score": 85,
+ "reward_delta": 5,
+ "findings": [
+ {
+ "category": "security",
+ "severity": "warning",
+ "tool": "ruff",
+ "rule": "S101",
+ "file": "src/example.py",
+ "line": 12,
+ "message": "Avoid assert in production code.",
+ "fixable": false
+ }
+ ],
+ "summary": "Warnings remain but no blocking findings.",
+ "house_rules_updates": []
+}
+```
+
+## Governance-01 Alignment
+
+`ReviewReport` is scaffolded as a governance-01-compatible evidence envelope:
+
+- `schema_version`, `run_id`, `timestamp`, `overall_verdict`, and `ci_exit_code` are always present.
+- Review-specific fields (`score`, `reward_delta`, `findings`, `summary`, `house_rules_updates`) extend the standard evidence shape without replacing it.
+- CI can treat `ci_exit_code` as the contract-bound gate result from the start.
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..56ba1803 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) |
@@ -253,7 +254,7 @@ Target repos: `nold-ai/specfact-cli-modules` (module implementation) + `nold-ai/
| Module | Order | Change folder | GitHub # | Blocked by |
|--------|-------|---------------|----------|------------|
-| code-review | 01 | code-review-01-module-scaffold | TBD | — |
+| code-review | 01 | code-review-01-module-scaffold | [#398](https://github.com/nold-ai/specfact-cli/issues/398) | — |
| code-review | 02 | code-review-02-ruff-radon-runners | TBD | code-review-01 |
| code-review | 03 | code-review-03-type-governance-runners | TBD | code-review-01 |
| code-review | 04 | code-review-04-contract-test-runners | TBD | code-review-01; code-review-02; code-review-03 |
diff --git a/openspec/changes/code-review-01-module-scaffold/TDD_EVIDENCE.md b/openspec/changes/code-review-01-module-scaffold/TDD_EVIDENCE.md
new file mode 100644
index 00000000..412acc1e
--- /dev/null
+++ b/openspec/changes/code-review-01-module-scaffold/TDD_EVIDENCE.md
@@ -0,0 +1,19 @@
+# TDD Evidence
+
+## Pre-implementation failing run
+
+- Timestamp: `2026-03-11T21:50:05Z`
+- Command:
+ `PYTHONPATH=/home/dom/git/nold-ai/specfact-cli-worktrees/feature/code-review-01-module-scaffold/src:src:packages/specfact-project/src:packages/specfact-backlog/src:packages/specfact-codebase/src:packages/specfact-code-review/src:packages/specfact-spec/src:packages/specfact-govern/src python3 -m pytest tests/unit/specfact_code_review/run -v`
+- Result: failed during test collection
+- Failure summary:
+ `ModuleNotFoundError: No module named 'specfact_code_review'` in both `test_findings.py` and `test_scorer.py`
+
+## Post-implementation passing run
+
+- Timestamp: `2026-03-11T21:58:26Z`
+- Command:
+ `PYTHONPATH=/home/dom/git/nold-ai/specfact-cli-worktrees/feature/code-review-01-module-scaffold/src:src:packages/specfact-project/src:packages/specfact-backlog/src:packages/specfact-codebase/src:packages/specfact-code-review/src:packages/specfact-spec/src:packages/specfact-govern/src python3 -m pytest tests/unit/specfact_code_review/run -v`
+- Result: passed
+- Passing summary:
+ `28 passed in 0.78s`
diff --git a/openspec/changes/code-review-01-module-scaffold/proposal.md b/openspec/changes/code-review-01-module-scaffold/proposal.md
index 4022a1ab..9bf45a07 100644
--- a/openspec/changes/code-review-01-module-scaffold/proposal.md
+++ b/openspec/changes/code-review-01-module-scaffold/proposal.md
@@ -52,7 +52,7 @@ reward_delta = score - 80 (range: -80..+20)
## Source Tracking
-- **GitHub Issue**: TBD
-- **Issue URL**: TBD
+- **GitHub Issue**: [#398](https://github.com/nold-ai/specfact-cli/issues/398)
+- **Issue URL**: https://github.com/nold-ai/specfact-cli/issues/398
- **Repository**: nold-ai/specfact-cli
-- **Last Synced Status**: proposed
+- **Last Synced Status**: in_progress
diff --git a/openspec/changes/code-review-01-module-scaffold/tasks.md b/openspec/changes/code-review-01-module-scaffold/tasks.md
index 17b4835e..985d86aa 100644
--- a/openspec/changes/code-review-01-module-scaffold/tasks.md
+++ b/openspec/changes/code-review-01-module-scaffold/tasks.md
@@ -11,58 +11,58 @@ Do not implement production code until tests exist and have been run (expecting
## 1. Create git worktree for this change
- [ ] 1.1 Fetch latest and create a worktree with a new branch from `origin/dev`.
- - [ ] 1.1.1 `git fetch origin`
- - [ ] 1.1.2 `git worktree add ../specfact-cli-worktrees/feature/code-review-01-module-scaffold -b feature/code-review-01-module-scaffold origin/dev`
- - [ ] 1.1.3 Change into the worktree: `cd ../specfact-cli-worktrees/feature/code-review-01-module-scaffold`
+ - [x] 1.1.1 `git fetch origin`
+ - [x] 1.1.2 `git worktree add ../specfact-cli-worktrees/feature/code-review-01-module-scaffold -b feature/code-review-01-module-scaffold origin/dev`
+ - [x] 1.1.3 Change into the worktree: `cd ../specfact-cli-worktrees/feature/code-review-01-module-scaffold`
- [ ] 1.1.4 Create virtual environment: `python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]"`
- - [ ] 1.1.5 `git branch --show-current` (verify `feature/code-review-01-module-scaffold`)
+ - [x] 1.1.5 `git branch --show-current` (verify `feature/code-review-01-module-scaffold`)
## 2. Set up specfact-cli-modules worktree and package scaffold
All following tasks run inside the worktree **and** require the `specfact-cli-modules` repository to be accessible.
-- [ ] 2.1 In `specfact-cli-modules`: create `packages/specfact-code-review/` directory structure
- - [ ] 2.1.1 Create all directories per module package structure (see design.md)
- - [ ] 2.1.2 Write `packages/specfact-code-review/module-package.yaml` with all required fields
+- [x] 2.1 In `specfact-cli-modules`: create `packages/specfact-code-review/` directory structure
+ - [x] 2.1.1 Create all directories per module package structure (see design.md)
+ - [x] 2.1.2 Write `packages/specfact-code-review/module-package.yaml` with all required fields
## 3. Write tests BEFORE implementation (TDD-first)
-- [ ] 3.1 Write `tests/unit/specfact_code_review/run/test_findings.py`
- - [ ] 3.1.1 Test `ReviewFinding` field validation (valid/invalid severity, valid/invalid category)
- - [ ] 3.1.2 Test `fixable` field defaults to `False`
- - [ ] 3.1.3 Test `@require` contract on empty file/message
-- [ ] 3.2 Write `tests/unit/specfact_code_review/run/test_scorer.py`
- - [ ] 3.2.1 Test clean run (zero findings) scores 100, reward_delta=20
- - [ ] 3.2.2 Test single blocking error: score=85, reward_delta=5
- - [ ] 3.2.3 Test single fixable error: score=95, reward_delta=15
- - [ ] 3.2.4 Test warning deductions: 3 warnings → score=94
- - [ ] 3.2.5 Test PASS/WARN/BLOCK verdict thresholds
- - [ ] 3.2.6 Test all 5 bonus conditions
- - [ ] 3.2.7 Test blocking error overrides score to FAIL regardless
- - [ ] 3.2.8 Test score is capped at 120
-- [ ] 3.3 Run tests — expect failure (modules don't exist yet)
- - [ ] 3.3.1 `hatch test -- tests/unit/specfact_code_review/run/ -v` → capture failing output
- - [ ] 3.3.2 Record failing evidence in `openspec/changes/code-review-01-module-scaffold/TDD_EVIDENCE.md`
+- [x] 3.1 Write `tests/unit/specfact_code_review/run/test_findings.py`
+ - [x] 3.1.1 Test `ReviewFinding` field validation (valid/invalid severity, valid/invalid category)
+ - [x] 3.1.2 Test `fixable` field defaults to `False`
+ - [x] 3.1.3 Test `@require` contract on empty file/message
+- [x] 3.2 Write `tests/unit/specfact_code_review/run/test_scorer.py`
+ - [x] 3.2.1 Test clean run (zero findings) scores 100, reward_delta=20
+ - [x] 3.2.2 Test single blocking error: score=85, reward_delta=5
+ - [x] 3.2.3 Test single fixable error: score=95, reward_delta=15
+ - [x] 3.2.4 Test warning deductions: 3 warnings → score=94
+ - [x] 3.2.5 Test PASS/WARN/BLOCK verdict thresholds
+ - [x] 3.2.6 Test all 5 bonus conditions
+ - [x] 3.2.7 Test blocking error overrides score to FAIL regardless
+ - [x] 3.2.8 Test score is capped at 120
+- [x] 3.3 Run tests — expect failure (modules don't exist yet)
+ - [x] 3.3.1 `hatch test -- tests/unit/specfact_code_review/run/ -v` → capture failing output
+ - [x] 3.3.2 Record failing evidence in `openspec/changes/code-review-01-module-scaffold/TDD_EVIDENCE.md`
## 4. Implement module scaffold
-- [ ] 4.1 Create `packages/specfact-code-review/src/specfact_code_review/__init__.py`
-- [ ] 4.2 Create `run/findings.py` — `ReviewFinding` and `ReviewReport` Pydantic models with all governance-01 fields and review extensions; add `@require`/`@ensure`/`@beartype` to all public methods
-- [ ] 4.3 Create `run/scorer.py` — scoring algorithm; pure function with `@require`/`@ensure`
-- [ ] 4.4 Create `review/app.py` — Typer extension entrypoint; `module_io_shim` re-exports
-- [ ] 4.5 Create `review/commands.py` — review subgroup wiring (run/ledger/rules stubs)
-- [ ] 4.6 Create `run/commands.py` stub
+- [x] 4.1 Create `packages/specfact-code-review/src/specfact_code_review/__init__.py`
+- [x] 4.2 Create `run/findings.py` — `ReviewFinding` and `ReviewReport` Pydantic models with all governance-01 fields and review extensions; add `@require`/`@ensure`/`@beartype` to all public methods
+- [x] 4.3 Create `run/scorer.py` — scoring algorithm; pure function with `@require`/`@ensure`
+- [x] 4.4 Create `review/app.py` — Typer extension entrypoint; `module_io_shim` re-exports
+- [x] 4.5 Create `review/commands.py` — review subgroup wiring (run/ledger/rules stubs)
+- [x] 4.6 Create `run/commands.py` stub
## 5. Run tests and validate
-- [ ] 5.1 Run tests — expect passing
- - [ ] 5.1.1 `hatch test -- tests/unit/specfact_code_review/run/ -v`
- - [ ] 5.1.2 Record passing evidence in `TDD_EVIDENCE.md`
+- [x] 5.1 Run tests — expect passing
+ - [x] 5.1.1 `hatch test -- tests/unit/specfact_code_review/run/ -v`
+ - [x] 5.1.2 Record passing evidence in `TDD_EVIDENCE.md`
- [ ] 5.2 `hatch run format` — ruff format + fix
- [ ] 5.3 `hatch run type-check` — basedpyright strict
-- [ ] 5.4 `hatch run contract-test` — validate icontract decorators
+- [x] 5.4 `hatch run contract-test` — validate icontract decorators
- [ ] 5.5 `hatch run lint` — full lint suite
-- [ ] 5.6 Verify `specfact code review --help` shows review subgroup
+- [x] 5.6 Verify `specfact code review --help` shows review subgroup
## 6. Module signing
@@ -72,23 +72,23 @@ All following tasks run inside the worktree **and** require the `specfact-cli-mo
## 7. Documentation
-- [ ] 7.1 Create `docs/modules/code-review.md` with: install command, command overview, scoring algorithm, JSON output schema, governance-01 alignment note
-- [ ] 7.2 Update `docs/index.md` and `docs/_layouts/default.html` sidebar to include the new code-review module page
-- [ ] 7.3 Verify front-matter: `layout`, `title`, `permalink`, `description`
+- [x] 7.1 Create `docs/modules/code-review.md` with: install command, command overview, scoring algorithm, JSON output schema, governance-01 alignment note
+- [x] 7.2 Update `docs/index.md` and `docs/_layouts/default.html` sidebar to include the new code-review module page
+- [x] 7.3 Verify front-matter: `layout`, `title`, `permalink`, `description`
## 8. Version and changelog
-- [ ] 8.1 Bump minor version (new feature): sync `pyproject.toml`, `setup.py`, `src/specfact_cli/__init__.py`
-- [ ] 8.2 Add CHANGELOG.md entry: `Added: specfact-code-review module scaffold (SP-001)`
+- [x] 8.1 Bump minor version (new feature): sync `pyproject.toml`, `setup.py`, `src/specfact_cli/__init__.py`
+- [x] 8.2 Add CHANGELOG.md entry: `Added: specfact-code-review module scaffold (SP-001)`
## 9. Create GitHub issue
-- [ ] 9.1 Create issue in `nold-ai/specfact-cli`:
+- [x] 9.1 Create issue in `nold-ai/specfact-cli`:
- Title: `[Change] specfact-code-review module scaffold with ReviewFinding/ReviewReport models`
- Labels: `enhancement`, `change-proposal`
- Body: from proposal.md Why + What Changes sections
- Footer: `*OpenSpec Change Proposal: code-review-01-module-scaffold*`
-- [ ] 9.2 Update `proposal.md` Source Tracking with issue number and URL
+- [x] 9.2 Update `proposal.md` Source Tracking with issue number and URL
## 10. Create PR
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/.openspec.yaml b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/.openspec.yaml
new file mode 100644
index 00000000..e94306be
--- /dev/null
+++ b/openspec/changes/module-migration-11-project-codebase-ownership-realignment/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-03-11
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/pyproject.toml b/pyproject.toml
index a35d1ee5..6272cce4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "specfact-cli"
-version = "0.40.4"
+version = "0.41.0"
description = "The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases."
readme = "README.md"
requires-python = ">=3.11"
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/setup.py b/setup.py
index 28a038d3..ab576dbb 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@
if __name__ == "__main__":
_setup = setup(
name="specfact-cli",
- version="0.40.4",
+ version="0.41.0",
description=(
"The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with "
"validation and contract enforcement for new projects and long-lived codebases."
diff --git a/src/__init__.py b/src/__init__.py
index c7dceefd..5c49d260 100644
--- a/src/__init__.py
+++ b/src/__init__.py
@@ -3,4 +3,4 @@
"""
# Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
-__version__ = "0.40.3"
+__version__ = "0.41.0"
diff --git a/src/specfact_cli/__init__.py b/src/specfact_cli/__init__.py
index f64e6532..7ffb21c2 100644
--- a/src/specfact_cli/__init__.py
+++ b/src/specfact_cli/__init__.py
@@ -42,6 +42,6 @@ def _bootstrap_bundle_paths() -> None:
_bootstrap_bundle_paths()
-__version__ = "0.40.4"
+__version__ = "0.41.0"
__all__ = ["__version__"]
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..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
@@ -19,6 +25,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",
@@ -31,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:",
@@ -41,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)]
@@ -67,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
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: