Skip to content

feat: uniform [tool.forge.precommit] config to enable/disable steps #6

@misnaej

Description

@misnaej

Problem

The pre-commit step sequence is a hardcoded tuple in
forge.precommit.run_all (src/forge/precommit.py:585). Whether a given
step runs is decided by three different ad-hoc mechanisms, with no
single place a consumer can turn a step on or off:

  • Always-onruff, docstrings, test_naming run unconditionally
    (modulo source-dir presence).
  • Opt-in via a step-specific tablecli_wiring requires
    [tool.forge.cli_wiring] enabled = true; docstring_coverage reads
    [tool.forge.docstring_coverage]; the proposed doctest step (feat: doctest pre-commit step + CI integration #5) would
    add yet another [tool.forge.doctest].
  • File-presence conditionalmanifest_json / plugin_version
    self-skip when .claude-plugin/ is absent; pip_audit skips when
    pip-audit is off PATH.

There is no [tool.forge.precommit] table and no --skip / --only CLI
flag. A consumer who wants to drop one step (e.g. silence pip_audit
entirely, or disable repo_structure in a repo that doesn't keep
REPO_STRUCTURE.md) has no uniform lever — they must either edit
.githooks/pre-commit by hand or rely on whatever bespoke gate that one
step happens to expose.

Proposal

A single override layer applied uniformly in run_all, on top of (not
replacing) each step's existing self-skip:

  1. [tool.forge.precommit] config table

    [tool.forge.precommit]
    disable = ["pip_audit"]      # force-skip these steps by name
    enable  = ["doctest"]        # opt in to normally-off steps by name

    Read once at the top of run_all; a disabled step yields a
    StepResult(skipped=True, output="(disabled via [tool.forge.precommit])")
    so the skip is visible in the log, not silent.

  2. --skip <step> / --only <step> CLI flags on forge-precommit for
    ad-hoc local runs (repeatable, validated against the known step names).

The per-step bespoke gating stays as the default behavior; this is an
override layer, not a rewrite. Step names are the existing StepResult.name
values (ruff, docstrings, docstring_coverage, test_naming,
repo_structure, manifest_json, cli_wiring, commit_types_parity,
plugin_version, pip_audit).

Guardrails

  • Disabling must be visible. A disabled step renders as an explicit
    SKIP (disabled) line + log entry — never a silent omission. Weakening a
    quality gate should leave a trail (FOUNDATION §2 "never bypass", §4
    scope policy).
  • --only is for local iteration, not CI. Document that CI should run
    the full sequence; --only is a dev-loop convenience.
  • Unknown step name → hard error, not silent no-op (catches typos).

Acceptance criteria

  • [tool.forge.precommit] disable / enable honored by run_all,
    applied uniformly to every step.
  • Disabled steps surface as skipped=True with a "disabled" reason in the
    log and the printed line.
  • --skip / --only flags on forge-precommit, validated against known
    step names (unknown → exit non-zero with the valid list).
  • Unknown step name in config or flag is an error, not a no-op.
  • Tests cover: disable a normally-on step, enable a normally-off step,
    --only single step, --skip repeated, unknown-name error.

Out of scope

  • Reordering steps (the sequence is fixed; this only toggles membership).
  • Per-step config beyond enable/disable (each step keeps its own table for
    step-specific options like docstring_coverage.badge).

Related

  • forge.precommit.run_all (src/forge/precommit.py:585) — the hardcoded
    sequence this layers an override onto.
  • _cli_wiring_enabled (src/forge/precommit.py:468) — example of the
    current per-step ad-hoc opt-in this would generalize.
  • feat: doctest pre-commit step + CI integration #5 (doctest step) — would register under the new enable list instead of
    inventing a fourth bespoke gate.
  • FOUNDATION §4 pre-commit scope policy — the discipline this config must
    not undermine.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions