Quick answer: Fingerprint every fixed bug (stack hash, feature vector), store the fingerprint in your bug tracker, match incoming reports against it, and alert the original fixer the moment a match is found. Catch regressions on the first occurrence, not after 50.

A bug takes you two days to fix. Six weeks later, it ships again because somebody reverted the wrong file in a merge. By the time a player reports it, 20 more players have already seen it. A sticky alert would have flagged it the instant the first recurrence hit your crash backend.

The Fingerprint

A fingerprint is a deterministic key derived from the bug’s signature. For crashes, hash the normalized stack:

def crash_fingerprint(stack):
    frames = [normalize(f) for f in stack[:5]]
    return sha256("\n".join(frames)).hexdigest()[:16]

def normalize(frame):
    # strip line numbers, inlined wrappers, anonymous lambdas
    f = re.sub(r':\d+', '', frame)
    f = re.sub(r'<lambda_\d+>', '<lambda>', f)
    return f

For non-crash bugs (UI glitches, gameplay logic errors), combine a fixed set of context keys: scene, action, game mode, build, player OS.

Storage and Lookup

When a bug is closed, record its fingerprint and the closing commit in the bug tracker. Every incoming report gets its fingerprint computed and looked up. A hit means a possible regression.

# On new crash report
fp = crash_fingerprint(report.stack)
closed_bug = bugs.find_one({"fingerprint": fp, "status": "closed"})
if closed_bug:
    raise_alert(
        bug=closed_bug,
        new_report=report,
        assignees=[closed_bug.closed_by, closed_bug.owner_lead],
    )

Alert Content

The alert should be immediately actionable:

Route to the original fixer and their team lead. They have the context to decide: real regression, false-positive fingerprint collision, or a different bug that happens to hit the same stack.

False Positive Rate

Stack hashing produces some collisions. A good fingerprint has collision rate under 1%. Measure by sampling alerts and checking whether each match is really the same bug. If collisions exceed 5%, widen the hash (include more frames or file paths).

Sticky Duration

Fingerprints don’t expire. A bug fixed two years ago that regresses today still matters — especially because nobody remembers it. The storage cost of keeping fingerprints forever is trivial; the benefit of catching ancient regressions is real.

“A regression alert fires when one player hits a known bug. The alternative is waiting until fifty players hit it.”

Related Issues

For broader deduplication, see how to build a crash report deduplication system. For regression budgets, see how to set up a regression budget for your game.

Fingerprint every bug you close, forever. Storage is cheap, and the first time an alert fires after two silent years you’ll be glad you did.