Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ローカルしきい値ゲート

Run the threshold gate before committing to catch complexity regressions before CI. This recipe runs the same checker and configuration (the repo-root bca.toml manifest and its .bca-baseline.toml) locally and in CI, with an additional local tier for values approaching their limits. The local gate fires at git commit, alongside cargo fmt --check and cargo clippy -- -D warnings, while the author still has the change in hand.

This recipe captures the pattern big-code-analysis uses on its own source (Makefile’s self-scan* targets, backed by a consolidated bca.toml manifest) and distils it into something you can drop into your own repo’s Makefile, justfile, package.json script, or pre-commit config. The idea is provider-neutral: any threshold checker (bca, ESLint, clippy, SonarLint, Qodana) can be wired the same way.

原則

設計を駆動するのは 3 つの原則です。これらは bca に固有のものではありません。Sonar がデフォルトの品質ゲートを新しいコードに焦点を当てる方向へ転換したときに到達したのと同じ結論であり、より広いラチェットパターンが定式化しているものです。

  1. Gate locally, mirror CI exactly. The local gate must run the same binary with the same arguments and the same threshold, baseline, and exclude files as CI. If the local gate is “almost what CI runs”, it stops catching regressions the moment one diverges from the other. Running the gate once before pushing is cheap; a red PR-bot ping is not.
  2. Ratchet, do not reset. When you introduce thresholds on an existing codebase, every reasonable limit fires on dozens of pre-existing functions. The realistic adoption path is “absorb today’s offenders into a baseline file, fail only on new or worsening ones, shrink the baseline over time”. This is the same strategy that lets a multi-year codebase introduce strict TypeScript or strict clippy lints without a months-long boil-the-ocean pass. See the Baselines recipe for the bootstrap, CI, refresh, and retire flow.
  3. Warn before you fail. A hard 100% gate fails only once a value exceeds the limit and gives no signal as a function creeps from 80% to 95% to 99% of its threshold. A stricter tier reports values approaching the hard limit. The author still has the file open, the test cases in their head, and the freedom to refactor before the offender hardens into “well, it’s in main now”. Sonar’s “new code” Quality Gate, the GCC -Wall / -Werror split, and clippy’s warn vs. deny lint levels all encode the same insight: a tier between clean and broken is where teams catch drift.

2 つのティア

このパターンは、同じチェッカーをラップする 2 つのレシピと、各ティアでベースラインを更新するための 2 つのレシピから成ります。

ターゲットティアしきい値ベースラインでフィルタユースケース
self-scanハード設定の 100%はいCI のミラー。すべてのコミットでグリーンを維持しなければなりません。
self-scan-headroomソフトHEADROOM で引き締めはい早期警告バンド。ハードティアより先に発火します。
self-scan-write-baselineハード設定の 100%(書き込み)今日のハードティア違反を吸収します。
self-scan-write-baseline-headroomソフトHEADROOM で引き締め(書き込み)バンドの導入時や拡大時にソフトティアの違反を吸収します。

This repository’s own Makefile adds two checks on the baseline file rather than on the code: self-scan-baseline-fresh regenerates to a temporary file and runs bca diff-baseline against the committed one (exit 2 when the file no longer describes the tree — the quarterly freshness job’s question, answerable locally), and self-scan-profile-parity regenerates under both cargo profiles and cmps the results, which is what lets the repo build its gate binary under the fast dev profile. Neither belongs in a generic adopter skeleton; an installed bca has no profile to vary.

The hard tier and the soft tier consume the same [thresholds] table and the same .bca-baseline.toml. The only difference between them is the HEADROOM ratio applied to every threshold value before bca check sees it. The ratio tightens each limit, which for the lower-is-worse mi.* family means raising it rather than lowering it.

共有ベースラインはソフトティア(self-scan-write-baseline-headroom)で書き込みます。v5 のベースラインは、書き込み時のティアとヘッドルームを [provenance] テーブルに記録し、bca check は現在の実行がベースライン書き込み時よりも「厳しい」場合に警告します。ソフト 0.95 のベースラインはハードゲートの違反の上位集合なので、ハードの self-scan はそれを黙って読みます。逆にハードティアでベースラインを書くと、ソフトの self-scan-headroom が自分のほうが厳しいゲートだと警告するようになります。ティア/ヘッドルームの来歴を参照してください。

A contributor who wants the soft tier to be stricter (to catch encroachment further out) therefore bumps a single environment variable rather than maintaining a parallel soft-threshold file, which drifts out of sync with the hard config the first time anyone forgets to update both.

2 ティアのしきい値

bca check --tier <hard|soft|soft=RATIO> selects which tier to gate against. hard (the default) compares against the configured limits verbatim. soft is the early-warning tier, derived from the limits the file’s tables resolved to — the project table, its language table and any matching path entry, in the order How the layers compose states once. If a [thresholds.soft] table exists its overrides are merged on top, and metrics absent from it inherit their hard limit (no soft band); when a soft table is present the blanket RATIO does not apply, because explicit per-metric limits win over the scalar. Otherwise every limit is tightened by the soft RATIO (default 0.95 for a bare soft, so --tier=soft is never a silent no-op; soft=1.0 disables scaling). Repeated --threshold name=value flags apply last, absolutely.

A bare --tier=soft (ratio 0.95) is the zero-config entry point. Use [thresholds.soft] when metrics need different warning bands. The table records each soft limit beside the hard limits:

[thresholds]
cognitive  = 25
cyclomatic = 15
nargs      = 7

[thresholds.soft]
cognitive  = 22       # 絶対値のソフト制限
cyclomatic = "0.9x"   # ハード制限の 90% → 13.5
# nargs は未指定 → ソフト層はハード制限を継承(ソフト帯なし)

Soft limits with integer types read more cleanly as absolute values than as float-scaled ones: prefer nargs = 6 (for a hard nargs = 7) over the 0.95 × 7 = 6.65 a scalar would produce. Use the "<ratio>x" form for the large-valued metrics (halstead.*, loc.*) where an exact integer soft limit is fussy to pick. The scale factor must be in (0, 1]: the soft tier is an early-warning band that fires before the hard gate, never looser than it.

That “tighter, never looser” rule is what fixes the direction of the scaling, and it is not always a multiplication. A mi.* limit is a floor rather than a ceiling (a value below it is the violation), and the index has no true zero, so RATIO raises it by 1 − RATIO of one maintainability band (17.1 points of mi.original) instead: "mi.original" = 20 under --tier=soft=0.9 resolves to 21.71, not 18. The intuition that a soft band is “90% of the limit” is right for every other metric and exactly backwards here.

Both tiers ratchet through the same .bca-baseline.toml (no separate soft baseline file). bca check --print-effective-config --tier=soft prints the resolved limits; paste its [thresholds] output into [thresholds.soft] to migrate from a blanket-ratio band to explicit per-metric limits.

ゼロコンフィグ: bca.toml マニフェスト

すべてのレシピに --paths、--exclude-from、--jobs、--config、--baseline、--tier=soft=<ratio> を渡して回る代わりに、リポジトリルートに bca.toml を置き、bca check に発見させます:

# bca.toml, discovered automatically at (or above) the working dir.
paths        = ["."]
exclude_from = ".bcaignore"
jobs         = "auto"          # or an integer (was `num_jobs`)

[check]
baseline     = ".bca-baseline.toml"

[thresholds]
cognitive    = 25
cyclomatic   = 15
"halstead.effort" = 50000
nom          = 30
nargs        = 7
nexits       = 5
abc          = 50
wmc          = 60

The headroom key is the soft-tier scale ratio: it only takes effect under --tier=soft, so a bare bca check (hard tier) stays the exact CI mirror regardless of any headroom key. For per-metric soft limits, prefer a [thresholds.soft] table over the scalar; it records the band you chose next to the hard limit instead of leaving it to a runtime multiplier.

このファイルを置けば、4 つのレシピはそれぞれフラグ 1 つに集約されます:

.PHONY: self-scan self-scan-headroom \
        self-scan-write-baseline self-scan-write-baseline-headroom

self-scan:                          # hard tier (CI mirror)
	bca check
self-scan-headroom:                 # soft tier (early warning)
	bca check --tier=soft=0.95
self-scan-write-baseline:           # absorb hard-tier offenders
	bca check --write-baseline
self-scan-write-baseline-headroom:  # absorb soft-tier offenders
	bca check --tier=soft=0.95 --write-baseline

発見と優先順位

  • bca は作業ディレクトリからリポジトリルート(.git を含むディレクトリ)まで遡って bca.toml を探し、最初に見つかったものが使われます。マニフェスト内の相対パスはマニフェスト自身のディレクトリを基準に解決されるため、現在のディレクトリより上にある bca.toml でも正しいファイルを指します。
  • Scalars and positive scope keys: CLI wins. Any explicit --baseline, --tier, --jobs, and so on overrides the corresponding manifest key, and the positive scope list keys (paths, include) are replaced by any explicit CLI value (bca check one.rs with manifest paths = ["src"] checks just one.rs). --config <file> merges on top of the manifest [thresholds] table (config keys win on collision), and repeated --threshold name=value flags apply last as absolute limits. The full order, including the per-language and per-path layers, is stated once in How the layers compose; it is shared across --config, --tier, and the manifest.
  • Negative filter keys: CLI unions with the manifest. The exclude list keys (top-level exclude, [check] exclude) are merged, not replaced: a CLI --exclude / --check-exclude is added to the manifest’s deny-set. A command-line filter can therefore never silently un-exclude a directory the project config deliberately skipped (such as vendor/). Duplicates across the two sources collapse; CLI patterns sort first. This mirrors ruff and ESLint’s exclude (replace) vs extend-exclude (add), generalized: targets replace, filters add. --x and --x-from union with each other regardless. Reach for --no-config when you need the manifest excludes gone entirely.
  • --no-config skips discovery entirely, for reproducible fully-explicit invocations that must not pick up repo-level config. bca init also ignores any existing manifest; it scaffolds config rather than consuming it.
  • トップレベルの include / exclude キーは、どのファイルを「そもそも解析するか」を決めるグローバルなファイルフィルタのグロブ(--include / --exclude フラグ)です。これらは [check] exclude テーブル(解析され報告されるがゲートされないパス。ファイルカテゴリ全体の除外を参照)とは別物です。
  • [check] テーブルはゲート専用のオプションを設定します。exclude はグロブのリストで、一致したファイルは解析・報告されますが、しきい値ゲート(および --write-baseline)からは除外されます。exclude_from は同じグロブを並べた .gitignore 形式のファイルを指します(どちらも --check-exclude / --check-exclude-from フラグに対応します)。exit_codes = "tiered" はより細かい終了コードにオプトインします(--exit-codes=tiered に対応。終了コードを参照)。"default"(暗黙の値)は安定した 0/1/2 の契約を維持します。ベースラインとヘッドルームのキーもゲート専用なのでここに置かれます: baseline(bca check が読み、引数なしの --write-baseline が書き込むファイル)、baseline_line_tolerance、baseline_fuzzy_match、そして headroom(ソフトティアのスケール比率。--tier=soft=<R> に対応)。いずれのキーも、どちらの方向でも CLI の値がテーブルの値を上書きします。
  • これら 4 つのキーは以前トップレベルにありました。その綴りは非推奨(#599)で、一度だけ警告が出ます。1 リリースサイクルの間は尊重され、その後の次のメジャーバージョンで削除されます。baseline、baseline_line_tolerance、baseline_fuzzy_match、headroom を [check] の下へ移してください。キーが両方に設定されている場合は [check] の値が勝ちます。
  • A [vcs] table sets change-history ranking options for bca vcs. Its file_types key ("metrics", the default, or "all", or a "rs,py"-style extension list) scopes which files are ranked; as a positive scope key, an explicit --file-types CLI flag replaces it (see bca vcs file-type scope).
  • cyclomatic_count_try and exclude_tests are walker-tuning bools that mirror the --cyclomatic-count-try / --exclude-tests flags. exclude_tests = true prunes Rust inline-test subtrees (#[test], #[cfg(test)], …) before metric computation. Both are Rust-only and inert for other grammars. --exclude-tests is presence-only (no =false form), so its manifest key can only turn pruning on: a CLI --exclude-tests wins, but the manifest cannot turn off a key the CLI did not set.
  • mi_charges_docs mirrors --mi-charges-docs: true has mi.sei’s comment share count documentation rows as comments, which can only raise mi.sei; mi.original and mi.visual_studio read the same either way. Off by default, merged like cyclomatic_count_try (the CLI value wins in either direction). A baseline records the mode it was written under and bca check warns when it is read under the other; see Charging documentation.
  • [thresholds.soft] テーブルは、メトリクスごとのソフトティア制限を設定します(--tier=soft によって消費されます。2 ティアのしきい値を参照)。認識されないキーは 1 行の警告とともに無視されるため、古い bca ビルドを壊すことなく、今後のスキーマ追加を先行採用できます。
  • bca check --print-effective-config は、manifest の来歴行を含む解決済みのビューを出力するので、マージが何を生成したかを正確に確認できます。

The explicit-flag skeletons below remain fully supported; the manifest is sugar over the same flags, not a replacement. Reach for them when you cannot drop a file at the repo root, or when one CI job needs a different layout than the committed manifest (pair the flags with --no-config).

スケルトン: GNU Make(明示フラグ)

The four recipes below are a self-contained drop-in that thread every flag explicitly, the long form of the manifest recipe above. Adjust the BCA variable to point at whatever invocation gives you the checker (a pinned release binary, cargo run --release, an npm or pip wrapper). Adjust PATHS and EXCLUDE_FROM to match your layout.

# --- bca ローカルしきい値ゲート ------------------------------------------
# ハード(HARD)ティアは CI を正確にミラーします。両ティアは同じ
# thresholds.toml + .bca-baseline.toml を消費し、ソフトティアはすべての
# しきい値を $(BCA_HEADROOM)(デフォルト 0.95)でスケールします。
#
# Knobs are namespaced with `BCA_` so they don't collide with anything
# else in your environment. The big-code-analysis repo itself uses the
# manifest form above (a single `bca.toml`) rather than these explicit
# flags; reach for this skeleton when you can't drop a manifest at the
# repo root and must point `--config` at a standalone threshold file.
BCA               := bca
BCA_PATHS         := .
BCA_EXCLUDE_FROM  := .bcaignore
BCA_THRESHOLDS    := thresholds.toml
BCA_BASELINE      := .bca-baseline.toml
BCA_HEADROOM      ?= 0.95

# 共通引数。4 つのレシピが揃った状態を保てるよう括り出しています。
# `--jobs` のデフォルトは OS が報告する実効 CPU 数
# (Linux では cgroup / cpuset を考慮)なので、`$(nproc)` の引き回しは
# needed. Override with `--jobs N` (or `--jobs 1` to force
# serial mode for debugging).
BCA_BASE_ARGS := --paths $(BCA_PATHS) --exclude-from $(BCA_EXCLUDE_FROM)

.PHONY: self-scan self-scan-headroom \
        self-scan-write-baseline self-scan-write-baseline-headroom

self-scan:
	@echo "bca self-scan (hard gate)..."
	@$(BCA) check $(BCA_BASE_ARGS) \
	  --config $(BCA_THRESHOLDS) \
	  --baseline $(BCA_BASELINE)

# `self-scan-headroom: self-scan` is intentional: under `make -j` Make
# would otherwise run both gates in parallel and the soft tier's scaled
# error message could land before the true regression on the hard tier.
# `--tier=soft=$(BCA_HEADROOM)` scales every config limit before the
# offender comparison: no helper script, no second TOML file.
self-scan-headroom: self-scan
	@echo "bca self-scan (soft gate, BCA_HEADROOM=$(BCA_HEADROOM))..."
	@$(BCA) check $(BCA_BASE_ARGS) \
	  --config $(BCA_THRESHOLDS) \
	  --tier=soft=$(BCA_HEADROOM) \
	  --baseline $(BCA_BASELINE)

self-scan-write-baseline:
	@echo "Refreshing $(BCA_BASELINE) at hard thresholds..."
	@$(BCA) check $(BCA_BASE_ARGS) \
	  --config $(BCA_THRESHOLDS) \
	  --write-baseline $(BCA_BASELINE)

# Soft-tier baseline write. NOTE: this and `self-scan-write-baseline`
# どちらも `$(BCA_BASELINE)` に書き込みます。これらを並列に
# prerequisites of one umbrella target or invoke them with `make -j2`,
# or the two `bca` processes will race on the same file and the
# losing tier's offenders will silently vanish from the baseline.
# Run them sequentially (hard first, then soft) and commit the diff.
self-scan-write-baseline-headroom:
	@echo "Refreshing $(BCA_BASELINE) at soft thresholds (BCA_HEADROOM=$(BCA_HEADROOM))..."
	@$(BCA) check $(BCA_BASE_ARGS) \
	  --config $(BCA_THRESHOLDS) \
	  --tier=soft=$(BCA_HEADROOM) \
	  --write-baseline $(BCA_BASELINE)

The soft tier tightens limits from --config, then applies the shared baseline. It multiplies count ceilings by the ratio (default 0.95 for a bare --tier=soft) and raises mi.* floors by 1 − ratio of one maintainability band. Explicit --threshold values apply last and are not scaled. There is no separate helper script or second TOML file to maintain; the soft tier is the hard-tier invocation plus one flag.

終了コード

The gate exit codes propagate verbatim from bca check: 0 clean, 2 on any threshold violation (hard or soft), 1 on tool error. The soft tier is a real gate. Never wrap make self-scan-headroom in || true thinking it is advisory; the non-zero exit is the whole point of the encroachment band.

Pass --exit-codes=tiered (or set [check] exit_codes = "tiered") to split the single violation code 2 by severity: 2 new offenders only, 3 regressions only, 4 both, 5 a --tier=soft violation that also breaches the hard limit. The tiered codes are opt-in; the default stays 0/1/2, and every fail-state remains non-zero. Use them when CI needs to route “a new offender appeared” differently from “a baselined offender got worse” without parsing the [new] / [regr …] row tags.

pre-commit と CI への組み込み

Add the soft gate to whatever umbrella target your developers already run before pushing. The hard gate runs as its prerequisite (see the self-scan-headroom: self-scan edge above), so listing only the soft target is enough. That edge also survives make -j, which would otherwise schedule both leaves in parallel and interleave their output:

.PHONY: pre-commit
pre-commit: fmt-check clippy test self-scan-headroom

順序が重要です。ハードティアは、スケーリング後ではなく 100% の限度に対する真のリグレッションを指摘します。前提条件のエッジは、並列 Make の下でもその順序を強制します。

CI では、ハードティアのみを実行します:

- name: Threshold gate
  run: make self-scan

The soft tier is a developer feedback knob, not a release gate. Running it in CI either duplicates the hard tier (when nothing has encroached) or fires noisily on a baseline-absorbed offender that crept upward without crossing 100%. Neither buys you anything CI does not already cover.

ヘッドルームノブ

BCA_HEADROOM は (0, 1] の範囲の単一のスカラー値です。意味のあるバンドは狭い範囲に限られます:

BCA_HEADROOM関数が次に達すると発火…ユースケース
0.9999% of a count ceilingNarrow warning band.
0.9595% of a count ceiling (default)Default warning band.
0.9090% of a count ceilingWider band, useful immediately after raising a limit, while the new ceiling settles.
1.00100%(ハードゲートと同等)2 つのティアが一致していることを確認するサニティチェックです。

An mi.* floor is raised by 1 − BCA_HEADROOM of one band instead of scaled, as Two-tier thresholds explains.

およそ 0.80 を下回る値では、ソフトティアは恣意的な数値による第 2 のハードティアと化し、有用でなくなります。現実のコードベースでは、どのしきい値にもその 80% 付近にある関数が 何かしら 存在するため、ソフトティアは早期警告シグナルではなく、恒常的なベースライン管理の雑務になってしまいます。

ソフトティアが発火したとき

A failed soft gate is a decision point, not a bug report. There are three legitimate resolutions:

  1. Refactor. Same workflow as any other complexity regression: extract a helper, collapse a dispatch arm, split the function. This is the common case, and the soft tier exists to give you the time to do it on the same branch.
  2. Raise the limit. Edit the [thresholds] table (in bca.toml for this repo, or your own threshold file) and leave a why-comment explaining what changed (a new language module, a real algorithmic floor, a re-classified macro). Re-run make self-scan-headroom to confirm the new value covers the offender with room to spare.
  3. Absorb into the baseline. Run make self-scan-write-baseline (hard tier) or make self-scan-write-baseline-headroom (soft tier) when the value is legitimate forever: a parser dispatch arm whose width matches the grammar it covers, a stable state machine, generated code. Commit the diff in .bca-baseline.toml in the same PR as the code that produced it.

Do not pick “raise the limit” silently to make the gate go away. The committed why-comment is the only audit trail the next reader has; without it the bumped limit looks indistinguishable from neglect.

スケルトン:justfile

just を好むプロジェクトの場合:

# bca local threshold gates. Hard tier mirrors CI; soft tier (headroom)
# is local-only early warning.
bca         := "bca"
paths       := "."
exclude     := ".bcaignore"
thresholds  := "thresholds.toml"
baseline    := ".bca-baseline.toml"
headroom    := env_var_or_default("BCA_HEADROOM", "0.95")

# `--jobs` defaults to the effective CPU count, so the skeleton
# no longer threads `$(nproc)` through `just`. Override
# inline if needed: `just self-scan --jobs 1`.
base_args   := "--paths " + paths + " --exclude-from " + exclude

self-scan:
    {{bca}} check {{base_args}} \
        --config {{thresholds}} --baseline {{baseline}}

self-scan-headroom: self-scan
    {{bca}} check {{base_args}} \
        --config {{thresholds}} --tier=soft={{headroom}} --baseline {{baseline}}

self-scan-write-baseline:
    {{bca}} check {{base_args}} \
        --config {{thresholds}} --write-baseline {{baseline}}

# Like the Make skeleton, never compose this with `self-scan-write-baseline`
# in parallel; they race on the same {{baseline}} file.
self-scan-write-baseline-headroom:
    {{bca}} check {{base_args}} \
        --config {{thresholds}} --tier=soft={{headroom}} --write-baseline {{baseline}}

スケルトン:package.json スクリプト

npx またはピン留めしたバイナリで bca を取り込む JavaScript プロジェクト向けです。--jobs のデフォルトは実効 CPU 数(Linux では cgroup / cpuset を考慮)なので、npm 側でも Make / just とバイト単位で同一の bca check 呼び出しを生成するために BCA_NUM_JOBS 環境変数はもう必要ありません。--jobs 1 を明示的に渡すのはデバッグ時だけにしてください:

{
  "scripts": {
    "self-scan": "bca check --paths . --exclude-from .bcaignore --config thresholds.toml --baseline .bca-baseline.toml",
    "self-scan-headroom": "bca check --paths . --exclude-from .bcaignore --config thresholds.toml --tier=soft=0.95 --baseline .bca-baseline.toml",
    "self-scan-write-baseline": "bca check --paths . --exclude-from .bcaignore --config thresholds.toml --write-baseline .bca-baseline.toml",
    "self-scan-write-baseline-headroom": "bca check --paths . --exclude-from .bcaignore --config thresholds.toml --tier=soft=0.95 --write-baseline .bca-baseline.toml"
  }
}

Because the soft tier is a plain bca check invocation, the npm scripts are byte-identical across shells: no helper script, no python3-vs-py alias to paper over, no env-var-vs-shell-expansion portability traps. To widen the band, edit the literal 0.95 in the script (or wire it through your task runner of choice); the flag parses the same on every platform.

husky や pre-commit と組み合わせて、同じスクリプトが git commit 時に実行されるようにしてください。

スケルトン:pre-commit フック

If you use the pre-commit framework (version 3.2.0 or newer; see the version note below), both tiers are local hooks that shell out to make:

- repo: local
  hooks:
    - id: bca-self-scan
      name: bca self-scan (hard gate)
      entry: make self-scan
      language: system
      pass_filenames: false
      stages: [pre-commit]
    - id: bca-self-scan-headroom
      name: bca self-scan-headroom (soft gate)
      entry: make self-scan-headroom
      language: system
      pass_filenames: false
      stages: [pre-commit]

pass_filenames: false is deliberate: bca discovers its own inputs from --paths plus the baseline. Letting pre-commit pass the changed files in would shrink the scan to just those files and miss the cross-file effect of a baseline refresh.

Minimum pre-commit version 3.2.0. The stages: vocabulary was renamed in pre-commit 3.2.0 (2023-03-17): commit became pre-commit, push became pre-push, and so on. Older installs (notably RHEL 8 EPEL, Ubuntu 20.04 default packages, and any .pre-commit-config.yaml pinned to the legacy vocabulary) reject stages: [pre-commit] as an unknown stage name and the hook never registers. If you must support older installations, substitute stages: [commit]; in mixed fleets, pin the framework with pre-commit --version ≥ 3.2.0 in the dev-tooling docs so this contradiction does not surface silently.

より広いベースラインワークフローとの組み合わせ

The four self-scan* targets above are not a replacement for the documented Baselines recipe; they are that recipe, mechanised into developer-machine commands. The same ordering still applies:

  1. 最初に一度ブートストラップする。 初期のしきい値を書き、初期のベースラインを書き、両方をコミットします。
  2. コミットごとにゲートする。 ハードティアはリグレッションで失敗し、ソフトティアは限度への接近で失敗します。
  3. 集中的なリファクタリング中に更新する。 関数の値が正当に動いた(誰かが 実際に 負債を返済した)場合は、ベースラインを再生成して差分をレビューします。
  4. 空になったら退役させる。 .bca-baseline.toml が version = 6 だけ(違反エントリのない素のスキーマスタンプ)に縮んだら、--baseline フラグを外してファイルを削除します。以後はしきい値が単独で機能します。

関連する業界パターン

ハード / ソフトのティア分割は、より広いパターンの一例です。以下のいずれかを使ったことがあれば、そのメンタルモデルがそのまま通用します:

  • Sonar の新規コードに焦点を当てた品質ゲート。 既存コードは現状のまま維持され、変更 が事態を悪化させてはならない、という考え方です。ベースラインファイルは、「新規コード」/「リーク期間」という発想の bca ネイティブな形です。
  • clippy の warn-vs-deny リントレベル。 warn リントはローカルビルドで表面化し、同じリントを -D warnings で deny すると CI が失敗します。2 段構えの設定は、実験的により厳しいルールを導入する場所を与えてくれます。
  • 一般的な移行ツーリングにおける ラチェットパターン。今日のカウントを記録し、増加で失敗させ、カウントが減るにつれ上限を下げていきます。bca check はパターン単位ではなく関数単位でラチェットしますが、単調性の保証は同じです。
  • -Wall + -Werror in C/C++. A first pass with -Wall reveals the noise; promoting to -Werror after the baseline reaches zero is the same retirement step as deleting .bca-baseline.toml once it is empty.