抑制マーカー
In-source suppression markers silence threshold violations without editing the offending function or excluding the file from the walk. Drop a marker in any comment in the source file and bca check treats the covered metrics as if they were within limits for that scope. Metric computation is unaffected: raw bca metrics output still reports every number. Suppression is a display concern. bca check drops the covered violations from the gate, and bca report markdown|html omits the covered functions from the matching hotspot tables by default (pass bca report --no-suppress for the raw audit view; see report).
Markers exist for the cases where editing the code is not an option: legacy modules awaiting rewrite, accepted exceptions documented in the comment, and migration from Lizard’s #lizard forgives convention. This page is the marker reference: the syntax, the metric names it accepts, where a marker may sit, and the flags that audit or bypass markers.
ネイティブマーカー(bca:)
ネイティブ方言は bca: 名前空間と suppress 動詞を使用し、プロジェクト内部の「suppression(抑制)」語彙(SuppressionPolicy、FuncSpace::suppressed、--no-suppress)と一致しています。形式は 4 つあります:
| マーカー | スコープ | 効果 |
|---|---|---|
bca: suppress | 囲んでいる関数 | すべてのメトリクスを抑制 |
bca: suppress(metric, ...) | 囲んでいる関数 | 列挙したメトリクスのみを抑制 |
bca: suppress-file | ファイル | すべてのメトリクスを抑制 |
bca: suppress-file(metric, ...) | ファイル | 列挙したメトリクスのみを抑制 |
The two metric-list forms may carry a rationale: free text on the same line, after the marker itself:
#![allow(unused)]
fn main() {
// bca: suppress(nargs) — 引き回されるコンテキストであって、神関数ではない
}
No separator is required and none is privileged: — why, - why, : why, // why, and bare prose all read the same. The two bare verbs take no trailing text at all; bca: suppress see #123 is not a marker, whatever punctuation opens the trailing words. See Rationale text for why.
A function-scope marker attaches to the innermost FuncSpace (see the FuncSpace rustdoc) whose source range contains the comment. A function-scope marker outside every function body is silently ignored; for file-wide silencing use the explicit suppress-file verb. A file-scope marker may appear anywhere in the source; there is no “must be in first N lines” rule.
bca: suppress: function-scoped, all metrics (Rust)
#![allow(unused)]
fn main() {
// bca: suppress
fn legacy_dispatch(opcode: u8) -> Action {
// サポートされる全オペコードに対する高密度な match
match opcode { /* ... */ }
}
}
bca: suppress(metric, ...): function-scoped, listed metrics (Python)
def parse_token_stream(tokens):
# bca: suppress(cognitive)
# 認知的複雑度はこのステートマシンに本質的なもの。
# 循環的複雑度は依然として制限内に収まっている。
...
その他のしきい値(cyclomatic、halstead、loc など)は引き続き適用されます。
bca: suppress-file: file-scoped, all metrics (JavaScript)
// bca: suppress-file
// 手動チューニングされたホットパス。しきい値を満たすための書き換えはしないこと。
function transform(input) { /* ... */ }
function validate(input) { /* ... */ }
bca: suppress-file(metric, ...): file-scoped, listed metrics (C++)
/* bca: suppress-file(halstead) */
// Halstead の volume は下の生成テーブルによって膨らんでいる。
// それ以外のメトリクスはファイル全体で引き続き適用される。
Prefer a narrower tool first. Thresholds apply at each metric’s defined scope. A file-wide or
impl-wide aggregate does not trigger a per-function limit, so muting a file-levelhalstead/nargs/nexits/nomtotal is no longer a reason to reach forsuppress-file(#969). Usesuppress-filewhen you intend to silence the metric throughout the file. To excuse one irreducibly complex function, use a function-scopedbca: suppress(...)inside it. To grandfather existing offenders without blinding the gate to future regressions, prefer a baseline entry, which keeps firing once a function gets worse than its recorded value.
Lizard 互換マーカー
既存の Lizard 対応コードベースを書き換えずに済むよう、2 つの Lizard 形式マーカーがそのまま認識されます:
| Lizard マーカー | スコープ | 対応するネイティブマーカー |
|---|---|---|
#lizard forgives | 囲んでいる関数 | bca: suppress |
#lizard forgive global | ファイル | bca: suppress-file |
The compatibility layer is intentionally narrow: only these two shapes are accepted. Other Lizard directives parse as ordinary comments. Lizard offers no per-metric scoping, so the native form’s bca: suppress(metric, ...) list has no Lizard analogue; every Lizard-style marker silences every metric.
Lizard の GENERATED CODE マーカーはここでは扱いません。これは生成コードの自動スキップ機構の一部です(生成コードのスキップと --no-skip-generated フラグを参照)。
ネイティブと Lizard の対照表
| 効果 | ネイティブ形式 | Lizard 形式 |
|---|---|---|
| 1 つの関数のすべてのメトリクスを沈黙させる | // bca: suppress | // #lizard forgives |
| 1 つの関数の 1 つのメトリクスを沈黙させる | // bca: suppress(cyclomatic) | (該当なし) |
| ファイル全体のすべてのメトリクスを沈黙させる | // bca: suppress-file | // #lizard forgive global |
| ファイル全体の 1 つのメトリクスを沈黙させる | // bca: suppress-file(halstead) | (該当なし) |
メトリクス識別子
bca: suppress(...) と bca: suppress-file(...) の内側で受け付けられる識別子は次のとおりです:
abc, cognitive, cyclomatic, halstead, loc, mi, nargs, nexits, nom, npa, npm, wmc.
これらは、しきい値名および CodeMetrics に出力される JSON フィールド名と一致しますが、意図的な除外が 1 つあります:
nexitsis the canonical spelling:bca: suppress(nexits)silences anexitsthreshold violation. The legacyexitalias was retired in #555 and is no longer accepted. Spelling itexitis an unknown identifier, which warns and is skipped; the recognized names beside it still suppress (see below).tokensはしきい値チェック可能なメトリクス(かつCodeMetricsの JSON フィールド)ですが、意図的に抑制リストから外されています: マーカーで無効化することはできません。tokensは保守性のヒューリスティックではなく、ハードなリソース上限として扱ってください。
ファミリー(例えば halstead)を沈黙させると、その配下のすべてのサブメトリクスしきい値(halstead.volume、halstead.effort など)が対象になります。抑制の語彙にドット付きの形式はありません。
bca: suppress(...) リスト内の未知の識別子は、次の形式の stderr 警告を出力します
warning: path/to/file.rs:42: unknown metric 'no_such_metric' in bca suppression marker; known metrics: abc, cognitive, ...
Only the offending identifier is dropped: bca: suppress(cognitive, exit) still silences cognitive. Skipping can only shrink what a marker covers, so a typo never widens scope to a metric the author did not name. Rejecting the whole marker, which is what earlier releases did, would also discard valid metric names, leaving intended suppressions inactive.
Unknown verbs (anything other than suppress / suppress-file) and bodies that parse to no directive at all (an unbalanced parenthesis, a bare verb followed by any trailing text) produce the same shape of warning, and those do void the marker, since there is nothing left of it to honour. None of these are fatal: a typo in one file does not derail a workspace walk, and a doc comment that merely mentions the syntax does not fail your gate.
根拠テキスト
メトリクスリストの後のテキストは書き手のものです。bca はそこを読み飛ばし、解釈しません。2 つの形式の間の非対称性は意図的なものです:
-
After a metric list (
bca: suppress(nargs) threaded context) anything goes. The parentheses are a positive signal that this comment is a marker, and the list has already stated the intent unambiguously, so whatever follows is prose. -
After a bare verb (
bca: suppress — irreducible dispatch) there is no trailing text. Nothing in this shape separates a rationale from a sentence about the feature, and no separator can:-,:,//,#and the dashes are exactly the punctuation someone writing// bca: suppress - we removed this marker, see #123reaches for. Accepting them silences every metric in the enclosing function on the strength of a comment, so the whole shape warns instead.To record a reason, name the metrics (
bca: suppress(cognitive, cyclomatic) — reason), which is more precise than theAllhammer anyway. IfAllreally is what you mean, put the reason on the line above the marker.
マーカーを書ける場所
マーカーは、コメントスタイルを問わず、任意のソースコメント内で認識されます。スキャナーはマッチングの前に、先頭の区切り文字 /、*、!、#、;、- と ASCII 空白を取り除きます。これは bca が現在パースするすべてのコメント形式をカバーします:
- C 系の行コメント:
// bca: suppress - C 系のブロックコメント:
/* bca: suppress */ - Rust の内部ドキュメントコメント:
//! bca: suppressと/*! bca: suppress */ - Python / シェル / Ruby / Perl の
#コメント:# bca: suppress - Lisp / Lua / SQL の行コメント:
;; bca: suppress、-- bca: suppress
Function-scope markers attach to the innermost Function-kind FuncSpace whose (start_line..=end_line) range contains the comment’s line. Markers buried in a class or struct body but outside every method are silently ignored; for class-wide silencing use bca: suppress-file or repeat the marker on each method.
ファイルスコープのマーカーはトップレベルの Unit スペースにマージされ、ネストに関係なくファイル内のすべての関数に適用されます。
マーカーはコメントの先頭近くに配置してください。スキャナーは両端の区切り文字を取り除いた後、先頭に bca:(または #lizard)が来ることを期待します。複数行ブロックコメントの奥深くに埋もれたマーカーは認識されません。
--no-suppress(CI での監査)
bca check --no-suppress ignores every suppression marker, native and Lizard alike, and reports every threshold violation in the walk. Use it in audit pipelines that need the raw, un-silenced offender list:
bca check --paths src/ --no-suppress
このフラグはメトリクスの値自体には影響しません: 生の bca metrics 出力は常にすべての数値を報告します。bca report markdown|html はデフォルトでホットスポットテーブルにおいてマーカーを尊重し、同じ生の監査ビューのために独自の --no-suppress フラグを受け付けます。
抑制された負債の可視化(--report-suppressed)
Suppression keeps an offender out of the gate, which also keeps it out of the --report-format document, so a suppressed module disappears from the code-scan report entirely. bca check --report-suppressed puts it back, as suppressed rather than active:
bca check --report-format sarif --no-fail --report-suppressed \
--tier=soft=0.95 --output bca.sarif
Offenders silenced by an in-source marker or covered by the baseline are emitted into the SARIF document with a SARIF suppressions entry: kind: "inSource" for markers, kind: "external" for the baseline. The suppression never fails the gate (exit code and the human offender rows are unaffected); the suppressions entry lets downstream tooling tell suppressed debt apart from active offenders.
GitHub Code Scanning. GitHub renders a result that carries a
suppressionsentry as a suppressed (closed) alert, so the debt stays visible on the Security tab without failing the gate. If you only want active offenders to appear, omit--report-suppressedfrom the upload (this repo’s own Pages workflow does exactly that).
注記:
- Use SARIF to export suppressed offenders; other report formats emit only active offenders.
- Match the tier to your baseline’s provenance (
--tier=soft=0.95for a soft-0.95baseline) so offenders below the hard limit still appear. - Do not combine
--report-suppressedwith--no-suppressor--write-baseline.
適用除外の監査(bca exemptions)
--no-suppress shows you the offenders a marker silences, but not the markers themselves; to find every silencer you previously had to diff a --no-suppress run against a normal one. bca exemptions replaces that workaround with a direct listing of everything the bca check gate skips, across all three exemption tiers, in one report:
| ティア | 粒度 | ソース |
|---|---|---|
| ソース内マーカー | 関数単位 / ファイル単位 | bca: suppress、#lizard forgives、… |
[check.exclude] グロブ | グロブ単位(ファイルのカテゴリ) | bca.toml [check] exclude / --check-exclude |
| ベースラインエントリ | (path, symbol, metric) 単位 | .bca-baseline.toml |
# ツリー内のすべての適用除外を一覧表示します(ソース内マーカーは
# 他のすべての走査コマンドと同様に [walker.exclude] を尊重します)。
bca exemptions --paths src/
# In-source markers (2)
src/parser.rs:120 bca: suppress metrics=all parse_long
src/lib.rs:1 bca: suppress-file metrics=halstead (whole file)
# [check.exclude] globs (1)
tests/**
# Baseline (.bca-baseline.toml, 1 entry)
src/markdown_report.rs write_language_section cognitive 29
The surrounding function (for function-scoped markers) gives scope context; file-scoped markers read (whole file), and a function-scoped marker written outside any function, which silences nothing, reads (no enclosing fn) so dead markers are visible.
フォーマットとセクションフィルタ
--format markdown は PR コメント向けのテーブルを出力します。--format json は、ダッシュボードや jq によるフィルタリングのために、3 つのティアすべてを単一の suppressions エンベロープの下にネストします:
bca exemptions --paths src/ --format json | jq '.suppressions.markers[] | select(.dialect == "lizard")'
JSON 形式では、省略されたセクション(--*-only フラグで要求されなかったもの)は null になり、要求されたが空だったセクションは [] になるため、フィルタは両者を区別できます。
The mutually exclusive --markers-only / --excludes-only / --baseline-only flags narrow the report to a single tier for a specialised PR bot, such as one that only comments on newly added in-source markers. The baseline (bca.toml top-level baseline) and [check.exclude] ([check] exclude) inputs default to the same sources bca check reads, so the audit reflects exactly what the gate would skip; override the baseline with --baseline <path>.
以前の --only-markers / --only-excludes / --only-baseline の綴りは、既存の PR ボットの呼び出しを動かし続けるため、1 リリースサイクルの間は非表示のエイリアスとして残ります。diff-baseline のセクションフィルタと一致する --<section>-only 形式を優先してください。
Unlike bca check, bca exemptions is informational and always exits 0 on success. It is a review surface, not a gate.
PR レビュー中に bca exemptions を bca diff-baseline と併用する方法については、ベースラインのレシピ も参照してください。
JSON 出力
FuncSpace は、マージされた抑制スコープを JSON 出力のオプションフィールド suppressed として公開します。スペースに適用されるマーカーがない場合、このフィールドは省略されるため、既存のスナップショット利用者には変化がありません。マーカーが発動した場合、このフィールドは次の 2 つの形のいずれかになります:
{ "suppressed": { "kind": "all" } }
{ "suppressed": { "kind": "some", "metrics": ["cognitive", "loc"] } }
kind: all は素のマーカー(bca: suppress、bca: suppress-file、または任意の Lizard 形式のマーカー)に対応します。kind: some は bca: suppress(...) / bca: suppress-file(...) で指定された明示的なメトリクスのリストを保持します。どちらの形も、ダッシュボードや監査ログに適した安定したシリアライズ出力です。
Lizard からの移行
互換レイヤーがあるため、移行は段階的に行えます:
- Keep existing
#lizard forgivesand#lizard forgive globalmarkers during migration;bca checkrecognizes them. - Replace markers with
bca: suppress(...)when you need per-metric scoping; the Lizard form silences every metric.
本プロジェクトは Lizard 互換レイヤーを無期限に維持します。削除予定日はありません。
予約済み構文
次の形は将来の使用のために予約されており、現時点ではパースされません:
bca: suppress-next: silence the immediately following declaration rather than the enclosing function. Rejected today as an unknown verb; it will be promoted to first-class behavior in a future release without breaking existing markers.
The reason = "..." argument this section used to reserve is no longer planned. Write the rationale after the metric list instead (see Rationale text), which is the spelling authors already reach for. Inside the parentheses, reason = "..." is still an unknown metric identifier and is skipped with a stderr warning.