@mitre/hdf-diff 3.1.0-rc.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -104,7 +104,7 @@ hdf diff --mode baseline golden.json current.json
104
104
  The diff engine is also available as a Go module:
105
105
 
106
106
  ```go
107
- import diff "github.com/mitre/hdf-libs/hdf-diff/go"
107
+ import diff "github.com/mitre/hdf-libs/hdf-diff/go/v3"
108
108
  ```
109
109
 
110
110
  See the [hdf-diff/go](https://github.com/mitre/hdf-libs/tree/main/hdf-diff/go) directory for the Go API.
package/dist/index.d.ts CHANGED
@@ -377,6 +377,8 @@ interface MatchPair {
377
377
  strategy: string;
378
378
  /** Confidence score for the match (0.0 - 1.0) */
379
379
  confidence: number;
380
+ /** Relationship type for delta matching: 'primary' (code source) or 'related' (informational) */
381
+ relationship?: 'primary' | 'related';
380
382
  }
381
383
  /**
382
384
  * A pluggable strategy for matching requirements between evaluations.
@@ -450,6 +452,58 @@ declare function jaccardSimilarity(a: Set<string>, b: Set<string>): number;
450
452
  */
451
453
  declare function createFuzzyTitleStrategy(minConfidence?: number): MatchStrategy;
452
454
  //#endregion
455
+ //#region src/matching/srg-deterministic.d.ts
456
+ /**
457
+ * Create a deterministic SRG matching strategy (Tier 1 of the delta pipeline).
458
+ *
459
+ * Matches requirements by exact `tags.gtitle` (SRG-OS requirement ID).
460
+ *
461
+ * For each gtitle shared between old and new:
462
+ * - 1 old + 1 new → single MatchPair (confidence 1.0, relationship "primary")
463
+ * - 1 new + N old → N MatchPairs (first old "primary", rest "related")
464
+ * - N new + 1 old → N MatchPairs (first new "primary", rest "related")
465
+ * - N:M (both > 1) → skip, leave for fallback strategies
466
+ *
467
+ * Requirements without a gtitle pass through as unmatched.
468
+ */
469
+ declare function createSrgDeterministicStrategy(): MatchStrategy;
470
+ //#endregion
471
+ //#region src/matching/srg-cci-tiebreak.d.ts
472
+ /**
473
+ * Create an SRG CCI Tiebreak matching strategy (Tier 2 of the delta pipeline).
474
+ *
475
+ * Handles ambiguous SRG matches where multiple old or new requirements share
476
+ * the same tags.gtitle. Uses a composite score of CCI Jaccard (70%) and
477
+ * token Jaccard on titles (30%) to pick the best match.
478
+ *
479
+ * Only activates for gtitle groups with multiple candidates (>1 old or >1 new).
480
+ * 1:1 matches are left for srgDeterministic (Tier 1).
481
+ */
482
+ declare function createSrgCciTiebreakStrategy(): MatchStrategy;
483
+ //#endregion
484
+ //#region src/matching/vendor-fuzzy-title.d.ts
485
+ /**
486
+ * Compute the Levenshtein edit distance between two strings.
487
+ */
488
+ declare function levenshteinDistance(a: string, b: string): number;
489
+ /**
490
+ * Normalized Levenshtein distance (0.0 = identical, 1.0 = completely different).
491
+ */
492
+ declare function normalizedLevenshtein(a: string, b: string): number;
493
+ /**
494
+ * Create a vendor fuzzy title matching strategy (Tier 3 of the delta pipeline).
495
+ *
496
+ * Cross-vendor matching with auto-detected vendor prefix stripping.
497
+ * Uses normalized Levenshtein distance to compare titles after removing
498
+ * the dominant vendor prefix (e.g., "RHEL 9" or "Amazon Linux 2023").
499
+ *
500
+ * Accepts matches below threshold 0.45 (confidence = 1.0 - distance).
501
+ * Greedy best-match.
502
+ *
503
+ * @param acceptThreshold Max normalized Levenshtein distance to accept (default: 0.45)
504
+ */
505
+ declare function createVendorFuzzyTitleStrategy(acceptThreshold?: number): MatchStrategy;
506
+ //#endregion
453
507
  //#region src/matching/index.d.ts
454
508
  /**
455
509
  * Options for configuring requirement matching.
@@ -619,5 +673,5 @@ declare function renderCsv(comparison: HdfComparison, options?: RenderOptions):
619
673
  */
620
674
  declare function render(comparison: HdfComparison, format: 'json' | 'markdown' | 'terminal' | 'csv', options?: RenderOptions): string;
621
675
  //#endregion
622
- export { type Annotation, type BaselineDiff, type ChangeReason, type ComparisonSummary, type ComponentDiff, type DetailLevel, type DiffOptions, type DiffStatus, type DiffSummary, EXIT_DETAILED_BASELINE_CHANGED, EXIT_DETAILED_DRIFT_ONLY, EXIT_DETAILED_ERROR, EXIT_DETAILED_FIXES_ONLY, EXIT_DETAILED_IDENTICAL, EXIT_DETAILED_MIXED, EXIT_DETAILED_REGRESSIONS_ONLY, EXIT_DIFFERENCES, EXIT_ERROR, EXIT_IDENTICAL, type FieldChange, type HdfComparison, type HdfDiff, type MatchOptions, type MatchPair, type MatchResult, type MatchStrategy, type MatchingConfig, type PackageDiff, type RenderOptions, type RequirementDiff, type RequirementState, type SbomDiffResult, type Source, type ValidationResult, classifyChangeReasons, classifyDiffStatus, computeDetailedExitCode, computeEffectiveStatus, computeExitCode, computeSummary, createCciMatchStrategy, createExactIdStrategy, createFuzzyTitleStrategy, createMappedIdStrategy, diffBaselines, diffHdf, diffSboms, diffSystems, isV1Format, jaccardSimilarity, matchRequirements, normalizeToV2, render, renderCsv, renderJson, renderMarkdown, renderTerminal, tokenize, validateComparison };
676
+ export { type Annotation, type BaselineDiff, type ChangeReason, type ComparisonSummary, type ComponentDiff, type DetailLevel, type DiffOptions, type DiffStatus, type DiffSummary, EXIT_DETAILED_BASELINE_CHANGED, EXIT_DETAILED_DRIFT_ONLY, EXIT_DETAILED_ERROR, EXIT_DETAILED_FIXES_ONLY, EXIT_DETAILED_IDENTICAL, EXIT_DETAILED_MIXED, EXIT_DETAILED_REGRESSIONS_ONLY, EXIT_DIFFERENCES, EXIT_ERROR, EXIT_IDENTICAL, type FieldChange, type HdfComparison, type HdfDiff, type MatchOptions, type MatchPair, type MatchResult, type MatchStrategy, type MatchingConfig, type PackageDiff, type RenderOptions, type RequirementDiff, type RequirementState, type SbomDiffResult, type Source, type ValidationResult, classifyChangeReasons, classifyDiffStatus, computeDetailedExitCode, computeEffectiveStatus, computeExitCode, computeSummary, createCciMatchStrategy, createExactIdStrategy, createFuzzyTitleStrategy, createMappedIdStrategy, createSrgCciTiebreakStrategy, createSrgDeterministicStrategy, createVendorFuzzyTitleStrategy, diffBaselines, diffHdf, diffSboms, diffSystems, isV1Format, jaccardSimilarity, levenshteinDistance, matchRequirements, normalizeToV2, normalizedLevenshtein, render, renderCsv, renderJson, renderMarkdown, renderTerminal, tokenize, validateComparison };
623
677
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/sbom.ts","../src/types.ts","../src/diff.ts","../src/status.ts","../src/summary.ts","../src/normalize.ts","../src/matching/types.ts","../src/matching/exact-id.ts","../src/matching/mapped-id.ts","../src/matching/cci-match.ts","../src/matching/fuzzy-match.ts","../src/matching/index.ts","../src/validate.ts","../src/exit-codes.ts","../src/renderers/types.ts","../src/renderers/json.ts","../src/renderers/markdown.ts","../src/renderers/terminal.ts","../src/renderers/csv.ts","../src/renderers/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/sbom.ts","../src/types.ts","../src/diff.ts","../src/status.ts","../src/summary.ts","../src/normalize.ts","../src/matching/types.ts","../src/matching/exact-id.ts","../src/matching/mapped-id.ts","../src/matching/cci-match.ts","../src/matching/fuzzy-match.ts","../src/matching/srg-deterministic.ts","../src/matching/srg-cci-tiebreak.ts","../src/matching/vendor-fuzzy-title.ts","../src/matching/index.ts","../src/validate.ts","../src/exit-codes.ts","../src/renderers/types.ts","../src/renderers/json.ts","../src/renderers/markdown.ts","../src/renderers/terminal.ts","../src/renderers/csv.ts","../src/renderers/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -398,7 +398,7 @@ function createMappedIdStrategy(mapping) {
398
398
  * Extract CCI identifiers from a requirement's tags.
399
399
  * Looks for `tags.cci` as an array of strings.
400
400
  */
401
- function extractCcis(req) {
401
+ function extractCcis$1(req) {
402
402
  const tags = req["tags"];
403
403
  if (!tags) return [];
404
404
  const cci = tags["cci"];
@@ -426,13 +426,13 @@ function createCciMatchStrategy() {
426
426
  unmatchedNew: []
427
427
  };
428
428
  const oldCciMap = /* @__PURE__ */ new Map();
429
- for (let i = 0; i < oldReqs.length; i++) for (const cci of extractCcis(oldReqs[i])) {
429
+ for (let i = 0; i < oldReqs.length; i++) for (const cci of extractCcis$1(oldReqs[i])) {
430
430
  const list = oldCciMap.get(cci);
431
431
  if (list) list.push(i);
432
432
  else oldCciMap.set(cci, [i]);
433
433
  }
434
434
  const newCciMap = /* @__PURE__ */ new Map();
435
- for (let i = 0; i < newReqs.length; i++) for (const cci of extractCcis(newReqs[i])) {
435
+ for (let i = 0; i < newReqs.length; i++) for (const cci of extractCcis$1(newReqs[i])) {
436
436
  const list = newCciMap.get(cci);
437
437
  if (list) list.push(i);
438
438
  else newCciMap.set(cci, [i]);
@@ -648,6 +648,410 @@ function createFuzzyTitleStrategy(minConfidence) {
648
648
  };
649
649
  }
650
650
  //#endregion
651
+ //#region src/matching/srg-deterministic.ts
652
+ /**
653
+ * Extract the SRG-OS ID from a requirement's tags.gtitle field.
654
+ * Returns null if missing or not a string.
655
+ */
656
+ function extractGtitle$1(req) {
657
+ const tags = req["tags"];
658
+ if (!tags) return null;
659
+ const gtitle = tags["gtitle"];
660
+ if (typeof gtitle !== "string" || gtitle === "") return null;
661
+ return gtitle;
662
+ }
663
+ /**
664
+ * Create a deterministic SRG matching strategy (Tier 1 of the delta pipeline).
665
+ *
666
+ * Matches requirements by exact `tags.gtitle` (SRG-OS requirement ID).
667
+ *
668
+ * For each gtitle shared between old and new:
669
+ * - 1 old + 1 new → single MatchPair (confidence 1.0, relationship "primary")
670
+ * - 1 new + N old → N MatchPairs (first old "primary", rest "related")
671
+ * - N new + 1 old → N MatchPairs (first new "primary", rest "related")
672
+ * - N:M (both > 1) → skip, leave for fallback strategies
673
+ *
674
+ * Requirements without a gtitle pass through as unmatched.
675
+ */
676
+ function createSrgDeterministicStrategy() {
677
+ return {
678
+ name: "srgDeterministic",
679
+ match(oldReqs, newReqs) {
680
+ const oldGtitleMap = /* @__PURE__ */ new Map();
681
+ for (let i = 0; i < oldReqs.length; i++) {
682
+ const g = extractGtitle$1(oldReqs[i]);
683
+ if (g) {
684
+ const list = oldGtitleMap.get(g);
685
+ if (list) list.push(i);
686
+ else oldGtitleMap.set(g, [i]);
687
+ }
688
+ }
689
+ const newGtitleMap = /* @__PURE__ */ new Map();
690
+ for (let i = 0; i < newReqs.length; i++) {
691
+ const g = extractGtitle$1(newReqs[i]);
692
+ if (g) {
693
+ const list = newGtitleMap.get(g);
694
+ if (list) list.push(i);
695
+ else newGtitleMap.set(g, [i]);
696
+ }
697
+ }
698
+ const matched = [];
699
+ const matchedOldIndices = /* @__PURE__ */ new Set();
700
+ const matchedNewIndices = /* @__PURE__ */ new Set();
701
+ const claimedOldIndices = /* @__PURE__ */ new Set();
702
+ for (const [gtitle, newIdxList] of newGtitleMap) {
703
+ const oldIdxList = oldGtitleMap.get(gtitle);
704
+ if (!oldIdxList || oldIdxList.length === 0) continue;
705
+ const nc = newIdxList.length;
706
+ const oc = oldIdxList.length;
707
+ if (nc > 1 && oc > 1) continue;
708
+ for (const ni of newIdxList) {
709
+ let primaryOldSet = false;
710
+ for (const oi of oldIdxList) {
711
+ let relationship;
712
+ if (oc === 1) {
713
+ relationship = claimedOldIndices.has(oi) ? "related" : "primary";
714
+ if (relationship === "primary") claimedOldIndices.add(oi);
715
+ } else {
716
+ relationship = primaryOldSet ? "related" : "primary";
717
+ primaryOldSet = true;
718
+ }
719
+ matched.push({
720
+ oldReq: oldReqs[oi],
721
+ newReq: newReqs[ni],
722
+ strategy: "srgDeterministic",
723
+ confidence: 1,
724
+ relationship
725
+ });
726
+ matchedOldIndices.add(oi);
727
+ }
728
+ matchedNewIndices.add(ni);
729
+ }
730
+ }
731
+ const unmatchedOld = [];
732
+ for (let i = 0; i < oldReqs.length; i++) if (!matchedOldIndices.has(i)) unmatchedOld.push(oldReqs[i]);
733
+ const unmatchedNew = [];
734
+ for (let i = 0; i < newReqs.length; i++) if (!matchedNewIndices.has(i)) unmatchedNew.push(newReqs[i]);
735
+ return {
736
+ matched,
737
+ unmatchedOld,
738
+ unmatchedNew
739
+ };
740
+ }
741
+ };
742
+ }
743
+ //#endregion
744
+ //#region src/matching/srg-cci-tiebreak.ts
745
+ /** Composite score weights matching SAF CLI's Tier 2. */
746
+ const CCI_WEIGHT = .7;
747
+ const TITLE_WEIGHT = .3;
748
+ /**
749
+ * Extract CCI identifiers from a requirement's tags.cci.
750
+ */
751
+ function extractCcis(req) {
752
+ const tags = req["tags"];
753
+ if (!tags) return /* @__PURE__ */ new Set();
754
+ const cci = tags["cci"];
755
+ if (!Array.isArray(cci)) return /* @__PURE__ */ new Set();
756
+ return new Set(cci.filter((c) => typeof c === "string"));
757
+ }
758
+ /**
759
+ * Extract tags.gtitle from a requirement.
760
+ */
761
+ function extractGtitle(req) {
762
+ const tags = req["tags"];
763
+ if (!tags) return null;
764
+ const gtitle = tags["gtitle"];
765
+ if (typeof gtitle !== "string" || gtitle === "") return null;
766
+ return gtitle;
767
+ }
768
+ /**
769
+ * Extract title from a requirement.
770
+ */
771
+ function safeTitle$1(req) {
772
+ const title = req["title"];
773
+ return typeof title === "string" ? title : "";
774
+ }
775
+ /**
776
+ * Jaccard similarity between two sets.
777
+ */
778
+ function cciJaccard(a, b) {
779
+ if (a.size === 0 && b.size === 0) return 0;
780
+ let intersectionSize = 0;
781
+ for (const x of a) if (b.has(x)) intersectionSize++;
782
+ const unionSize = a.size + b.size - intersectionSize;
783
+ return intersectionSize / unionSize;
784
+ }
785
+ /**
786
+ * Simple whitespace-split token Jaccard similarity.
787
+ */
788
+ function tokenJaccard(a, b) {
789
+ const ta = new Set(a.toLowerCase().split(/\s+/).filter((t) => t.length > 0));
790
+ const tb = new Set(b.toLowerCase().split(/\s+/).filter((t) => t.length > 0));
791
+ if (ta.size === 0 || tb.size === 0) return 0;
792
+ let intersectionSize = 0;
793
+ for (const x of ta) if (tb.has(x)) intersectionSize++;
794
+ const unionSize = ta.size + tb.size - intersectionSize;
795
+ return intersectionSize / unionSize;
796
+ }
797
+ /**
798
+ * Create an SRG CCI Tiebreak matching strategy (Tier 2 of the delta pipeline).
799
+ *
800
+ * Handles ambiguous SRG matches where multiple old or new requirements share
801
+ * the same tags.gtitle. Uses a composite score of CCI Jaccard (70%) and
802
+ * token Jaccard on titles (30%) to pick the best match.
803
+ *
804
+ * Only activates for gtitle groups with multiple candidates (>1 old or >1 new).
805
+ * 1:1 matches are left for srgDeterministic (Tier 1).
806
+ */
807
+ function createSrgCciTiebreakStrategy() {
808
+ return {
809
+ name: "srgCciTiebreak",
810
+ match(oldReqs, newReqs) {
811
+ const oldGtitleMap = /* @__PURE__ */ new Map();
812
+ for (let i = 0; i < oldReqs.length; i++) {
813
+ const g = extractGtitle(oldReqs[i]);
814
+ if (g) {
815
+ const list = oldGtitleMap.get(g);
816
+ if (list) list.push(i);
817
+ else oldGtitleMap.set(g, [i]);
818
+ }
819
+ }
820
+ const newGtitleMap = /* @__PURE__ */ new Map();
821
+ for (let i = 0; i < newReqs.length; i++) {
822
+ const g = extractGtitle(newReqs[i]);
823
+ if (g) {
824
+ const list = newGtitleMap.get(g);
825
+ if (list) list.push(i);
826
+ else newGtitleMap.set(g, [i]);
827
+ }
828
+ }
829
+ const matched = [];
830
+ const matchedOldIndices = /* @__PURE__ */ new Set();
831
+ const matchedNewIndices = /* @__PURE__ */ new Set();
832
+ for (const [gtitle, newIdxList] of newGtitleMap) {
833
+ const oldIdxList = oldGtitleMap.get(gtitle);
834
+ if (!oldIdxList || oldIdxList.length === 0) continue;
835
+ const nc = newIdxList.length;
836
+ const oc = oldIdxList.length;
837
+ if (nc === 1 && oc === 1) continue;
838
+ for (const ni of newIdxList) {
839
+ if (matchedNewIndices.has(ni)) continue;
840
+ const newCcis = extractCcis(newReqs[ni]);
841
+ const newTitle = safeTitle$1(newReqs[ni]);
842
+ let bestIdx = -1;
843
+ let bestComposite = -1;
844
+ let bestCci = 0;
845
+ let bestIsUnclaimed = false;
846
+ for (const oi of oldIdxList) {
847
+ const oldCcis = extractCcis(oldReqs[oi]);
848
+ const oldTitle = safeTitle$1(oldReqs[oi]);
849
+ const cci = cciJaccard(newCcis, oldCcis);
850
+ const title = tokenJaccard(newTitle, oldTitle);
851
+ const composite = CCI_WEIGHT * cci + TITLE_WEIGHT * title;
852
+ const isUnclaimed = !matchedOldIndices.has(oi);
853
+ if (bestIdx === -1 || isUnclaimed && !bestIsUnclaimed || isUnclaimed === bestIsUnclaimed && composite > bestComposite) {
854
+ bestIdx = oi;
855
+ bestComposite = composite;
856
+ bestCci = cci;
857
+ bestIsUnclaimed = isUnclaimed;
858
+ }
859
+ }
860
+ if (bestIdx >= 0) {
861
+ const relationship = matchedOldIndices.has(bestIdx) ? "related" : "primary";
862
+ matched.push({
863
+ oldReq: oldReqs[bestIdx],
864
+ newReq: newReqs[ni],
865
+ strategy: "srgCciTiebreak",
866
+ confidence: Math.max(bestCci, 0),
867
+ relationship
868
+ });
869
+ matchedOldIndices.add(bestIdx);
870
+ matchedNewIndices.add(ni);
871
+ }
872
+ }
873
+ }
874
+ const unmatchedOld = [];
875
+ for (let i = 0; i < oldReqs.length; i++) if (!matchedOldIndices.has(i)) unmatchedOld.push(oldReqs[i]);
876
+ const unmatchedNew = [];
877
+ for (let i = 0; i < newReqs.length; i++) if (!matchedNewIndices.has(i)) unmatchedNew.push(newReqs[i]);
878
+ return {
879
+ matched,
880
+ unmatchedOld,
881
+ unmatchedNew
882
+ };
883
+ }
884
+ };
885
+ }
886
+ //#endregion
887
+ //#region src/matching/vendor-fuzzy-title.ts
888
+ /** Default threshold for accepting a Levenshtein match. */
889
+ const DEFAULT_ACCEPT_THRESHOLD = .45;
890
+ /** Modal verbs that mark the start of compliance statements. */
891
+ const COMPLIANCE_MODALS = new Set([
892
+ "must",
893
+ "will",
894
+ "shall",
895
+ "should",
896
+ "may",
897
+ "needs"
898
+ ]);
899
+ /**
900
+ * Compute the Levenshtein edit distance between two strings.
901
+ */
902
+ function levenshteinDistance(a, b) {
903
+ const m = a.length;
904
+ const n = b.length;
905
+ if (m === 0) return n;
906
+ if (n === 0) return m;
907
+ let prev = new Array(n + 1);
908
+ let curr = new Array(n + 1);
909
+ for (let j = 0; j <= n; j++) prev[j] = j;
910
+ for (let i = 1; i <= m; i++) {
911
+ curr[0] = i;
912
+ for (let j = 1; j <= n; j++) {
913
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
914
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
915
+ }
916
+ [prev, curr] = [curr, prev];
917
+ }
918
+ return prev[n];
919
+ }
920
+ /**
921
+ * Normalized Levenshtein distance (0.0 = identical, 1.0 = completely different).
922
+ */
923
+ function normalizedLevenshtein(a, b) {
924
+ const maxLen = Math.max(a.length, b.length);
925
+ if (maxLen === 0) return 0;
926
+ return levenshteinDistance(a, b) / maxLen;
927
+ }
928
+ /**
929
+ * Extract tokens before the first modal verb in a title.
930
+ */
931
+ function tokensBeforeModal(title) {
932
+ const tokens = title.split(/\s+/).filter((t) => t.length > 0);
933
+ const modalIdx = tokens.findIndex((t) => COMPLIANCE_MODALS.has(t.toLowerCase()));
934
+ return modalIdx === -1 ? tokens : tokens.slice(0, modalIdx);
935
+ }
936
+ /**
937
+ * Auto-detect the dominant vendor prefix in a corpus of titles.
938
+ *
939
+ * Tries progressively shorter leading-token prefixes. Returns the prefix
940
+ * that appears in > 50% of titles, stopping before modal verbs.
941
+ * Returns '' when no prefix reaches the threshold.
942
+ */
943
+ function autoDetectPrefix(titles, threshold = .5) {
944
+ if (titles.length === 0) return "";
945
+ const leading = titles.map((t) => tokensBeforeModal(t));
946
+ const maxLen = Math.max(...leading.map((l) => l.length));
947
+ for (let n = maxLen; n > 0; n--) {
948
+ const counts = /* @__PURE__ */ new Map();
949
+ for (const l of leading) if (l.length >= n) {
950
+ const key = l.slice(0, n).join(" ");
951
+ counts.set(key, (counts.get(key) ?? 0) + 1);
952
+ }
953
+ let bestKey = "";
954
+ let bestCount = 0;
955
+ for (const [key, count] of counts) if (count > bestCount) {
956
+ bestKey = key;
957
+ bestCount = count;
958
+ }
959
+ if (bestCount / titles.length > threshold) return bestKey;
960
+ }
961
+ return "";
962
+ }
963
+ /**
964
+ * Strip a detected vendor prefix from a title.
965
+ */
966
+ function normalizeTitle(title, prefix) {
967
+ if (!prefix) return title;
968
+ if (title === prefix) return "";
969
+ if (title.startsWith(prefix + " ")) return title.slice(prefix.length + 1);
970
+ return title;
971
+ }
972
+ /**
973
+ * Extract title string from a requirement.
974
+ */
975
+ function safeTitle(req) {
976
+ const title = req["title"];
977
+ return typeof title === "string" ? title : "";
978
+ }
979
+ /**
980
+ * Create a vendor fuzzy title matching strategy (Tier 3 of the delta pipeline).
981
+ *
982
+ * Cross-vendor matching with auto-detected vendor prefix stripping.
983
+ * Uses normalized Levenshtein distance to compare titles after removing
984
+ * the dominant vendor prefix (e.g., "RHEL 9" or "Amazon Linux 2023").
985
+ *
986
+ * Accepts matches below threshold 0.45 (confidence = 1.0 - distance).
987
+ * Greedy best-match.
988
+ *
989
+ * @param acceptThreshold Max normalized Levenshtein distance to accept (default: 0.45)
990
+ */
991
+ function createVendorFuzzyTitleStrategy(acceptThreshold) {
992
+ const threshold = acceptThreshold ?? DEFAULT_ACCEPT_THRESHOLD;
993
+ return {
994
+ name: "vendorFuzzyTitle",
995
+ match(oldReqs, newReqs) {
996
+ const oldTitles = oldReqs.map(safeTitle).filter((t) => t.length > 0);
997
+ const newTitles = newReqs.map(safeTitle).filter((t) => t.length > 0);
998
+ const oldPrefix = autoDetectPrefix(oldTitles);
999
+ const newPrefix = autoDetectPrefix(newTitles);
1000
+ const oldNorm = [];
1001
+ for (let i = 0; i < oldReqs.length; i++) {
1002
+ const t = safeTitle(oldReqs[i]);
1003
+ if (t) oldNorm.push({
1004
+ idx: i,
1005
+ normalized: normalizeTitle(t, oldPrefix)
1006
+ });
1007
+ }
1008
+ const newNorm = [];
1009
+ for (let i = 0; i < newReqs.length; i++) {
1010
+ const t = safeTitle(newReqs[i]);
1011
+ if (t) newNorm.push({
1012
+ idx: i,
1013
+ normalized: normalizeTitle(t, newPrefix)
1014
+ });
1015
+ }
1016
+ const candidates = [];
1017
+ for (const old of oldNorm) for (const nw of newNorm) {
1018
+ if (!old.normalized || !nw.normalized) continue;
1019
+ const dist = normalizedLevenshtein(old.normalized, nw.normalized);
1020
+ if (dist < threshold) candidates.push({
1021
+ oldIdx: old.idx,
1022
+ newIdx: nw.idx,
1023
+ distance: dist
1024
+ });
1025
+ }
1026
+ candidates.sort((a, b) => a.distance - b.distance);
1027
+ const matched = [];
1028
+ const matchedOldIndices = /* @__PURE__ */ new Set();
1029
+ const matchedNewIndices = /* @__PURE__ */ new Set();
1030
+ for (const c of candidates) {
1031
+ if (matchedOldIndices.has(c.oldIdx) || matchedNewIndices.has(c.newIdx)) continue;
1032
+ matched.push({
1033
+ oldReq: oldReqs[c.oldIdx],
1034
+ newReq: newReqs[c.newIdx],
1035
+ strategy: "vendorFuzzyTitle",
1036
+ confidence: 1 - c.distance,
1037
+ relationship: "primary"
1038
+ });
1039
+ matchedOldIndices.add(c.oldIdx);
1040
+ matchedNewIndices.add(c.newIdx);
1041
+ }
1042
+ const unmatchedOld = [];
1043
+ for (let i = 0; i < oldReqs.length; i++) if (!matchedOldIndices.has(i)) unmatchedOld.push(oldReqs[i]);
1044
+ const unmatchedNew = [];
1045
+ for (let i = 0; i < newReqs.length; i++) if (!matchedNewIndices.has(i)) unmatchedNew.push(newReqs[i]);
1046
+ return {
1047
+ matched,
1048
+ unmatchedOld,
1049
+ unmatchedNew
1050
+ };
1051
+ }
1052
+ };
1053
+ }
1054
+ //#endregion
651
1055
  //#region src/matching/index.ts
652
1056
  /**
653
1057
  * Create a strategy instance by name, using the provided options for
@@ -659,6 +1063,9 @@ function createStrategy(name, options) {
659
1063
  case "mappedId": return createMappedIdStrategy(options.mappingTable ?? {});
660
1064
  case "cciMatch": return createCciMatchStrategy();
661
1065
  case "fuzzyTitle": return createFuzzyTitleStrategy(options.minConfidence);
1066
+ case "srgDeterministic": return createSrgDeterministicStrategy();
1067
+ case "srgCciTiebreak": return createSrgCciTiebreakStrategy();
1068
+ case "vendorFuzzyTitle": return createVendorFuzzyTitleStrategy(options.minConfidence !== void 0 && options.minConfidence > 0 ? 1 - options.minConfidence : void 0);
662
1069
  default: throw new Error(`Unknown matching strategy: '${name}'`);
663
1070
  }
664
1071
  }
@@ -2033,6 +2440,6 @@ function render(comparison, format, options) {
2033
2440
  }
2034
2441
  }
2035
2442
  //#endregion
2036
- export { EXIT_DETAILED_BASELINE_CHANGED, EXIT_DETAILED_DRIFT_ONLY, EXIT_DETAILED_ERROR, EXIT_DETAILED_FIXES_ONLY, EXIT_DETAILED_IDENTICAL, EXIT_DETAILED_MIXED, EXIT_DETAILED_REGRESSIONS_ONLY, EXIT_DIFFERENCES, EXIT_ERROR, EXIT_IDENTICAL, classifyChangeReasons, classifyDiffStatus, computeDetailedExitCode, computeEffectiveStatus, computeExitCode, computeSummary, createCciMatchStrategy, createExactIdStrategy, createFuzzyTitleStrategy, createMappedIdStrategy, diffBaselines, diffHdf, diffSboms, diffSystems, isV1Format, jaccardSimilarity, matchRequirements, normalizeToV2, render, renderCsv, renderJson, renderMarkdown, renderTerminal, tokenize, validateComparison };
2443
+ export { EXIT_DETAILED_BASELINE_CHANGED, EXIT_DETAILED_DRIFT_ONLY, EXIT_DETAILED_ERROR, EXIT_DETAILED_FIXES_ONLY, EXIT_DETAILED_IDENTICAL, EXIT_DETAILED_MIXED, EXIT_DETAILED_REGRESSIONS_ONLY, EXIT_DIFFERENCES, EXIT_ERROR, EXIT_IDENTICAL, classifyChangeReasons, classifyDiffStatus, computeDetailedExitCode, computeEffectiveStatus, computeExitCode, computeSummary, createCciMatchStrategy, createExactIdStrategy, createFuzzyTitleStrategy, createMappedIdStrategy, createSrgCciTiebreakStrategy, createSrgDeterministicStrategy, createVendorFuzzyTitleStrategy, diffBaselines, diffHdf, diffSboms, diffSystems, isV1Format, jaccardSimilarity, levenshteinDistance, matchRequirements, normalizeToV2, normalizedLevenshtein, render, renderCsv, renderJson, renderMarkdown, renderTerminal, tokenize, validateComparison };
2037
2444
 
2038
2445
  //# sourceMappingURL=index.js.map