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/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/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/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md
index f560248e..6438f406 100644
--- a/openspec/CHANGE_ORDER.md
+++ b/openspec/CHANGE_ORDER.md
@@ -253,7 +253,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/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/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__"]