@suss/ir-core 0.33.1 → 0.34.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.d.cts CHANGED
@@ -1,22 +1,22 @@
1
1
  import { z } from 'zod';
2
- import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-CIns0fqF.cjs';
3
- export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, R as RestSemantics, l as RestSemanticsSchema, m as RuntimeConfigSemantics, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, p as StorageSemantics, q as StorageSemanticsSchema, r as TypeShapeSchema, s as ecsContainerInstanceName, t as methodsAgree, u as normalizePath, v as pathShape, w as routePathAdmits, x as routePathsMeet, y as storageContainerLabel, z as storageLabel, A as storageSystemLabel, H as typeDefinitionKey, I as withDefinitionsInlined } from './schemas-CIns0fqF.cjs';
2
+ import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-lfg8kvak.cjs';
3
+ export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, R as RestSemantics, l as RestSemanticsSchema, m as RuntimeConfigSemantics, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, p as StorageSemantics, q as StorageSemanticsSchema, r as TypeShapeSchema, s as ecsContainerInstanceName, t as isModuleName, u as methodsAgree, v as normalizePath, w as pathShape, x as routePathAdmits, y as routePathsMeet, z as storageContainerLabel, A as storageLabel, H as storageSystemLabel, I as typeDefinitionKey, J as withDefinitionsInlined } from './schemas-lfg8kvak.cjs';
4
4
 
5
5
  /**
6
6
  * The boundary-name syntax, parsed and printed in one place.
7
7
  *
8
- * A name in a summary means one of three things, told apart by the
9
- * braces alone: a literal (`orders-v1`), a pattern with deploy-time
10
- * holes (`{stage}-orders-v1`), or a reference saying where to go and
11
- * ask (`{location.bucket}`, `{ORDER_TABLE}`). A second parser can
12
- * disagree about which is which, and a second printer can spell a
13
- * value this one cannot read back, so everything that touches the
14
- * braces calls this module: `parseBoundaryName` and
15
- * `boundaryNameString` are the two directions, and the helpers below
16
- * are views over them. The package README tells the longer story,
17
- * including why REST route paths and message-bus channels stay apart.
18
- */
19
- /** One piece of a pattern: text the writer stated, or a hole. */
8
+ * A name in a summary is one of three things, and the braces alone tell
9
+ * them apart: a literal (`orders-v1`), a pattern with holes a deployment
10
+ * fills (`{stage}-orders-v1`), or a reference that says where to look
11
+ * the name up (`{location.bucket}`, `{ORDER_TABLE}`). A second parser
12
+ * could classify a string differently, and a second printer could write
13
+ * a string this parser cannot read back. So all code that reads or
14
+ * writes the braces goes through `parseBoundaryName` and
15
+ * `boundaryNameString`, and the other helpers here are built on those
16
+ * two. The package README has the longer explanation, including why
17
+ * REST route paths and message-bus channels are handled separately.
18
+ */
19
+ /** One piece of a pattern: fixed text, or a hole. */
20
20
  type NamePart = {
21
21
  type: "text";
22
22
  text: string;
@@ -25,10 +25,10 @@ type NamePart = {
25
25
  label: string;
26
26
  };
27
27
  /**
28
- * What a name string means. A `reference` keeps its raw dot-separated
29
- * path, and `referenceOf` is the view that checks the parts are all
30
- * present, so a malformed spelling still classifies as a reference and
31
- * still pairs with nothing.
28
+ * A parsed boundary name. A `reference` keeps its raw dot-separated
29
+ * path, and `referenceOf` checks that every part is present. A
30
+ * malformed reference still classifies as a reference, so it still
31
+ * pairs with nothing.
32
32
  */
33
33
  type BoundaryName = {
34
34
  type: "literal";
@@ -40,97 +40,88 @@ type BoundaryName = {
40
40
  type: "reference";
41
41
  path: string[];
42
42
  };
43
- /** What a name string means. The exact inverse of `boundaryNameString`. */
43
+ /** Parse a name string. The exact inverse of `boundaryNameString`. */
44
44
  declare function parseBoundaryName(name: string): BoundaryName;
45
- /** The one serializer. Everything a summary spells goes through here. */
45
+ /** The name as a summary writes it. The exact inverse of `parseBoundaryName`. */
46
46
  declare function boundaryNameString(name: BoundaryName): string;
47
47
  /**
48
- * How a hole is spelled. A reader that assembles a pattern a part at a
49
- * time, the way the adapter's name reader does, mints each hole here
50
- * so the spelling cannot drift from the parse above.
48
+ * The string for one hole. Code that builds a pattern one part at a
49
+ * time calls this for each hole, so the result always parses back.
51
50
  */
52
51
  declare function patternHole(label: string): string;
53
52
  /**
54
- * The name a CloudFormation `Fn::Sub` value states. The array form
55
- * takes its template from the first element, and the variable map only
56
- * says where a substitution comes from, which does not change the name.
53
+ * The name pattern a CloudFormation `Fn::Sub` value produces, with each
54
+ * `${X}` turned into a hole. In the array form the template is the
55
+ * first element. The variable map only gives each substitution's
56
+ * source, which does not change the pattern.
57
57
  */
58
58
  declare function namePatternFromSub(value: unknown): string | null;
59
59
  /**
60
- * Whether a name says only that somebody else knows it. A wrapper that
61
- * takes its bucket as an argument states `{location.bucket}` and
62
- * nothing more, which says which parameter to ask rather than which
63
- * bucket. A name like that agrees with nothing until something grounds
64
- * it, since otherwise it would agree with every name there is.
60
+ * Whether a name is a reference, which gives where to look the name up
61
+ * and not the name itself. A wrapper that takes its bucket as an
62
+ * argument writes `{location.bucket}`. Such a name agrees with nothing
63
+ * until it is grounded, since otherwise it would agree with every name.
65
64
  */
66
65
  declare function namesNothing(name: string): boolean;
67
- /** Whether a name has anything a source left for deploy time to fill. */
66
+ /** Whether a name has any hole left for the deployment to fill. */
68
67
  declare function hasNameHole(name: string): boolean;
69
68
  /**
70
- * The form two patterns are compared in: every hole reduced to the same
71
- * token, since the two sides pick their own name for the parameter.
69
+ * The name with every hole label blanked, for comparing two patterns.
70
+ * Each side chooses its own label for a parameter, so labels never
71
+ * decide a match.
72
72
  */
73
73
  declare function namePatternKey(name: string): string;
74
- /** How much of a name the writer stated rather than left for deploy time. */
74
+ /** How many characters of fixed text a name has. A reference has none. */
75
75
  declare function fixedTextLength(name: string): number;
76
76
  /**
77
77
  * Whether two names are the same name. Two patterns agree when their
78
78
  * fixed parts line up, since a hole on one side meets a hole on the
79
- * other. A pattern and a concrete name agree when the fixed parts are
80
- * where the pattern says they are, which is what happens when one side
81
- * hardcoded what the other parameterized. A reference agrees with
82
- * nothing on either side.
79
+ * other. A pattern and a concrete name agree when the fixed text is
80
+ * where the pattern puts it. That happens when one side hardcoded what
81
+ * the other parameterized. A reference agrees with nothing.
83
82
  */
84
83
  declare function namesAgree(a: string, b: string): boolean;
85
- /** Where a reference says to go and ask. */
84
+ /** A parsed reference: the value the code starts from, and the fields it reads inside it. */
86
85
  interface Reference {
87
86
  /**
88
- * The value the code starts from: a parameter of the unit the
89
- * reference was written in, or a variable the deployment sets. Which
90
- * of those it is depends on the unit's inputs, so the reader that
91
- * grounds a reference decides, not the string.
87
+ * A parameter of the unit the reference was written in, or a variable
88
+ * the deployment sets. The string does not record which. The grounding
89
+ * pass works that out from the unit's inputs.
92
90
  */
93
91
  root: string;
94
- /** The fields to read inside it, outermost first. */
92
+ /** The fields read inside the root, outermost first. */
95
93
  fields: string[];
96
94
  }
97
95
  /**
98
- * How a reference is written. Null when a part of it is empty, since a
99
- * reference has to say what to ask about.
96
+ * The string for a reference, such as `{location.bucket}`. Null when
97
+ * any part is empty, since such a reference could never be settled.
100
98
  */
101
99
  declare function referenceName(reference: Reference): string | null;
102
100
  /**
103
- * The place a parsed reference says to ask, or null for a name that is
104
- * not a reference, or for a reference with a part missing, which says
105
- * nothing anybody could answer.
101
+ * The `Reference` in a parsed name. Null when the name is not a
102
+ * reference, or when a part of it is empty and nothing could settle it.
106
103
  */
107
104
  declare function referenceOf(name: BoundaryName): Reference | null;
108
- /**
109
- * The reference a name states, or null when the name states a name
110
- * rather than where to go and ask.
111
- */
105
+ /** The `Reference` in a name string, or null when the name is a literal or a pattern. */
112
106
  declare function referenceFromName(name: string): Reference | null;
113
107
 
114
108
  /**
115
- * What the deployment running a piece of code fills its variables in
116
- * with.
109
+ * The values a deployment sets for the variables its code reads.
117
110
  *
118
111
  * A queue URL, a function name and a table name only exist once a stack
119
112
  * is deployed, so the source reaches them through a variable and the
120
- * template says what that variable is. Every protocol whose name has a
121
- * hole in it asks the same two questions here, and whoever knows which
122
- * deployment runs the code fills them in.
113
+ * template sets that variable. A protocol whose boundary name has a
114
+ * hole in it looks the hole up through this interface.
123
115
  *
124
- * The interface is declared next to the protocols because a protocol
125
- * has to ask without knowing what a summary is. `@suss/behavioral-ir`
126
- * works the values out from a set of summaries.
116
+ * The interface is declared in ir-core so a protocol can use it without
117
+ * depending on the summary types. `@suss/behavioral-ir` implements it
118
+ * from a set of summaries.
127
119
  */
128
120
 
129
121
  interface Deployment {
130
122
  /**
131
- * Which variable a reference asks about, or null when what settles it
132
- * is an argument a caller passes rather than anything the deployment
133
- * says.
123
+ * The variable a reference points at. Null when a caller's argument
124
+ * settles the reference and the deployment has no say in it.
134
125
  */
135
126
  variableFor(reference: Reference): string | null;
136
127
  /**
@@ -140,11 +131,10 @@ interface Deployment {
140
131
  */
141
132
  setTo(reference: Reference): string | null;
142
133
  /**
143
- * The declared resource this deployment wires that variable to, by
144
- * the name the resource is declared under. A template that writes
145
- * `!Ref ArchiveWorker` says which unit an invoke reaches without ever
146
- * writing the deployed function's name, and that logical id is what
147
- * the unit's own summary is keyed by.
134
+ * The logical id of the declared resource this deployment wires the
135
+ * variable to. A template that writes `!Ref ArchiveWorker` never gives
136
+ * the deployed function's name, but the unit's own summary is keyed by
137
+ * that logical id, so an invoke can still be matched to its unit.
148
138
  */
149
139
  pointsAt(reference: Reference): string | null;
150
140
  }
@@ -152,56 +142,49 @@ interface Deployment {
152
142
  declare const NOTHING_DEPLOYED: Deployment;
153
143
 
154
144
  /**
155
- * Comparing two TypeShapes structurally.
145
+ * Structural comparison of two TypeShapes.
156
146
  *
157
- * Both checkers do this. The behavioural checker compares a provider
158
- * body against a declared contract, and the intent checker compares a
159
- * code body against declared intent, and the two have to reach the same
160
- * verdict for the same pair. The comparison is here, next to the
161
- * TypeShape it works on, so neither checker owns it and the two cannot
162
- * drift apart.
147
+ * The behavioral checker compares a provider body against a declared
148
+ * contract, and the intent checker compares a code body against declared
149
+ * intent. The two have to reach the same verdict for the same pair, so
150
+ * the comparison is defined next to TypeShape and both checkers import
151
+ * it.
163
152
  *
164
- * The comparison is asymmetric, and the answer has three values rather
165
- * than two. `unknown` is what keeps a shape nobody can see into from
166
- * being reported as agreement.
153
+ * The comparison is asymmetric and has three results. `unknown` keeps a
154
+ * shape that cannot be inspected from being reported as a match.
167
155
  */
168
156
 
169
157
  /**
170
- * A comparison result with three values:
158
+ * The result of comparing two shapes:
171
159
  * - "match": `actual` satisfies `declared`
172
- * - "nomatch": there is a concrete, verifiable incompatibility
173
- * - "unknown": uncertainty that would otherwise mask a mismatch
174
- * (spreads, refs, unknown shapes)
160
+ * - "nomatch": the shapes have a specific, checkable incompatibility
161
+ * - "unknown": part of a shape cannot be inspected (a spread, a ref, an
162
+ * unknown shape), and calling it a match could hide a mismatch
175
163
  */
176
164
  type MatchResult = "match" | "nomatch" | "unknown";
177
165
  /**
178
- * Compare an actual body against a declared body and say whether the
179
- * actual satisfies the declared.
166
+ * Whether an actual body satisfies a declared body.
180
167
  *
181
- * The two sides are not interchangeable. `actual` is the value that gets
168
+ * The arguments are not interchangeable. `actual` is the value that is
182
169
  * produced (a response body, a return value), and `declared` is the
183
- * contract it has to conform to. `unknown` is a soft signal, and the
184
- * caller decides whether to show it.
170
+ * contract it has to conform to. The caller decides whether to report
171
+ * an `"unknown"` result.
185
172
  */
186
173
  declare function bodyShapesMatch(actual: TypeShape, declared: TypeShape): MatchResult;
187
174
 
188
175
  /**
189
- * The contract a boundary protocol implements.
190
- *
191
- * A protocol (REST, message-bus, one side of GraphQL) is a single
192
- * module in this directory. Its schema says what the identity fields
193
- * are, its behavior says how those fields key and agree, and the two
194
- * travel together so neither can be added without the other. Nothing
195
- * outside a protocol's own module decides how its boundaries behave.
176
+ * The interface a boundary protocol implements.
196
177
  *
197
- * These definitions ship with ir-core rather than with the packs,
198
- * because a published summary has to mean the same thing to a reader
199
- * who never installed the pack that wrote it. If a pack needs a
200
- * protocol nobody has defined yet, add a module here.
178
+ * Each protocol (REST, message-bus, one side of GraphQL) is one module
179
+ * in this directory. Its schema lists the identity fields, and its
180
+ * behavior defines how those fields key and agree. The two are defined
181
+ * together, so neither can be added without the other.
201
182
  *
202
- * A protocol also says which of its words come from OpenTelemetry's
203
- * semantic conventions, in `semconv`. The README says why that
204
- * matters and where it stops.
183
+ * The definitions ship with ir-core and not with the packs, because a
184
+ * published summary has to mean the same thing to a reader who never
185
+ * installed the pack that wrote it. A pack that needs a new protocol
186
+ * adds a module here. Each protocol also maps its fields to
187
+ * OpenTelemetry attributes in `semconv`, as the package README explains.
205
188
  */
206
189
 
207
190
  /** One identity field written as an OpenTelemetry attribute. */
@@ -209,16 +192,16 @@ interface SemconvAttribute {
209
192
  /** The attribute name, as the semantic conventions spell it. */
210
193
  name: string;
211
194
  /**
212
- * Values suss writes where the source named none. A span never says
213
- * them, so the projection leaves the attribute off rather than
214
- * emitting a string that could only ever mismatch.
195
+ * Values suss writes when the source gave none. A span never has
196
+ * them, so the projection leaves the attribute out instead of writing
197
+ * a value that could never match.
215
198
  */
216
199
  placeholderValues?: readonly string[];
217
200
  }
218
201
  /**
219
202
  * Which identity fields the semantic conventions have an attribute
220
- * for. A field is absent when they have no attribute for it, or when
221
- * our value is our own string rather than the one a span gets.
203
+ * for. A field is absent when the conventions have no attribute for it,
204
+ * or when suss writes its own value there instead of the one a span gets.
222
205
  */
223
206
  type SemconvMapping<S extends {
224
207
  name: string;
@@ -226,9 +209,9 @@ type SemconvMapping<S extends {
226
209
  readonly [K in Exclude<keyof S, "name">]?: SemconvAttribute;
227
210
  };
228
211
  /**
229
- * How one semantics variant keys its boundaries and pairs them up. Each
230
- * variant fills this in inside its own module, and nothing else in the
231
- * tree gets a say in how a boundary keys or agrees.
212
+ * How one protocol keys its boundaries and pairs them up. Each protocol
213
+ * implements this in its own module, and every rule for how its
214
+ * boundaries key or agree is defined there.
232
215
  */
233
216
  interface BoundaryBehavior<S extends {
234
217
  name: string;
@@ -244,10 +227,17 @@ interface BoundaryBehavior<S extends {
244
227
  */
245
228
  pairingKey?(semantics: S): string | null;
246
229
  /**
247
- * Settles whatever `pairingKey` left out of the bucket. A variant that
248
- * does not define it always agrees.
230
+ * Compares the fields `pairingKey` left out of the bucket. When a
231
+ * protocol does not define it, every pair in a bucket agrees.
249
232
  */
250
233
  sidesAgree?(a: S, b: S): boolean;
234
+ /**
235
+ * The key two providers of one operation share, such as a handler and
236
+ * the spec that documents it. Defaults to `identityKey`. Leave out
237
+ * what two sources can spell differently without serving different
238
+ * requests: REST drops parameter names, so `{id}` meets `:pk`.
239
+ */
240
+ operationKey?(semantics: S): string | null;
251
241
  /**
252
242
  * Whether this boundary's bucket can meet buckets with other keys. A
253
243
  * REST path with a hole that spans some number of segments has a key
@@ -260,85 +250,89 @@ interface BoundaryBehavior<S extends {
260
250
  /** Whether two buckets describe at least one boundary in common. */
261
251
  bucketsMeet?(a: S, b: S): boolean;
262
252
  /**
263
- * How narrowly this bucket states what it serves, compared
264
- * lexicographically. When a consumer meets more than one bucket, the
265
- * one ranking highest is the one it reaches, and an even contest is
266
- * reported rather than paired.
253
+ * How well a provider fits what a consumer states, compared
254
+ * lexicographically. When a consumer meets more than one provider
255
+ * bucket, it reaches the one ranked highest, and a tie is reported
256
+ * instead of paired. Null when the two meet only by a guess the
257
+ * consumer gives no ground for, so they do not pair.
267
258
  */
268
- bucketRank?(semantics: S): readonly number[];
269
- /** The line a reader sees for this boundary. Defaults to `identityKey`. */
259
+ pairRank?(provider: S, consumer: S): readonly number[] | null;
260
+ /** The label a reader sees for this boundary. Defaults to `identityKey`. */
270
261
  displayLabel?(semantics: S): string | null;
271
262
  /**
272
- * The semantics with any filesystem path it states rewritten, for
273
- * the pass that makes a summary's paths project-relative. A
274
- * protocol that states no path declares nothing here.
263
+ * The semantics with every filesystem path in it rewritten, for the
264
+ * pass that makes a summary's paths project-relative. A protocol
265
+ * without paths leaves this undefined.
275
266
  */
276
267
  rewritePaths?(semantics: S, rewrite: (path: string) => string): S;
277
268
  /**
278
- * The first protocol whose `claims` returns true normalizes a
279
- * hand-written suppression boundary, and a string nobody claims is
280
- * compared byte for byte. A protocol whose keys are exact declares
281
- * nothing here and stays verbatim.
269
+ * How a hand-written suppression boundary is normalized. The first
270
+ * protocol whose `claims` returns true normalizes the string, and a
271
+ * string no protocol claims is compared byte for byte. A protocol
272
+ * whose keys compare exactly leaves this undefined.
282
273
  */
283
274
  ruleBoundary?: {
284
275
  claims(raw: string): boolean;
285
276
  normalize(raw: string): string;
286
277
  };
287
278
  /**
288
- * A protocol whose boundaries have no URL leaves this undefined, which
289
- * is different from an "unknown" result: undefined means the question
290
- * does not apply, and unknown means this declaration cannot settle it.
279
+ * Whether this boundary serves a request with the given method and
280
+ * path. A protocol whose boundaries have no URL leaves this undefined.
281
+ * Undefined means the question does not apply, and an `"unknown"`
282
+ * result means this declaration cannot settle it.
291
283
  */
292
284
  servesRequest?(semantics: S, method: string, path: string): MatchResult;
293
285
  /**
294
286
  * Whether every request this boundary takes falls inside a pattern
295
287
  * something else was registered for. Middleware registered for
296
288
  * `/v1/*` runs for `/v1/tenants/{id}` and not for `/health`, so
297
- * composing it into a unit asks this first.
289
+ * composing middleware into a unit checks this first.
298
290
  *
299
291
  * A protocol whose boundaries no pattern addresses leaves this
300
292
  * undefined, and nothing registered with a pattern reaches them.
301
293
  */
302
294
  withinScope?(semantics: S, scope: string): boolean;
303
295
  /**
304
- * The same boundary with a name the deployment fills in put in.
296
+ * The same boundary with the deployment's values filled into its name.
305
297
  *
306
298
  * A call written as `fetch(`${process.env.API_BASE}/orders`)` gets
307
299
  * part of its boundary from the source and part from whatever runs
308
- * the code. Both parts have to be in before anybody can see that the
309
- * two sides describe one boundary.
300
+ * the code. Both parts are needed before the two sides can be matched
301
+ * as one boundary.
310
302
  *
311
303
  * `deployment` is already scoped to the unit this boundary belongs
312
- * to. A protocol hands over the reference its name states and gets
313
- * back what fills it in, or null. Return null to leave it as it is,
314
- * which is right whenever nothing needs filling in or nothing can
315
- * fill it.
316
- *
317
- * A protocol whose names are settled in the source leaves this
318
- * undefined.
304
+ * to. The protocol looks up the reference in its name through it.
305
+ * Return null to leave the semantics unchanged, when nothing needs
306
+ * filling in or nothing can fill it. A protocol whose names are fixed
307
+ * in the source leaves this undefined.
319
308
  */
320
309
  groundName?(semantics: S, deployment: Deployment): S | null;
321
310
  /**
322
- * Where this boundary's name says to go and ask, when it says that
323
- * rather than a name. A caller that has to explain why two sides did
324
- * not meet reads it to say which input would settle them.
311
+ * The reference in this boundary's name, when the name is a
312
+ * reference. A caller explaining why two sides did not pair uses it
313
+ * to say which input would settle the name.
325
314
  *
326
- * A protocol that defines `groundName` defines this too, and the
327
- * same reference is what `groundName` hands over.
315
+ * A protocol that defines `groundName` defines this too, and
316
+ * `groundName` looks up the same reference.
328
317
  */
329
318
  nameReference?(semantics: S): Reference | null;
319
+ /**
320
+ * The semantics with a host the project says it serves left out of
321
+ * the name, or null when the name has none of them. A protocol whose
322
+ * names never carry a host leaves this undefined.
323
+ */
324
+ withoutOwnHost?(semantics: S, ownHosts: ReadonlySet<string>): S | null;
330
325
  /**
331
326
  * Whether a provider produces a status and a body that a consumer
332
- * reads back. Every protocol has to state this, so that one added
333
- * later says what it is instead of landing in the HTTP-style checks
334
- * because nobody remembered to exclude it.
327
+ * reads back. It is required, so a new protocol cannot end up in the
328
+ * HTTP-style checks because nobody remembered to exclude it.
335
329
  */
336
330
  exchangesHttpResponses: boolean;
337
331
  /**
338
- * Whether crossing this boundary leaves the process. A report about
339
- * what a change means for somebody outside the code covers the ones
340
- * that do; a call from one function in a project to another is a
341
- * boundary as well, and a reader has the source diff for that.
332
+ * Whether crossing this boundary leaves the process. A report on what
333
+ * a change means for callers outside the code covers only these. A
334
+ * call between two functions in one project is a boundary too, and a
335
+ * reader has the source diff for it.
342
336
  */
343
337
  leavesTheProcess: boolean;
344
338
  /**
@@ -366,8 +360,8 @@ interface BoundarySemanticsDefinition<Z extends z.ZodType<{
366
360
  schema: Z;
367
361
  behavior: BoundaryBehavior<z.infer<Z>>;
368
362
  /**
369
- * Every protocol declares this, empty included, so that adding one
370
- * means deciding where its words come from.
363
+ * Required even when empty, so adding a protocol means deciding which
364
+ * of its fields are OpenTelemetry attributes.
371
365
  */
372
366
  semconv: SemconvMapping<z.infer<Z>>;
373
367
  }
@@ -383,7 +377,7 @@ type FnIdentityKey = `fn:${string}::${string}` & {
383
377
  readonly [IdentityKeyBrand]: "fn";
384
378
  };
385
379
  declare function fnIdentityKey(packageName: string, exportPath: readonly string[]): FnIdentityKey;
386
- /** `bus:technology subject`, with the technology closed off the schema. */
380
+ /** `bus:technology subject`, where the technology is one the message-bus schema allows. */
387
381
  type BusIdentityKey = `bus:${MessageBusSemantics["messageBus"]} ${string}` & {
388
382
  readonly [IdentityKeyBrand]: "bus";
389
383
  };
@@ -402,6 +396,17 @@ type MetricIdentityKey = `metric:${string} ${string}` & {
402
396
  readonly [IdentityKeyBrand]: "metric";
403
397
  };
404
398
  declare function metricIdentityKey(metricSystem: string, metricType: string): MetricIdentityKey;
399
+ /** `io:stream`, the key a write to one of the process's streams has. */
400
+ type IoIdentityKey = `io:${string}` & {
401
+ readonly [IdentityKeyBrand]: "io";
402
+ };
403
+ declare function ioIdentityKey(target: string): IoIdentityKey;
404
+
405
+ declare const IoSemanticsSchema: z.ZodObject<{
406
+ name: z.ZodLiteral<"io">;
407
+ target: z.ZodNullable<z.ZodString>;
408
+ }, z.core.$strip>;
409
+ type IoSemantics = z.infer<typeof IoSemanticsSchema>;
405
410
 
406
411
  declare const MetricSemanticsSchema: z.ZodObject<{
407
412
  name: z.ZodLiteral<"metric">;
@@ -412,9 +417,9 @@ type MetricSemantics = z.infer<typeof MetricSemanticsSchema>;
412
417
 
413
418
  /**
414
419
  * `instanceName` is nullable here and required on the unit itself,
415
- * because only the provider always knows the name. A call that works
416
- * its callee out at run time still happened, and recording it with no
417
- * name says so without pairing it against everything.
420
+ * because only the provider always knows the name. A call that picks
421
+ * its callee at run time still happened. Recording it with a null name
422
+ * keeps the call without pairing it against every unit.
418
423
  */
419
424
  declare const UnitInvocationSemanticsSchema: z.ZodObject<{
420
425
  deploymentTarget: z.ZodEnum<{
@@ -432,31 +437,33 @@ type UnitInvocationSemantics = z.infer<typeof UnitInvocationSemanticsSchema>;
432
437
  /**
433
438
  * A boundary binding read as OpenTelemetry attributes.
434
439
  *
435
- * A summary says what a unit can reach and a span says what it did
436
- * reach. Joining the two means both sides spelling the boundary the
437
- * same way, so suss writes the value a span gets wherever the semantic
438
- * conventions have a word for it, and this projection puts those
439
- * values under the attributes a trace store already indexes.
440
+ * A summary records what a unit can reach and a span records what it
441
+ * did reach. Joining the two means both spell the boundary the same
442
+ * way. suss writes the value a span gets wherever the semantic
443
+ * conventions have a word for it, and this projection puts those values
444
+ * under the attribute names a trace store already indexes.
440
445
  *
441
- * Which fields those are is each protocol's own declaration, in its
442
- * module under `semantics/`. Nothing here knows about any protocol.
446
+ * Each protocol declares its own field-to-attribute mapping next to its
447
+ * definition, so this module has no protocol-specific code.
443
448
  */
444
449
 
445
450
  /**
446
- * The attributes a boundary states, by name. A field the source never
447
- * gave, a placeholder, and a field the conventions have no attribute
448
- * for are all left out, so every pair here compares byte for byte
449
- * against the same attribute on a span.
451
+ * The binding's OpenTelemetry attributes, keyed by attribute name.
452
+ *
453
+ * A field the source never gave is left out, and so is a placeholder
454
+ * value or a field the conventions have no attribute for. Every value
455
+ * returned compares byte for byte against the same attribute on a span.
450
456
  */
451
457
  declare function semconvAttributes(binding: BoundaryBinding): Record<string, string>;
452
458
 
453
459
  /**
454
- * What a pack says about itself, for everything that has to know a pack
455
- * exists without reading its patterns.
460
+ * What a pack declares about itself, for tools that list or suggest
461
+ * packs without loading their patterns.
456
462
  *
457
- * `suss init` suggests a pack when it sees the library in a project's
458
- * manifest, and the packages page lists every pack with a line about
459
- * what it reads. Both come from here, so nobody maintains a table.
463
+ * `suss init` suggests a pack when a project's manifest lists the
464
+ * library, and the packages page lists every pack with a line about
465
+ * what it reads. Both read these declarations, so there is no separate
466
+ * table to keep in step with the packs.
460
467
  */
461
468
  /** The manifest a dependency is declared in. */
462
469
  type Ecosystem = "npm" | "pypi" | "rubygems";
@@ -474,6 +481,18 @@ interface PackConfiguration {
474
481
  required: boolean;
475
482
  /** What the value is, in a sentence. */
476
483
  why: string;
484
+ /**
485
+ * What `suss init` writes to `file` when it sets a project up: the
486
+ * values a project the library's own generator made has. Absent when no
487
+ * value suits every project.
488
+ */
489
+ defaults?: Record<string, unknown>;
490
+ /**
491
+ * Reads the values from a file the project already has, so init can
492
+ * write them when there are no defaults. Null when the project does
493
+ * not say.
494
+ */
495
+ readFromProject?: (projectRoot: string) => Record<string, unknown> | null;
477
496
  }
478
497
  interface PackDeclaration {
479
498
  /**
@@ -500,6 +519,13 @@ interface PackDeclaration {
500
519
  * Every project in that language is a candidate.
501
520
  */
502
521
  shippedWith?: "typescript" | "python" | "ruby";
522
+ /**
523
+ * Text in a source file that shows the project calls a library the
524
+ * language ships. No manifest can say that a project uses fetch, so
525
+ * `suss init` looks for a call before it sets up a project on the
526
+ * strength of this pack alone.
527
+ */
528
+ sourcePattern?: RegExp;
503
529
  /** The line the packages page shows, one sentence, what it reads. */
504
530
  reads: string;
505
531
  /** Set when the pack needs a value from the project to run at all. */
@@ -507,23 +533,22 @@ interface PackDeclaration {
507
533
  }
508
534
 
509
535
  /**
510
- * Keys for a boundary binding, and whether two of them agree. Every
511
- * function here asks the binding's protocol and returns whatever it
512
- * says, so the rules themselves are in the protocol's own module under
513
- * `semantics/` and not in this file.
536
+ * Keys for a boundary binding, and whether two bindings agree. Each
537
+ * function looks up the binding's protocol and delegates to it, so the
538
+ * rules are defined with each protocol's semantics.
514
539
  *
515
- * The sharing is the point. The behavioural checker pairs code
516
- * summaries by these keys, and the intent checker pairs intent against
517
- * code by the same keys. If the two ever keyed differently, intent and
518
- * code would stop lining up, so the keying is here next to the binding
519
- * rather than in either checker.
540
+ * The behavioral checker pairs code summaries by these keys, and the
541
+ * intent checker pairs intent against code by the same keys. If the two
542
+ * keyed differently, intent and code would stop lining up, so the
543
+ * keying is defined next to the binding and neither checker has its
544
+ * own.
520
545
  */
521
546
 
522
547
  /**
523
- * Whether a binding is of one protocol, narrowed to that protocol's
524
- * own semantics when it is. A caller reaching through the binding to
525
- * compare the name by hand gets `string | undefined` and no narrowing,
526
- * so a name that no protocol uses compiles and quietly never matches.
548
+ * Whether a binding is of one protocol, narrowing its semantics to that
549
+ * protocol's type. `name` only accepts a protocol that exists. Comparing
550
+ * `binding?.semantics.name` by hand does not narrow, and a misspelled
551
+ * protocol name there compiles and never matches.
527
552
  */
528
553
  declare function bindingIs<N extends Semantics["name"]>(binding: BoundaryBinding | null | undefined, name: N): binding is BoundaryBinding & {
529
554
  semantics: Extract<Semantics, {
@@ -532,51 +557,74 @@ declare function bindingIs<N extends Semantics["name"]>(binding: BoundaryBinding
532
557
  };
533
558
  declare function boundaryKey(binding: BoundaryBinding): string | null;
534
559
  /**
535
- * The binding with any filesystem path its semantics state rewritten.
536
- * The CLI uses it to make a summary's paths project-relative, and each
537
- * protocol says for itself whether it states one.
560
+ * The binding with every filesystem path in its semantics rewritten.
561
+ * The CLI uses it to make a summary's paths project-relative. A binding
562
+ * whose protocol has no paths comes back unchanged.
538
563
  */
539
564
  declare function withRewrittenPaths(binding: BoundaryBinding, rewrite: (path: string) => string): BoundaryBinding;
540
565
  /**
541
- * The bucket a boundary pairs in, with any name the deployment fills in
542
- * put in first.
566
+ * The binding with a host the project serves left out, so a call to
567
+ * the project's public host pairs with its routes.
568
+ */
569
+ declare function withoutOwnHost(binding: BoundaryBinding, ownHosts: ReadonlySet<string>): BoundaryBinding;
570
+ /**
571
+ * The pairing key after the deployment's values are filled into the
572
+ * boundary's name.
543
573
  *
544
- * A consumer that gets its base URL from the runtime states a different
545
- * string from the provider it reaches, and the two are one boundary.
546
- * Every protocol that has such a name says how to fill it in, and one
547
- * whose names are settled in the source keys exactly as before.
574
+ * A consumer that gets its base URL at run time writes a different
575
+ * string from the provider it reaches, though the two are one boundary.
576
+ * A protocol whose names are fixed in the source gets the same key as
577
+ * `pairingKey` would give.
548
578
  */
549
579
  declare function groundedPairingKey(binding: BoundaryBinding, deployment: Deployment): string | null;
550
580
  /**
551
- * The same boundary, with whatever the deployment fills in put in.
581
+ * The same boundary, with the deployment's values filled into its name.
552
582
  *
553
- * Everything that reads a boundary's name for a person to see goes
554
- * through here first: the pairing pass, the drafter that writes an
555
- * intent document, and the intent checker that reads one back. A step
556
- * only one of them took would have the drafter write a name the
557
- * checker then argued with.
583
+ * The pairing pass, the drafter that writes an intent document and the
584
+ * intent checker that reads one back all ground a binding here before
585
+ * reading its name. If only one of them grounded it, the drafter could
586
+ * write a name the checker then disputes.
558
587
  */
559
588
  declare function groundBinding(binding: BoundaryBinding, deployment: Deployment): BoundaryBinding;
560
589
  /**
561
- * Where this boundary's name says to go and ask, or null when the
562
- * source stated a name outright. A report that has to say why two
563
- * sides did not meet reads it to say which input would settle them.
590
+ * The reference in this boundary's name, or null when the source gave
591
+ * the name outright. A report that explains why two sides did not pair
592
+ * uses it to say which input would settle the name.
564
593
  */
565
594
  declare function nameReference(binding: BoundaryBinding): Reference | null;
566
595
  declare function pairingKey(binding: BoundaryBinding): string | null;
596
+ /**
597
+ * The key a handler and a document describing the same operation share.
598
+ * The contract checks match providers to each other on it, since two
599
+ * providers never go through pairing.
600
+ */
601
+ declare function operationKey(binding: BoundaryBinding): string | null;
567
602
  declare function semanticsAgree(a: Semantics, b: Semantics): boolean;
568
603
  /** Whether the binding's bucket can meet buckets with other keys. */
569
604
  declare function spansBuckets(binding: BoundaryBinding): boolean;
570
605
  /** Whether two bindings' buckets describe a boundary in common. */
571
606
  declare function bucketsMeet(a: BoundaryBinding, b: BoundaryBinding): boolean;
572
- /** How narrowly the binding's bucket states what it serves; see `compareRanks`. */
573
- declare function bucketRank(binding: BoundaryBinding): readonly number[];
607
+ /**
608
+ * How well a provider fits what a consumer states, or null when they do
609
+ * not pair; see `compareRanks`. A protocol that does not rank gives
610
+ * every provider the same rank.
611
+ */
612
+ declare function pairRank(provider: BoundaryBinding, consumer: BoundaryBinding): readonly number[] | null;
574
613
  declare function boundaryLabel(binding: BoundaryBinding): string | null;
575
614
  declare function displayLabel(binding: BoundaryBinding): string;
576
615
  /**
577
- * A boundary string that no protocol claims keeps its case, because
578
- * message-bus keys are case-sensitive and uppercasing one would break
579
- * the rule without saying so.
616
+ * The boundary and the name a read took across it, as a report prints
617
+ * them: `runtime-config ACCOUNTS_REGION`. A boundary with no label of its
618
+ * own prints as its protocol, because the name already says what was
619
+ * read, and the recognizer the fallback label adds is a package name
620
+ * nobody reading the report can act on.
621
+ */
622
+ declare function labelWithDetail(binding: BoundaryBinding, detail: string): string;
623
+ /**
624
+ * A suppression rule's boundary string, normalized by the protocol that
625
+ * recognizes it. A string no protocol recognizes keeps its case,
626
+ * because message-bus keys are case-sensitive and uppercasing one would
627
+ * make the rule stop matching without any error.
580
628
  */
581
629
  declare function normalizeRuleBoundary(raw: string): string;
582
630
  declare function exchangesHttpResponses(binding: BoundaryBinding): boolean;
@@ -589,9 +637,11 @@ declare function leavesTheProcess(binding: BoundaryBinding): boolean;
589
637
  declare function canPair(binding: BoundaryBinding): boolean;
590
638
  declare function reportsUnpairedItself(binding: BoundaryBinding): boolean;
591
639
  /**
640
+ * Whether this binding serves a request with the given method and path.
641
+ *
592
642
  * Null means the protocol does not address its boundaries by method and
593
- * path at all, which a caller has to tell apart from an unknown answer:
594
- * unknown means it does, but this declaration cannot settle the question.
643
+ * path at all. A caller has to tell that apart from `"unknown"`, which
644
+ * means the protocol does, but this declaration cannot settle it.
595
645
  */
596
646
  declare function servesRequest(binding: BoundaryBinding, method: string, path: string): MatchResult | null;
597
647
  /**
@@ -602,64 +652,61 @@ declare function servesRequest(binding: BoundaryBinding, method: string, path: s
602
652
  declare function withinScope(binding: BoundaryBinding, scope: string): boolean;
603
653
 
604
654
  /**
605
- * How somebody spells a boundary they want to talk about, and whether
606
- * what they wrote picks out a given one.
655
+ * How a person writes a boundary they want to ask about, and whether
656
+ * what they wrote picks out a given boundary.
607
657
  *
608
- * The words get cut into tokens, the boundary does too, and a boundary
609
- * matches when it has every token somebody wrote. So
658
+ * The text and the boundary are both split into tokens, and a boundary
659
+ * matches when it has every token in the text. So
610
660
  * `aws.dynamodb:editions` matches the table and every index on it, and
611
661
  * adding `#by-publication` narrows it to the one index.
612
662
  *
613
- * `suss ask`, `suss check --at` and an intent document that says which
614
- * store a write reaches all read this, so the question and the
615
- * assertion are spelled and resolved the same way.
663
+ * `suss ask`, `suss check --at` and an intent document that gives the
664
+ * store a write reaches all match through these functions, so a
665
+ * question and an assertion resolve the same way.
616
666
  */
617
667
 
618
668
  /**
619
- * The name inside a fully-qualified cloud resource id, and anything
620
- * else unchanged.
669
+ * The name inside a fully qualified cloud resource id. Any other string
670
+ * comes back unchanged.
621
671
  *
622
672
  * `arn:aws:lambda:us-east-1:1234:function:prod-worker` and
623
- * `projects/p/locations/l/functions/prod-worker` say the same thing as
624
- * `prod-worker` plus an account and a region. Keeping the whole string
625
- * makes one deployment's spelling of a resource disagree with
626
- * another's, so every reader that meets one reduces it here and the two
627
- * sides compare the part they can both know. A Lambda ARN's trailing
628
- * alias or version comes off with the rest: the function is the
629
- * boundary whichever published copy a call reaches.
673
+ * `projects/p/locations/l/functions/prod-worker` are `prod-worker` plus
674
+ * an account and a region. Two deployments of one resource have
675
+ * different full ids, so readers reduce an id to its name here and the
676
+ * two sides compare the part they both know. A Lambda ARN's trailing
677
+ * alias or version is dropped too, since the function is the boundary
678
+ * whichever published version a call reaches.
630
679
  */
631
680
  declare function resourceNameIn(spelling: string): string;
632
681
  /**
633
- * The words in a boundary spelling. Separators between parts of a name
634
- * are cut, and the characters inside one part are left alone, so
635
- * `by-publication` stays one word and `{id}` and `:id` both come out as
636
- * `id`.
682
+ * The lowercase words in a boundary spelling. The text is split at the
683
+ * separators between parts of a name, and each part is kept whole, so
684
+ * `by-publication` stays one word and `{id}` and `:id` both become `id`.
637
685
  */
638
686
  declare function spellingTokens(text: string): string[];
639
- /** Every word this boundary can be asked about by. */
687
+ /** Every word a person can use to ask about this boundary. */
640
688
  declare function bindingTokens(binding: BoundaryBinding): Set<string>;
641
689
  /**
642
- * Whether what somebody typed is the whole of this boundary's name
643
- * rather than part of it. `POST /articles` is exactly the collection
644
- * route and only part of `POST /articles/{slug}/comments`.
690
+ * Whether the typed text has every word of this boundary's label and
691
+ * nothing more. `POST /articles` matches the collection route exactly,
692
+ * and only partly matches `POST /articles/{slug}/comments`.
645
693
  */
646
694
  declare function namesBoundaryExactly(subject: string, binding: BoundaryBinding): boolean;
647
- /** Whether what somebody typed picks out this boundary. */
695
+ /** Whether the typed text picks out this boundary: every word in it is one of the boundary's words. */
648
696
  declare function namesBoundary(subject: string, binding: BoundaryBinding): boolean;
649
697
 
650
698
  /**
651
- * Deciding when two message-bus channel strings mean the same thing.
699
+ * When two message-bus channel strings mean the same channel.
652
700
  *
653
- * A channel is a subject, optionally qualified by the bus that carries
654
- * it, written `${bus}#${subject}`. The two sides of a pairing rarely
655
- * know the same amount, so they pair on the subject and the buses have
656
- * to agree only when both sides know one. The package README works
657
- * through why, with examples.
701
+ * A channel is a subject, optionally qualified by the bus it travels
702
+ * on, written `${bus}#${subject}`. The two sides of a pairing rarely
703
+ * know the same amount, so they pair on the subject, and the buses have
704
+ * to match only when both sides know one. The package README explains
705
+ * why, with examples.
658
706
  *
659
- * Everything that writes or reads that string goes through
660
- * `formatChannel` and `parseChannel`, so the wire format has a single
661
- * author. A template reader that hand-writes the `#` would be a second
662
- * author, and the two would drift the first time either one changed.
707
+ * All code that writes or reads the string goes through `formatChannel`
708
+ * and `parseChannel`. A template reader that wrote the `#` by hand would
709
+ * drift from them the first time either one changed.
663
710
  */
664
711
  /** A channel string, written `${bus}#${subject}`, split into its two parts. */
665
712
  interface ParsedChannel {
@@ -669,31 +716,33 @@ interface ParsedChannel {
669
716
  declare function parseChannel(channel: string): ParsedChannel;
670
717
  declare const ChannelBrand: unique symbol;
671
718
  /**
672
- * `bus#subject`, or the bare subject when no source said the bus. The
673
- * unqualified form is legal, so fields keep the type string and the
674
- * mint is the whole win: a channel assembled by hand cannot claim the
675
- * brand, and the format has one spelling (#167).
719
+ * `bus#subject`, or the bare subject when no source gave the bus.
720
+ *
721
+ * Fields that store a channel stay typed as `string`, since a bare
722
+ * subject is legal there. The brand exists so that a `Channel` value
723
+ * can only come from `formatChannel` and never from a string built by
724
+ * hand (#167).
676
725
  */
677
726
  type Channel = string & {
678
727
  readonly [ChannelBrand]: "channel";
679
728
  };
680
729
  declare function formatChannel(bus: string | null, subject: string): Channel;
730
+ /** A side that does not know its bus agrees with any bus. */
681
731
  declare function busesAgree(a: string | null, b: string | null): boolean;
682
732
  declare function channelsPair(a: string, b: string): boolean;
683
733
 
684
734
  /**
685
- * One convention for the source directory a deployable unit is built
686
- * from, one test for whether a file is inside it, and one reading of
687
- * the handler string that says which code the platform calls.
735
+ * The source directory a deployable unit is built from, and the handler
736
+ * string that says which code the platform calls.
688
737
  *
689
- * A deploy template gives a directory per unit, and a summary stores it
738
+ * A deploy template gives each unit a directory, and a summary stores it
690
739
  * as `metadata.codeScope.path`. Producers write that path and the
691
- * checker reads it back as a prefix test, so the two sides have to
692
- * agree on whether it ends in a slash. The test also has to stop at a
693
- * segment boundary, or `src/foo` would cover `src/foobar` and a handler
694
- * would pair with the wrong function. A CloudFormation template and a
695
- * Terraform configuration spell a handler the same way, so they read it
696
- * through the same function rather than through two of them.
740
+ * checker reads it back as a prefix test, so both sides normalize it
741
+ * through `codeScopePath` and agree on the trailing slash. The test
742
+ * stops at a segment boundary, or `src/foo` would cover `src/foobar` and
743
+ * a handler would pair with the wrong function. CloudFormation and
744
+ * Terraform write a handler the same way, so both read it through
745
+ * `parseHandler`.
697
746
  */
698
747
  /**
699
748
  * The canonical form of a code-scope directory: no leading `./`, no
@@ -706,8 +755,8 @@ declare function codeScopePath(raw: string): string;
706
755
  * at a segment boundary, so `src/foo` covers `src/foo/a.ts` and never
707
756
  * `src/foobar/a.ts`. A scope that is the project root covers every file.
708
757
  *
709
- * Both arguments go through `codeScopePath`, so a scope stored with a
710
- * trailing slash and one stored without it are read the same way.
758
+ * Both arguments are normalized with `codeScopePath`, so a trailing
759
+ * slash on either one makes no difference.
711
760
  */
712
761
  declare function fileInCodeScope(file: string, scope: string): boolean;
713
762
  interface ParsedHandler {
@@ -723,13 +772,12 @@ interface ParsedHandler {
723
772
  declare function parseHandler(handler: string): ParsedHandler | null;
724
773
 
725
774
  /**
726
- * The DispatchTable idiom: dispatch on a discriminated union through a
727
- * mapped-type Record, so a missing variant is a type error rather than a
728
- * runtime fall-through. It is decision #8 in design/docs-internal/style.md.
775
+ * Dispatch on a discriminated union through a mapped-type Record, so a
776
+ * table that misses a variant fails to compile. This is decision #8 in
777
+ * the internal style guide.
729
778
  *
730
- * It is here rather than in one package because the decision applies
731
- * repo-wide, and every package that walks an IR union needs it. Three
732
- * of them had written their own copy before this one existed.
779
+ * Every package that walks an IR union needs it, so it lives in ir-core
780
+ * and packages do not keep their own copies.
733
781
  */
734
782
  type DispatchTable<T extends {
735
783
  type: string;
@@ -743,17 +791,16 @@ declare function dispatchByType<T extends {
743
791
  }, R>(table: DispatchTable<T, R>, value: T): R;
744
792
 
745
793
  /**
746
- * The variables a deployment medium puts in a process's environment
794
+ * The variables a deployment platform puts in a process's environment
747
795
  * whatever its configuration says.
748
796
  *
749
- * Code reads them and nothing declares them, so a reader that left them
750
- * out would accuse every deployment of failing to supply `AWS_REGION`.
751
- * Two readers describe the same Lambda, a CloudFormation template and a
752
- * Terraform configuration, and a variable one of them knew about and
753
- * the other did not would be an error in one and not the other, so the
754
- * list is stated once here. A medium whose vendor documents a different
755
- * set per product, Cloud Run's `K_SERVICE` against a plain container's
756
- * nothing, states its own list in the pack that describes it.
797
+ * Code reads them and no template declares them, so without this list
798
+ * every deployment would be reported for failing to supply
799
+ * `AWS_REGION`. A CloudFormation template and a Terraform configuration
800
+ * can describe the same Lambda, and both use this one list so they
801
+ * agree on which variables are present. A platform whose vendor
802
+ * documents a different set per product, such as Cloud Run with its
803
+ * `K_SERVICE`, lists its variables in the pack that describes it.
757
804
  */
758
805
 
759
806
  /**
@@ -767,16 +814,17 @@ declare function dispatchByType<T extends {
767
814
  declare const PLATFORM_INJECTED_ENV_VARS: Record<DeployableUnit["deploymentTarget"], ReadonlyArray<string>>;
768
815
 
769
816
  /**
770
- * What a unit does at a boundary, in the words `suss ask` asks with.
817
+ * What a unit does at a boundary, in the words `suss ask` uses.
771
818
  *
772
- * `what writes postgresql:invoices` is the question and "this outcome
773
- * writes postgresql:invoices" is the assertion, so the report, the
774
- * question parser and an intent doc all have to spell the verbs the
775
- * same way. They are here rather than beside any one of them.
819
+ * A user asks `what writes postgresql:invoices`, and an intent doc
820
+ * asserts "this outcome writes postgresql:invoices". The report, the
821
+ * question parser and the intent reader all have to spell the verbs the
822
+ * same way, so the verbs are defined here once.
776
823
  *
777
- * `provides` is the unit's own boundary; `reads`, `writes` and
778
- * `invokes` are what a call site does at somebody else's. Calling a
779
- * deployed unit by name is one act, so it gets a verb of its own.
824
+ * `provides` is a boundary the unit serves. `reads`, `writes` and
825
+ * `invokes` are what a call site does at a boundary somebody else
826
+ * serves. Calling a deployed unit by name is its own act, so it gets
827
+ * its own verb.
780
828
  */
781
829
 
782
830
  declare const RelationSchema: z.ZodEnum<{
@@ -798,45 +846,45 @@ declare const EffectRelationSchema: z.ZodEnum<{
798
846
  type EffectRelation = z.infer<typeof EffectRelationSchema>;
799
847
 
800
848
  /**
801
- * pathPattern.ts: whether two route paths describe a request in common.
849
+ * Whether two route paths describe a request in common.
802
850
  *
803
851
  * A normalized path is text with holes in it. `{id}` is exactly one
804
852
  * segment, `{tenant?}` is zero or one, `{rest+}` is one or more and
805
853
  * `{rest*}` is zero or more, the modifiers Express puts on `:name`. A
806
854
  * bare `*` segment is zero or more segments, Express 4's reading of a
807
855
  * star. A set piece is written `(v1|v2)` and matches any one of its
808
- * options, and an option can contain a slash.
856
+ * options, and an option can contain a slash. A hole before the first
857
+ * slash is a base URL the client left open, and it matches the origin.
809
858
  *
810
859
  * `pathsMeet` expands the sets into alternatives, splits each one into
811
860
  * segments, and walks the two segment lists with a reachability table
812
861
  * in which a hole absorbs as many segments as its range allows.
813
862
  */
814
- /** How many segments a hole takes, in the words the value domain uses. */
863
+ /** How many segments a hole takes: exactly one, zero or one, one or more, or any number. */
815
864
  type HoleRange = "one" | "optional" | "many" | "any";
816
- /** How a hole taking `range` segments is spelled in a path. */
865
+ /** The path text for a hole that takes `range` segments, such as `{rest+}`. */
817
866
  declare function rangedHole(name: string, range: HoleRange): string;
818
867
  /**
819
- * How a piece that is one of several texts is spelled in a path, or
820
- * null when an option would be read as something else, such as a set
821
- * boundary or the start of a query.
868
+ * The path text for a piece that matches any one of `options`, such as
869
+ * `(v1|v2)`. Null when an option would parse as something else, such as
870
+ * a set boundary or the start of a query.
822
871
  */
823
872
  declare function setPiece(options: readonly string[]): string | null;
824
873
  /** Negative when `a` ranks below `b`, positive above, zero when equal. */
825
874
  declare function compareRanks(a: readonly number[], b: readonly number[]): number;
826
875
 
827
876
  /**
828
- * The suppression pipeline, over the smallest finding both checkers share.
877
+ * Suppression rules and how they apply to findings from either checker.
829
878
  *
830
- * Behavioural `Finding` and intent `IntentFinding` both have `kind`,
831
- * `severity`, and an optional `suppressed`, which is all the pipeline
832
- * needs. The rule schema, first-match-wins matching, effect application,
833
- * and threshold counting are here so the two checkers share one
834
- * implementation without depending on each other. Only the matching of a
835
- * rule's discriminators differs, and a caller passes that in.
879
+ * Behavioral `Finding` and intent `IntentFinding` both have `kind`,
880
+ * `severity` and an optional `suppressed`, and the pipeline needs
881
+ * nothing else. The rule schema, first-match-wins matching, effect
882
+ * application and threshold counting are here so the two checkers share
883
+ * one implementation without depending on each other. Each checker
884
+ * passes in its own matcher for a rule's discriminators past `kind`.
836
885
  *
837
- * The module owns rules and matching, not file I/O. The CLI reads a
838
- * .sussignore file, checks each kind against the published enums, and
839
- * hands the parsed rules over.
886
+ * The CLI reads the `.sussignore` file, checks each kind against the
887
+ * published enums, and passes the parsed rules in.
840
888
  */
841
889
 
842
890
  declare const SuppressionRuleSchema: z.ZodObject<{
@@ -850,6 +898,7 @@ declare const SuppressionRuleSchema: z.ZodObject<{
850
898
  summary: z.ZodOptional<z.ZodString>;
851
899
  transitionId: z.ZodOptional<z.ZodString>;
852
900
  }, z.core.$strip>>;
901
+ scenario: z.ZodOptional<z.ZodString>;
853
902
  scope: z.ZodDefault<z.ZodEnum<{
854
903
  narrow: "narrow";
855
904
  broad: "broad";
@@ -875,6 +924,7 @@ declare const SuppressionFileSchema: z.ZodObject<{
875
924
  summary: z.ZodOptional<z.ZodString>;
876
925
  transitionId: z.ZodOptional<z.ZodString>;
877
926
  }, z.core.$strip>>;
927
+ scenario: z.ZodOptional<z.ZodString>;
878
928
  scope: z.ZodDefault<z.ZodEnum<{
879
929
  narrow: "narrow";
880
930
  broad: "broad";
@@ -897,11 +947,11 @@ interface FindingSuppression {
897
947
  originalSeverity?: SuppressableSeverity | undefined;
898
948
  }
899
949
  /**
900
- * The structural base that both finding types satisfy. Behavioural
901
- * `Finding` and intent `IntentFinding` each declare these fields in
902
- * their own schemas, kept structurally identical, and the pipeline needs
903
- * nothing more. The `| undefined` unions match what zod infers for
904
- * `.optional()` fields under exactOptionalPropertyTypes.
950
+ * The fields both finding types share. Behavioral `Finding` and intent
951
+ * `IntentFinding` each declare these fields in their own schemas, and
952
+ * the two declarations have to stay structurally identical. The
953
+ * `| undefined` unions match what zod infers for `.optional()` fields
954
+ * under exactOptionalPropertyTypes.
905
955
  */
906
956
  interface SuppressibleFinding {
907
957
  kind: string;
@@ -909,10 +959,11 @@ interface SuppressibleFinding {
909
959
  suppressed?: FindingSuppression | undefined;
910
960
  }
911
961
  /**
912
- * Check that a narrow rule constrains something. A bare rule with only
913
- * a `reason` would suppress every finding in the codebase, which is
914
- * almost always a mistake. Broad-scope rules are allowed to match less
915
- * specifically, on purpose.
962
+ * An error message when a rule does not constrain enough, or null when
963
+ * it is valid. A rule with only a `reason` would suppress every finding
964
+ * in the codebase, which is almost always a mistake. A broad rule needs
965
+ * one constraint of any kind, and a narrow rule needs `kind` plus a
966
+ * boundary or transition id.
916
967
  */
917
968
  declare function validateRule(rule: SuppressionRule): string | null;
918
969
 
@@ -923,60 +974,76 @@ declare function validateRule(rule: SuppressionRule): string | null;
923
974
  */
924
975
  declare function ruleBoundaryMatchesKey(ruleBoundary: string, key: string | null): boolean;
925
976
  /**
926
- * Apply suppression rules to a list of findings. This works for either
927
- * finding type: `matches` decides whether a rule's discriminators past
928
- * `kind` (boundary, consumer, and so on) match a finding, and the kind
929
- * check itself is the same everywhere, so it happens here.
977
+ * Apply suppression rules to a list of findings of either type. This
978
+ * function checks `kind`, and `matches` checks the rest of a rule's
979
+ * discriminators (boundary, consumer, and so on) against a finding.
930
980
  *
931
- * Returns a new array. Findings with `effect: "hide"` are omitted from
932
- * the output entirely unless `keepHidden` is set. Findings with
933
- * `effect: "mark"` or `"downgrade"` are included with an added
934
- * `suppressed` field. First matching rule wins.
981
+ * Returns a new array. The first matching rule applies. A finding a
982
+ * `hide` rule matches is left out unless `keepHidden` is set. A finding
983
+ * a `mark` or `downgrade` rule matches is kept with a `suppressed` field
984
+ * added.
935
985
  */
936
986
  declare function applySuppressionsToFindings<T extends SuppressibleFinding>(findings: T[], rules: SuppressionRule[], matches: (rule: SuppressionRule, finding: T) => boolean, opts?: {
937
987
  keepHidden?: boolean;
938
988
  }): T[];
939
989
  /**
940
- * `hide` and `mark` findings are left out of the exit-code threshold,
941
- * and a `downgrade` finding counts at the severity it was downgraded
942
- * to. Callers use this to decide whether a finding contributes to
943
- * `hasErrors`-style gating.
990
+ * Whether a finding counts toward the exit-code threshold. A `hide` or
991
+ * `mark` finding does not count, and a `downgrade` finding counts at the
992
+ * severity it was downgraded to.
944
993
  */
945
994
  declare function countsForThreshold(finding: SuppressibleFinding): boolean;
946
995
 
947
996
  /**
948
- * urlPath.ts: the path part of a URL, however the URL was written.
997
+ * How a `test` unit is named. Every test pack names a test by its title
998
+ * path, the suite titles outermost first and then the test's own, and a
999
+ * PRD scenario's `coveredBy` entry is matched against that name, so the
1000
+ * adapters that write it and the check that reads it share this one
1001
+ * spelling.
1002
+ */
1003
+ /** What joins the titles in a test unit's name, and the file and titles in a `coveredBy` entry. */
1004
+ declare const TEST_TITLE_SEPARATOR = " > ";
1005
+ declare function testUnitName(titles: readonly string[]): string;
1006
+
1007
+ /**
1008
+ * The path part of a URL, however the URL was written.
949
1009
  *
950
- * Two sides of one boundary spell it differently. A provider says
951
- * `/orders`, because a route is mounted at a path. A consumer says
952
- * `http://backend.internal/orders`, because a call has to say which
953
- * host. They are the same boundary, and pairing them means reading the
954
- * path out of both.
1010
+ * The two sides of one boundary spell a URL differently. A provider
1011
+ * writes `/orders`, because a route is mounted at a path. A consumer
1012
+ * writes `http://backend.internal/orders`, because a call has to give a
1013
+ * host. Pairing them means reading the path out of both.
955
1014
  *
956
- * The query and the fragment come off with the origin. Neither picks a
957
- * route: `/orders?page=2` reaches the same handler as `/orders`.
1015
+ * The query and the fragment are removed along with the origin, because
1016
+ * neither one picks a route: `/orders?page=2` reaches the same handler
1017
+ * as `/orders`.
958
1018
  */
959
1019
  /**
960
1020
  * The path a URL states, with any origin, query, and fragment removed.
961
1021
  *
962
- * Text that states no origin comes back with only the query and the
1022
+ * Text without an origin comes back with only the query and the
963
1023
  * fragment removed, since a relative URL is already a path. A URL that
964
- * is nothing but an origin comes back as an empty string, which is what
965
- * a caller wanting a path should treat as "the root".
1024
+ * is only an origin comes back as an empty string, and a caller should
1025
+ * treat that as the root.
966
1026
  */
967
1027
  declare function pathAfterOrigin(text: string): string;
968
- /** Whether the text opens with an origin rather than with a path. */
1028
+ /** Whether the text starts with an origin (a scheme and host, or `//host`). */
969
1029
  declare function statesAnOrigin(text: string): boolean;
1030
+ /**
1031
+ * Whether a host a client wrote out can belong to the project itself: a
1032
+ * loopback or private address, a name with no dot such as a container's
1033
+ * service name, or a name under a suffix kept for private networks or
1034
+ * examples. Any other name is a public host the project does not serve.
1035
+ */
1036
+ declare function hostCanBeOwn(host: string): boolean;
970
1037
 
971
1038
  /**
972
1039
  * @suss/ir-core: primitives shared across suss IRs.
973
1040
  *
974
- * The schemas are the single source of truth, and the types come from
975
- * them. Each boundary protocol's schema and behavior are in one module
976
- * under `./semantics`, and everything else is in `./schemas`. The
977
- * boundary-binding constructors are here too, so that any package that
978
- * produces an IR object (pattern packs, contract readers, intent docs,
979
- * tests) can build a binding without depending on a specific IR.
1041
+ * The zod schemas are the source of truth, and the types are derived
1042
+ * from them. Each boundary protocol defines its schema and its pairing
1043
+ * behavior together in one module. The boundary-binding constructors
1044
+ * are here too, so any package that produces an IR object, such as a
1045
+ * pattern pack or a contract reader, can build a binding without
1046
+ * depending on a specific IR.
980
1047
  */
981
1048
 
982
1049
  type ConfidenceSource = z.infer<typeof ConfidenceSourceSchema>;
@@ -998,10 +1065,14 @@ declare function restBinding(opts: {
998
1065
  path: string | null;
999
1066
  recognition: string;
1000
1067
  declaredResponses?: number[];
1068
+ /** The host of an absolute URL a client calls; see `RestSemantics`. */
1069
+ host?: string | undefined;
1070
+ /** True for a route also served with `.{format}` after its path. */
1071
+ optionalFormat?: boolean;
1001
1072
  }): BoundaryBinding;
1002
1073
  /**
1003
- * Build a function-call-semantics binding. Used by in-process packs
1004
- * (React components, custom-hook boundaries, bare TS function exports).
1074
+ * Build a function-call-semantics binding, for an in-process boundary
1075
+ * such as a React component or an exported TypeScript function.
1005
1076
  */
1006
1077
  declare function functionCallBinding(opts: {
1007
1078
  transport: string;
@@ -1022,6 +1093,17 @@ declare function packageExportBinding(opts: {
1022
1093
  packageName: string;
1023
1094
  exportPath: string[];
1024
1095
  }): BoundaryBinding;
1096
+ /**
1097
+ * Build a function-call binding for a public export of one of the
1098
+ * modules a project lists in `suss.json`. Its key is
1099
+ * `fn:<module>::<exportName>`, so an intent document or a PRD scenario
1100
+ * can point at it by the module's name.
1101
+ */
1102
+ declare function moduleExportBinding(opts: {
1103
+ recognition: string;
1104
+ module: string;
1105
+ exportName: string;
1106
+ }): BoundaryBinding;
1025
1107
  /**
1026
1108
  * Build a graphql-resolver-semantics binding. Transport varies by
1027
1109
  * deployment: `"http"` for Apollo Server, `"aws-https"` for AppSync.
@@ -1044,20 +1126,20 @@ declare function graphqlOperationBinding(opts: {
1044
1126
  operationName?: string;
1045
1127
  }): BoundaryBinding;
1046
1128
  /**
1047
- * Whether a binding is the consumer side of a GraphQL boundary,
1048
- * settled by the protocol's own schema so callers do not compare the
1049
- * semantics tag themselves.
1129
+ * Whether a binding is the consumer side of a GraphQL boundary, checked
1130
+ * against the protocol's own schema so callers do not compare the
1131
+ * semantics tag by hand.
1050
1132
  */
1051
1133
  declare function isGraphqlOperationBinding(binding: BoundaryBinding | null | undefined): boolean;
1052
1134
  /**
1053
- * Build a runtime-config binding for a runtime configuration channel
1054
- * (env vars on a Lambda, ECS task, container, or k8s pod). Transport is
1055
- * `"os"` because the OS hands env vars to the process at startup no
1056
- * matter what the deployment medium is.
1135
+ * Build a runtime-config binding, for the environment variables a
1136
+ * deployed unit starts with. Transport is `"os"` because the operating
1137
+ * system passes environment variables to the process at startup,
1138
+ * whatever platform deployed it.
1057
1139
  *
1058
- * A provider says which deployment it is. A recognizer standing at a
1059
- * read in the code leaves both off, since nothing in the code says
1060
- * which deployment will run it.
1140
+ * A provider passes its deployment target and instance name. A
1141
+ * recognizer at a read in the code leaves both out, since the code does
1142
+ * not say which deployment runs it.
1061
1143
  */
1062
1144
  declare function runtimeConfigBinding(opts: {
1063
1145
  recognition: string;
@@ -1077,11 +1159,11 @@ declare function unitInvocationBinding(opts: {
1077
1159
  instanceName: string | null;
1078
1160
  }): BoundaryBinding;
1079
1161
  /**
1080
- * Build a storage binding, the side of a store that both a schema
1081
- * reader and a call site can spell. `transport` defaults to the store's
1082
- * own name, which is right for a database whose product and wire
1083
- * protocol are the same word; a store reached over an SDK passes its
1084
- * wire instead, and one whose engine nobody settled has none to pass.
1162
+ * Build a storage binding, which describes a store in terms both a
1163
+ * schema reader and a call site can write. `transport` defaults to the
1164
+ * storage system's name, which suits a database whose product and wire
1165
+ * protocol share a name. A store reached through an SDK passes its wire
1166
+ * protocol. With no storage system either, the transport is `"storage"`.
1085
1167
  */
1086
1168
  declare function storageBinding(opts: {
1087
1169
  recognition: string;
@@ -1114,5 +1196,15 @@ declare function metricBinding(opts: {
1114
1196
  /** Null when this source states a metric it could not name. */
1115
1197
  metricType: string | null;
1116
1198
  }): BoundaryBinding;
1199
+ /**
1200
+ * Build an io binding, for a write to one of the process's own streams.
1201
+ * The transport is `"in-process"` because the write is a call the
1202
+ * program makes, and the runtime moves the bytes on from there.
1203
+ */
1204
+ declare function ioBinding(opts: {
1205
+ recognition: string;
1206
+ /** Null when this source does not say which stream. */
1207
+ target: string | null;
1208
+ }): BoundaryBinding;
1117
1209
 
1118
- export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketRank, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, isGraphqlOperationBinding, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, packageExportBinding, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope };
1210
+ export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type IoIdentityKey, type IoSemantics, IoSemanticsSchema, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TEST_TITLE_SEPARATOR, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, hostCanBeOwn, ioBinding, ioIdentityKey, isGraphqlOperationBinding, labelWithDetail, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, moduleExportBinding, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, operationKey, packageExportBinding, pairRank, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, testUnitName, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope, withoutOwnHost };