Skip to content

Commit 52f2290

Browse files
authored
Merge pull request #128 from nold-ai/feature/clean-code-02-expanded-review-module
[codex] expand code review clean-code checks
2 parents 2c22ebe + 488f39f commit 52f2290

26 files changed

Lines changed: 1200 additions & 181 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ and this project follows SemVer for bundle versions.
1010
### Added
1111

1212
- Documentation: authoritative `docs/reference/documentation-url-contract.md` for core vs modules URL ownership; `redirect_from` aliases for legacy `/guides/<basename>/` on pages whose canonical path is outside `/guides/`; sidebar link to the contract page.
13+
- Add expanded clean-code review coverage to `specfact-code-review`, including
14+
naming, KISS, YAGNI, DRY, SOLID, and PR-checklist findings plus the bundled
15+
`specfact/clean-code-principles` policy-pack payload.
16+
17+
### Changed
18+
19+
- Refresh the canonical `specfact-code-review` house-rules skill to a compact
20+
clean-code charter and bump the bundle metadata for the signed 0.45.0 release.
1321

1422
## [0.44.0] - 2026-03-17
1523

docs/bundles/code-review/overview.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ Use it together with the [Codebase](../codebase/overview/) bundle (`import`, `an
4545

4646
## Bundle-owned skills and policy packs
4747

48-
House rules and review payloads ship **inside the bundle** (for example Semgrep packs and skill metadata). They are **not** core CLI-owned resources. Install or refresh IDE-side assets with `specfact init ide` after upgrading the bundle.
48+
House rules and review payloads ship **inside the bundle** (for example Semgrep
49+
packs, the `specfact/clean-code-principles` policy-pack manifest, and skill
50+
metadata). They are **not** core CLI-owned resources. Install or refresh
51+
IDE-side assets with `specfact init ide` after upgrading the bundle.
4952

5053
## Quick examples
5154

docs/modules/code-review.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ Custom rule mapping:
225225

226226
| Semgrep rule | ReviewFinding category |
227227
| --- | --- |
228+
| `banned-generic-public-names` | `naming` |
229+
| `swallowed-exception-pattern` | `clean_code` |
228230
| `get-modify-same-method` | `clean_code` |
229231
| `unguarded-nested-access` | `clean_code` |
230232
| `cross-layer-call` | `architecture` |
@@ -234,6 +236,8 @@ Custom rule mapping:
234236
Representative anti-patterns covered by the ruleset:
235237

236238
- methods that both read state and mutate it
239+
- public symbols that use banned generic names like `data` or `process`
240+
- swallowed exceptions that hide an underlying failure path
237241
- direct nested attribute access like `obj.config.value`
238242
- repository and HTTP client calls in the same function
239243
- module-level network client instantiation
@@ -243,7 +247,7 @@ Additional behavior:
243247

244248
- only the provided file list is considered
245249
- semgrep rule IDs emitted with path prefixes are normalized back to the governed rule IDs above
246-
- malformed output or a missing Semgrep executable yields a single `tool_error` finding
250+
- malformed output, a missing `results` list, or a missing Semgrep executable yields a single `tool_error` finding
247251

248252
### Contract runner
249253

@@ -323,7 +327,15 @@ Then rerun the ledger command from the same repository checkout.
323327
## House rules skill
324328

325329
The `specfact-code-review` bundle can derive a compact house-rules skill from the
326-
reward ledger and keep it small enough for AI session context injection.
330+
reward ledger and keep it small enough for AI session context injection. The
331+
default charter now encodes the clean-code principles directly:
332+
333+
- Naming: use intention-revealing names instead of placeholders.
334+
- KISS: keep functions small, shallow, and narrow in parameters.
335+
- YAGNI: remove unused private helpers and speculative layers.
336+
- DRY: extract repeated function shapes once duplication appears.
337+
- SOLID: keep transport and persistence responsibilities separate.
338+
- TDD + contracts: keep test-first and icontract discipline in the baseline skill.
327339

328340
### Command flow
329341

@@ -362,13 +374,31 @@ bundle runners in this order:
362374

363375
1. Ruff
364376
2. Radon
365-
3. basedpyright
366-
4. pylint
367-
5. contract runner
368-
6. TDD gate, unless `no_tests=True`
377+
3. Semgrep
378+
4. AST clean-code checks
379+
5. basedpyright
380+
6. pylint
381+
7. contract runner
382+
8. TDD gate, unless `no_tests=True`
383+
384+
When `SPECFACT_CODE_REVIEW_PR_MODE=1` is present, the runner also evaluates a
385+
bundle-local advisory PR checklist from `SPECFACT_CODE_REVIEW_PR_TITLE`,
386+
`SPECFACT_CODE_REVIEW_PR_BODY`, and `SPECFACT_CODE_REVIEW_PR_PROPOSAL` without
387+
adding a new CLI flag.
369388

370389
The merged findings are then scored into a governed `ReviewReport`.
371390

391+
## Bundled policy pack
392+
393+
The bundle now ships `specfact/clean-code-principles` as a resource payload at:
394+
395+
- `packages/specfact-code-review/resources/policy-packs/specfact/clean-code-principles.yaml`
396+
- `packages/specfact-code-review/src/specfact_code_review/resources/policy-packs/specfact/clean-code-principles.yaml`
397+
398+
The manifest exposes the clean-code rule IDs directly so downstream policy code
399+
can apply advisory, mixed, or hard modes without a second review-specific
400+
severity schema.
401+
372402
### TDD gate
373403

374404
`specfact_code_review.run.runner.run_tdd_gate(files)` enforces a bundle-local
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# TDD Evidence
2+
3+
## 2026-03-31
4+
5+
- `2026-03-31T00:56:00+02:00` Bootstrap:
6+
`hatch run dev-deps`
7+
linked the local `specfact-cli` checkout into this worktree so the bundle tests and review runner could execute against the live code.
8+
- `2026-03-31T01:02:00+02:00` Red phase:
9+
`SPECFACT_ALLOW_UNSIGNED=1 hatch run pytest tests/unit/specfact_code_review/run/test_runner.py tests/unit/specfact_code_review/tools/test_ast_clean_code_runner.py tests/unit/specfact_code_review/tools/test_radon_runner.py tests/unit/specfact_code_review/tools/test_semgrep_runner.py -q`
10+
failed with 5 targeted regressions that matched the new spec change:
11+
- `test_run_review_requires_explicit_pr_mode_token_for_clean_code_reasoning`
12+
expected `clean-code.pr-checklist-missing-rationale` but `_checklist_findings()` returned `[]`.
13+
- `test_run_ast_clean_code_reports_mixed_dependency_roles_for_injected_dependencies`
14+
expected `solid.mixed-dependency-role` for `self.repo.save()` / `self.client.get()` but the leftmost dependency was still treated as `self`.
15+
- `test_run_ast_clean_code_continues_after_parse_error`
16+
expected a per-file `tool_error` plus later-file findings, but the parser branch returned early.
17+
- `test_run_radon_uses_dedicated_tool_identifier_for_kiss_findings`
18+
expected `tool="radon-kiss"` but the emitted finding still used `tool="radon"`.
19+
- `test_run_semgrep_returns_tool_error_when_results_key_is_missing`
20+
expected a `tool_error` for malformed Semgrep JSON, but the runner treated a missing `results` key as a clean run.
21+
- `2026-03-31T01:04:30+02:00` Implementation:
22+
updated `packages/specfact-code-review/src/specfact_code_review/run/runner.py`,
23+
`packages/specfact-code-review/src/specfact_code_review/tools/ast_clean_code_runner.py`,
24+
`packages/specfact-code-review/src/specfact_code_review/tools/radon_runner.py`,
25+
`packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py`,
26+
`packages/specfact-code-review/src/specfact_code_review/resources/skills/specfact-code-review/SKILL.md`,
27+
`packages/specfact-code-review/src/specfact_code_review/resources/policy-packs/specfact/clean-code-principles.yaml`,
28+
`docs/modules/code-review.md`,
29+
and the targeted unit tests so the new clean-code checks, strict PR-mode gating, dependency-root detection, KISS tool labeling, and Semgrep parsing behavior matched the review comments.
30+
- `2026-03-31T01:06:30+02:00` Green phase:
31+
`SPECFACT_ALLOW_UNSIGNED=1 hatch run pytest tests/unit/specfact_code_review/run/test_runner.py tests/unit/specfact_code_review/tools/test_ast_clean_code_runner.py tests/unit/specfact_code_review/tools/test_radon_runner.py tests/unit/specfact_code_review/tools/test_semgrep_runner.py -q`
32+
passed with `50 passed in 20.26s`.
33+
- `2026-03-31T01:08:11+02:00` Release validation:
34+
`hatch run verify-modules-signature --require-signature --payload-from-filesystem --enforce-version-bump`
35+
passed after the module was signed again.
36+
- `2026-03-31T01:10:42+02:00` Review validation:
37+
`SPECFACT_ALLOW_UNSIGNED=1 hatch run specfact code review run --json --out .specfact/code-review.json`
38+
passed with `findings: []`.

openspec/changes/clean-code-02-expanded-review-module/tasks.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
## 1. Branch and dependency guardrails
44

5-
- [ ] 1.1 Create dedicated worktree branch `feature/clean-code-02-expanded-review-module` from `dev` before implementation work.
6-
- [ ] 1.2 Confirm the archived runner and review-run changes are available locally and note the cross-repo dependency on specfact-cli `code-review-zero-findings`.
7-
- [ ] 1.3 Reconfirm scope against the 2026-03-22 clean-code implementation plan and `openspec/CHANGE_ORDER.md`.
5+
- [x] 1.1 Create dedicated worktree branch `feature/clean-code-02-expanded-review-module` from `dev` before implementation work.
6+
- [x] 1.2 Confirm the archived runner and review-run changes are available locally and note the cross-repo dependency on specfact-cli `code-review-zero-findings`.
7+
- [x] 1.3 Reconfirm scope against the 2026-03-22 clean-code implementation plan and `openspec/CHANGE_ORDER.md`.
88

99
## 2. Spec-first and test-first preparation
1010

11-
- [ ] 2.1 Finalize spec deltas for finding schema expansion, runner behavior, policy-pack payload, and house-rules skill output.
12-
- [ ] 2.2 Add or update tests derived from those scenarios before touching implementation.
13-
- [ ] 2.3 Run targeted tests expecting failure and record results in `TDD_EVIDENCE.md`.
11+
- [x] 2.1 Finalize spec deltas for finding schema expansion, runner behavior, policy-pack payload, and house-rules skill output.
12+
- [x] 2.2 Add or update tests derived from those scenarios before touching implementation.
13+
- [x] 2.3 Run targeted tests expecting failure and record results in `TDD_EVIDENCE.md`.
1414

1515
## 3. Implementation
1616

17-
- [ ] 3.1 Extend the review finding schema and runner orchestration for the new clean-code categories.
18-
- [ ] 3.2 Implement or update the semgrep, radon, solid, yagni, dry, and checklist paths required by the new scenarios.
19-
- [ ] 3.3 Ship the `specfact/clean-code-principles` policy-pack payload and refresh `skills/specfact-code-review/SKILL.md` with the compact charter.
17+
- [x] 3.1 Extend the review finding schema and runner orchestration for the new clean-code categories.
18+
- [x] 3.2 Implement or update the semgrep, radon, solid, yagni, dry, and checklist paths required by the new scenarios.
19+
- [x] 3.3 Ship the `specfact/clean-code-principles` policy-pack payload and refresh `skills/specfact-code-review/SKILL.md` with the compact charter.
2020

2121
## 4. Validation and documentation
2222

23-
- [ ] 4.1 Re-run targeted tests, quality gates, and review fixtures until all changed scenarios pass.
24-
- [ ] 4.2 Update bundle docs, changelog, and release metadata for the new categories and pack payload.
25-
- [ ] 4.3 Run `openspec validate clean-code-02-expanded-review-module --strict` and resolve all issues.
23+
- [x] 4.1 Re-run targeted tests, quality gates, and review fixtures until all changed scenarios pass.
24+
- [x] 4.2 Update bundle docs, changelog, and release metadata for the new categories and pack payload.
25+
- [x] 4.3 Run `openspec validate clean-code-02-expanded-review-module --strict` and resolve all issues.
2626

2727
## 5. Delivery
2828

packages/specfact-code-review/.semgrep/clean_code.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,25 @@ rules:
5353
severity: WARNING
5454
languages: [python]
5555
pattern: print(...)
56+
57+
- id: banned-generic-public-names
58+
message: Public API names should be specific; avoid generic names like process, handle, or manager.
59+
severity: WARNING
60+
languages: [python]
61+
pattern-regex: '(?m)^(?:def|class)\s+(?:process|handle|manager|data)\b'
62+
63+
- id: swallowed-exception-pattern
64+
message: Exception handlers must not swallow failures with pass or silent returns.
65+
severity: WARNING
66+
languages: [python]
67+
pattern-either:
68+
- pattern: |
69+
try:
70+
...
71+
except Exception:
72+
pass
73+
- pattern: |
74+
try:
75+
...
76+
except:
77+
pass

packages/specfact-code-review/module-package.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: nold-ai/specfact-code-review
2-
version: 0.44.3
2+
version: 0.45.1
33
commands:
44
- code
55
tier: official
@@ -22,5 +22,5 @@ description: Official SpecFact code review bundle package.
2222
category: codebase
2323
bundle_group_command: code
2424
integrity:
25-
checksum: sha256:eeef7d281055dceae470e317a37eb7c76087f12994b991d8bce86c6612746758
26-
signature: BaV6fky8HlxFC5SZFgWAHLMAXf62MEQEp1S6wsgV+otMjkr5IyhCoQ8TJvx072klIAMh11N130Wzg4aexlcADA==
25+
checksum: sha256:db46665149d4931c3f99da03395a172810e4b9ef2cabd23d46e177a23983e7f4
26+
signature: RNvYgAPLfFtV6ywXvs/9umIAyewZPbEZD+homAIt1+n4IwDFhwneEwqzpK7RlfvCnT0Rb3Xefa5ZMW7GwiWXBw==
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
pack_ref: specfact/clean-code-principles
2+
version: 1
3+
description: Built-in clean-code review rules mapped to the governed code-review bundle outputs.
4+
default_mode: advisory
5+
rules:
6+
- id: banned-generic-public-names
7+
category: naming
8+
principle: naming
9+
- id: swallowed-exception-pattern
10+
category: clean_code
11+
principle: clean_code
12+
- id: kiss.loc.warning
13+
category: kiss
14+
principle: kiss
15+
- id: kiss.loc.error
16+
category: kiss
17+
principle: kiss
18+
- id: kiss.nesting.warning
19+
category: kiss
20+
principle: kiss
21+
- id: kiss.nesting.error
22+
category: kiss
23+
principle: kiss
24+
- id: kiss.parameter-count.warning
25+
category: kiss
26+
principle: kiss
27+
- id: kiss.parameter-count.error
28+
category: kiss
29+
principle: kiss
30+
- id: yagni.unused-private-helper
31+
category: yagni
32+
principle: yagni
33+
- id: dry.duplicate-function-shape
34+
category: dry
35+
principle: dry
36+
- id: solid.mixed-dependency-role
37+
category: solid
38+
principle: solid
39+
- id: clean-code.pr-checklist-missing-rationale
40+
category: clean_code
41+
principle: checklist
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
pack_ref: specfact/clean-code-principles
2+
version: 1
3+
description: Built-in clean-code review rules mapped to the governed code-review bundle outputs.
4+
default_mode: advisory
5+
rules:
6+
- id: banned-generic-public-names
7+
category: naming
8+
principle: naming
9+
- id: swallowed-exception-pattern
10+
category: clean_code
11+
principle: clean_code
12+
- id: kiss.loc.warning
13+
category: kiss
14+
principle: kiss
15+
- id: kiss.loc.error
16+
category: kiss
17+
principle: kiss
18+
- id: kiss.nesting.warning
19+
category: kiss
20+
principle: kiss
21+
- id: kiss.nesting.error
22+
category: kiss
23+
principle: kiss
24+
- id: kiss.parameter-count.warning
25+
category: kiss
26+
principle: kiss
27+
- id: kiss.parameter-count.error
28+
category: kiss
29+
principle: kiss
30+
- id: yagni.unused-private-helper
31+
category: yagni
32+
principle: yagni
33+
- id: dry.duplicate-function-shape
34+
category: dry
35+
principle: dry
36+
- id: solid.mixed-dependency-role
37+
category: solid
38+
principle: solid
39+
- id: clean-code.pr-checklist-missing-rationale
40+
category: clean_code
41+
principle: checklist

packages/specfact-code-review/src/specfact_code_review/resources/skills/specfact-code-review/SKILL.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@ allowed-tools: []
66

77
# House Rules - AI Coding Context (v1)
88

9-
Updated: 2026-03-16 | Module: nold-ai/specfact-code-review
9+
Updated: 2026-03-30 | Module: nold-ai/specfact-code-review
1010

1111
## DO
1212
- Ask whether tests should be included before repo-wide review; default to excluding tests unless test changes are the target
13-
- Keep functions under 120 LOC and cyclomatic complexity <= 12
13+
- Use intention-revealing names; avoid placeholder public names like data/process/handle
14+
- Keep functions under 120 LOC, shallow nesting, and <= 5 parameters (KISS)
15+
- Delete unused private helpers and speculative abstractions quickly (YAGNI)
16+
- Extract repeated function shapes once the second copy appears (DRY)
17+
- Split persistence and transport concerns instead of mixing `repository.*` with `http_client.*` (SOLID)
1418
- Add @require/@ensure (icontract) + @beartype to all new public APIs
1519
- Run hatch run contract-test-contracts before any commit
16-
- Guard all chained attribute access: a.b.c needs null-check or early return
17-
- Return typed values from all public methods
1820
- Write the test file BEFORE the feature file (TDD-first)
19-
- Use get_logger(__name__) from common.logger_setup, never print()
21+
- Return typed values from all public methods and guard chained attribute access
2022

2123
## DON'T
2224
- Don't enable known noisy findings unless you explicitly want strict/full review output
23-
- Don't mix read + write in the same method; split responsibilities
2425
- Don't use bare except: or except Exception: pass
2526
- Don't add # noqa / # type: ignore without inline justification
26-
- Don't call repository.* and http_client.* in the same function
27+
- Don't mix read + write in the same method or call `repository.*` and `http_client.*` together
2728
- Don't import at module level if it triggers network calls
2829
- Don't hardcode secrets; use env vars via pydantic.BaseSettings
29-
- Don't create functions > 120 lines
30+
- Don't create functions that exceed the KISS thresholds without a documented reason
3031

3132
## TOP VIOLATIONS (auto-updated by specfact code review rules update)
3233
<!-- auto-managed: do not edit manually -->

0 commit comments

Comments
 (0)