From 76485f08b6f6d1e09309e439227be1d781d71a8c Mon Sep 17 00:00:00 2001 From: Krishan Kant Sharma Date: Mon, 22 Jun 2026 22:30:37 -0500 Subject: [PATCH] =?UTF-8?q?docs(adr):=20ADR=20007=20=E2=80=94=20stable=20f?= =?UTF-8?q?inding=20fingerprint=20schema=20for=20v1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defines provider:callType:flagKey:normalizedFilePath as the v1.0 fingerprint schema. Foundation for baseline mode (ADR 008) and SARIF stability. Part of the v1.0.0 milestone. Signed-off-by: Krishan Kant Sharma --- docs/adr/007-stable-finding-fingerprints.md | 97 +++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/adr/007-stable-finding-fingerprints.md diff --git a/docs/adr/007-stable-finding-fingerprints.md b/docs/adr/007-stable-finding-fingerprints.md new file mode 100644 index 0000000..85bd91f --- /dev/null +++ b/docs/adr/007-stable-finding-fingerprints.md @@ -0,0 +1,97 @@ +--- +# ADR 007 — Stable Finding Fingerprints + +**Date:** 2026-06-22 +**Status:** ACCEPTED + +## Context + +FlagLint v1.0 introduces baseline mode, which requires stable identifiers for +findings across runs. Line numbers are fragile — they change when code is +reformatted, comments are added, or unrelated code moves around. We need +fingerprints that remain stable as long as the logical finding has not changed. + +Consumers of stable fingerprints: +- **Baseline mode** — matches current findings against a stored baseline to + identify new debt without failing on historical debt +- **SARIF output** — stable result identities prevent GitHub Code Scanning + alert churn between runs +- **Future reporting** — trend tracking, exception registry, dashboards + +## Decision + +### v1.0 fingerprint schema + +``` +provider:callType:flagKey:normalizedFilePath +``` + +| Component | Example | Notes | +|---|---|---| +| `provider` | `launchdarkly` | hardcoded in v1.0; extensible post-v1 | +| `callType` | `boolVariation` | the SDK method name | +| `flagKey` | `checkout-v2` | the literal string key | +| `normalizedFilePath` | `src/checkout/service.ts` | relative to scan root, forward slashes, no leading `./` | + +**Example fingerprints:** +``` +launchdarkly:boolVariation:checkout-v2:src/checkout/service.ts +launchdarkly:stringVariation:payment-provider:src/payments/processor.ts +``` + +### File path normalization + +- Path is relative to the scan root directory +- All backslashes replaced with forward slashes (Windows compatibility) +- No leading `./` +- No trailing slash + +### Dynamic key handling + +For dynamic keys (`isDynamic: true` or `flagKey === "*"`), include a +sequential index within the file to differentiate multiple dynamic calls: + +``` +launchdarkly:boolVariation:*:src/service.ts:0 +launchdarkly:boolVariation:*:src/service.ts:1 +``` + +This is imperfect — index order may shift if dynamic calls reorder — but it +is better than omitting fingerprints for dynamic calls entirely. + +### Known collision + +If the same `flagKey` is called with the same `callType` more than once in +the same file, the fingerprints collide and both findings share the same +fingerprint. + +**Why not add `containingSymbol` in v1.0?** Finding the enclosing +function/class requires additional AST traversal. Same-file collisions are +rare in practice. Deferring to v1.1 where the fifth component can be added +additively without breaking existing baselines. + +### File rename / move behavior + +When a file is renamed or moved, the fingerprints for all its findings change +because the `normalizedFilePath` component changes. Those findings will +appear as new debt in baseline comparisons. This is documented behavior — +users should re-run `--write-baseline` after significant refactors. + +## Implementation + +- Add `fingerprint: string` to `FlagUsage` in `src/types.ts` (additive) +- Create `src/scanner/fingerprint.ts` with a `generateFingerprint()` helper +- Call in scanner after each `FlagUsage` is built +- Include in all JSON output +- SARIF consumers use fingerprint as result identity (see ADR 008) +- Baseline artifacts store fingerprint arrays (see ADR 008) + +## Consequences + +- `FlagUsage` gains a `fingerprint: string` field — additive, no breaking change +- Fingerprints survive line-number changes +- Baseline mode is unblocked (see ADR 008) +- **Known limitation:** same-file collision for identical `callType` + `flagKey`; + to be addressed in v1.1 by adding `containingSymbol` as a fifth component +- **Known limitation:** file renames change fingerprints; re-run + `--write-baseline` after significant refactors