DEV Community

Muhammet ŞAFAK
Muhammet ŞAFAK

Posted on

Stop re-flagging the same finding — without going silent

A reviewer that flags the same known issue on every run trains you to ignore it. The fix can't be "hide findings," because a tool that silently drops things is worse than one that nags. CommitBrief has two ways to accept a finding and move on — a per-developer baseline and an in-source suppression marker — and both are built so that what they remove is always counted, never quietly swallowed. The interesting part is how a finding keeps its identity when the code around it moves.

TL;DR

  • Baseline (.commitbrief/baseline.json, gitignored): accept the current findings once; later runs drop anything whose fingerprint is already in the file.
  • Inline suppression: a commitbrief-ignore: <reason> comment on or above a line removes that finding — and lives in committed source, so a reviewer sees it.
  • A finding's fingerprint deliberately excludes its line number, so accepting it survives the code drifting up and down the file.
  • Both are TRUE removals — they affect --fail-on and the JSON findings[], not just the display — and both print what they removed.
  • The limit. The baseline is per-developer, not a shared team policy; it quiets your runs, not CI's.

The fingerprint that survives code drift

The whole design rests on one question: when is a finding "the same finding" you already accepted? If the answer included the line number, a baseline would evaporate the moment you added an import above the issue. So it doesn't. A finding's identity is three fields, hashed:

func normalizeTitle(title string) string {
    return strings.ToLower(strings.Join(strings.Fields(title), " "))
}

func Fingerprint(f render.Finding) string {
    h := sha256.New()
    h.Write([]byte(f.File))
    h.Write([]byte{0})
    h.Write([]byte(f.Severity))
    h.Write([]byte{0})
    h.Write([]byte(normalizeTitle(f.Title)))
    return hex.EncodeToString(h.Sum(nil))
}
Enter fullscreen mode Exit fullscreen mode

File, severity, and a normalized title — and nothing else. Line is out, so the same issue keeps its fingerprint after the surrounding code shifts. Description and Snippet are out too, because an LLM rephrases those between runs; folding them in would re-mint the fingerprint every time the model picked a different sentence, and the baseline would never actually catch anything. The NUL bytes between fields keep them unambiguous — "ab" + "c" and "a" + "bc" can't collide into the same hash.

That single exclusion — the line number — is what makes a baseline durable instead of fragile.

Baseline: accept once, move on

A baseline is a set of accepted fingerprints. Filtering is set membership:

func Filter(findings []render.Finding, set Set) (kept []render.Finding, baselined int) {
    if len(set) == 0 {
        return findings, 0
    }
    kept = make([]render.Finding, 0, len(findings))
    for _, f := range findings {
        if set.Contains(Fingerprint(f)) {
            baselined++
            continue
        }
        kept = append(kept, f)
    }
    return kept, baselined
}
Enter fullscreen mode Exit fullscreen mode

You opt in with --update-baseline, which absorbs the current findings into baseline.json and returns them unfiltered for that run — you see the full set once, then future runs go quiet on exactly those. --no-baseline ignores the file for a run when you want everything back. The two are mutually exclusive at the flag layer.

The failure modes are deliberate. A missing baseline.json is a transparent no-op — a developer who never opted in has nothing baselined. A present but corrupt file is a loud error, not a silent empty set, because silently un-baselining would resurface findings you thought were settled, and a trust-sensitive tool should fail closed there. The file lives under the gitignored .commitbrief/, so it's yours alone.

Inline suppression: a reasoned marker in the source

The baseline is invisible. Sometimes you want the opposite — a suppression a reviewer can see and challenge. That's the marker:

var markerRe = regexp.MustCompile(`(?i)commitbrief-ignore\s*(?:\[\s*([a-z]+)\s*\])?\s*:\s*(.*)`)
Enter fullscreen mode Exit fullscreen mode

commitbrief-ignore: <reason> silences any finding on the line; commitbrief-ignore[high]: <reason> silences only that severity. Two design choices matter. The comment syntax is not parsed — the regex matches the commitbrief-ignore token anywhere on the line, so //, #, --, and /* */ all work without a per-language table. And a marker is only read from the added lines of the diff: a suppression has to be part of the change under review, never smuggled in from untouched code.

A marker silences a finding on its own line or the one directly above it — the idiomatic spot when the statement is long:

func isSuppressed(f render.Finding, sup Suppressions) bool {
    if f.Line <= 0 {
        return false
    }
    if r, ok := sup[f.Line]; ok && r.matches(f.Severity) {
        return true
    }
    if r, ok := sup[f.Line-1]; ok && r.matches(f.Severity) {
        return true
    }
    return false
}
Enter fullscreen mode Exit fullscreen mode

A bracketed severity the parser doesn't recognize (a typo like [bogus]) falls back to unscoped — it suppresses rather than silently doing nothing, because the marker is visible in the diff either way and a reviewer can catch the typo.

True removals, always counted

Both layers run in one stage, baseline then suppression, before the --fail-on gate and the renderer:

// SC1 — baseline filter
if app.Config.Review.Baseline && !global.noBaseline {
    set, lerr := baseline.Load(app.RepoRoot)
    // ...
    findings, baselined = baseline.Filter(findings, set)
}
// SC2 — inline suppression (always active)
sup := suppress.ParseSuppressions(parsed)
findings, suppressed = suppress.Filter(findings, sup)
Enter fullscreen mode Exit fullscreen mode

This is what makes them true removals, deliberately unlike the display-only --min-severity (which hides findings from the human but leaves them in the JSON and the gate). A baselined finding doesn't trip --fail-on=high in CI; it's gone from the actionable set. But "gone" is never "silent": the counts ride out as optional meta.baselined / meta.suppressed JSON fields (the schema stays v1) and a one-line stderr footer.

func signalControlFooter(cmd *cobra.Command, app *appContext, baselined, suppressed int) {
    if baselined == 0 && suppressed == 0 {
        return
    }
    // ... "3 baselined · 1 suppressed" to stderr, honoring --quiet
}
Enter fullscreen mode Exit fullscreen mode

It goes to stderr so it never corrupts a piped --json stdout. A review tool you can't trust to tell you what it dropped isn't one you'd leave in your pre-commit hook.

What it is not

The baseline is per-developer and gitignored on purpose — it's not a shared team policy. It quiets your runs; a teammate, or CI, or the senior reviewer at the end still sees every finding. That's the point (your accepted-cruft list shouldn't hide a real bug from the next person), and it's the cost (you can't baseline something for the whole team). Inline suppression is the inverse trade: it does travel with the code, which is exactly why it's reviewable — the reason sits in the diff for someone to push back on. Neither one edits your source; suppression only takes effect because you wrote the marker yourself.

Repo: github.com/CommitBrief/commitbrief.


Part 8 of **Building CommitBrief. Next: remote PR review — a self-hosted reviewer that runs on your own gh auth and posts inline comments.

Top comments (0)