tga 2.8.1

Developer productivity analytics — git commit collection, classification, and reporting
Documentation
//! Code-review, cleanup, infra, and generic-keyword rules.

use crate::classify::rules::types::Rule;

/// Why: linting, formatting, review-feedback, and cleanup commits all share
/// the property of being maintenance-style rather than feature work; grouping
/// their rules together keeps the classification policy easy to audit.
/// What: returns rules for lint runs (rustfmt / prettier / clippy / eslint),
/// generic format passes, code-review-feedback markers, and cleanup keywords
/// (`remove unused`, `dead code`).
/// Test: covered by `lint_and_format_classify_to_style`,
/// `cleanup_classifies_to_refactor`, `review_feedback_classifies_to_refactor`.
pub(super) fn code_review_and_cleanup_rules() -> Vec<Rule> {
    vec![
        Rule {
            id: "kw-lint".into(),
            category: "style".into(),
            subcategory: Some("lint".into()),
            keywords: vec![
                "fix lint".into(),
                "lint fix".into(),
                "fix linting".into(),
                "fix linter".into(),
                "satisfy lint".into(),
                "clippy fix".into(),
                "fix clippy".into(),
                "eslint fix".into(),
                "rubocop".into(),
                "prettier".into(),
                "gofmt".into(),
                "rustfmt".into(),
                "black format".into(),
            ],
            patterns: vec![r"(?i)\bfix(es|ed|ing)?\s+lint(ing|er)?\b".into()],
            priority: 75,
            confidence: 0.85,
        },
        Rule {
            id: "kw-format".into(),
            category: "style".into(),
            subcategory: Some("format".into()),
            keywords: vec![
                "reformat".into(),
                "code formatting".into(),
                "fix formatting".into(),
                "fix whitespace".into(),
                "trailing whitespace".into(),
                "fix indentation".into(),
            ],
            patterns: vec![],
            priority: 65,
            confidence: 0.8,
        },
        Rule {
            id: "kw-review".into(),
            category: "refactor".into(),
            subcategory: Some("review".into()),
            keywords: vec![
                "address review".into(),
                "address feedback".into(),
                "address comments".into(),
                "review feedback".into(),
                "review comments".into(),
                "pr feedback".into(),
                "code review".into(),
                "apply suggestions".into(),
                "incorporate review".into(),
            ],
            patterns: vec![],
            priority: 70,
            confidence: 0.8,
        },
        Rule {
            id: "kw-cleanup".into(),
            category: "refactor".into(),
            subcategory: Some("cleanup".into()),
            keywords: vec![
                "clean up".into(),
                "cleanup".into(),
                "dead code".into(),
                "remove unused".into(),
                "delete unused".into(),
                "tidy up".into(),
                "housekeeping".into(),
            ],
            patterns: vec![r"(?i)\bremove\s+(unused|dead|stale|obsolete)\b".into()],
            priority: 60,
            confidence: 0.8,
        },
    ]
}

/// Why: Dockerfile / k8s / Terraform / GitHub Actions changes are
/// infrastructure work that should be reported separately from product
/// development.
/// What: returns four rules for the major infra ecosystems (Docker,
/// Kubernetes/Helm, Terraform/Ansible, CI runners).
/// Test: covered by `infra_keywords_classify_appropriately`.
pub(super) fn infra_rules() -> Vec<Rule> {
    vec![
        Rule {
            id: "kw-docker".into(),
            category: "build".into(),
            subcategory: Some("docker".into()),
            keywords: vec![
                "dockerfile".into(),
                "docker-compose".into(),
                "docker compose".into(),
                "docker image".into(),
            ],
            patterns: vec![],
            priority: 70,
            confidence: 0.85,
        },
        Rule {
            id: "kw-k8s".into(),
            category: "build".into(),
            subcategory: Some("kubernetes".into()),
            keywords: vec![
                "kubernetes".into(),
                "k8s".into(),
                "helm chart".into(),
                "kustomize".into(),
            ],
            patterns: vec![],
            priority: 70,
            confidence: 0.85,
        },
        Rule {
            id: "kw-terraform".into(),
            category: "build".into(),
            subcategory: Some("terraform".into()),
            keywords: vec![
                "terraform".into(),
                "tf module".into(),
                "tflint".into(),
                "ansible playbook".into(),
            ],
            patterns: vec![],
            priority: 70,
            confidence: 0.85,
        },
        Rule {
            id: "kw-github-actions".into(),
            category: "ci".into(),
            subcategory: Some("github-actions".into()),
            keywords: vec![
                "github action".into(),
                "github actions".into(),
                "github workflow".into(),
                "gh action".into(),
                ".github/workflows".into(),
                "circleci".into(),
                "gitlab ci".into(),
                "jenkinsfile".into(),
                "azure pipeline".into(),
                "azure pipelines".into(),
                "travis".into(),
            ],
            patterns: vec![],
            priority: 70,
            confidence: 0.85,
        },
    ]
}

/// Why: prose commit messages without conventional-commit prefixes still need
/// a category; these mid-priority keyword rules cover the most common verbs
/// and topics so the catch-all only fires on truly unstructured prose.
/// What: returns rules for "add/implement" (→ feature), "fix/resolve"
/// (→ bugfix), bug/regression prose, security/CVE keywords, performance,
/// docs, tests, config, database, and WIP markers.
/// Test: covered by `bug_fix_prose_classifies_to_bugfix`,
/// `security_prose_classifies_to_security`, `performance_prose_classifies_to_performance`,
/// `docs_prose_classifies_to_documentation`, `test_prose_classifies_to_test`,
/// `wip_prose_classifies_to_wip`, and `database_migration_classifies_to_feature`.
pub(super) fn generic_keyword_rules() -> Vec<Rule> {
    vec![
        Rule {
            id: "kw-add-implement".into(),
            category: "feature".into(),
            subcategory: None,
            keywords: vec![
                "implement".into(),
                "introduce".into(),
                "add support".into(),
                "add feature".into(),
                "new feature".into(),
                "initial implementation".into(),
            ],
            patterns: vec![r"(?i)^\s*add\s+(new\s+)?(support\s+for|feature|the)\b".into()],
            priority: 45,
            confidence: 0.7,
        },
        Rule {
            id: "kw-fix-resolve".into(),
            category: "bugfix".into(),
            subcategory: None,
            keywords: vec![
                "fix bug".into(),
                "fix issue".into(),
                "fix crash".into(),
                "fix regression".into(),
                "fix race".into(),
                "fix deadlock".into(),
                "fix leak".into(),
                "fix segfault".into(),
                "fix panic".into(),
                "fix error".into(),
                "resolve issue".into(),
                "resolve bug".into(),
                "resolve race".into(),
                "resolve deadlock".into(),
                "fixes #".into(),
                "fixes:".into(),
                "closes #".into(),
                "patch bug".into(),
                "correct behavior".into(),
                "correct handling".into(),
            ],
            patterns: vec![r"(?i)\b(fix(es|ed)?|resolves?|closes?)\s+#\d+".into()],
            priority: 60,
            confidence: 0.85,
        },
        Rule {
            id: "kw-bug".into(),
            category: "bugfix".into(),
            subcategory: None,
            keywords: vec!["defect".into(), "regression".into()],
            patterns: vec![r"(?i)\b(bug|bugs)\b".into()],
            priority: 40,
            confidence: 0.7,
        },
        Rule {
            id: "kw-security".into(),
            category: "security".into(),
            subcategory: None,
            keywords: vec![
                "security patch".into(),
                "security fix".into(),
                "vulnerability".into(),
                "cve-".into(),
                "xss".into(),
                "csrf".into(),
                "sql injection".into(),
                "rce".into(),
                "ssrf".into(),
            ],
            patterns: vec![r"(?i)\bCVE-\d{4}-\d+".into()],
            priority: 80,
            confidence: 0.9,
        },
        Rule {
            id: "kw-performance".into(),
            category: "performance".into(),
            subcategory: None,
            keywords: vec![
                "speed up".into(),
                "speedup".into(),
                "optimize".into(),
                "optimization".into(),
                "improve performance".into(),
                "reduce latency".into(),
                "reduce memory".into(),
                "memory leak".into(),
            ],
            patterns: vec![],
            priority: 55,
            confidence: 0.8,
        },
        Rule {
            id: "kw-docs".into(),
            category: "documentation".into(),
            subcategory: None,
            keywords: vec![
                "readme".into(),
                "changelog".into(),
                "update docs".into(),
                "documentation".into(),
                "javadoc".into(),
                "rustdoc".into(),
                "docstring".into(),
                "doc comment".into(),
            ],
            patterns: vec![r"(?i)\bupdate\s+(the\s+)?(readme|changelog|docs)\b".into()],
            priority: 50,
            confidence: 0.8,
        },
        Rule {
            id: "kw-test-add".into(),
            category: "test".into(),
            subcategory: None,
            keywords: vec![
                "add test".into(),
                "add tests".into(),
                "unit test".into(),
                "unit tests".into(),
                "integration test".into(),
                "e2e test".into(),
                "snapshot test".into(),
                "test coverage".into(),
                "test suite".into(),
                "fix test".into(),
                "fix tests".into(),
                "fix flaky".into(),
                "flaky test".into(),
            ],
            patterns: vec![],
            priority: 55,
            confidence: 0.85,
        },
        Rule {
            id: "kw-config".into(),
            category: "chore".into(),
            subcategory: Some("config".into()),
            keywords: vec![
                "update config".into(),
                "config change".into(),
                "configuration".into(),
                ".gitignore".into(),
                ".editorconfig".into(),
                "tsconfig".into(),
                "pyproject".into(),
                "package.json".into(),
                "cargo.toml".into(),
            ],
            patterns: vec![],
            priority: 50,
            confidence: 0.75,
        },
        Rule {
            id: "kw-database".into(),
            category: "feature".into(),
            subcategory: Some("database".into()),
            keywords: vec![
                "db migration".into(),
                "database migration".into(),
                "schema migration".into(),
                "add migration".into(),
                "new migration".into(),
                "alter table".into(),
            ],
            patterns: vec![],
            priority: 60,
            confidence: 0.8,
        },
        Rule {
            id: "kw-wip".into(),
            category: "wip".into(),
            subcategory: None,
            keywords: vec![
                "work in progress".into(),
                "todo:".into(),
                "fixme:".into(),
                "checkpoint".into(),
            ],
            patterns: vec![r"(?i)^\s*wip\b".into(), r"(?i)^\s*\[wip\]".into()],
            priority: 40,
            confidence: 0.65,
        },
    ]
}