← STATIONSCH 05 — SPEC/CH/05 · ESC TO CLOSEENFR

Vestige — static-analysis issue tracker

Static analysers answer "what is wrong with this file, right now". They do not answer the question a team actually cares about: is this new, or the same thing we agreed to live with three months ago — and who agreed to it? Vestige owns that claim, sitting between CI and the developer.

IDENTITY
Three-rung fingerprint ladder, O(P+C)
INGESTION
Idempotent, outbox, SKIP LOCKED
TENANCY
Postgres RLS, forced on every role
AUDIT
Hash-chained, trigger-enforced
DECISION RECORDS
10 ADRs with rejected options
FIG. 1 — INGESTION PATH
SARIF
from CI
RUN + OUTBOX
one transaction
CLAIM
skip locked
MATCH
ladder
GATE

↳ byte-identical repeat → the original result↳ same key, different report → 409

MATCHER
32 fixtures · 0 false splits · 0 false merges
TESTS
23 unit classes · 153 methods
ISOLATION
Proven by an adversarial RLS test
PARSE
Streaming SARIF · heap independent of size

THE HARD PART

A finding is not a line number. Add twelve imports and rename a method and line 42 becomes line 58 — match naively on rule, file and line and the tool calls the old issue fixed and the new one introduced. Every choice here trades false merges against false splits, and the two pull in opposite directions.

WHAT I REJECTED

Embedding similarity, and a plain diff. The first is not reproducible run to run, so it cannot be explained to someone disputing a failed gate; the second answers "what changed" rather than "is this the same problem". The ladder is deterministic and its tie-break is written down.

WHAT I'D FIX FIRST

The actor on a triage decision is a caller-supplied string, not a checked identity — v1 has organisation-scoped API keys and no per-user auth. The chain proves an action happened and was not altered afterwards; it does not prove who performed it. Per-user identity is the next thing that matters.