@suss/ir-core 0.0.2 → 0.1.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
@@ -6,7 +6,7 @@ Primitives shared across suss's intermediate representations: the shapes every I
6
6
 
7
7
  The types that any suss IR is built from:
8
8
 
9
- - `TypeShape` — the structural shape of a value, for body / payload / field comparison.
9
+ - `TypeShape`: the structural shape of a value, for body / payload / field comparison.
10
10
  - `BoundaryBinding` + the `Semantics` variants (rest, function-call, graphql-resolver, graphql-operation, runtime-config, storage-relational, message-bus), plus the eight blessed binding constructors (`restBinding`, `functionCallBinding`, …).
11
11
  - `SourceLocation` and `Confidence` (`source` + `level`).
12
12
 
@@ -25,7 +25,7 @@ Schemas are the single source of truth (`@suss/ir-core/schemas`); the types are
25
25
 
26
26
  ## Where it sits in suss
27
27
 
28
- The base both `@suss/behavioral-ir` (what code does) and `@suss/intent-ir` (what the team meant) build on, so neither IR depends on the other — they describe boundaries in the same vocabulary and are compared, not merged. `@suss/behavioral-ir` re-exports these primitives, so existing consumers keep importing them from there unchanged.
28
+ The base both `@suss/behavioral-ir` (what code does) and `@suss/intent-ir` (what the team meant) build on, so neither IR depends on the other. They describe boundaries in the same vocabulary and are compared rather than merged. `@suss/behavioral-ir` re-exports these primitives, so existing consumers keep importing them from there unchanged.
29
29
 
30
30
  ## Status
31
31
 
@@ -7,9 +7,19 @@ var ConfidenceSourceSchema = z.enum([
7
7
  "derived"
8
8
  ]);
9
9
  var ConfidenceLevelSchema = z.enum(["high", "medium", "low"]);
10
+ var CorroborationSchema = z.object({
11
+ outcome: z.enum(["observed", "refuted", "untested"]),
12
+ /** Executions that produced a verdict for this claim. */
13
+ runs: z.number(),
14
+ /** Present when refuted: the input and observation that disagreed. */
15
+ counterexample: z.unknown().optional(),
16
+ /** Present when untested: why no verdict was reachable. */
17
+ reason: z.string().optional()
18
+ });
10
19
  var ConfidenceInfoSchema = z.object({
11
20
  source: ConfidenceSourceSchema,
12
- level: ConfidenceLevelSchema
21
+ level: ConfidenceLevelSchema,
22
+ corroboration: CorroborationSchema.optional()
13
23
  });
14
24
  var SourceLocationSchema = z.object({
15
25
  file: z.string(),
@@ -151,6 +161,7 @@ var TypeShapeSchema = z.lazy(
151
161
  export {
152
162
  ConfidenceSourceSchema,
153
163
  ConfidenceLevelSchema,
164
+ CorroborationSchema,
154
165
  ConfidenceInfoSchema,
155
166
  SourceLocationSchema,
156
167
  RestSemanticsSchema,
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  ConfidenceInfoSchema: () => ConfidenceInfoSchema,
25
25
  ConfidenceLevelSchema: () => ConfidenceLevelSchema,
26
26
  ConfidenceSourceSchema: () => ConfidenceSourceSchema,
27
+ CorroborationSchema: () => CorroborationSchema,
27
28
  FunctionCallSemanticsSchema: () => FunctionCallSemanticsSchema,
28
29
  GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
29
30
  GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
@@ -39,6 +40,8 @@ __export(index_exports, {
39
40
  applySuppressionsToFindings: () => applySuppressionsToFindings,
40
41
  bodyShapesMatch: () => bodyShapesMatch,
41
42
  boundaryKey: () => boundaryKey,
43
+ busesAgree: () => busesAgree,
44
+ channelsPair: () => channelsPair,
42
45
  countsForThreshold: () => countsForThreshold,
43
46
  functionCallBinding: () => functionCallBinding,
44
47
  graphqlOperationBinding: () => graphqlOperationBinding,
@@ -47,6 +50,7 @@ __export(index_exports, {
47
50
  normalizePath: () => normalizePath,
48
51
  normalizeRuleBoundary: () => normalizeRuleBoundary,
49
52
  packageExportBinding: () => packageExportBinding,
53
+ parseChannel: () => parseChannel,
50
54
  restBinding: () => restBinding,
51
55
  ruleBoundaryMatchesKey: () => ruleBoundaryMatchesKey,
52
56
  runtimeConfigBinding: () => runtimeConfigBinding,
@@ -64,9 +68,19 @@ var ConfidenceSourceSchema = import_zod.z.enum([
64
68
  "derived"
65
69
  ]);
66
70
  var ConfidenceLevelSchema = import_zod.z.enum(["high", "medium", "low"]);
71
+ var CorroborationSchema = import_zod.z.object({
72
+ outcome: import_zod.z.enum(["observed", "refuted", "untested"]),
73
+ /** Executions that produced a verdict for this claim. */
74
+ runs: import_zod.z.number(),
75
+ /** Present when refuted: the input and observation that disagreed. */
76
+ counterexample: import_zod.z.unknown().optional(),
77
+ /** Present when untested: why no verdict was reachable. */
78
+ reason: import_zod.z.string().optional()
79
+ });
67
80
  var ConfidenceInfoSchema = import_zod.z.object({
68
81
  source: ConfidenceSourceSchema,
69
- level: ConfidenceLevelSchema
82
+ level: ConfidenceLevelSchema,
83
+ corroboration: CorroborationSchema.optional()
70
84
  });
71
85
  var SourceLocationSchema = import_zod.z.object({
72
86
  file: import_zod.z.string(),
@@ -205,6 +219,23 @@ var TypeShapeSchema = import_zod.z.lazy(
205
219
  ])
206
220
  );
207
221
 
222
+ // src/channel.ts
223
+ function parseChannel(channel) {
224
+ const hash = channel.indexOf("#");
225
+ if (hash === -1) {
226
+ return { bus: null, subject: channel };
227
+ }
228
+ return { bus: channel.slice(0, hash), subject: channel.slice(hash + 1) };
229
+ }
230
+ function busesAgree(a, b) {
231
+ return a === null || b === null || a === b;
232
+ }
233
+ function channelsPair(a, b) {
234
+ const left = parseChannel(a);
235
+ const right = parseChannel(b);
236
+ return left.subject === right.subject && busesAgree(left.bus, right.bus);
237
+ }
238
+
208
239
  // src/boundaryKey.ts
209
240
  function normalizePath(path) {
210
241
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -230,6 +261,13 @@ function boundaryKey(binding) {
230
261
  if (semantics.name === "graphql-resolver") {
231
262
  return `gql:${semantics.typeName}.${semantics.fieldName}`;
232
263
  }
264
+ if (semantics.name === "message-bus") {
265
+ const { subject } = parseChannel(semantics.channel);
266
+ if (subject === "") {
267
+ return null;
268
+ }
269
+ return `bus:${semantics.messageBus} ${subject}`;
270
+ }
233
271
  if (semantics.name === "function-call") {
234
272
  if (semantics.package !== void 0 && semantics.exportPath !== void 0 && semantics.exportPath.length > 0) {
235
273
  return `fn:${semantics.package}::${semantics.exportPath.join(".")}`;
@@ -241,6 +279,10 @@ function boundaryKey(binding) {
241
279
 
242
280
  // src/suppressions.ts
243
281
  var import_zod2 = require("zod");
282
+ var SuppressionSideSchema = import_zod2.z.object({
283
+ summary: import_zod2.z.string().optional(),
284
+ transitionId: import_zod2.z.string().optional()
285
+ }).optional();
244
286
  var SuppressionRuleSchema = import_zod2.z.object({
245
287
  /**
246
288
  * Finding kind to match — any behavioural or intent finding kind.
@@ -261,15 +303,21 @@ var SuppressionRuleSchema = import_zod2.z.object({
261
303
  * `consumer` never matches an intent finding, which has no
262
304
  * consumer side.
263
305
  */
264
- consumer: import_zod2.z.object({
265
- summary: import_zod2.z.string().optional(),
266
- transitionId: import_zod2.z.string().optional()
267
- }).optional(),
306
+ consumer: SuppressionSideSchema,
307
+ /**
308
+ * Provider-side discriminators, the mirror of `consumer`. A finding
309
+ * about a status the provider produces carries its transition id on
310
+ * this side, and that id is the only handle narrow enough to name
311
+ * that one finding. Like `consumer`, a rule that specifies
312
+ * `provider` never matches an intent finding.
313
+ */
314
+ provider: SuppressionSideSchema,
268
315
  /**
269
- * "narrow" (default): requires at least (kind + boundary) OR
270
- * (kind + consumer.transitionId) — enough to target a specific
271
- * finding class. "broad" opts in to kind-only or boundary-only
272
- * matches, which silence future regressions in that category too.
316
+ * "narrow" (default): requires kind plus one of boundary,
317
+ * consumer.transitionId, or provider.transitionId — enough to
318
+ * target a specific finding class. "broad" opts in to kind-only or
319
+ * boundary-only matches, which silence future regressions in that
320
+ * category too.
273
321
  */
274
322
  scope: import_zod2.z.enum(["narrow", "broad"]).default("narrow"),
275
323
  /** Required human-written justification. */
@@ -283,18 +331,18 @@ var SuppressionFileSchema = import_zod2.z.object({
283
331
  }).strict();
284
332
  function validateRule(rule) {
285
333
  if (rule.scope === "broad") {
286
- if (rule.kind === void 0 && rule.boundary === void 0 && rule.consumer === void 0) {
287
- return "broad-scope rule must constrain at least one field (kind, boundary, or consumer)";
334
+ if (rule.kind === void 0 && rule.boundary === void 0 && rule.consumer === void 0 && rule.provider === void 0) {
335
+ return "broad-scope rule must constrain at least one field (kind, boundary, consumer, or provider)";
288
336
  }
289
337
  return null;
290
338
  }
291
339
  const hasKind = rule.kind !== void 0;
292
340
  const hasBoundary = rule.boundary !== void 0;
293
- const hasConsumerTxn = rule.consumer?.transitionId !== void 0;
294
- if (hasKind && (hasBoundary || hasConsumerTxn)) {
341
+ const hasTransition = rule.consumer?.transitionId !== void 0 || rule.provider?.transitionId !== void 0;
342
+ if (hasKind && (hasBoundary || hasTransition)) {
295
343
  return null;
296
344
  }
297
- return "narrow-scope rule must specify kind AND (boundary OR consumer.transitionId); set scope: 'broad' to silence wider categories";
345
+ return "narrow-scope rule must specify kind AND (boundary OR consumer.transitionId OR provider.transitionId); set scope: 'broad' to silence wider categories";
298
346
  }
299
347
  function normalizeRuleBoundary(raw) {
300
348
  const trimmed = raw.trim();
@@ -595,6 +643,7 @@ function messageBusBinding(opts) {
595
643
  ConfidenceInfoSchema,
596
644
  ConfidenceLevelSchema,
597
645
  ConfidenceSourceSchema,
646
+ CorroborationSchema,
598
647
  FunctionCallSemanticsSchema,
599
648
  GraphqlOperationSemanticsSchema,
600
649
  GraphqlResolverSemanticsSchema,
@@ -610,6 +659,8 @@ function messageBusBinding(opts) {
610
659
  applySuppressionsToFindings,
611
660
  bodyShapesMatch,
612
661
  boundaryKey,
662
+ busesAgree,
663
+ channelsPair,
613
664
  countsForThreshold,
614
665
  functionCallBinding,
615
666
  graphqlOperationBinding,
@@ -618,6 +669,7 @@ function messageBusBinding(opts) {
618
669
  normalizePath,
619
670
  normalizeRuleBoundary,
620
671
  packageExportBinding,
672
+ parseChannel,
621
673
  restBinding,
622
674
  ruleBoundaryMatchesKey,
623
675
  runtimeConfigBinding,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { TypeShape, BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, SemanticsSchema, SourceLocationSchema } from './schemas.cjs';
2
+ import { TypeShape, BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, CorroborationSchema, SemanticsSchema, SourceLocationSchema } from './schemas.cjs';
3
3
  export { FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, StorageRelationalSemanticsSchema, TypeShapeSchema } from './schemas.cjs';
4
4
 
5
5
  /**
@@ -15,6 +15,8 @@ declare function normalizePath(path: string): string;
15
15
  * Dispatches on `semantics.name`:
16
16
  * - `rest` → `"METHOD /normalized/path"` (null if method or path empty)
17
17
  * - `graphql-resolver` → `"gql:<TypeName>.<fieldName>"`
18
+ * - `message-bus` → `"bus:<messageBus> <subject>"` (null if the
19
+ * subject is empty)
18
20
  * - `function-call` → `"fn:<package>::<exportPath>"` when both
19
21
  * `package` and `exportPath` are set; other in-process function-call
20
22
  * units (intra-repo components, bare handlers) return null.
@@ -22,6 +24,27 @@ declare function normalizePath(path: string): string;
22
24
  */
23
25
  declare function boundaryKey(binding: BoundaryBinding): string | null;
24
26
 
27
+ /**
28
+ * A channel split into the bus that carries it and the subject on that
29
+ * bus. `default#order.placed` is the subject `order.placed` on the bus
30
+ * `default`. `OrdersQueue` is a subject with no bus, which is what a
31
+ * queue's logical id and an env-var-named channel look like.
32
+ */
33
+ interface ParsedChannel {
34
+ bus: string | null;
35
+ subject: string;
36
+ }
37
+ /**
38
+ * Split a channel on its first `#`. Later `#`s stay in the subject, so
39
+ * a subject that contains one is compared whole rather than being cut
40
+ * into pieces that pair with the wrong things.
41
+ */
42
+ declare function parseChannel(channel: string): ParsedChannel;
43
+ /** Two buses agree when they are the same, or when either is unknown. */
44
+ declare function busesAgree(a: string | null, b: string | null): boolean;
45
+ /** Whether two channels name the same subject on agreeing buses. */
46
+ declare function channelsPair(a: string, b: string): boolean;
47
+
25
48
  declare const SuppressionRuleSchema: z.ZodObject<{
26
49
  kind: z.ZodOptional<z.ZodString>;
27
50
  boundary: z.ZodOptional<z.ZodString>;
@@ -29,6 +52,10 @@ declare const SuppressionRuleSchema: z.ZodObject<{
29
52
  summary: z.ZodOptional<z.ZodString>;
30
53
  transitionId: z.ZodOptional<z.ZodString>;
31
54
  }, z.core.$strip>>;
55
+ provider: z.ZodOptional<z.ZodObject<{
56
+ summary: z.ZodOptional<z.ZodString>;
57
+ transitionId: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>>;
32
59
  scope: z.ZodDefault<z.ZodEnum<{
33
60
  narrow: "narrow";
34
61
  broad: "broad";
@@ -50,6 +77,10 @@ declare const SuppressionFileSchema: z.ZodObject<{
50
77
  summary: z.ZodOptional<z.ZodString>;
51
78
  transitionId: z.ZodOptional<z.ZodString>;
52
79
  }, z.core.$strip>>;
80
+ provider: z.ZodOptional<z.ZodObject<{
81
+ summary: z.ZodOptional<z.ZodString>;
82
+ transitionId: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>>;
53
84
  scope: z.ZodDefault<z.ZodEnum<{
54
85
  narrow: "narrow";
55
86
  broad: "broad";
@@ -148,6 +179,7 @@ declare function bodyShapesMatch(actual: TypeShape, declared: TypeShape): MatchR
148
179
  type ConfidenceSource = z.infer<typeof ConfidenceSourceSchema>;
149
180
  type ConfidenceLevel = z.infer<typeof ConfidenceLevelSchema>;
150
181
  type ConfidenceInfo = z.infer<typeof ConfidenceInfoSchema>;
182
+ type Corroboration = z.infer<typeof CorroborationSchema>;
151
183
  type SourceLocation = z.infer<typeof SourceLocationSchema>;
152
184
  type BoundaryBinding = z.infer<typeof BoundaryBindingSchema>;
153
185
  type Semantics = z.infer<typeof SemanticsSchema>;
@@ -261,4 +293,4 @@ declare function messageBusBinding(opts: {
261
293
  channel: string;
262
294
  }): BoundaryBinding;
263
295
 
264
- export { type BoundaryBinding, BoundaryBindingSchema, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type FindingSuppression, type FunctionCallSemantics, type GraphqlOperationSemantics, type GraphqlResolverSemantics, type MatchResult, type MessageBusSemantics, type RestSemantics, type RuntimeConfigSemantics, type Semantics, SemanticsSchema, type SourceLocation, SourceLocationSchema, type StorageRelationalSemantics, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TypeShape, applySuppressionsToFindings, bodyShapesMatch, boundaryKey, countsForThreshold, functionCallBinding, graphqlOperationBinding, graphqlResolverBinding, messageBusBinding, normalizePath, normalizeRuleBoundary, packageExportBinding, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, storageRelationalBinding, validateRule };
296
+ export { type BoundaryBinding, BoundaryBindingSchema, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, type FindingSuppression, type FunctionCallSemantics, type GraphqlOperationSemantics, type GraphqlResolverSemantics, type MatchResult, type MessageBusSemantics, type ParsedChannel, type RestSemantics, type RuntimeConfigSemantics, type Semantics, SemanticsSchema, type SourceLocation, SourceLocationSchema, type StorageRelationalSemantics, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TypeShape, applySuppressionsToFindings, bodyShapesMatch, boundaryKey, busesAgree, channelsPair, countsForThreshold, functionCallBinding, graphqlOperationBinding, graphqlResolverBinding, messageBusBinding, normalizePath, normalizeRuleBoundary, packageExportBinding, parseChannel, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, storageRelationalBinding, validateRule };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { TypeShape, BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, SemanticsSchema, SourceLocationSchema } from './schemas.js';
2
+ import { TypeShape, BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, CorroborationSchema, SemanticsSchema, SourceLocationSchema } from './schemas.js';
3
3
  export { FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, StorageRelationalSemanticsSchema, TypeShapeSchema } from './schemas.js';
4
4
 
5
5
  /**
@@ -15,6 +15,8 @@ declare function normalizePath(path: string): string;
15
15
  * Dispatches on `semantics.name`:
16
16
  * - `rest` → `"METHOD /normalized/path"` (null if method or path empty)
17
17
  * - `graphql-resolver` → `"gql:<TypeName>.<fieldName>"`
18
+ * - `message-bus` → `"bus:<messageBus> <subject>"` (null if the
19
+ * subject is empty)
18
20
  * - `function-call` → `"fn:<package>::<exportPath>"` when both
19
21
  * `package` and `exportPath` are set; other in-process function-call
20
22
  * units (intra-repo components, bare handlers) return null.
@@ -22,6 +24,27 @@ declare function normalizePath(path: string): string;
22
24
  */
23
25
  declare function boundaryKey(binding: BoundaryBinding): string | null;
24
26
 
27
+ /**
28
+ * A channel split into the bus that carries it and the subject on that
29
+ * bus. `default#order.placed` is the subject `order.placed` on the bus
30
+ * `default`. `OrdersQueue` is a subject with no bus, which is what a
31
+ * queue's logical id and an env-var-named channel look like.
32
+ */
33
+ interface ParsedChannel {
34
+ bus: string | null;
35
+ subject: string;
36
+ }
37
+ /**
38
+ * Split a channel on its first `#`. Later `#`s stay in the subject, so
39
+ * a subject that contains one is compared whole rather than being cut
40
+ * into pieces that pair with the wrong things.
41
+ */
42
+ declare function parseChannel(channel: string): ParsedChannel;
43
+ /** Two buses agree when they are the same, or when either is unknown. */
44
+ declare function busesAgree(a: string | null, b: string | null): boolean;
45
+ /** Whether two channels name the same subject on agreeing buses. */
46
+ declare function channelsPair(a: string, b: string): boolean;
47
+
25
48
  declare const SuppressionRuleSchema: z.ZodObject<{
26
49
  kind: z.ZodOptional<z.ZodString>;
27
50
  boundary: z.ZodOptional<z.ZodString>;
@@ -29,6 +52,10 @@ declare const SuppressionRuleSchema: z.ZodObject<{
29
52
  summary: z.ZodOptional<z.ZodString>;
30
53
  transitionId: z.ZodOptional<z.ZodString>;
31
54
  }, z.core.$strip>>;
55
+ provider: z.ZodOptional<z.ZodObject<{
56
+ summary: z.ZodOptional<z.ZodString>;
57
+ transitionId: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>>;
32
59
  scope: z.ZodDefault<z.ZodEnum<{
33
60
  narrow: "narrow";
34
61
  broad: "broad";
@@ -50,6 +77,10 @@ declare const SuppressionFileSchema: z.ZodObject<{
50
77
  summary: z.ZodOptional<z.ZodString>;
51
78
  transitionId: z.ZodOptional<z.ZodString>;
52
79
  }, z.core.$strip>>;
80
+ provider: z.ZodOptional<z.ZodObject<{
81
+ summary: z.ZodOptional<z.ZodString>;
82
+ transitionId: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>>;
53
84
  scope: z.ZodDefault<z.ZodEnum<{
54
85
  narrow: "narrow";
55
86
  broad: "broad";
@@ -148,6 +179,7 @@ declare function bodyShapesMatch(actual: TypeShape, declared: TypeShape): MatchR
148
179
  type ConfidenceSource = z.infer<typeof ConfidenceSourceSchema>;
149
180
  type ConfidenceLevel = z.infer<typeof ConfidenceLevelSchema>;
150
181
  type ConfidenceInfo = z.infer<typeof ConfidenceInfoSchema>;
182
+ type Corroboration = z.infer<typeof CorroborationSchema>;
151
183
  type SourceLocation = z.infer<typeof SourceLocationSchema>;
152
184
  type BoundaryBinding = z.infer<typeof BoundaryBindingSchema>;
153
185
  type Semantics = z.infer<typeof SemanticsSchema>;
@@ -261,4 +293,4 @@ declare function messageBusBinding(opts: {
261
293
  channel: string;
262
294
  }): BoundaryBinding;
263
295
 
264
- export { type BoundaryBinding, BoundaryBindingSchema, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type FindingSuppression, type FunctionCallSemantics, type GraphqlOperationSemantics, type GraphqlResolverSemantics, type MatchResult, type MessageBusSemantics, type RestSemantics, type RuntimeConfigSemantics, type Semantics, SemanticsSchema, type SourceLocation, SourceLocationSchema, type StorageRelationalSemantics, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TypeShape, applySuppressionsToFindings, bodyShapesMatch, boundaryKey, countsForThreshold, functionCallBinding, graphqlOperationBinding, graphqlResolverBinding, messageBusBinding, normalizePath, normalizeRuleBoundary, packageExportBinding, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, storageRelationalBinding, validateRule };
296
+ export { type BoundaryBinding, BoundaryBindingSchema, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, type FindingSuppression, type FunctionCallSemantics, type GraphqlOperationSemantics, type GraphqlResolverSemantics, type MatchResult, type MessageBusSemantics, type ParsedChannel, type RestSemantics, type RuntimeConfigSemantics, type Semantics, SemanticsSchema, type SourceLocation, SourceLocationSchema, type StorageRelationalSemantics, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TypeShape, applySuppressionsToFindings, bodyShapesMatch, boundaryKey, busesAgree, channelsPair, countsForThreshold, functionCallBinding, graphqlOperationBinding, graphqlResolverBinding, messageBusBinding, normalizePath, normalizeRuleBoundary, packageExportBinding, parseChannel, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, storageRelationalBinding, validateRule };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  ConfidenceInfoSchema,
4
4
  ConfidenceLevelSchema,
5
5
  ConfidenceSourceSchema,
6
+ CorroborationSchema,
6
7
  FunctionCallSemanticsSchema,
7
8
  GraphqlOperationSemanticsSchema,
8
9
  GraphqlResolverSemanticsSchema,
@@ -13,7 +14,24 @@ import {
13
14
  SourceLocationSchema,
14
15
  StorageRelationalSemanticsSchema,
15
16
  TypeShapeSchema
16
- } from "./chunk-BWK3IPL7.js";
17
+ } from "./chunk-BQEWYFCF.js";
18
+
19
+ // src/channel.ts
20
+ function parseChannel(channel) {
21
+ const hash = channel.indexOf("#");
22
+ if (hash === -1) {
23
+ return { bus: null, subject: channel };
24
+ }
25
+ return { bus: channel.slice(0, hash), subject: channel.slice(hash + 1) };
26
+ }
27
+ function busesAgree(a, b) {
28
+ return a === null || b === null || a === b;
29
+ }
30
+ function channelsPair(a, b) {
31
+ const left = parseChannel(a);
32
+ const right = parseChannel(b);
33
+ return left.subject === right.subject && busesAgree(left.bus, right.bus);
34
+ }
17
35
 
18
36
  // src/boundaryKey.ts
19
37
  function normalizePath(path) {
@@ -40,6 +58,13 @@ function boundaryKey(binding) {
40
58
  if (semantics.name === "graphql-resolver") {
41
59
  return `gql:${semantics.typeName}.${semantics.fieldName}`;
42
60
  }
61
+ if (semantics.name === "message-bus") {
62
+ const { subject } = parseChannel(semantics.channel);
63
+ if (subject === "") {
64
+ return null;
65
+ }
66
+ return `bus:${semantics.messageBus} ${subject}`;
67
+ }
43
68
  if (semantics.name === "function-call") {
44
69
  if (semantics.package !== void 0 && semantics.exportPath !== void 0 && semantics.exportPath.length > 0) {
45
70
  return `fn:${semantics.package}::${semantics.exportPath.join(".")}`;
@@ -51,6 +76,10 @@ function boundaryKey(binding) {
51
76
 
52
77
  // src/suppressions.ts
53
78
  import { z } from "zod";
79
+ var SuppressionSideSchema = z.object({
80
+ summary: z.string().optional(),
81
+ transitionId: z.string().optional()
82
+ }).optional();
54
83
  var SuppressionRuleSchema = z.object({
55
84
  /**
56
85
  * Finding kind to match — any behavioural or intent finding kind.
@@ -71,15 +100,21 @@ var SuppressionRuleSchema = z.object({
71
100
  * `consumer` never matches an intent finding, which has no
72
101
  * consumer side.
73
102
  */
74
- consumer: z.object({
75
- summary: z.string().optional(),
76
- transitionId: z.string().optional()
77
- }).optional(),
103
+ consumer: SuppressionSideSchema,
104
+ /**
105
+ * Provider-side discriminators, the mirror of `consumer`. A finding
106
+ * about a status the provider produces carries its transition id on
107
+ * this side, and that id is the only handle narrow enough to name
108
+ * that one finding. Like `consumer`, a rule that specifies
109
+ * `provider` never matches an intent finding.
110
+ */
111
+ provider: SuppressionSideSchema,
78
112
  /**
79
- * "narrow" (default): requires at least (kind + boundary) OR
80
- * (kind + consumer.transitionId) — enough to target a specific
81
- * finding class. "broad" opts in to kind-only or boundary-only
82
- * matches, which silence future regressions in that category too.
113
+ * "narrow" (default): requires kind plus one of boundary,
114
+ * consumer.transitionId, or provider.transitionId — enough to
115
+ * target a specific finding class. "broad" opts in to kind-only or
116
+ * boundary-only matches, which silence future regressions in that
117
+ * category too.
83
118
  */
84
119
  scope: z.enum(["narrow", "broad"]).default("narrow"),
85
120
  /** Required human-written justification. */
@@ -93,18 +128,18 @@ var SuppressionFileSchema = z.object({
93
128
  }).strict();
94
129
  function validateRule(rule) {
95
130
  if (rule.scope === "broad") {
96
- if (rule.kind === void 0 && rule.boundary === void 0 && rule.consumer === void 0) {
97
- return "broad-scope rule must constrain at least one field (kind, boundary, or consumer)";
131
+ if (rule.kind === void 0 && rule.boundary === void 0 && rule.consumer === void 0 && rule.provider === void 0) {
132
+ return "broad-scope rule must constrain at least one field (kind, boundary, consumer, or provider)";
98
133
  }
99
134
  return null;
100
135
  }
101
136
  const hasKind = rule.kind !== void 0;
102
137
  const hasBoundary = rule.boundary !== void 0;
103
- const hasConsumerTxn = rule.consumer?.transitionId !== void 0;
104
- if (hasKind && (hasBoundary || hasConsumerTxn)) {
138
+ const hasTransition = rule.consumer?.transitionId !== void 0 || rule.provider?.transitionId !== void 0;
139
+ if (hasKind && (hasBoundary || hasTransition)) {
105
140
  return null;
106
141
  }
107
- return "narrow-scope rule must specify kind AND (boundary OR consumer.transitionId); set scope: 'broad' to silence wider categories";
142
+ return "narrow-scope rule must specify kind AND (boundary OR consumer.transitionId OR provider.transitionId); set scope: 'broad' to silence wider categories";
108
143
  }
109
144
  function normalizeRuleBoundary(raw) {
110
145
  const trimmed = raw.trim();
@@ -404,6 +439,7 @@ export {
404
439
  ConfidenceInfoSchema,
405
440
  ConfidenceLevelSchema,
406
441
  ConfidenceSourceSchema,
442
+ CorroborationSchema,
407
443
  FunctionCallSemanticsSchema,
408
444
  GraphqlOperationSemanticsSchema,
409
445
  GraphqlResolverSemanticsSchema,
@@ -419,6 +455,8 @@ export {
419
455
  applySuppressionsToFindings,
420
456
  bodyShapesMatch,
421
457
  boundaryKey,
458
+ busesAgree,
459
+ channelsPair,
422
460
  countsForThreshold,
423
461
  functionCallBinding,
424
462
  graphqlOperationBinding,
@@ -427,6 +465,7 @@ export {
427
465
  normalizePath,
428
466
  normalizeRuleBoundary,
429
467
  packageExportBinding,
468
+ parseChannel,
430
469
  restBinding,
431
470
  ruleBoundaryMatchesKey,
432
471
  runtimeConfigBinding,
package/dist/schemas.cjs CHANGED
@@ -24,6 +24,7 @@ __export(schemas_exports, {
24
24
  ConfidenceInfoSchema: () => ConfidenceInfoSchema,
25
25
  ConfidenceLevelSchema: () => ConfidenceLevelSchema,
26
26
  ConfidenceSourceSchema: () => ConfidenceSourceSchema,
27
+ CorroborationSchema: () => CorroborationSchema,
27
28
  FunctionCallSemanticsSchema: () => FunctionCallSemanticsSchema,
28
29
  GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
29
30
  GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
@@ -44,9 +45,19 @@ var ConfidenceSourceSchema = import_zod.z.enum([
44
45
  "derived"
45
46
  ]);
46
47
  var ConfidenceLevelSchema = import_zod.z.enum(["high", "medium", "low"]);
48
+ var CorroborationSchema = import_zod.z.object({
49
+ outcome: import_zod.z.enum(["observed", "refuted", "untested"]),
50
+ /** Executions that produced a verdict for this claim. */
51
+ runs: import_zod.z.number(),
52
+ /** Present when refuted: the input and observation that disagreed. */
53
+ counterexample: import_zod.z.unknown().optional(),
54
+ /** Present when untested: why no verdict was reachable. */
55
+ reason: import_zod.z.string().optional()
56
+ });
47
57
  var ConfidenceInfoSchema = import_zod.z.object({
48
58
  source: ConfidenceSourceSchema,
49
- level: ConfidenceLevelSchema
59
+ level: ConfidenceLevelSchema,
60
+ corroboration: CorroborationSchema.optional()
50
61
  });
51
62
  var SourceLocationSchema = import_zod.z.object({
52
63
  file: import_zod.z.string(),
@@ -190,6 +201,7 @@ var TypeShapeSchema = import_zod.z.lazy(
190
201
  ConfidenceInfoSchema,
191
202
  ConfidenceLevelSchema,
192
203
  ConfidenceSourceSchema,
204
+ CorroborationSchema,
193
205
  FunctionCallSemanticsSchema,
194
206
  GraphqlOperationSemanticsSchema,
195
207
  GraphqlResolverSemanticsSchema,
@@ -11,6 +11,29 @@ declare const ConfidenceLevelSchema: z.ZodEnum<{
11
11
  medium: "medium";
12
12
  low: "low";
13
13
  }>;
14
+ /**
15
+ * The result of corroborating a claim against real execution
16
+ * (`suss corroborate`): generated inputs satisfying the claim's own
17
+ * conditions were run through the actual function and the observation
18
+ * either agreed every time (`observed`), disagreed at least once
19
+ * (`refuted` — an extractor bug or a genuine surprise; the
20
+ * counterexample says which input), or never produced a verdict
21
+ * (`untested` — no satisfying input was found, or every satisfying
22
+ * run hit a dependency the harness cannot supply).
23
+ *
24
+ * Corroboration upgrades a *derivation* with *observations*; it is
25
+ * additive evidence, never a rewrite of the derived claim.
26
+ */
27
+ declare const CorroborationSchema: z.ZodObject<{
28
+ outcome: z.ZodEnum<{
29
+ observed: "observed";
30
+ refuted: "refuted";
31
+ untested: "untested";
32
+ }>;
33
+ runs: z.ZodNumber;
34
+ counterexample: z.ZodOptional<z.ZodUnknown>;
35
+ reason: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strip>;
14
37
  declare const ConfidenceInfoSchema: z.ZodObject<{
15
38
  source: z.ZodEnum<{
16
39
  inferred_static: "inferred_static";
@@ -23,6 +46,16 @@ declare const ConfidenceInfoSchema: z.ZodObject<{
23
46
  medium: "medium";
24
47
  low: "low";
25
48
  }>;
49
+ corroboration: z.ZodOptional<z.ZodObject<{
50
+ outcome: z.ZodEnum<{
51
+ observed: "observed";
52
+ refuted: "refuted";
53
+ untested: "untested";
54
+ }>;
55
+ runs: z.ZodNumber;
56
+ counterexample: z.ZodOptional<z.ZodUnknown>;
57
+ reason: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>>;
26
59
  }, z.core.$strip>;
27
60
  declare const SourceLocationSchema: z.ZodObject<{
28
61
  file: z.ZodString;
@@ -269,4 +302,4 @@ type TypeShape = {
269
302
  };
270
303
  declare const TypeShapeSchema: z.ZodType<TypeShape>;
271
304
 
272
- export { BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, SemanticsSchema, SourceLocationSchema, StorageRelationalSemanticsSchema, type TypeShape, TypeShapeSchema };
305
+ export { BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, CorroborationSchema, FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, SemanticsSchema, SourceLocationSchema, StorageRelationalSemanticsSchema, type TypeShape, TypeShapeSchema };
package/dist/schemas.d.ts CHANGED
@@ -11,6 +11,29 @@ declare const ConfidenceLevelSchema: z.ZodEnum<{
11
11
  medium: "medium";
12
12
  low: "low";
13
13
  }>;
14
+ /**
15
+ * The result of corroborating a claim against real execution
16
+ * (`suss corroborate`): generated inputs satisfying the claim's own
17
+ * conditions were run through the actual function and the observation
18
+ * either agreed every time (`observed`), disagreed at least once
19
+ * (`refuted` — an extractor bug or a genuine surprise; the
20
+ * counterexample says which input), or never produced a verdict
21
+ * (`untested` — no satisfying input was found, or every satisfying
22
+ * run hit a dependency the harness cannot supply).
23
+ *
24
+ * Corroboration upgrades a *derivation* with *observations*; it is
25
+ * additive evidence, never a rewrite of the derived claim.
26
+ */
27
+ declare const CorroborationSchema: z.ZodObject<{
28
+ outcome: z.ZodEnum<{
29
+ observed: "observed";
30
+ refuted: "refuted";
31
+ untested: "untested";
32
+ }>;
33
+ runs: z.ZodNumber;
34
+ counterexample: z.ZodOptional<z.ZodUnknown>;
35
+ reason: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strip>;
14
37
  declare const ConfidenceInfoSchema: z.ZodObject<{
15
38
  source: z.ZodEnum<{
16
39
  inferred_static: "inferred_static";
@@ -23,6 +46,16 @@ declare const ConfidenceInfoSchema: z.ZodObject<{
23
46
  medium: "medium";
24
47
  low: "low";
25
48
  }>;
49
+ corroboration: z.ZodOptional<z.ZodObject<{
50
+ outcome: z.ZodEnum<{
51
+ observed: "observed";
52
+ refuted: "refuted";
53
+ untested: "untested";
54
+ }>;
55
+ runs: z.ZodNumber;
56
+ counterexample: z.ZodOptional<z.ZodUnknown>;
57
+ reason: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>>;
26
59
  }, z.core.$strip>;
27
60
  declare const SourceLocationSchema: z.ZodObject<{
28
61
  file: z.ZodString;
@@ -269,4 +302,4 @@ type TypeShape = {
269
302
  };
270
303
  declare const TypeShapeSchema: z.ZodType<TypeShape>;
271
304
 
272
- export { BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, SemanticsSchema, SourceLocationSchema, StorageRelationalSemanticsSchema, type TypeShape, TypeShapeSchema };
305
+ export { BoundaryBindingSchema, ConfidenceInfoSchema, ConfidenceLevelSchema, ConfidenceSourceSchema, CorroborationSchema, FunctionCallSemanticsSchema, GraphqlOperationSemanticsSchema, GraphqlResolverSemanticsSchema, MessageBusSemanticsSchema, RestSemanticsSchema, RuntimeConfigSemanticsSchema, SemanticsSchema, SourceLocationSchema, StorageRelationalSemanticsSchema, type TypeShape, TypeShapeSchema };
package/dist/schemas.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  ConfidenceInfoSchema,
4
4
  ConfidenceLevelSchema,
5
5
  ConfidenceSourceSchema,
6
+ CorroborationSchema,
6
7
  FunctionCallSemanticsSchema,
7
8
  GraphqlOperationSemanticsSchema,
8
9
  GraphqlResolverSemanticsSchema,
@@ -13,12 +14,13 @@ import {
13
14
  SourceLocationSchema,
14
15
  StorageRelationalSemanticsSchema,
15
16
  TypeShapeSchema
16
- } from "./chunk-BWK3IPL7.js";
17
+ } from "./chunk-BQEWYFCF.js";
17
18
  export {
18
19
  BoundaryBindingSchema,
19
20
  ConfidenceInfoSchema,
20
21
  ConfidenceLevelSchema,
21
22
  ConfidenceSourceSchema,
23
+ CorroborationSchema,
22
24
  FunctionCallSemanticsSchema,
23
25
  GraphqlOperationSemanticsSchema,
24
26
  GraphqlResolverSemanticsSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/ir-core",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "description": "Shared IR primitives for suss — type shapes, boundary bindings, source locations, and confidence. Imported by both @suss/behavioral-ir and @suss/intent-ir so neither depends on the other.",
6
6
  "keywords": [