-
Notifications
You must be signed in to change notification settings - Fork 1
feat: clean-code-01-principle-gates — 7-principle charter gates, v0.44.0 #474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,148 +1,109 @@ | ||
| --- | ||
| description: Enforce clean-code principles and enforcements across the repository. | ||
| description: Enforce the 7-principle clean-code charter across the repository. | ||
| globs: | ||
| alwaysApply: true | ||
| --- | ||
| # Rule: Clean Code Principles and Enforcements | ||
|
|
||
| Description: | ||
| This rule enforces concrete clean-code practices across the repository. It complements existing high-level rules (TDD, linting, formatting, coverage) by adding behavioral and API-consistency checks, with deterministic commands and examples. | ||
|
|
||
| Why: | ||
|
|
||
| - Reduce cognitive load and debugging time by standardizing error handling, return types, logging, and small, single-purpose functions. | ||
| - Make automated checks (pre-commit/CI) able to catch non-style problems (bare-excepts, prints, mixed return semantics, state-machine/config mismatches). | ||
|
|
||
| Scope: | ||
| Applies to all python files under src/ and tests/ and any state-machine generation artifacts. | ||
|
|
||
| Enforcement checklist (machine-checkable where possible): | ||
|
|
||
| 1. No bare except or broad except Exception without re-raising or logging full context | ||
| - Rationale: Broad excepts hide real failures. | ||
| - Check: run pylint with a custom plugin or flake8 rule to detect "except:" or "except Exception:" that either: | ||
| - swallow the exception without re-raising, or | ||
| - do not call logger.exception(...) (stack trace). | ||
| - Command (CI): flake8 --select E722,B001 (or custom check) | ||
| - Example (bad): | ||
| try: | ||
| ... | ||
| except Exception: | ||
| pass | ||
| - Example (good): | ||
| except SpecificError as e: | ||
| logger.error("...: %s", e) | ||
| raise | ||
|
|
||
| 2. No direct print() calls in library modules | ||
| - Rationale: Use LoggerSetup for structured logs and session IDs. | ||
| - Check: grep for "print(" in src/ and tests/ (fail in src/) | ||
| - Command (CI): git grep -n -- '^\s*print\(' -- src/ && fail | ||
| - Fix: Replace print with LoggerSetup.get_logger(...) or setup_logger(...) | ||
|
|
||
| 3. Enforce consistent return types (avoid implicit None/False mixing) | ||
| - Rationale: Functions exposed as API should have typed, predictable returns. | ||
| - Rules: | ||
| - Publishing/IO methods must return bool (True/False), not None. If underlying library returned int, normalize. | ||
| - connect() should return bool only. | ||
| - Check: static analysis rule or unit test that asserts function annotations and runtime contract on a selection of public functions (RedisClient.publish/connect, MessagingStandardization.*) | ||
| - Example (good): | ||
| def publish(...) -> bool: ... | ||
| return True/False | ||
|
|
||
| 4. Prefer specific exceptions & re-raise after logging | ||
| - Rationale: Keep failure semantics explicit for callers and tests. | ||
| - Rule: Do not swallow exceptions. If a function handles and cannot continue, raise a domain-specific exception or re-raise. | ||
|
|
||
| 5. Limit line / function complexity | ||
| - Rationale: Keep functions short and single-responsibility. | ||
| - Rules: | ||
| - Maximum function length: 120 lines (configurable) | ||
| - Maximum cyclomatic complexity: 12 | ||
| - Check: use radon cc --total-average and flake8-ext or pylint thresholds | ||
| - Command (CI): radon cc -nc -s src/ && fail if any > 12 | ||
|
|
||
| 6. Use centralized logging, never ad-hoc formatting | ||
| - Rationale: Keep consistent format and redaction. | ||
| - Rules: | ||
| - Use LoggerSetup.get_logger or setup_logger to obtain logger. | ||
| - No module-level printing of messages; message flow logs should go via agent_flow logger. | ||
| - Check: grep for 'logging.getLogger(' and verify consistent usage, grep for 'print(' (see rule 2). | ||
|
|
||
| 7. Avoid filesystem operations with overly permissive modes | ||
| - Rationale: 0o777 should not be used by default. | ||
| - Rule: mkdir/os.makedirs must not be invoked with mode=0o777. Use 0o755 or use environment-controlled mode. | ||
| - Check: grep for '0o777' and require explicit justification in code comments; CI should flag occurrences. | ||
|
|
||
| 8. State machine / YAML consistency check | ||
| - Rationale: Generated state machines must match canonical YAML config. | ||
| - Rule: Add a unit/regression test that: | ||
| - reloads src/common/*.py generated state machine enums and compares state names and transitions to autodev_config.yaml and productplan_config.yaml | ||
| - fails the build if mismatch or case differences are present | ||
| - Check: add tests/unit/test_state_machine_config_sync.py | ||
| - Command (CI): hatch test tests/unit/test_state_machine_config_sync.py | ||
|
|
||
| 9. No side-effects at import time | ||
| - Rationale: Module imports should be safe and predictable for tests and tools. | ||
| - Rule: Avoid heavy I/O or network calls on import. get_runtime_logs_dir may create directories — allowed only if idempotent and documented; avoid network calls or spawn threads. | ||
| - Check: grep for network or redis connection calls at module-level (e.g., RedisSDK(...)). | ||
|
|
||
| 10. Async / signal safety | ||
| - Rationale: Signal handlers must not call non-signal-safe operations. | ||
| - Rule: Signal handlers may only set a flag or call a thread-safe routine; do not call asyncio.create_task directly from a POSIX signal handler. | ||
| - Check: grep for "signal.signal(" and assert handler functions only set flags or use loop.call_soon_threadsafe. | ||
| - Suggested fix: replace create_task calls in handler with loop.call_soon_threadsafe(lambda: asyncio.create_task(...)) | ||
|
|
||
| 11. Secure secret redaction guaranteed | ||
| - Rationale: Sensitive keys must be masked in logs. | ||
| - Rule: LoggerSetup.redact_secrets must be covered by unit tests for nested dicts and strings. | ||
| - Check: add tests/unit/test_logger_redaction.py | ||
|
|
||
| 12. Messaging coercion & strict validation | ||
| - Rationale: Legacy message coercion is useful but must be exercised and tested. | ||
| - Rule: Any place that uses coercion (MessagingStandardization.process_standardized_message) must have tests that validate coercion success/failure and metrics increments. | ||
| - Check: add unit tests that assert contextschema_coercion_success/failed metrics behave as expected. | ||
|
|
||
| 13. Enforce pre-commit & CI gating | ||
| - Add pre-commit config that runs: black, isort, mypy, flake8 (with B/C plugins), radon, tests for state machine sync. | ||
| - CI job must fail on: | ||
| - lint failures | ||
| - radon/cyclomatic complexity | ||
| - state-machine config mismatch test | ||
| - flake8 error codes for prints and bare excepts | ||
|
|
||
| 14. Documentation/commit habits | ||
| - Rule: Any code change that modifies public API, state machine YAMLs, or generated state machine outputs MUST: | ||
| - include/modify a unit test covering new behavior | ||
| - update docs/ and CHANGELOG.md | ||
| - include 'BREAKING' section in PR if public API changed | ||
| - Check: CI script that rejects PRs lacking test files changed when src/ is modified (heuristic). | ||
|
|
||
| Implementation guidance (how to add tests / checks quickly) | ||
|
|
||
| - Add a lightweight pytest module for state-machine YAML<->enum sync (example included in docs). | ||
| - Add flake8 plugin rules or configure pylint to error on 'print' and bare excepts; enable in CI config. | ||
| - Add radon complexity check step to pipeline; fail if thresholds exceeded. | ||
| - Add a small assertion test for RedisClient.publish return normalization. | ||
|
|
||
| Mapping to existing rules (what to augment) | ||
|
|
||
| - docs/rules/python-github-rules.md: Add explicit "no-bare-except" and "no-print" items and function complexity thresholds. | ||
| - docs/rules/spec-fact-cli-rules.md: Add "state-machine YAML / generated code sync check" and "normalize public API return types". | ||
| - docs/rules/testing-and-build-guide.md: Add specific test files to run (state-machine sync test, logger redaction tests) and mention radon/complexity checks. | ||
| - .cursor/rules/testing-and-build-guide.mdc and .cursor/rules/python-github-rules.mdc: include exact CLI commands and required test files (see enforcement checklist). | ||
|
|
||
| Developer notes (priorities) | ||
|
|
||
| 1. Add the state-machine sync unit test (high value, low effort). | ||
| 2. Add flake8/pylint rule to detect print/bare-except (medium effort). | ||
| 3. Normalize RedisClient.publish/connect return values & add tests (low-to-medium effort). | ||
| 4. Add radon step to CI and fix top offenders iteratively (ongoing). | ||
| 5. Replace print() in AutoDevStateMachine.log with LoggerSetup.get_logger (small change, run tests). | ||
| # Rule: Clean-Code Principles and Review Gate | ||
|
|
||
| --- | ||
| ## Charter source of truth | ||
|
|
||
| The canonical 7-principle clean-code charter lives in: | ||
| - **Policy-pack**: `specfact/clean-code-principles` (shipped by `specfact-cli-modules`) | ||
| - **Skill file**: `skills/specfact-code-review/SKILL.md` in `nold-ai/specfact-cli-modules` | ||
|
|
||
| This file is an **alias surface** for the specfact-cli repository. It maps each | ||
| principle to its review category and records the Phase A gate thresholds so that | ||
| contributors, reviewers, and AI coding agents operate from the same reference | ||
| without duplicating the full charter text. | ||
|
|
||
| ## The 7 clean-code principles | ||
|
|
||
| | # | Principle | Review category | | ||
| |---|-----------|-----------------| | ||
| | 1 | **Meaningful Naming** — identifiers reveal intent; avoid abbreviations | `naming` | | ||
| | 2 | **KISS** — keep functions and modules small and single-purpose | `kiss` | | ||
| | 3 | **YAGNI** — do not add functionality until it is needed | `yagni` | | ||
| | 4 | **DRY** — single source of truth; eliminate copy-paste duplication | `dry` | | ||
| | 5 | **SOLID** — single responsibility, open/closed, Liskov, interface segregation, dependency inversion | `solid` | | ||
| | 6 | **Small, focused functions** — each function does exactly one thing (subsumed by KISS metrics) | `kiss` | | ||
| | 7 | **Self-documenting code** — prefer expressive code over inline comments; comments explain *why* not *what* | `naming` | | ||
|
|
||
| ## Active gate: Phase A KISS metrics | ||
|
|
||
| The following thresholds are **enforced** through the `specfact code review run` | ||
| gate and the pre-commit hook (`scripts/pre_commit_code_review.py`): | ||
|
|
||
| | Metric | Warning | Error | | ||
| |--------|---------|-------| | ||
| | Lines of code per function (LOC) | > 80 (warning) | > 120 (error) | | ||
| | Nesting depth | configurable (phase A) | configurable (phase A) | | ||
| | Parameter count | configurable (phase A) | configurable (phase A) | | ||
|
|
||
| Nesting-depth and parameter-count checks are **active** in Phase A. | ||
|
|
||
| ### Phase B (deferred) | ||
|
|
||
| Phase B thresholds (`> 40` warning / `> 80` error for LOC) are planned for a | ||
| future cleanup change once the initial Phase A remediation is complete. | ||
| **Phase B is not yet a hard gate.** Do not silently promote Phase B thresholds | ||
| when configuring or extending the review gate. | ||
|
|
||
| ## Review categories consumed by this repo | ||
|
|
||
| When `specfact code review run` executes against this codebase the following | ||
| clean-code categories from the expanded review module are included: | ||
|
|
||
| - `naming` — semgrep naming and exception-pattern rules | ||
| - `kiss` — radon LOC/nesting/parameter findings under Phase A thresholds | ||
| - `yagni` — AST-based unused-abstraction detection | ||
| - `dry` — AST clone-detection and duplication findings | ||
| - `solid` — AST dependency-role and single-responsibility checks | ||
|
|
||
| Zero regressions in these categories are required before a PR is merge-ready. | ||
|
|
||
| ## Per-principle enforcement notes | ||
|
|
||
| ### Naming (`naming`) | ||
|
|
||
| - Identifiers in `src/` must use `snake_case` (modules/functions), `PascalCase` (classes), `UPPER_SNAKE_CASE` (constants). | ||
| - Avoid single-letter names outside short loop variables. | ||
| - Exception patterns must not use broad `except Exception` without re-raising or logging. | ||
|
|
||
| ### KISS (`kiss`) | ||
|
|
||
| - Maximum function length: **120 lines** (Phase A error threshold). | ||
| - Maximum cyclomatic complexity: **12** (radon `cc` threshold; `>= 16` is error band). | ||
| - Phase A LOC warning at > 80, error at > 120. | ||
|
|
||
| ### YAGNI (`yagni`) | ||
|
|
||
| - Do not add configuration options, flags, or extension points until a concrete use-case drives them. | ||
| - Remove dead code paths rather than commenting them out. | ||
|
|
||
| ### DRY (`dry`) | ||
|
|
||
| - Do not copy-paste logic; extract to a shared function or module. | ||
| - Single source of truth for schemas (Pydantic `BaseModel`), constants (`UPPER_SNAKE_CASE`), and templates (`resources/templates/`). | ||
|
|
||
| ### SOLID (`solid`) | ||
|
|
||
| - Each module/class has a single clearly named responsibility. | ||
| - Extend via dependency injection (adapters pattern) rather than modifying existing classes. | ||
| - Use `@icontract` (`@require`/`@ensure`) and `@beartype` on all public APIs. | ||
|
|
||
| ## Additional behavioral rules (complement SOLID/KISS) | ||
|
|
||
| - No `print()` calls in `src/` — use `from specfact_cli.common import get_bridge_logger`. | ||
| *(Note: T20 is currently ignored in pyproject.toml and not enforced by the review gate; this is aspirational.)* | ||
| - No broad `except Exception` without re-raising or logging. | ||
| *(Note: W0718 is disabled in .pylintrc; broad-exception checks are aspirational.)* | ||
| - No side-effects at import time (no network calls, no file I/O on module load). | ||
| - Signal handlers must only set a flag or use `loop.call_soon_threadsafe`. | ||
| - Filesystem modes must not use `0o777`; use `0o755` or environment-controlled mode. | ||
| - Secret redaction via `LoggerSetup.redact_secrets` must be covered by unit tests. | ||
|
|
||
| Changelog / Expected follow-up | ||
| ## Pre-commit and CI enforcement | ||
|
|
||
| - After adding these rules, update CI to run the new checks and add sample unit tests that fail on violations. | ||
| - Run hatch test and the new linters locally; fix top offenders in an iterative PR with small, focused commits. | ||
| The `specfact-code-review-gate` pre-commit hook and the `hatch run specfact code | ||
| review run --json --out .specfact/code-review.json` command both enforce these | ||
| principles. Run the review before submitting a PR and resolve every finding. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # GitHub Copilot Instructions — specfact-cli | ||
|
|
||
| ## Clean-Code Charter | ||
|
|
||
| This repository enforces the **7-principle clean-code charter** defined in: | ||
| - `skills/specfact-code-review/SKILL.md` (`nold-ai/specfact-cli-modules`) | ||
| - Policy-pack: `specfact/clean-code-principles` | ||
|
|
||
| Review categories checked on every PR: **naming · kiss · yagni · dry · solid** | ||
|
|
||
| Phase A KISS thresholds: LOC > 80 warning / > 120 error per function. | ||
| Nesting-depth and parameter-count checks are active. Phase B (>40/80) is deferred. | ||
|
|
||
| Run `hatch run specfact code review run --json --out .specfact/code-review.json` before submitting. | ||
|
|
||
| ## Key conventions | ||
|
|
||
| - Python 3.11+, Typer CLI, Pydantic models, `@icontract` + `@beartype` on all public APIs | ||
| - No `print()` in `src/` — use `get_bridge_logger()` | ||
| - Branch protection: work on `feature/*`, `bugfix/*`, `hotfix/*` branches; PRs to `dev` | ||
| - Pre-commit checklist: `hatch run format` → `type-check` → `lint` → `yaml-lint` → `contract-test` → `smart-test` | ||
|
|
||
| See `AGENTS.md` and `.cursor/rules/` for the full contributor guide. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.