@suss/ir-core 0.20.0 → 0.21.1

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/dist/index.cjs CHANGED
@@ -26,11 +26,15 @@ __export(index_exports, {
26
26
  ConfidenceSourceSchema: () => ConfidenceSourceSchema,
27
27
  CorroborationSchema: () => CorroborationSchema,
28
28
  DeployableUnitSchema: () => DeployableUnitSchema,
29
+ EVERY_FIELD: () => EVERY_FIELD,
30
+ EffectRelationSchema: () => EffectRelationSchema,
29
31
  FunctionCallSemanticsSchema: () => FunctionCallSemanticsSchema,
30
32
  GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
31
33
  GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
32
34
  MessageBusSemanticsSchema: () => MessageBusSemanticsSchema,
33
35
  MetricSemanticsSchema: () => MetricSemanticsSchema,
36
+ NOTHING_DEPLOYED: () => NOTHING_DEPLOYED,
37
+ RelationSchema: () => RelationSchema,
34
38
  RestSemanticsSchema: () => RestSemanticsSchema,
35
39
  RuntimeConfigSemanticsSchema: () => RuntimeConfigSemanticsSchema,
36
40
  SemanticsSchema: () => SemanticsSchema,
@@ -39,7 +43,10 @@ __export(index_exports, {
39
43
  SuppressionFileSchema: () => SuppressionFileSchema,
40
44
  SuppressionRuleSchema: () => SuppressionRuleSchema,
41
45
  TypeShapeSchema: () => TypeShapeSchema,
46
+ UnitInvocationSemanticsSchema: () => UnitInvocationSemanticsSchema,
42
47
  applySuppressionsToFindings: () => applySuppressionsToFindings,
48
+ bindingIs: () => bindingIs,
49
+ bindingTokens: () => bindingTokens,
43
50
  bodyShapesMatch: () => bodyShapesMatch,
44
51
  boundaryKey: () => boundaryKey,
45
52
  boundaryLabel: () => boundaryLabel,
@@ -62,6 +69,7 @@ __export(index_exports, {
62
69
  gqlIdentityKey: () => gqlIdentityKey,
63
70
  graphqlOperationBinding: () => graphqlOperationBinding,
64
71
  graphqlResolverBinding: () => graphqlResolverBinding,
72
+ groundBinding: () => groundBinding,
65
73
  groundedPairingKey: () => groundedPairingKey,
66
74
  hasNameHole: () => hasNameHole,
67
75
  isGraphqlOperationBinding: () => isGraphqlOperationBinding,
@@ -71,7 +79,10 @@ __export(index_exports, {
71
79
  metricIdentityKey: () => metricIdentityKey,
72
80
  namePatternFromSub: () => namePatternFromSub,
73
81
  namePatternKey: () => namePatternKey,
82
+ nameReference: () => nameReference,
74
83
  namesAgree: () => namesAgree,
84
+ namesBoundary: () => namesBoundary,
85
+ namesBoundaryExactly: () => namesBoundaryExactly,
75
86
  namesNothing: () => namesNothing,
76
87
  normalizePath: () => normalizePath,
77
88
  normalizeRuleBoundary: () => normalizeRuleBoundary,
@@ -86,6 +97,7 @@ __export(index_exports, {
86
97
  referenceName: () => referenceName,
87
98
  referenceOf: () => referenceOf,
88
99
  reportsUnpairedItself: () => reportsUnpairedItself,
100
+ resourceNameIn: () => resourceNameIn,
89
101
  restBinding: () => restBinding,
90
102
  routePathAdmits: () => routePathAdmits,
91
103
  ruleBoundaryMatchesKey: () => ruleBoundaryMatchesKey,
@@ -93,12 +105,18 @@ __export(index_exports, {
93
105
  semanticsAgree: () => semanticsAgree,
94
106
  semconvAttributes: () => semconvAttributes,
95
107
  servesRequest: () => servesRequest,
108
+ spellingTokens: () => spellingTokens,
96
109
  statesAnOrigin: () => statesAnOrigin,
97
110
  storageBinding: () => storageBinding,
111
+ storageContainerLabel: () => storageContainerLabel,
112
+ storageLabel: () => storageLabel,
98
113
  typeDefinitionKey: () => typeDefinitionKey,
114
+ unitIdentityKey: () => unitIdentityKey,
115
+ unitInvocationBinding: () => unitInvocationBinding,
99
116
  validateRule: () => validateRule,
100
117
  withDefinitionsInlined: () => withDefinitionsInlined,
101
- withRewrittenPaths: () => withRewrittenPaths
118
+ withRewrittenPaths: () => withRewrittenPaths,
119
+ withinScope: () => withinScope
102
120
  });
103
121
  module.exports = __toCommonJS(index_exports);
104
122
 
@@ -151,15 +169,18 @@ function fnIdentityKey(packageName, exportPath) {
151
169
  function busIdentityKey(messageBus, subject) {
152
170
  return `bus:${messageBus} ${subject}`;
153
171
  }
172
+ function unitIdentityKey(deploymentTarget, instanceName) {
173
+ return `unit:${deploymentTarget} ${instanceName}`;
174
+ }
154
175
  function metricIdentityKey(metricSystem, metricType) {
155
176
  return `metric:${metricSystem} ${metricType}`;
156
177
  }
157
178
 
158
179
  // src/schemas.ts
159
- var import_zod11 = require("zod");
180
+ var import_zod12 = require("zod");
160
181
 
161
182
  // src/semantics/registry.ts
162
- var import_zod10 = require("zod");
183
+ var import_zod11 = require("zod");
163
184
 
164
185
  // src/semantics/functionCall.ts
165
186
  var import_zod2 = require("zod");
@@ -424,6 +445,141 @@ var metricSemantics = defineBoundarySemantics({
424
445
  // src/semantics/rest.ts
425
446
  var import_zod6 = require("zod");
426
447
 
448
+ // src/dispatch.ts
449
+ function dispatchByType(table, value) {
450
+ const handler = table[value.type];
451
+ return handler(value);
452
+ }
453
+
454
+ // src/boundaryName.ts
455
+ var HOLE_SPLIT = /(\{[^}]*\})/;
456
+ var SUB_TOKEN = /\$\{([^}]*)\}/g;
457
+ var SUB_ESCAPE = /\$\{!/;
458
+ function isHole(piece) {
459
+ return piece.startsWith("{") && piece.endsWith("}");
460
+ }
461
+ function parseBoundaryName(name) {
462
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
463
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
464
+ );
465
+ const only = parts.length === 1 ? parts[0] : void 0;
466
+ if (only !== void 0 && only.type === "hole") {
467
+ return { type: "reference", path: only.label.split(".") };
468
+ }
469
+ if (parts.some((part) => part.type === "hole")) {
470
+ return { type: "pattern", parts };
471
+ }
472
+ return { type: "literal", value: name };
473
+ }
474
+ var partString = {
475
+ text: (part) => part.text,
476
+ hole: (part) => patternHole(part.label)
477
+ };
478
+ var nameString = {
479
+ literal: (name) => name.value,
480
+ pattern: (name) => name.parts.map((part) => dispatchByType(partString, part)).join(""),
481
+ reference: (name) => patternHole(name.path.join("."))
482
+ };
483
+ function boundaryNameString(name) {
484
+ return dispatchByType(nameString, name);
485
+ }
486
+ function patternHole(label) {
487
+ return `{${label}}`;
488
+ }
489
+ function namePatternFromSub(value) {
490
+ if (Array.isArray(value)) {
491
+ return typeof value[0] === "string" ? namePatternFromSub(value[0]) : null;
492
+ }
493
+ if (typeof value !== "string") {
494
+ return null;
495
+ }
496
+ if (SUB_ESCAPE.test(value)) {
497
+ return null;
498
+ }
499
+ return value.replace(
500
+ SUB_TOKEN,
501
+ (_whole, inner) => patternHole(inner)
502
+ );
503
+ }
504
+ function namesNothing(name) {
505
+ return parseBoundaryName(name).type === "reference";
506
+ }
507
+ function hasNameHole(name) {
508
+ return parseBoundaryName(name).type !== "literal";
509
+ }
510
+ function namePatternKey(name) {
511
+ return dispatchByType(
512
+ {
513
+ literal: (parsed) => parsed.value,
514
+ pattern: (parsed) => boundaryNameString({
515
+ type: "pattern",
516
+ parts: parsed.parts.map(
517
+ (part) => part.type === "hole" ? { type: "hole", label: "" } : part
518
+ )
519
+ }),
520
+ reference: () => patternHole("")
521
+ },
522
+ parseBoundaryName(name)
523
+ );
524
+ }
525
+ function fixedTextLength(name) {
526
+ return dispatchByType(
527
+ {
528
+ literal: (parsed) => parsed.value.length,
529
+ pattern: (parsed) => parsed.parts.reduce(
530
+ (total, part) => total + (part.type === "text" ? part.text.length : 0),
531
+ 0
532
+ ),
533
+ reference: () => 0
534
+ },
535
+ parseBoundaryName(name)
536
+ );
537
+ }
538
+ function quote(text) {
539
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
540
+ }
541
+ function admits(pattern, name) {
542
+ const source = pattern.parts.map((part) => part.type === "hole" ? ".+" : quote(part.text)).join("");
543
+ return new RegExp(`^${source}$`).test(name);
544
+ }
545
+ function namesAgree(a, b) {
546
+ const left = parseBoundaryName(a);
547
+ const right = parseBoundaryName(b);
548
+ if (left.type === "reference" || right.type === "reference") {
549
+ return false;
550
+ }
551
+ if (left.type === "pattern" && right.type === "pattern") {
552
+ return namePatternKey(a) === namePatternKey(b);
553
+ }
554
+ if (left.type === "pattern") {
555
+ return admits(left, b);
556
+ }
557
+ if (right.type === "pattern") {
558
+ return admits(right, a);
559
+ }
560
+ return a === b;
561
+ }
562
+ function referenceName(reference) {
563
+ const path = [reference.root, ...reference.fields];
564
+ if (path.some((part) => part === "")) {
565
+ return null;
566
+ }
567
+ return boundaryNameString({ type: "reference", path });
568
+ }
569
+ function referenceOf(name) {
570
+ if (name.type !== "reference") {
571
+ return null;
572
+ }
573
+ const root = name.path[0];
574
+ if (root === void 0 || name.path.some((part) => part === "")) {
575
+ return null;
576
+ }
577
+ return { root, fields: name.path.slice(1) };
578
+ }
579
+ function referenceFromName(name) {
580
+ return referenceOf(parseBoundaryName(name));
581
+ }
582
+
427
583
  // src/urlPath.ts
428
584
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
429
585
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
@@ -456,9 +612,9 @@ var RestSemanticsSchema = import_zod6.z.object({
456
612
  declaredResponses: import_zod6.z.array(import_zod6.z.number()).optional()
457
613
  });
458
614
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
459
- function variableOf(label) {
460
- const parts = label.split(".");
461
- return parts[parts.length - 1] ?? label;
615
+ function baseUrlReference(semantics) {
616
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
617
+ return label === void 0 ? null : referenceFromName(patternHole(label));
462
618
  }
463
619
  function normalizePath(path) {
464
620
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -569,6 +725,14 @@ var restSemantics = defineBoundarySemantics({
569
725
  }
570
726
  return routePathAdmits(semantics.path, path) ? "match" : "nomatch";
571
727
  },
728
+ /**
729
+ * A route the registration pattern admits is inside it. A route
730
+ * whose path this source never gave is left outside, because
731
+ * nothing here can show it is one the pattern covers.
732
+ */
733
+ withinScope(semantics, scope) {
734
+ return semantics.path !== null && routePathAdmits(scope, semantics.path);
735
+ },
572
736
  /**
573
737
  * A call whose base URL the deployment fills in, resolved to the
574
738
  * path it reaches.
@@ -584,22 +748,20 @@ var restSemantics = defineBoundarySemantics({
584
748
  * route parameter, and `/orders/{id}` means every id rather than a
585
749
  * variable somebody set.
586
750
  */
587
- groundName(semantics, deployedAs) {
588
- if (semantics.path === null) {
589
- return null;
590
- }
591
- const opening = OPENING_HOLE.exec(semantics.path);
592
- if (opening === null) {
751
+ groundName(semantics, deployment) {
752
+ const reference = baseUrlReference(semantics);
753
+ if (reference === null) {
593
754
  return null;
594
755
  }
595
- const [, label, rest] = opening;
596
- const base = deployedAs(variableOf(label));
756
+ const base = deployment.setTo(reference);
597
757
  if (base === null) {
598
758
  return null;
599
759
  }
760
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
600
761
  const grounded = pathAfterOrigin(`${base}${rest}`);
601
762
  return { ...semantics, path: grounded === "" ? "/" : grounded };
602
763
  },
764
+ nameReference: baseUrlReference,
603
765
  ruleBoundary: {
604
766
  // "METHOD /path": one leading token, then an absolute path.
605
767
  claims(raw) {
@@ -689,6 +851,9 @@ var StorageSemanticsSchema = import_zod9.z.object({
689
851
  */
690
852
  accessPath: import_zod9.z.string().nullable()
691
853
  });
854
+ function containerReference(semantics) {
855
+ return semantics.container === null ? null : referenceFromName(semantics.container);
856
+ }
692
857
  var storageSemantics = defineBoundarySemantics({
693
858
  name: "storage",
694
859
  schema: StorageSemanticsSchema,
@@ -704,12 +869,109 @@ var storageSemantics = defineBoundarySemantics({
704
869
  /** A query returns rows or items, not a status and a body. */
705
870
  exchangesHttpResponses: false,
706
871
  reportsUnpairedItself: false,
707
- identityKey: () => null
872
+ identityKey: () => null,
873
+ displayLabel: storageLabel,
874
+ /**
875
+ * A container the source states as a variable is whatever the
876
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
877
+ * code and `prod-subscribers-v1` in the manifest are one table.
878
+ */
879
+ groundName(semantics, deployment) {
880
+ const reference = containerReference(semantics);
881
+ if (reference === null) {
882
+ return null;
883
+ }
884
+ const name = deployment.setTo(reference);
885
+ return name === null ? null : { ...semantics, container: name };
886
+ },
887
+ nameReference: containerReference
888
+ }
889
+ });
890
+ function storageLabel(semantics) {
891
+ return `${semantics.storageSystem}:${storageContainerLabel(semantics)}`;
892
+ }
893
+ var EVERY_FIELD = "*";
894
+ function storageContainerLabel(semantics) {
895
+ const container = semantics.container ?? "<unnamed container>";
896
+ const addressed = semantics.accessPath === null ? container : `${container}#${semantics.accessPath}`;
897
+ return semantics.scope === "default" ? addressed : `${semantics.scope}/${addressed}`;
898
+ }
899
+
900
+ // src/semantics/unitInvocation.ts
901
+ var import_zod10 = require("zod");
902
+ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
903
+ name: import_zod10.z.literal("unit-invocation"),
904
+ instanceName: DeployableUnitSchema.shape.instanceName.nullable()
905
+ });
906
+ function calleeReference(semantics) {
907
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
908
+ }
909
+ var unitInvocationSemantics = defineBoundarySemantics({
910
+ name: "unit-invocation",
911
+ schema: UnitInvocationSemanticsSchema,
912
+ // faas.name is the deployed function's own name and instanceName is
913
+ // the deployment template's logical id, which is a different string.
914
+ // Runtime config leaves the pair off for the same reason.
915
+ semconv: {},
916
+ behavior: {
917
+ /**
918
+ * A synchronous invoke gives back whatever the handler returned,
919
+ * which is a value rather than a status and a body. A handler's
920
+ * return only becomes an HTTP response under a proxy integration,
921
+ * and that route gets a REST binding instead of this one.
922
+ */
923
+ exchangesHttpResponses: false,
924
+ /**
925
+ * A unit nothing in the run invokes is the ordinary case, since
926
+ * most services are reached from a stack suss never read. So an
927
+ * uninvoked unit stays in the generic unmatched list rather than
928
+ * being reported as a problem here.
929
+ */
930
+ reportsUnpairedItself: false,
931
+ /**
932
+ * A callee the source states only as a variable is not a name for
933
+ * anything until the deployment fills it in, so it keys as nothing
934
+ * rather than as a bucket that would agree with itself alone.
935
+ */
936
+ identityKey(semantics) {
937
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
938
+ return null;
939
+ }
940
+ return unitIdentityKey(
941
+ semantics.deploymentTarget,
942
+ semantics.instanceName
943
+ );
944
+ },
945
+ displayLabel(semantics) {
946
+ if (semantics.instanceName === null) {
947
+ return `unit:${semantics.deploymentTarget} (named at runtime)`;
948
+ }
949
+ return unitIdentityKey(
950
+ semantics.deploymentTarget,
951
+ semantics.instanceName
952
+ );
953
+ },
954
+ /**
955
+ * A call that reads its callee's name out of the environment
956
+ * reaches whichever resource the template wires that variable to.
957
+ * The logical id is the answer rather than the deployed name,
958
+ * because the invoked unit's own summary is keyed by the logical
959
+ * id and neither side ever writes the other's string.
960
+ */
961
+ groundName(semantics, deployment) {
962
+ const reference = calleeReference(semantics);
963
+ if (reference === null) {
964
+ return null;
965
+ }
966
+ const logicalId = deployment.pointsAt(reference);
967
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
968
+ },
969
+ nameReference: calleeReference
708
970
  }
709
971
  });
710
972
 
711
973
  // src/semantics/registry.ts
712
- var SemanticsSchema = import_zod10.z.discriminatedUnion("name", [
974
+ var SemanticsSchema = import_zod11.z.discriminatedUnion("name", [
713
975
  restSemantics.schema,
714
976
  functionCallSemantics.schema,
715
977
  graphqlResolverSemantics.schema,
@@ -717,7 +979,8 @@ var SemanticsSchema = import_zod10.z.discriminatedUnion("name", [
717
979
  runtimeConfigSemantics.schema,
718
980
  storageSemantics.schema,
719
981
  messageBusSemantics.schema,
720
- metricSemantics.schema
982
+ metricSemantics.schema,
983
+ unitInvocationSemantics.schema
721
984
  ]);
722
985
  var DEFINITIONS = [
723
986
  restSemantics,
@@ -727,7 +990,8 @@ var DEFINITIONS = [
727
990
  runtimeConfigSemantics,
728
991
  storageSemantics,
729
992
  messageBusSemantics,
730
- metricSemantics
993
+ metricSemantics,
994
+ unitInvocationSemantics
731
995
  ];
732
996
  var BY_NAME = new Map(
733
997
  DEFINITIONS.map((d) => [d.name, d])
@@ -750,31 +1014,31 @@ function allBehaviors() {
750
1014
  }
751
1015
 
752
1016
  // src/schemas.ts
753
- var ConfidenceSourceSchema = import_zod11.z.enum([
1017
+ var ConfidenceSourceSchema = import_zod12.z.enum([
754
1018
  "inferred_static",
755
1019
  "inferred_ai",
756
1020
  "declared",
757
1021
  "derived"
758
1022
  ]);
759
- var ConfidenceLevelSchema = import_zod11.z.enum(["high", "medium", "low"]);
760
- var CorroborationSchema = import_zod11.z.object({
761
- outcome: import_zod11.z.enum(["observed", "refuted", "untested"]),
1023
+ var ConfidenceLevelSchema = import_zod12.z.enum(["high", "medium", "low"]);
1024
+ var CorroborationSchema = import_zod12.z.object({
1025
+ outcome: import_zod12.z.enum(["observed", "refuted", "untested"]),
762
1026
  /** Executions that produced a verdict for this claim. */
763
- runs: import_zod11.z.number(),
1027
+ runs: import_zod12.z.number(),
764
1028
  /** Present when refuted: the input and observation that disagreed. */
765
- counterexample: import_zod11.z.unknown().optional(),
1029
+ counterexample: import_zod12.z.unknown().optional(),
766
1030
  /** Present when untested: why no verdict was reachable. */
767
- reason: import_zod11.z.string().optional()
1031
+ reason: import_zod12.z.string().optional()
768
1032
  });
769
- var ConfidenceInfoSchema = import_zod11.z.object({
1033
+ var ConfidenceInfoSchema = import_zod12.z.object({
770
1034
  source: ConfidenceSourceSchema,
771
1035
  level: ConfidenceLevelSchema,
772
1036
  corroboration: CorroborationSchema.optional()
773
1037
  });
774
- var SourceLocationSchema = import_zod11.z.object({
775
- file: import_zod11.z.string(),
1038
+ var SourceLocationSchema = import_zod12.z.object({
1039
+ file: import_zod12.z.string(),
776
1040
  /** Line numbers, for a person reading the summary or an editor link. */
777
- range: import_zod11.z.object({ start: import_zod11.z.number(), end: import_zod11.z.number() }),
1041
+ range: import_zod12.z.object({ start: import_zod12.z.number(), end: import_zod12.z.number() }),
778
1042
  /**
779
1043
  * Character offsets of the unit in its file. Identity and joins
780
1044
  * measure with these, since two functions can share a line and never
@@ -782,8 +1046,8 @@ var SourceLocationSchema = import_zod11.z.object({
782
1046
  * same place. Absent on summaries no source position backs, a
783
1047
  * contract artifact's say.
784
1048
  */
785
- span: import_zod11.z.object({ start: import_zod11.z.number(), end: import_zod11.z.number() }).optional(),
786
- exportName: import_zod11.z.string().nullable(),
1049
+ span: import_zod12.z.object({ start: import_zod12.z.number(), end: import_zod12.z.number() }).optional(),
1050
+ exportName: import_zod12.z.string().nullable(),
787
1051
  /**
788
1052
  * The project the extract was pointed at, by the name that project
789
1053
  * calls itself.
@@ -793,47 +1057,47 @@ var SourceLocationSchema = import_zod11.z.object({
793
1057
  * summaries puts them on top of each other. This field is what tells
794
1058
  * them apart, and what a reader groups by.
795
1059
  */
796
- workspace: import_zod11.z.string().optional()
1060
+ workspace: import_zod12.z.string().optional()
797
1061
  });
798
- var BoundaryBindingSchema = import_zod11.z.object({
799
- transport: import_zod11.z.string(),
1062
+ var BoundaryBindingSchema = import_zod12.z.object({
1063
+ transport: import_zod12.z.string(),
800
1064
  semantics: SemanticsSchema,
801
- recognition: import_zod11.z.string()
1065
+ recognition: import_zod12.z.string()
802
1066
  });
803
1067
  function typeDefinitionKey(ref) {
804
1068
  return ref.def ?? null;
805
1069
  }
806
- var TypeShapeSchema = import_zod11.z.lazy(
807
- () => import_zod11.z.discriminatedUnion("type", [
808
- import_zod11.z.object({
809
- type: import_zod11.z.literal("record"),
810
- properties: import_zod11.z.record(import_zod11.z.string(), TypeShapeSchema),
811
- spreads: import_zod11.z.array(import_zod11.z.object({ sourceText: import_zod11.z.string() })).optional()
1070
+ var TypeShapeSchema = import_zod12.z.lazy(
1071
+ () => import_zod12.z.discriminatedUnion("type", [
1072
+ import_zod12.z.object({
1073
+ type: import_zod12.z.literal("record"),
1074
+ properties: import_zod12.z.record(import_zod12.z.string(), TypeShapeSchema),
1075
+ spreads: import_zod12.z.array(import_zod12.z.object({ sourceText: import_zod12.z.string() })).optional()
812
1076
  }),
813
- import_zod11.z.object({ type: import_zod11.z.literal("dictionary"), values: TypeShapeSchema }),
814
- import_zod11.z.object({ type: import_zod11.z.literal("array"), items: TypeShapeSchema }),
815
- import_zod11.z.object({
816
- type: import_zod11.z.literal("literal"),
817
- value: import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean()]),
818
- raw: import_zod11.z.string().optional()
1077
+ import_zod12.z.object({ type: import_zod12.z.literal("dictionary"), values: TypeShapeSchema }),
1078
+ import_zod12.z.object({ type: import_zod12.z.literal("array"), items: TypeShapeSchema }),
1079
+ import_zod12.z.object({
1080
+ type: import_zod12.z.literal("literal"),
1081
+ value: import_zod12.z.union([import_zod12.z.string(), import_zod12.z.number(), import_zod12.z.boolean()]),
1082
+ raw: import_zod12.z.string().optional()
819
1083
  }),
820
- import_zod11.z.object({ type: import_zod11.z.literal("text") }),
821
- import_zod11.z.object({ type: import_zod11.z.literal("integer") }),
822
- import_zod11.z.object({ type: import_zod11.z.literal("number") }),
823
- import_zod11.z.object({ type: import_zod11.z.literal("boolean") }),
824
- import_zod11.z.object({ type: import_zod11.z.literal("null") }),
825
- import_zod11.z.object({ type: import_zod11.z.literal("undefined") }),
826
- import_zod11.z.object({
827
- type: import_zod11.z.literal("union"),
828
- variants: import_zod11.z.array(TypeShapeSchema)
1084
+ import_zod12.z.object({ type: import_zod12.z.literal("text") }),
1085
+ import_zod12.z.object({ type: import_zod12.z.literal("integer") }),
1086
+ import_zod12.z.object({ type: import_zod12.z.literal("number") }),
1087
+ import_zod12.z.object({ type: import_zod12.z.literal("boolean") }),
1088
+ import_zod12.z.object({ type: import_zod12.z.literal("null") }),
1089
+ import_zod12.z.object({ type: import_zod12.z.literal("undefined") }),
1090
+ import_zod12.z.object({
1091
+ type: import_zod12.z.literal("union"),
1092
+ variants: import_zod12.z.array(TypeShapeSchema)
829
1093
  }),
830
- import_zod11.z.object({
831
- type: import_zod11.z.literal("ref"),
832
- name: import_zod11.z.string(),
833
- from: import_zod11.z.string().optional(),
834
- def: import_zod11.z.string().optional()
1094
+ import_zod12.z.object({
1095
+ type: import_zod12.z.literal("ref"),
1096
+ name: import_zod12.z.string(),
1097
+ from: import_zod12.z.string().optional(),
1098
+ def: import_zod12.z.string().optional()
835
1099
  }),
836
- import_zod11.z.object({ type: import_zod11.z.literal("unknown") })
1100
+ import_zod12.z.object({ type: import_zod12.z.literal("unknown") })
837
1101
  ])
838
1102
  );
839
1103
  var MAX_DEFINITION_DEPTH = 6;
@@ -897,6 +1161,9 @@ function semconvAttributes(binding) {
897
1161
  }
898
1162
 
899
1163
  // src/boundaryKey.ts
1164
+ function bindingIs(binding, name) {
1165
+ return binding?.semantics.name === name;
1166
+ }
900
1167
  function boundaryKey(binding) {
901
1168
  return behaviorOf(binding.semantics).identityKey(binding.semantics);
902
1169
  }
@@ -910,12 +1177,16 @@ function withRewrittenPaths(binding, rewrite) {
910
1177
  semantics: behavior.rewritePaths(binding.semantics, rewrite)
911
1178
  };
912
1179
  }
913
- function groundedPairingKey(binding, deployedAs) {
1180
+ function groundedPairingKey(binding, deployment) {
1181
+ return pairingKey(groundBinding(binding, deployment));
1182
+ }
1183
+ function groundBinding(binding, deployment) {
914
1184
  const behavior = behaviorOf(binding.semantics);
915
- const grounded = behavior.groundName?.(binding.semantics, deployedAs) ?? null;
916
- return pairingKey(
917
- grounded === null ? binding : { ...binding, semantics: grounded }
918
- );
1185
+ const grounded = behavior.groundName?.(binding.semantics, deployment) ?? null;
1186
+ return grounded === null ? binding : { ...binding, semantics: grounded };
1187
+ }
1188
+ function nameReference(binding) {
1189
+ return behaviorOf(binding.semantics).nameReference?.(binding.semantics) ?? null;
919
1190
  }
920
1191
  function pairingKey(binding) {
921
1192
  const behavior = behaviorOf(binding.semantics);
@@ -964,140 +1235,60 @@ function servesRequest(binding, method, path) {
964
1235
  }
965
1236
  return serves(binding.semantics, method, path);
966
1237
  }
967
-
968
- // src/dispatch.ts
969
- function dispatchByType(table, value) {
970
- const handler = table[value.type];
971
- return handler(value);
1238
+ function withinScope(binding, scope) {
1239
+ const within = behaviorOf(binding.semantics).withinScope;
1240
+ return within === void 0 ? false : within(binding.semantics, scope);
972
1241
  }
973
1242
 
974
- // src/boundaryName.ts
975
- var HOLE_SPLIT = /(\{[^}]*\})/;
976
- var SUB_TOKEN = /\$\{([^}]*)\}/g;
977
- var SUB_ESCAPE = /\$\{!/;
978
- function isHole(piece) {
979
- return piece.startsWith("{") && piece.endsWith("}");
980
- }
981
- function parseBoundaryName(name) {
982
- const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
983
- (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
984
- );
985
- const only = parts.length === 1 ? parts[0] : void 0;
986
- if (only !== void 0 && only.type === "hole") {
987
- return { type: "reference", path: only.label.split(".") };
988
- }
989
- if (parts.some((part) => part.type === "hole")) {
990
- return { type: "pattern", parts };
991
- }
992
- return { type: "literal", value: name };
993
- }
994
- var partString = {
995
- text: (part) => part.text,
996
- hole: (part) => patternHole(part.label)
997
- };
998
- var nameString = {
999
- literal: (name) => name.value,
1000
- pattern: (name) => name.parts.map((part) => dispatchByType(partString, part)).join(""),
1001
- reference: (name) => patternHole(name.path.join("."))
1002
- };
1003
- function boundaryNameString(name) {
1004
- return dispatchByType(nameString, name);
1005
- }
1006
- function patternHole(label) {
1007
- return `{${label}}`;
1008
- }
1009
- function namePatternFromSub(value) {
1010
- if (Array.isArray(value)) {
1011
- return typeof value[0] === "string" ? namePatternFromSub(value[0]) : null;
1012
- }
1013
- if (typeof value !== "string") {
1014
- return null;
1243
+ // src/boundarySpelling.ts
1244
+ function resourceNameIn(spelling) {
1245
+ if (spelling.startsWith("arn:")) {
1246
+ const segments2 = spelling.split(":");
1247
+ return segments2[6] ?? segments2[5] ?? spelling;
1248
+ }
1249
+ const segments = spelling.split("/");
1250
+ if (segments.length >= 4 && segments.length % 2 === 0) {
1251
+ return segments[segments.length - 1] ?? spelling;
1252
+ }
1253
+ return spelling;
1254
+ }
1255
+ function spellingTokens(text) {
1256
+ return text.toLowerCase().replace(/[{}]/g, " ").split(/[\s:#,()/]+/).filter((token) => token.length > 0);
1257
+ }
1258
+ function bindingTokens(binding) {
1259
+ const tokens = new Set(spellingTokens(displayLabel(binding)));
1260
+ for (const value of Object.values(binding.semantics)) {
1261
+ if (typeof value === "string") {
1262
+ for (const token of spellingTokens(value)) {
1263
+ tokens.add(token);
1264
+ }
1265
+ }
1015
1266
  }
1016
- if (SUB_ESCAPE.test(value)) {
1017
- return null;
1267
+ for (const token of [...tokens]) {
1268
+ for (const part of token.split(".")) {
1269
+ tokens.add(part);
1270
+ }
1018
1271
  }
1019
- return value.replace(
1020
- SUB_TOKEN,
1021
- (_whole, inner) => patternHole(inner)
1022
- );
1023
- }
1024
- function namesNothing(name) {
1025
- return parseBoundaryName(name).type === "reference";
1026
- }
1027
- function hasNameHole(name) {
1028
- return parseBoundaryName(name).type !== "literal";
1272
+ return tokens;
1029
1273
  }
1030
- function namePatternKey(name) {
1031
- return dispatchByType(
1032
- {
1033
- literal: (parsed) => parsed.value,
1034
- pattern: (parsed) => boundaryNameString({
1035
- type: "pattern",
1036
- parts: parsed.parts.map(
1037
- (part) => part.type === "hole" ? { type: "hole", label: "" } : part
1038
- )
1039
- }),
1040
- reference: () => patternHole("")
1041
- },
1042
- parseBoundaryName(name)
1043
- );
1044
- }
1045
- function fixedTextLength(name) {
1046
- return dispatchByType(
1047
- {
1048
- literal: (parsed) => parsed.value.length,
1049
- pattern: (parsed) => parsed.parts.reduce(
1050
- (total, part) => total + (part.type === "text" ? part.text.length : 0),
1051
- 0
1052
- ),
1053
- reference: () => 0
1054
- },
1055
- parseBoundaryName(name)
1056
- );
1057
- }
1058
- function quote(text) {
1059
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1060
- }
1061
- function admits(pattern, name) {
1062
- const source = pattern.parts.map((part) => part.type === "hole" ? ".+" : quote(part.text)).join("");
1063
- return new RegExp(`^${source}$`).test(name);
1064
- }
1065
- function namesAgree(a, b) {
1066
- const left = parseBoundaryName(a);
1067
- const right = parseBoundaryName(b);
1068
- if (left.type === "reference" || right.type === "reference") {
1274
+ function namesBoundaryExactly(subject, binding) {
1275
+ const wanted = new Set(spellingTokens(subject));
1276
+ if (wanted.size === 0) {
1069
1277
  return false;
1070
1278
  }
1071
- if (left.type === "pattern" && right.type === "pattern") {
1072
- return namePatternKey(a) === namePatternKey(b);
1073
- }
1074
- if (left.type === "pattern") {
1075
- return admits(left, b);
1076
- }
1077
- if (right.type === "pattern") {
1078
- return admits(right, a);
1079
- }
1080
- return a === b;
1081
- }
1082
- function referenceName(reference) {
1083
- const path = [reference.root, ...reference.fields];
1084
- if (path.some((part) => part === "")) {
1085
- return null;
1279
+ const spelled = new Set(spellingTokens(displayLabel(binding)));
1280
+ if (spelled.size !== wanted.size) {
1281
+ return false;
1086
1282
  }
1087
- return boundaryNameString({ type: "reference", path });
1283
+ return [...spelled].every((token) => wanted.has(token));
1088
1284
  }
1089
- function referenceOf(name) {
1090
- if (name.type !== "reference") {
1091
- return null;
1092
- }
1093
- const root = name.path[0];
1094
- if (root === void 0 || name.path.some((part) => part === "")) {
1095
- return null;
1285
+ function namesBoundary(subject, binding) {
1286
+ const wanted = spellingTokens(subject);
1287
+ if (wanted.length === 0) {
1288
+ return false;
1096
1289
  }
1097
- return { root, fields: name.path.slice(1) };
1098
- }
1099
- function referenceFromName(name) {
1100
- return referenceOf(parseBoundaryName(name));
1290
+ const tokens = bindingTokens(binding);
1291
+ return wanted.every((token) => tokens.has(token));
1101
1292
  }
1102
1293
 
1103
1294
  // src/codeScope.ts
@@ -1113,26 +1304,43 @@ function fileInCodeScope(file, scope) {
1113
1304
  return path === prefix || path.startsWith(`${prefix}/`);
1114
1305
  }
1115
1306
 
1307
+ // src/deployment.ts
1308
+ var NOTHING_DEPLOYED = {
1309
+ variableFor: () => null,
1310
+ setTo: () => null,
1311
+ pointsAt: () => null
1312
+ };
1313
+
1314
+ // src/relation.ts
1315
+ var import_zod13 = require("zod");
1316
+ var RelationSchema = import_zod13.z.enum([
1317
+ "provides",
1318
+ "reads",
1319
+ "writes",
1320
+ "invokes"
1321
+ ]);
1322
+ var EffectRelationSchema = RelationSchema.exclude(["provides"]);
1323
+
1116
1324
  // src/suppressions.ts
1117
- var import_zod12 = require("zod");
1118
- var SuppressionSideSchema = import_zod12.z.object({
1119
- summary: import_zod12.z.string().optional(),
1120
- transitionId: import_zod12.z.string().optional()
1325
+ var import_zod14 = require("zod");
1326
+ var SuppressionSideSchema = import_zod14.z.object({
1327
+ summary: import_zod14.z.string().optional(),
1328
+ transitionId: import_zod14.z.string().optional()
1121
1329
  }).optional();
1122
- var SuppressionRuleSchema = import_zod12.z.object({
1330
+ var SuppressionRuleSchema = import_zod14.z.object({
1123
1331
  /**
1124
1332
  * The finding kind to match, behavioural or intent. It is an open
1125
1333
  * string here because this package is below both IRs, and the loader
1126
1334
  * is what validates it against the published kind enums.
1127
1335
  */
1128
- kind: import_zod12.z.string().optional(),
1336
+ kind: import_zod14.z.string().optional(),
1129
1337
  /**
1130
1338
  * Boundary as a human-readable key, e.g. "GET /pet/{petId}" or
1131
1339
  * "fn:@acme/api::getUser". REST keys are normalized via the same
1132
1340
  * path normalizer the checkers use, so `:id` and `{id}` compare
1133
1341
  * equal.
1134
1342
  */
1135
- boundary: import_zod12.z.string().optional(),
1343
+ boundary: import_zod14.z.string().optional(),
1136
1344
  /**
1137
1345
  * Consumer-side discriminators, the narrowest useful match. These
1138
1346
  * mean something only for behavioural findings: a rule that
@@ -1155,15 +1363,15 @@ var SuppressionRuleSchema = import_zod12.z.object({
1155
1363
  * kind-only or boundary-only matches, which also silence future
1156
1364
  * regressions in that category.
1157
1365
  */
1158
- scope: import_zod12.z.enum(["narrow", "broad"]).default("narrow"),
1366
+ scope: import_zod14.z.enum(["narrow", "broad"]).default("narrow"),
1159
1367
  /** Required human-written justification. */
1160
- reason: import_zod12.z.string().min(1),
1368
+ reason: import_zod14.z.string().min(1),
1161
1369
  /** What to do when a finding matches. */
1162
- effect: import_zod12.z.enum(["mark", "downgrade", "hide"]).default("mark")
1370
+ effect: import_zod14.z.enum(["mark", "downgrade", "hide"]).default("mark")
1163
1371
  }).strict();
1164
- var SuppressionFileSchema = import_zod12.z.object({
1165
- version: import_zod12.z.literal(1),
1166
- rules: import_zod12.z.array(SuppressionRuleSchema)
1372
+ var SuppressionFileSchema = import_zod14.z.object({
1373
+ version: import_zod14.z.literal(1),
1374
+ rules: import_zod14.z.array(SuppressionRuleSchema)
1167
1375
  }).strict();
1168
1376
  function validateRule(rule) {
1169
1377
  if (rule.scope === "broad") {
@@ -1453,6 +1661,17 @@ function runtimeConfigBinding(opts) {
1453
1661
  recognition: opts.recognition
1454
1662
  };
1455
1663
  }
1664
+ function unitInvocationBinding(opts) {
1665
+ return {
1666
+ transport: "invoke",
1667
+ semantics: {
1668
+ name: "unit-invocation",
1669
+ deploymentTarget: opts.deploymentTarget,
1670
+ instanceName: namedOrNull(opts.instanceName, "invoked unit")
1671
+ },
1672
+ recognition: opts.recognition
1673
+ };
1674
+ }
1456
1675
  function storageBinding(opts) {
1457
1676
  return {
1458
1677
  transport: opts.transport ?? opts.storageSystem,
@@ -1496,11 +1715,15 @@ function metricBinding(opts) {
1496
1715
  ConfidenceSourceSchema,
1497
1716
  CorroborationSchema,
1498
1717
  DeployableUnitSchema,
1718
+ EVERY_FIELD,
1719
+ EffectRelationSchema,
1499
1720
  FunctionCallSemanticsSchema,
1500
1721
  GraphqlOperationSemanticsSchema,
1501
1722
  GraphqlResolverSemanticsSchema,
1502
1723
  MessageBusSemanticsSchema,
1503
1724
  MetricSemanticsSchema,
1725
+ NOTHING_DEPLOYED,
1726
+ RelationSchema,
1504
1727
  RestSemanticsSchema,
1505
1728
  RuntimeConfigSemanticsSchema,
1506
1729
  SemanticsSchema,
@@ -1509,7 +1732,10 @@ function metricBinding(opts) {
1509
1732
  SuppressionFileSchema,
1510
1733
  SuppressionRuleSchema,
1511
1734
  TypeShapeSchema,
1735
+ UnitInvocationSemanticsSchema,
1512
1736
  applySuppressionsToFindings,
1737
+ bindingIs,
1738
+ bindingTokens,
1513
1739
  bodyShapesMatch,
1514
1740
  boundaryKey,
1515
1741
  boundaryLabel,
@@ -1532,6 +1758,7 @@ function metricBinding(opts) {
1532
1758
  gqlIdentityKey,
1533
1759
  graphqlOperationBinding,
1534
1760
  graphqlResolverBinding,
1761
+ groundBinding,
1535
1762
  groundedPairingKey,
1536
1763
  hasNameHole,
1537
1764
  isGraphqlOperationBinding,
@@ -1541,7 +1768,10 @@ function metricBinding(opts) {
1541
1768
  metricIdentityKey,
1542
1769
  namePatternFromSub,
1543
1770
  namePatternKey,
1771
+ nameReference,
1544
1772
  namesAgree,
1773
+ namesBoundary,
1774
+ namesBoundaryExactly,
1545
1775
  namesNothing,
1546
1776
  normalizePath,
1547
1777
  normalizeRuleBoundary,
@@ -1556,6 +1786,7 @@ function metricBinding(opts) {
1556
1786
  referenceName,
1557
1787
  referenceOf,
1558
1788
  reportsUnpairedItself,
1789
+ resourceNameIn,
1559
1790
  restBinding,
1560
1791
  routePathAdmits,
1561
1792
  ruleBoundaryMatchesKey,
@@ -1563,10 +1794,16 @@ function metricBinding(opts) {
1563
1794
  semanticsAgree,
1564
1795
  semconvAttributes,
1565
1796
  servesRequest,
1797
+ spellingTokens,
1566
1798
  statesAnOrigin,
1567
1799
  storageBinding,
1800
+ storageContainerLabel,
1801
+ storageLabel,
1568
1802
  typeDefinitionKey,
1803
+ unitIdentityKey,
1804
+ unitInvocationBinding,
1569
1805
  validateRule,
1570
1806
  withDefinitionsInlined,
1571
- withRewrittenPaths
1807
+ withRewrittenPaths,
1808
+ withinScope
1572
1809
  });