@usefragments/core 1.5.1 → 1.6.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.
Files changed (45) hide show
  1. package/dist/{chunk-AOG4FTV6.js → chunk-WVFNDPM4.js} +448 -190
  2. package/dist/chunk-WVFNDPM4.js.map +1 -0
  3. package/dist/codes/index.d.ts +1 -1
  4. package/dist/codes/index.js +1 -1
  5. package/dist/compiled-types/index.d.ts +1 -1
  6. package/dist/generate/index.d.ts +1 -1
  7. package/dist/{governance-B88uR3Zq.d.ts → governance-DxFipN5V.d.ts} +654 -22
  8. package/dist/index.d.ts +678 -40
  9. package/dist/index.js +534 -38
  10. package/dist/index.js.map +1 -1
  11. package/dist/react-types.d.ts +1 -1
  12. package/dist/test-utils.d.ts +1 -1
  13. package/package.json +1 -1
  14. package/src/__tests__/policy-exclude.test.ts +180 -0
  15. package/src/canonical-bridge.ts +69 -1
  16. package/src/canonical-direction.test.ts +118 -0
  17. package/src/canonical-direction.ts +43 -2
  18. package/src/codes/__tests__/codes.test.ts +14 -1
  19. package/src/codes/codes.ts +60 -0
  20. package/src/config.ts +20 -0
  21. package/src/facts/builders.ts +35 -0
  22. package/src/facts/compile.ts +135 -21
  23. package/src/facts/fact-index.ts +22 -2
  24. package/src/facts/facts.test.ts +19 -19
  25. package/src/facts/index.ts +9 -6
  26. package/src/facts/types.ts +45 -9
  27. package/src/governance-integrity.test.ts +277 -1
  28. package/src/governance-integrity.ts +616 -0
  29. package/src/governance.test.ts +20 -1
  30. package/src/governance.ts +131 -0
  31. package/src/index.ts +45 -2
  32. package/src/policy-exclude.ts +113 -0
  33. package/src/rules/families.test.ts +69 -0
  34. package/src/rules/families.ts +52 -0
  35. package/src/rules/index.ts +6 -0
  36. package/src/rules/jsx-preferred-import-path.ts +29 -11
  37. package/src/rules/rules.test.ts +125 -1
  38. package/src/rules/styles-no-raw-color.ts +13 -4
  39. package/src/rules/styles-no-raw-dimensions.ts +13 -4
  40. package/src/rules/styles-no-raw-spacing.test.ts +48 -0
  41. package/src/rules/styles-no-raw-spacing.ts +15 -7
  42. package/src/rules/styles-no-raw-typography.ts +13 -4
  43. package/src/rules/utils.ts +39 -0
  44. package/src/types.ts +21 -3
  45. package/dist/chunk-AOG4FTV6.js.map +0 -1
package/dist/index.js CHANGED
@@ -44,6 +44,8 @@ import {
44
44
  CODES,
45
45
  EXPLAIN_URL_BASE,
46
46
  FactIndex,
47
+ RULE_FAMILY_IDS,
48
+ RULE_FAMILY_MEMBERS,
47
49
  asComponentId,
48
50
  bridgeSourceViolation,
49
51
  bridgeSourceViolations,
@@ -56,6 +58,8 @@ import {
56
58
  componentGovernanceRecordSchema,
57
59
  componentGovernanceRecordsSchema,
58
60
  componentId,
61
+ describePolicyExclude,
62
+ excludeGlobToRegExp,
59
63
  explainUrlForCode,
60
64
  factId,
61
65
  g,
@@ -65,6 +69,8 @@ import {
65
69
  governanceConfigSchema,
66
70
  governanceSeveritySchema,
67
71
  hash64Hex,
72
+ isPresetSourcedRule,
73
+ isRuleFamilyId,
68
74
  makeA11yNameRequiredFact,
69
75
  makeCanonicalCandidateFact,
70
76
  makeCanonicalMappingFact,
@@ -105,14 +111,22 @@ import {
105
111
  makeUsageNodeFact,
106
112
  makeUsagePropResolvedFact,
107
113
  makeUsageTextChildFact,
114
+ markPresetSourcedRules,
115
+ matchPolicyExclude,
108
116
  matchesGlob,
117
+ normalizeExcludePath,
109
118
  normalizeGovernanceConfig,
119
+ normalizePolicyExcludes,
110
120
  ownedComponentIdsEqual,
111
121
  ownedImportMatchesRoot,
112
122
  ownedImportsEqual,
123
+ policyExcludeMatchesPath,
124
+ policyExcludeSchema,
125
+ projectSupersededImportPathPreferences,
113
126
  resolveComponentGovernance,
127
+ ruleFamilyMembers,
114
128
  scaleGovernanceRecordSchema
115
- } from "./chunk-AOG4FTV6.js";
129
+ } from "./chunk-WVFNDPM4.js";
116
130
  import {
117
131
  AGENT_FORMAT_SCHEMA_VERSION,
118
132
  agentErrorEnvelopeSchema,
@@ -1841,9 +1855,14 @@ var governedFragmentDefinitionSchema = z4.object({
1841
1855
  var recipeDefinitionSchema = blockDefinitionSchema;
1842
1856
 
1843
1857
  // src/config.ts
1858
+ var RAW_CONFIG_DECLARATION = /* @__PURE__ */ Symbol.for("@usefragments/core/raw-config-declaration");
1844
1859
  function formatZodErrors(errors) {
1845
1860
  return errors.map((error) => ` - ${error.path.join(".")}: ${error.message}`).join("\n");
1846
1861
  }
1862
+ function configDeclarationForDiagnostics(config) {
1863
+ if (!config || typeof config !== "object") return config;
1864
+ return config[RAW_CONFIG_DECLARATION] ?? config;
1865
+ }
1847
1866
  function defineConfig(config) {
1848
1867
  const normalized = normalizeGovernanceConfig(config);
1849
1868
  const result = fragmentsConfigSchema.safeParse(normalized);
@@ -1851,6 +1870,12 @@ function defineConfig(config) {
1851
1870
  throw new Error(`Invalid fragments config:
1852
1871
  ${formatZodErrors(result.error.errors)}`);
1853
1872
  }
1873
+ Object.defineProperty(result.data, RAW_CONFIG_DECLARATION, {
1874
+ value: normalized,
1875
+ enumerable: false,
1876
+ configurable: false,
1877
+ writable: false
1878
+ });
1854
1879
  return result.data;
1855
1880
  }
1856
1881
 
@@ -4485,6 +4510,19 @@ function readUsageNode(ix, id) {
4485
4510
  const fact = ix.get(id);
4486
4511
  return fact && fact.kind === "usage_node" ? fact : void 0;
4487
4512
  }
4513
+ function hoppedValue(fact) {
4514
+ const from = fact.valueFrom;
4515
+ if (!from) return void 0;
4516
+ const declaredAt = `${from.location.file}:${from.location.line}`;
4517
+ return {
4518
+ suffix: ` Value comes from \`${from.name}\`, declared at ${declaredAt}.`,
4519
+ attributes: {
4520
+ valueFrom: "const-binding",
4521
+ declaredAs: from.name,
4522
+ declaredAt
4523
+ }
4524
+ };
4525
+ }
4488
4526
  function contractPrefixFamilies(names) {
4489
4527
  const families = /* @__PURE__ */ new Set();
4490
4528
  for (const name of names) {
@@ -4966,7 +5004,7 @@ function projectCanonicalDirectionConflicts(ix, canonicalSources) {
4966
5004
  const conflicts = [];
4967
5005
  for (const definition of ix.byKind("component_definition")) {
4968
5006
  if (!definition.exported || definition.renderRoot.resolution !== "canonical") continue;
4969
- const target = npmTarget(definition.renderRoot.canonical, npmSources);
5007
+ const target = npmTarget(definition.renderRoot, npmSources);
4970
5008
  if (!target) continue;
4971
5009
  const identity = identityByComponent.get(definition.componentKey);
4972
5010
  if (identity?.decisionId && decisionTargetsExport(identity.canonicalTarget, target.exportName)) {
@@ -5000,7 +5038,10 @@ function canonicalDirectionConflictsTarget(conflicts, importPath, exportName) {
5000
5038
  (conflict) => ownedImportMatchesRoot(importPath, conflict.packageName) && conflict.exportName === exportName
5001
5039
  );
5002
5040
  }
5003
- function npmTarget(canonicalTarget, sources) {
5041
+ function npmTarget(renderRoot, sources) {
5042
+ return npmTargetFromCanonicalKey(renderRoot.canonical, sources) ?? npmTargetFromImportSource(renderRoot, sources);
5043
+ }
5044
+ function npmTargetFromCanonicalKey(canonicalTarget, sources) {
5004
5045
  const separator = canonicalTarget.lastIndexOf("#");
5005
5046
  if (separator <= 0 || separator === canonicalTarget.length - 1) return null;
5006
5047
  const importPath = canonicalTarget.slice(0, separator);
@@ -5017,6 +5058,19 @@ function npmTarget(canonicalTarget, sources) {
5017
5058
  }
5018
5059
  return null;
5019
5060
  }
5061
+ function npmTargetFromImportSource(renderRoot, sources) {
5062
+ const separator = renderRoot.canonical.lastIndexOf("#");
5063
+ if (separator <= 0 || separator === renderRoot.canonical.length - 1) return null;
5064
+ const exportName = renderRoot.canonical.slice(separator + 1).split(".").at(-1);
5065
+ if (!exportName || exportName === "default") return null;
5066
+ for (const source of sources) {
5067
+ if (!ownedImportMatchesRoot(renderRoot.importSource, source.specifier)) continue;
5068
+ if (source.exclude?.includes(exportName)) continue;
5069
+ if (source.include && !source.include.includes(exportName)) continue;
5070
+ return { packageName: source.specifier, exportName };
5071
+ }
5072
+ return null;
5073
+ }
5020
5074
  function packageSubpath(importPath, packageName) {
5021
5075
  return importPath === packageName ? "" : importPath.slice(packageName.length + 1);
5022
5076
  }
@@ -6217,19 +6271,15 @@ function ruleJsxPreferredImportPath(ix) {
6217
6271
  const findings = [];
6218
6272
  const seen = /* @__PURE__ */ new Set();
6219
6273
  for (const usage of ix.byKind("usage_import")) {
6274
+ const bridgeGoverned = policies.some((policy) => bridgeGovernsUnderlyingImport(policy, usage));
6220
6275
  const matches = policies.filter((policy) => {
6221
6276
  if (policy.bridge) {
6222
6277
  if (policy.bridge.implementationFiles.some((file) => sameRepoPath(file, usage.file))) {
6223
6278
  return false;
6224
6279
  }
6225
- if (!ownedImportMatchesRoot(usage.source, policy.from)) return false;
6226
- if (ownedImportsEqual(usage.source, policy.from)) {
6227
- return usage.imported === policy.bridge.underlyingExportName;
6228
- }
6229
- const subpath = usage.source.slice(policy.from.length + 1);
6230
- const leaf = subpath.split("/").at(-1);
6231
- return leaf === policy.bridge.underlyingExportName && (usage.imported === "default" || usage.imported === policy.bridge.underlyingExportName);
6280
+ return bridgeGovernsUnderlyingImport(policy, usage);
6232
6281
  }
6282
+ if (bridgeGoverned) return false;
6233
6283
  if (!ownedImportsEqual(policy.from, usage.source)) return false;
6234
6284
  if (policy.imported !== void 0 && policy.imported !== usage.imported) return false;
6235
6285
  return true;
@@ -6283,6 +6333,17 @@ function ruleJsxPreferredImportPath(ix) {
6283
6333
  }
6284
6334
  return findings;
6285
6335
  }
6336
+ function bridgeGovernsUnderlyingImport(policy, usage) {
6337
+ const bridge = policy.bridge;
6338
+ if (!bridge) return false;
6339
+ if (!ownedImportMatchesRoot(usage.source, policy.from)) return false;
6340
+ if (ownedImportsEqual(usage.source, policy.from)) {
6341
+ return usage.imported === bridge.underlyingExportName;
6342
+ }
6343
+ const subpath = usage.source.slice(policy.from.length + 1);
6344
+ const leaf = subpath.split("/").at(-1);
6345
+ return leaf === bridge.underlyingExportName && (usage.imported === "default" || usage.imported === bridge.underlyingExportName);
6346
+ }
6286
6347
  function sameRepoPath(left, right) {
6287
6348
  return normalizeRepoPath(left) === normalizeRepoPath(right);
6288
6349
  }
@@ -6538,14 +6599,15 @@ function ruleStylesNoRawColor(ix) {
6538
6599
  if (!color) continue;
6539
6600
  if (isExemptColor(color, policy.except)) continue;
6540
6601
  const resolution = resolveColorToken(decl.property, color, colorTokens);
6541
- const fixEmission = resolution?.kind === "exact" ? buildTokenFix(decl.property, decl.value, color, resolution, ix) : void 0;
6602
+ const hopped = hoppedValue(decl);
6603
+ const fixEmission = resolution?.kind === "exact" && !hopped ? buildTokenFix(decl.property, decl.value, color, resolution, ix) : void 0;
6542
6604
  const evidenceIds = resolution ? [decl.id, policy.id, resolution.token.id] : [decl.id, policy.id];
6543
6605
  findings.push(
6544
6606
  makeFinding({
6545
6607
  ruleId: RULE_ID9,
6546
6608
  ruleVersion: RULE_VERSION10,
6547
6609
  severity: policy.severity,
6548
- message: colorMessage(color, `\`${decl.property}\``, resolution, preferLabel),
6610
+ message: colorMessage(color, `\`${decl.property}\``, resolution, preferLabel) + (hopped?.suffix ?? ""),
6549
6611
  location: decl.location,
6550
6612
  evidence: ix.evidence(evidenceIds),
6551
6613
  fingerprintIdentity: {
@@ -6564,7 +6626,8 @@ function ruleStylesNoRawColor(ix) {
6564
6626
  source: "css",
6565
6627
  suggestedToken: resolution?.token.name,
6566
6628
  ...resolution ? { tokenMatch: resolution.kind } : {},
6567
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
6629
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
6630
+ ...hopped?.attributes ?? {}
6568
6631
  }
6569
6632
  })
6570
6633
  );
@@ -6610,7 +6673,8 @@ function ruleStylesNoRawColor(ix) {
6610
6673
  if (!node) continue;
6611
6674
  const componentEvidenceId = componentByNode.get(node.id)?.id;
6612
6675
  const resolution = resolveColorToken(inline.property, color, colorTokens);
6613
- const fixEmission = resolution?.kind === "exact" ? buildTokenFix(inline.property, inline.value, color, resolution, ix) : void 0;
6676
+ const hopped = hoppedValue(inline);
6677
+ const fixEmission = resolution?.kind === "exact" && !hopped ? buildTokenFix(inline.property, inline.value, color, resolution, ix) : void 0;
6614
6678
  const baseEvidence = componentEvidenceId ? [node.id, componentEvidenceId, inline.id, policy.id] : [node.id, inline.id, policy.id];
6615
6679
  const evidenceIds = resolution ? [...baseEvidence, resolution.token.id] : baseEvidence;
6616
6680
  findings.push(
@@ -6618,7 +6682,7 @@ function ruleStylesNoRawColor(ix) {
6618
6682
  ruleId: RULE_ID9,
6619
6683
  ruleVersion: RULE_VERSION10,
6620
6684
  severity: policy.severity,
6621
- message: colorMessage(color, `inline \`${inline.property}\``, resolution, preferLabel),
6685
+ message: colorMessage(color, `inline \`${inline.property}\``, resolution, preferLabel) + (hopped?.suffix ?? ""),
6622
6686
  location: node.location,
6623
6687
  evidence: ix.evidence(evidenceIds),
6624
6688
  fingerprintIdentity: {
@@ -6637,7 +6701,8 @@ function ruleStylesNoRawColor(ix) {
6637
6701
  source: "jsx",
6638
6702
  suggestedToken: resolution?.token.name,
6639
6703
  ...resolution ? { tokenMatch: resolution.kind } : {},
6640
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
6704
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
6705
+ ...hopped?.attributes ?? {}
6641
6706
  }
6642
6707
  })
6643
6708
  );
@@ -6829,13 +6894,14 @@ function ruleStylesNoRawDimensions(ix) {
6829
6894
  if (!resolution) continue;
6830
6895
  const tokenIds = resolutionTokenIds(resolution);
6831
6896
  const evidenceIds = tokenIds.length ? [decl.id, policy.id, ...tokenIds] : [decl.id, policy.id];
6832
- const fixEmission = dimensionFix(decl.property, resolution, ix);
6897
+ const hopped = hoppedValue(decl);
6898
+ const fixEmission = hopped ? void 0 : dimensionFix(decl.property, resolution, ix);
6833
6899
  findings.push(
6834
6900
  makeFinding({
6835
6901
  ruleId: RULE_ID10,
6836
6902
  ruleVersion: RULE_VERSION11,
6837
6903
  severity: policy.severity,
6838
- message: dimensionMessage(decl.value, decl.property, preferLabel, resolution, false),
6904
+ message: dimensionMessage(decl.value, decl.property, preferLabel, resolution, false) + (hopped?.suffix ?? ""),
6839
6905
  location: decl.location,
6840
6906
  evidence: ix.evidence(evidenceIds),
6841
6907
  fingerprintIdentity: {
@@ -6852,7 +6918,8 @@ function ruleStylesNoRawDimensions(ix) {
6852
6918
  rawValue: decl.value,
6853
6919
  source: "css",
6854
6920
  suggestedToken: resolutionSuggestedToken(resolution),
6855
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
6921
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
6922
+ ...hopped?.attributes ?? {}
6856
6923
  }
6857
6924
  })
6858
6925
  );
@@ -6871,13 +6938,14 @@ function ruleStylesNoRawDimensions(ix) {
6871
6938
  const baseEvidence = componentEvidenceId ? [node.id, componentEvidenceId, inline.id, policy.id] : [node.id, inline.id, policy.id];
6872
6939
  const tokenIds = resolutionTokenIds(resolution);
6873
6940
  const evidenceIds = tokenIds.length ? [...baseEvidence, ...tokenIds] : baseEvidence;
6874
- const fixEmission = dimensionFix(inline.property, resolution, ix);
6941
+ const hopped = hoppedValue(inline);
6942
+ const fixEmission = hopped ? void 0 : dimensionFix(inline.property, resolution, ix);
6875
6943
  findings.push(
6876
6944
  makeFinding({
6877
6945
  ruleId: RULE_ID10,
6878
6946
  ruleVersion: RULE_VERSION11,
6879
6947
  severity: policy.severity,
6880
- message: dimensionMessage(inline.value, inline.property, preferLabel, resolution, true),
6948
+ message: dimensionMessage(inline.value, inline.property, preferLabel, resolution, true) + (hopped?.suffix ?? ""),
6881
6949
  location: node.location,
6882
6950
  evidence: ix.evidence(evidenceIds),
6883
6951
  fingerprintIdentity: {
@@ -6894,7 +6962,8 @@ function ruleStylesNoRawDimensions(ix) {
6894
6962
  rawValue: inline.value,
6895
6963
  source: "jsx",
6896
6964
  suggestedToken: resolutionSuggestedToken(resolution),
6897
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
6965
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
6966
+ ...hopped?.attributes ?? {}
6898
6967
  }
6899
6968
  })
6900
6969
  );
@@ -7184,12 +7253,13 @@ function checkDeclaration(ix, decl, lookupFor) {
7184
7253
  tokens: lookupFor(scale)
7185
7254
  });
7186
7255
  if (!checked) return null;
7187
- const fixEmission = buildSpacingFix(decl.property, checked, ix);
7256
+ const hopped = hoppedValue(decl);
7257
+ const fixEmission = hopped ? void 0 : buildSpacingFix(decl.property, checked, ix);
7188
7258
  return makeFinding({
7189
7259
  ruleId: RULE_ID11,
7190
7260
  ruleVersion: RULE_VERSION12,
7191
7261
  severity: policy.severity,
7192
- message: spacingMessage(decl.property, decl.value, allowed, scale.unit, checked),
7262
+ message: spacingMessage(decl.property, decl.value, allowed, scale, checked) + (hopped?.suffix ?? ""),
7193
7263
  location: decl.location,
7194
7264
  evidence: ix.evidence([decl.id, policy.id, scale.id]),
7195
7265
  fingerprintIdentity: {
@@ -7215,7 +7285,8 @@ function checkDeclaration(ix, decl, lookupFor) {
7215
7285
  assumedRootFontSizePx: checked.assumedRootFontSizePx,
7216
7286
  assumedEmBasePx: checked.assumedEmBasePx,
7217
7287
  source: "css",
7218
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
7288
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
7289
+ ...hopped?.attributes ?? {}
7219
7290
  }
7220
7291
  });
7221
7292
  }
@@ -7235,7 +7306,8 @@ function checkInlineStyle(ix, inline, componentByNode, lookupFor) {
7235
7306
  bareNumberFix: inline.valueKind === "number"
7236
7307
  });
7237
7308
  if (!checked) return null;
7238
- const fixEmission = buildSpacingFix(inline.property, checked, ix);
7309
+ const hopped = hoppedValue(inline);
7310
+ const fixEmission = hopped ? void 0 : buildSpacingFix(inline.property, checked, ix);
7239
7311
  const node = readUsageNode(ix, inline.nodeId);
7240
7312
  if (!node) return null;
7241
7313
  const componentEvidenceId = componentByNode.get(node.id)?.id;
@@ -7244,7 +7316,7 @@ function checkInlineStyle(ix, inline, componentByNode, lookupFor) {
7244
7316
  ruleId: RULE_ID11,
7245
7317
  ruleVersion: RULE_VERSION12,
7246
7318
  severity: policy.severity,
7247
- message: spacingMessage(inline.property, inline.value, allowed, scale.unit, checked),
7319
+ message: spacingMessage(inline.property, inline.value, allowed, scale, checked) + (hopped?.suffix ?? ""),
7248
7320
  location: node.location,
7249
7321
  evidence: ix.evidence(evidenceIds),
7250
7322
  fingerprintIdentity: {
@@ -7270,7 +7342,8 @@ function checkInlineStyle(ix, inline, componentByNode, lookupFor) {
7270
7342
  assumedRootFontSizePx: checked.assumedRootFontSizePx,
7271
7343
  assumedEmBasePx: checked.assumedEmBasePx,
7272
7344
  source: "jsx",
7273
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
7345
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
7346
+ ...hopped?.attributes ?? {}
7274
7347
  }
7275
7348
  });
7276
7349
  }
@@ -7292,14 +7365,14 @@ function buildSpacingFix(property, checked, ix) {
7292
7365
  ix
7293
7366
  );
7294
7367
  }
7295
- function spacingMessage(property, value, allowed, unit, checked) {
7368
+ function spacingMessage(property, value, allowed, scale, checked) {
7296
7369
  if (checked.reason === "token-equivalent" && checked.matchedToken) {
7297
7370
  return `\`${property}: ${value}\` is a raw literal that matches token \`${checked.matchedToken}\`. Reference the token instead.`;
7298
7371
  }
7299
7372
  const sample = allowed.slice().sort((a, b) => a - b).slice(0, 6);
7300
- const suffix = `${sample.join(unit + ", ")}${unit}`;
7373
+ const suffix = `${sample.join(scale.unit + ", ")}${scale.unit}`;
7301
7374
  const ellipsis = allowed.length > sample.length ? ", \u2026" : "";
7302
- return `\`${property}: ${value}\` is not on the spacing scale. Allowed: ${suffix}${ellipsis}.`;
7375
+ return `\`${property}: ${value}\` is not on the \`${scale.name}\` scale. Allowed: ${suffix}${ellipsis}. Configure \`govern.scales.${scale.name}\` to change it.`;
7303
7376
  }
7304
7377
 
7305
7378
  // src/rules/styles-no-raw-typography.ts
@@ -7319,13 +7392,14 @@ function ruleStylesNoRawTypography(ix) {
7319
7392
  if (decl.property.toLowerCase() !== "font-size") continue;
7320
7393
  const checked = checkFontSize(decl.value, allowed, scale, tokens);
7321
7394
  if (!checked) continue;
7322
- const fixEmission = buildFix(decl.property, checked, ix);
7395
+ const hopped = hoppedValue(decl);
7396
+ const fixEmission = hopped ? void 0 : buildFix(decl.property, checked, ix);
7323
7397
  findings.push(
7324
7398
  makeFinding({
7325
7399
  ruleId: RULE_ID12,
7326
7400
  ruleVersion: RULE_VERSION13,
7327
7401
  severity: policy.severity,
7328
- message: typographyMessage(decl.property, decl.value, allowed, scale.unit, checked),
7402
+ message: typographyMessage(decl.property, decl.value, allowed, scale.unit, checked) + (hopped?.suffix ?? ""),
7329
7403
  location: decl.location,
7330
7404
  evidence: ix.evidence([decl.id, policy.id, scale.id]),
7331
7405
  fingerprintIdentity: {
@@ -7345,7 +7419,8 @@ function ruleStylesNoRawTypography(ix) {
7345
7419
  suggestedValue: checked.suggestedValue,
7346
7420
  matchedToken: checked.matchedToken,
7347
7421
  source: "css",
7348
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
7422
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
7423
+ ...hopped?.attributes ?? {}
7349
7424
  }
7350
7425
  })
7351
7426
  );
@@ -7362,7 +7437,8 @@ function ruleStylesNoRawTypography(ix) {
7362
7437
  inline.valueKind === "number"
7363
7438
  );
7364
7439
  if (!checked) continue;
7365
- const fixEmission = buildFix(inline.property, checked, ix);
7440
+ const hopped = hoppedValue(inline);
7441
+ const fixEmission = hopped ? void 0 : buildFix(inline.property, checked, ix);
7366
7442
  const node = readUsageNode(ix, inline.nodeId);
7367
7443
  if (!node) continue;
7368
7444
  const componentEvidenceId = componentByNode.get(node.id)?.id;
@@ -7372,7 +7448,7 @@ function ruleStylesNoRawTypography(ix) {
7372
7448
  ruleId: RULE_ID12,
7373
7449
  ruleVersion: RULE_VERSION13,
7374
7450
  severity: policy.severity,
7375
- message: typographyMessage(inline.property, inline.value, allowed, scale.unit, checked),
7451
+ message: typographyMessage(inline.property, inline.value, allowed, scale.unit, checked) + (hopped?.suffix ?? ""),
7376
7452
  location: node.location,
7377
7453
  evidence: ix.evidence(evidenceIds),
7378
7454
  fingerprintIdentity: {
@@ -7392,7 +7468,8 @@ function ruleStylesNoRawTypography(ix) {
7392
7468
  suggestedValue: checked.suggestedValue,
7393
7469
  matchedToken: checked.matchedToken,
7394
7470
  source: "jsx",
7395
- ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {}
7471
+ ...fixEmission?.downgradeReason ? { downgradeReason: fixEmission.downgradeReason } : {},
7472
+ ...hopped?.attributes ?? {}
7396
7473
  }
7397
7474
  })
7398
7475
  );
@@ -8612,6 +8689,374 @@ function policyDeclaresCssVars(policy) {
8612
8689
  function dedupe(values) {
8613
8690
  return [...new Set(values)];
8614
8691
  }
8692
+ var CONSUMED_RULE_IDS = new Set(Object.keys(RULE_TIER));
8693
+ var RECOGNIZED_RULE_IDS = /* @__PURE__ */ new Set([...CONSUMED_RULE_IDS, ...RULE_FAMILY_IDS]);
8694
+ var RULE_CONFIG_KEYS = /* @__PURE__ */ new Set(["enabled", "severity", "options", "exclude"]);
8695
+ var PASSTHROUGH_KEYS = [
8696
+ {
8697
+ path: ["tokens"],
8698
+ keys: [
8699
+ "include",
8700
+ "sources",
8701
+ "packages",
8702
+ "aliases",
8703
+ "upstream",
8704
+ "exclude",
8705
+ "themeSelectors",
8706
+ "enabled",
8707
+ "format",
8708
+ "namespace"
8709
+ ]
8710
+ },
8711
+ {
8712
+ path: ["screenshots"],
8713
+ keys: ["viewport", "threshold", "delay", "outputDir", "themes"]
8714
+ },
8715
+ {
8716
+ path: ["service"],
8717
+ keys: ["poolSize", "idleTimeout"]
8718
+ },
8719
+ {
8720
+ path: ["registry"],
8721
+ keys: ["requireStory", "publicOnly", "categoryDepth", "includeProps", "embedFragments"]
8722
+ },
8723
+ {
8724
+ path: ["govern", "tailwind"],
8725
+ keys: ["palette"]
8726
+ },
8727
+ {
8728
+ path: ["govern", "agent"],
8729
+ keys: ["repairOrder"]
8730
+ },
8731
+ {
8732
+ path: ["govern", "ci"],
8733
+ keys: ["failOnWarnings", "failOnInert"]
8734
+ }
8735
+ ];
8736
+ function objectRecord(value) {
8737
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
8738
+ return value;
8739
+ }
8740
+ function valueAtPath(value, path) {
8741
+ let current = value;
8742
+ for (const segment of path) {
8743
+ const record = objectRecord(current);
8744
+ if (!record) return void 0;
8745
+ current = record[segment];
8746
+ }
8747
+ return current;
8748
+ }
8749
+ function configPath(path) {
8750
+ return path.reduce(
8751
+ (output, segment) => typeof segment === "number" ? `${output}[${segment}]` : output ? `${output}.${segment}` : segment,
8752
+ ""
8753
+ );
8754
+ }
8755
+ function unconsumedKeyDiagnostic(path) {
8756
+ const renderedPath = configPath(path);
8757
+ return {
8758
+ code: "FUI9004",
8759
+ kind: "unconsumed-key",
8760
+ severity: "warn",
8761
+ path: renderedPath,
8762
+ message: `${renderedPath} is not consumed by Fragments and has no effect. Remove it or use a supported config key.`
8763
+ };
8764
+ }
8765
+ var CONFIG_RECORD_FACT_KINDS = {
8766
+ scale: { section: "govern.scales", record: "scale", keys: ["name"] },
8767
+ scale_value: { section: "govern.scales", record: "scale.values", keys: ["scale", "value"] },
8768
+ style_raw_color_forbidden: {
8769
+ section: "govern.styles",
8770
+ record: "style.rawColors.forbid",
8771
+ keys: []
8772
+ },
8773
+ style_raw_dimension_forbidden: {
8774
+ section: "govern.styles",
8775
+ record: "style.rawDimensions.forbid",
8776
+ keys: []
8777
+ },
8778
+ style_property_scale: {
8779
+ section: "govern.styles",
8780
+ record: "style.rawSpacing.mustMatchScale",
8781
+ keys: ["property"]
8782
+ },
8783
+ style_font_size_scale: {
8784
+ section: "govern.styles",
8785
+ record: "style.fontSize.mustMatchScale",
8786
+ keys: []
8787
+ },
8788
+ style_css_vars_must_be_defined: {
8789
+ section: "govern.styles",
8790
+ record: "style.cssVars.mustBeDefined",
8791
+ keys: []
8792
+ },
8793
+ jsx_unknown_props_forbidden: {
8794
+ section: "govern.jsx",
8795
+ record: "jsx.unknownProps.forbid",
8796
+ keys: []
8797
+ },
8798
+ jsx_inline_style_forbidden_raw: {
8799
+ section: "govern.jsx",
8800
+ record: "jsx.inlineStyle.forbidRaw",
8801
+ keys: ["property"]
8802
+ },
8803
+ jsx_import_path_preferred: {
8804
+ section: "govern.jsx",
8805
+ record: "jsx.importPath.prefer",
8806
+ keys: ["from", "to", "imported"]
8807
+ },
8808
+ jsx_component_preferred: {
8809
+ section: "govern.jsx",
8810
+ record: "jsx.component.prefer",
8811
+ keys: ["from", "to"]
8812
+ },
8813
+ prop_value_avoided: {
8814
+ section: "govern.components",
8815
+ record: "prop.value.avoid",
8816
+ keys: ["componentId", "prop", "value"]
8817
+ },
8818
+ prop_value_forbidden: {
8819
+ section: "govern.components",
8820
+ record: "prop.value.forbid",
8821
+ keys: ["componentId", "prop", "value", "pathPattern"]
8822
+ },
8823
+ a11y_name_required: {
8824
+ section: "govern.components",
8825
+ record: "a11y.requireName",
8826
+ keys: ["componentId"]
8827
+ },
8828
+ tailwind_palette_allow: {
8829
+ section: "govern.tailwind",
8830
+ record: "palette.allow",
8831
+ keys: []
8832
+ },
8833
+ tailwind_palette_deny: { section: "govern.tailwind", record: "palette.deny", keys: [] },
8834
+ tailwind_unknown_class_enabled: {
8835
+ section: "govern.tailwind",
8836
+ record: "unknownClass",
8837
+ keys: []
8838
+ },
8839
+ governance_rule_config: { section: "govern.rules", record: "rule", keys: ["ruleId"] }
8840
+ };
8841
+ var COLLISION_DETAIL_KEYS = [
8842
+ "severity",
8843
+ "scale",
8844
+ "prefer",
8845
+ "enabled",
8846
+ "appliesTo",
8847
+ "except",
8848
+ "properties",
8849
+ "because"
8850
+ ];
8851
+ function renderFactFields(fact, keys) {
8852
+ return keys.filter((key) => fact[key] !== void 0).map((key) => `${key}=${Array.isArray(fact[key]) ? JSON.stringify(fact[key]) : fact[key]}`).join(" ");
8853
+ }
8854
+ function collidingRecordDiagnostic(conflict) {
8855
+ return collidingRecordDiagnostics([conflict])[0] ?? null;
8856
+ }
8857
+ function collidingRecordDiagnostics(conflicts) {
8858
+ const groups = /* @__PURE__ */ new Map();
8859
+ for (const conflict of conflicts) {
8860
+ const shape = CONFIG_RECORD_FACT_KINDS[conflict.kept.kind];
8861
+ if (!shape || conflict.kept.kind !== conflict.skipped.kind) continue;
8862
+ const keptFact = conflict.kept;
8863
+ const skippedFact = conflict.skipped;
8864
+ const identity = renderFactFields(keptFact, shape.keys);
8865
+ const path = `${shape.section}[${identity ? `${shape.record} ${identity}` : shape.record}]`;
8866
+ const group = groups.get(path) ?? {
8867
+ record: shape.record,
8868
+ kept: renderFactFields(keptFact, COLLISION_DETAIL_KEYS),
8869
+ dropped: [],
8870
+ keptFallback: "the first record"
8871
+ };
8872
+ const dropped = renderFactFields(skippedFact, COLLISION_DETAIL_KEYS);
8873
+ group.dropped.push(dropped || `record ${group.dropped.length + 2}`);
8874
+ groups.set(path, group);
8875
+ }
8876
+ return [...groups].map(([path, group]) => ({
8877
+ code: "FUI9007",
8878
+ kind: "colliding-record",
8879
+ severity: "warn",
8880
+ path,
8881
+ message: `${path} has ${group.dropped.length + 1} \`${group.record}\` records that compile to the same policy fact \u2014 enforcing ${group.kept || group.keptFallback} and dropping ${group.dropped.join("; ")}. Author one record for this policy, or scope them apart, so the enforced setting is the one you can read.`
8882
+ }));
8883
+ }
8884
+ function configRecordShape(kind) {
8885
+ const shape = CONFIG_RECORD_FACT_KINDS[kind];
8886
+ return shape ? { section: shape.section, record: shape.record } : null;
8887
+ }
8888
+ function overriddenRecordSeverityDiagnostic(input) {
8889
+ const path = `${input.section}[${input.record}]`;
8890
+ return {
8891
+ code: "FUI9008",
8892
+ kind: "overridden-record-severity",
8893
+ severity: "warn",
8894
+ path,
8895
+ message: `${path} authored severity=${input.authored}, but ${input.source} enforces severity=${input.enforced} on \`${input.ruleId}\`. The record's severity is not what gates CI \u2014 drop the rule override, or author the record at the severity you want enforced.`
8896
+ };
8897
+ }
8898
+ function collectStrippedKeys(authored, parsed, path, diagnostics) {
8899
+ if (Array.isArray(authored)) {
8900
+ if (!Array.isArray(parsed)) return;
8901
+ authored.forEach((item, index) => {
8902
+ collectStrippedKeys(item, parsed[index], [...path, index], diagnostics);
8903
+ });
8904
+ return;
8905
+ }
8906
+ const authoredRecord = objectRecord(authored);
8907
+ const parsedRecord = objectRecord(parsed);
8908
+ if (!authoredRecord || !parsedRecord) return;
8909
+ for (const key of Object.keys(authoredRecord).sort()) {
8910
+ if (!Object.prototype.hasOwnProperty.call(parsedRecord, key)) {
8911
+ diagnostics.push(unconsumedKeyDiagnostic([...path, key]));
8912
+ continue;
8913
+ }
8914
+ collectStrippedKeys(authoredRecord[key], parsedRecord[key], [...path, key], diagnostics);
8915
+ }
8916
+ }
8917
+ function collectPassthroughKeys(authored, path, allowed, diagnostics) {
8918
+ const record = objectRecord(valueAtPath(authored, path));
8919
+ if (!record) return;
8920
+ for (const key of Object.keys(record).sort()) {
8921
+ if (!allowed.has(key)) diagnostics.push(unconsumedKeyDiagnostic([...path, key]));
8922
+ }
8923
+ }
8924
+ function collectRuleConfigKeys(authored, path, diagnostics) {
8925
+ const rules = objectRecord(valueAtPath(authored, path));
8926
+ if (!rules) return;
8927
+ for (const ruleId of Object.keys(rules).sort()) {
8928
+ if (!RECOGNIZED_RULE_IDS.has(ruleId)) {
8929
+ diagnostics.push(unconsumedKeyDiagnostic([...path, ruleId]));
8930
+ continue;
8931
+ }
8932
+ const config = objectRecord(rules[ruleId]);
8933
+ if (!config) continue;
8934
+ for (const key of Object.keys(config).sort()) {
8935
+ if (!RULE_CONFIG_KEYS.has(key)) {
8936
+ diagnostics.push(unconsumedKeyDiagnostic([...path, ruleId, key]));
8937
+ }
8938
+ }
8939
+ }
8940
+ }
8941
+ function collectPassthroughRecordValues(authored, path, allowed, diagnostics) {
8942
+ const entries = objectRecord(valueAtPath(authored, path));
8943
+ if (!entries) return;
8944
+ for (const [entryName, value] of Object.entries(entries).sort(
8945
+ ([left], [right]) => left.localeCompare(right)
8946
+ )) {
8947
+ const record = objectRecord(value);
8948
+ if (!record) continue;
8949
+ for (const key of Object.keys(record).sort()) {
8950
+ if (!allowed.has(key)) {
8951
+ diagnostics.push(unconsumedKeyDiagnostic([...path, entryName, key]));
8952
+ }
8953
+ }
8954
+ }
8955
+ }
8956
+ function stableConfigDiagnostics(diagnostics) {
8957
+ const unique = /* @__PURE__ */ new Map();
8958
+ for (const diagnostic of diagnostics) {
8959
+ unique.set(`${diagnostic.code}\0${diagnostic.path}`, diagnostic);
8960
+ }
8961
+ return [...unique.values()].sort(
8962
+ (left, right) => left.path.localeCompare(right.path) || left.code.localeCompare(right.code) || left.message.localeCompare(right.message)
8963
+ );
8964
+ }
8965
+ function detectUnconsumedConfigKeys(authoredConfig, parsedConfig) {
8966
+ const diagnostics = [];
8967
+ collectStrippedKeys(authoredConfig, parsedConfig, [], diagnostics);
8968
+ for (const boundary of PASSTHROUGH_KEYS) {
8969
+ collectPassthroughKeys(
8970
+ authoredConfig,
8971
+ boundary.path,
8972
+ new Set(boundary.keys),
8973
+ diagnostics
8974
+ );
8975
+ }
8976
+ collectRuleConfigKeys(authoredConfig, ["govern", "rules"], diagnostics);
8977
+ collectPassthroughRecordValues(
8978
+ authoredConfig,
8979
+ ["govern", "agents"],
8980
+ /* @__PURE__ */ new Set(["rules"]),
8981
+ diagnostics
8982
+ );
8983
+ collectPassthroughKeys(authoredConfig, ["govern", "audit"], /* @__PURE__ */ new Set(), diagnostics);
8984
+ collectPassthroughRecordValues(authoredConfig, ["govern", "runners"], /* @__PURE__ */ new Set(), diagnostics);
8985
+ return stableConfigDiagnostics(diagnostics);
8986
+ }
8987
+ function authoredPolicyExcludes(policy) {
8988
+ const out = [];
8989
+ const collect = (path, scope, raw) => {
8990
+ for (const exclude of normalizePolicyExcludes(raw) ?? []) {
8991
+ out.push({ path, scope, exclude });
8992
+ }
8993
+ };
8994
+ (policy?.styles ?? []).forEach((record, index) => {
8995
+ collect(`govern.styles[${index}].exclude`, record.kind, record.exclude);
8996
+ });
8997
+ (policy?.jsx ?? []).forEach((record, index) => {
8998
+ collect(`govern.jsx[${index}].exclude`, record.kind, record.exclude);
8999
+ });
9000
+ for (const ruleId of Object.keys(policy?.rules ?? {}).sort()) {
9001
+ const record = objectRecord(policy?.rules?.[ruleId]);
9002
+ if (!record) continue;
9003
+ collect(`govern.rules.${ruleId}.exclude`, ruleId, record.exclude);
9004
+ }
9005
+ return out;
9006
+ }
9007
+ function detectUnmatchedPolicyExcludes(policy, scannedFiles) {
9008
+ if (scannedFiles.length === 0) return [];
9009
+ const diagnostics = [];
9010
+ for (const { path, scope, exclude } of authoredPolicyExcludes(policy)) {
9011
+ if (scannedFiles.some((file) => policyExcludeMatchesPath(exclude, file))) continue;
9012
+ diagnostics.push({
9013
+ code: "FUI9006",
9014
+ kind: "unmatched-exclude",
9015
+ severity: "warn",
9016
+ path,
9017
+ message: `${path} pattern "${exclude.glob}" matched no scanned file, so ${scope} is not actually scoped by it. Correct the glob to a path this scan covers, or remove it.`
9018
+ });
9019
+ }
9020
+ return stableConfigDiagnostics(diagnostics);
9021
+ }
9022
+ function effectiveScaleBindings(policy) {
9023
+ const bindings = [];
9024
+ for (const style of policy?.styles ?? []) {
9025
+ if (style.kind === "style.rawSpacing.mustMatchScale") {
9026
+ bindings.push({
9027
+ label: "Spacing properties",
9028
+ mechanism: "style.rawSpacing.mustMatchScale",
9029
+ scale: style.scale
9030
+ });
9031
+ } else if (style.kind === "style.fontSize.mustMatchScale") {
9032
+ bindings.push({
9033
+ label: "Font-size properties",
9034
+ mechanism: "style.fontSize.mustMatchScale",
9035
+ scale: style.scale
9036
+ });
9037
+ }
9038
+ }
9039
+ return bindings;
9040
+ }
9041
+ function detectOrphanGovernanceScales(declaredPolicy, effectivePolicy) {
9042
+ const bindings = effectiveScaleBindings(effectivePolicy);
9043
+ const referenced = new Set(bindings.map((binding) => binding.scale));
9044
+ const diagnostics = [];
9045
+ for (const scale of Object.keys(declaredPolicy?.scales ?? {}).sort()) {
9046
+ if (referenced.has(scale)) continue;
9047
+ const path = `govern.scales.${scale}`;
9048
+ const preferred = (scale.toLowerCase().includes("spac") ? bindings.find((binding) => binding.mechanism === "style.rawSpacing.mustMatchScale") : void 0) ?? (scale.toLowerCase().includes("font") ? bindings.find((binding) => binding.mechanism === "style.fontSize.mustMatchScale") : void 0) ?? bindings[0];
9049
+ const remediation = preferred ? `${preferred.label} are bound to the scale named "${preferred.scale}" \u2014 rename the key to "${preferred.scale}" or bind it via ${preferred.mechanism}.` : `Bind it via style.rawSpacing.mustMatchScale or style.fontSize.mustMatchScale, or remove it.`;
9050
+ diagnostics.push({
9051
+ code: "FUI9005",
9052
+ kind: "orphan-scale",
9053
+ severity: "warn",
9054
+ path,
9055
+ message: `${path} is not referenced by any property policy. ${remediation}`
9056
+ });
9057
+ }
9058
+ return stableConfigDiagnostics(diagnostics);
9059
+ }
8615
9060
  function summarize(status, flags) {
8616
9061
  if (status === "inert") {
8617
9062
  return "Governance inert \u2014 no enforceable rule family is armed";
@@ -8627,6 +9072,7 @@ function summarize(status, flags) {
8627
9072
  }
8628
9073
  function evaluateGovernanceIntegrity(input) {
8629
9074
  const configs = effectiveRuleConfigs(input.policy);
9075
+ const configDiagnostics = stableConfigDiagnostics(input.configDiagnostics ?? []);
8630
9076
  const policyArmed = input.policy !== void 0 && input.policySource !== "none";
8631
9077
  const policyFamily = {
8632
9078
  id: "policy",
@@ -8727,6 +9173,17 @@ function evaluateGovernanceIntegrity(input) {
8727
9173
  families.map((family) => family.remediation).filter((remediation) => remediation !== void 0)
8728
9174
  );
8729
9175
  const summary = summarize(status, { componentsArmed, tokensArmed, blockingArmed });
9176
+ const configuredRuleCount = [...configs.keys()].filter(
9177
+ (ruleId) => CONSUMED_RULE_IDS.has(ruleId)
9178
+ ).length;
9179
+ const activeRuleCount = [...configs.entries()].filter(
9180
+ ([ruleId, config]) => CONSUMED_RULE_IDS.has(ruleId) && config.enabled
9181
+ ).length;
9182
+ const roster = {
9183
+ configured: configuredRuleCount + configDiagnostics.length,
9184
+ active: activeRuleCount,
9185
+ inert: configDiagnostics.length
9186
+ };
8730
9187
  return {
8731
9188
  status,
8732
9189
  declared: input.declared,
@@ -8735,7 +9192,9 @@ function evaluateGovernanceIntegrity(input) {
8735
9192
  families,
8736
9193
  armed,
8737
9194
  summary,
8738
- remediations
9195
+ remediations,
9196
+ configDiagnostics,
9197
+ roster
8739
9198
  };
8740
9199
  }
8741
9200
 
@@ -8756,6 +9215,19 @@ function canonicalBridgeContractMappings(bridges) {
8756
9215
  }
8757
9216
  }));
8758
9217
  }
9218
+ function canonicalBridgeIdentityBindings(bridges) {
9219
+ return (bridges ?? []).map((bridge) => ({
9220
+ source: {
9221
+ kind: "npm",
9222
+ specifier: bridge.underlying.packageName,
9223
+ include: [bridge.underlying.exportName]
9224
+ },
9225
+ localComponentKey: bridge.local.componentKey
9226
+ }));
9227
+ }
9228
+ function canonicalBridgeIdentitySources(bridges) {
9229
+ return canonicalBridgeIdentityBindings(bridges).map((binding) => binding.source);
9230
+ }
8759
9231
 
8760
9232
  // src/effective-governance-inputs.ts
8761
9233
  var EFFECTIVE_GOVERNANCE_INPUTS_SCHEMA = "effective-governance-inputs:v1";
@@ -9322,6 +9794,8 @@ export {
9322
9794
  REGISTRY_INSTALL_RECEIPT_SCHEMA_VERSION,
9323
9795
  REGISTRY_MANIFEST_SCHEMA_VERSION,
9324
9796
  RULES,
9797
+ RULE_FAMILY_IDS,
9798
+ RULE_FAMILY_MEMBERS,
9325
9799
  RULE_TIER,
9326
9800
  SEVERITIES,
9327
9801
  SEVERITY_RANK,
@@ -9359,6 +9833,8 @@ export {
9359
9833
  calculateDeltaE,
9360
9834
  canBlock,
9361
9835
  canonicalBridgeContractMappings,
9836
+ canonicalBridgeIdentityBindings,
9837
+ canonicalBridgeIdentitySources,
9362
9838
  canonicalBridgeV1Schema,
9363
9839
  canonicalDirectionConflictsTarget,
9364
9840
  canonicalJson,
@@ -9373,6 +9849,8 @@ export {
9373
9849
  classifyComplexity,
9374
9850
  classifyIdentity,
9375
9851
  collectRegistryInstallDependencies,
9852
+ collidingRecordDiagnostic,
9853
+ collidingRecordDiagnostics,
9376
9854
  colorSimilarity,
9377
9855
  compareByVocabularyRank,
9378
9856
  compareColors,
@@ -9396,6 +9874,8 @@ export {
9396
9874
  compositionMetadataSchema,
9397
9875
  compositionPatternSchema,
9398
9876
  computeRegistryHash,
9877
+ configDeclarationForDiagnostics,
9878
+ configRecordShape,
9399
9879
  containsTailwindV4Theme,
9400
9880
  contractComponentsFromFragments,
9401
9881
  contractHash,
@@ -9406,12 +9886,17 @@ export {
9406
9886
  defineConfig,
9407
9887
  defineFragment,
9408
9888
  defineRecipe,
9889
+ describePolicyExclude,
9890
+ detectOrphanGovernanceScales,
9409
9891
  detectSubComponentPaths,
9892
+ detectUnconsumedConfigKeys,
9893
+ detectUnmatchedPolicyExcludes,
9410
9894
  diffContractDomains,
9411
9895
  discoverComponents,
9412
9896
  dtcgTokenFileSchema,
9413
9897
  emptyConformResult,
9414
9898
  evaluateGovernanceIntegrity,
9899
+ excludeGlobToRegExp,
9415
9900
  executeVariantLoaders,
9416
9901
  explainUrlForCode,
9417
9902
  factEvidenceSchema,
@@ -9484,8 +9969,10 @@ export {
9484
9969
  isFigmaPropMapping,
9485
9970
  isForceIncluded,
9486
9971
  isPortableRepoPath,
9972
+ isPresetSourcedRule,
9487
9973
  isRawHtmlAdvisoryTier,
9488
9974
  isReactComponent,
9975
+ isRuleFamilyId,
9489
9976
  localCanonicalContractMappings,
9490
9977
  lowerCompositionContract,
9491
9978
  makeA11yNameRequiredFact,
@@ -9529,6 +10016,8 @@ export {
9529
10016
  makeUsageNodeFact,
9530
10017
  makeUsagePropResolvedFact,
9531
10018
  makeUsageTextChildFact,
10019
+ markPresetSourcedRules,
10020
+ matchPolicyExclude,
9532
10021
  matchesGlob,
9533
10022
  maxSeverity,
9534
10023
  mcpBlockSchema,
@@ -9554,8 +10043,10 @@ export {
9554
10043
  nearestSignedScaleValue,
9555
10044
  normalizeColor,
9556
10045
  normalizeConfigPath,
10046
+ normalizeExcludePath,
9557
10047
  normalizeFinding,
9558
10048
  normalizeGovernanceConfig,
10049
+ normalizePolicyExcludes,
9559
10050
  normalizeRegistryRepoPath,
9560
10051
  normalizeSeverity,
9561
10052
  normalizeStyleValue,
@@ -9563,6 +10054,7 @@ export {
9563
10054
  normalizeTokenGroupComment,
9564
10055
  normalizeTokenValue,
9565
10056
  normalizeViolation,
10057
+ overriddenRecordSeverityDiagnostic,
9566
10058
  ownedImportEquivalents,
9567
10059
  parseColor,
9568
10060
  parseColorToRgb,
@@ -9578,9 +10070,12 @@ export {
9578
10070
  parseTailwindV4Theme,
9579
10071
  parseTokenFile,
9580
10072
  parseTokens,
10073
+ policyExcludeMatchesPath,
10074
+ policyExcludeSchema,
9581
10075
  portableRepoPathError,
9582
10076
  projectCanonicalDirectionConflicts,
9583
10077
  projectContractPreimage,
10078
+ projectSupersededImportPathPreferences,
9584
10079
  projectV1OwnedComponentId,
9585
10080
  projectV1OwnedImportIdentity,
9586
10081
  propDefinitionSchema,
@@ -9624,6 +10119,7 @@ export {
9624
10119
  ruleComponentsPreferLibrary,
9625
10120
  ruleComponentsShadowComponent,
9626
10121
  ruleComponentsUnknownProp,
10122
+ ruleFamilyMembers,
9627
10123
  ruleJsxPreferredComponent,
9628
10124
  ruleJsxPreferredImportPath,
9629
10125
  rulePropsInvalidValue,