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
from CI
one transaction
skip locked
ladder
↳ 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.