@cat-factory/contracts 0.286.0 → 0.287.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.
@@ -43,6 +43,10 @@ export declare const PUBLIC_SPEC_MAX_ISSUES = 200;
43
43
  * than the one named. A null means the head could not be resolved at all: the tree below is still
44
44
  * what the branch held, we simply cannot name the commit.
45
45
  *
46
+ * Shared by both reads, which is why `ref` is the field a caller must actually look at rather than
47
+ * assume: WHICH branch each one answers is the distinction between them (see
48
+ * {@link publicRunSpecSchema}).
49
+ *
46
50
  * There is no `directory` here, and its absence is the fact: the `spec/` tree is anchored at the
47
51
  * REPOSITORY ROOT, so two services carved out of one monorepo share one spec. Naming a
48
52
  * subdirectory would imply a scoping the reader does not apply.
@@ -53,7 +57,13 @@ export declare const publicSpecProvenanceSchema: v.ObjectSchema<{
53
57
  readonly owner: v.StringSchema<undefined>;
54
58
  /** The repository's name. */
55
59
  readonly repo: v.StringSchema<undefined>;
56
- /** The branch the spec was read from: the repository's default branch. */
60
+ /**
61
+ * The branch the spec was read from, named rather than implied because the two reads answer at
62
+ * different refs: the repository's default branch for a service read, and the branch the run
63
+ * pushed its work to for a run read. A run read names the default branch when the run opened no
64
+ * pull request, and when the one it opened has had its head branch deleted (the usual sequel to
65
+ * a merge), which is the same tree under its surviving name.
66
+ */
57
67
  readonly ref: v.StringSchema<undefined>;
58
68
  /** The head commit of `ref` at read time, or null when it could not be resolved. */
59
69
  readonly commit: v.NullableSchema<v.StringSchema<undefined>, undefined>;
@@ -201,7 +211,13 @@ export declare const publicServiceSpecSchema: v.ObjectSchema<{
201
211
  readonly owner: v.StringSchema<undefined>;
202
212
  /** The repository's name. */
203
213
  readonly repo: v.StringSchema<undefined>;
204
- /** The branch the spec was read from: the repository's default branch. */
214
+ /**
215
+ * The branch the spec was read from, named rather than implied because the two reads answer at
216
+ * different refs: the repository's default branch for a service read, and the branch the run
217
+ * pushed its work to for a run read. A run read names the default branch when the run opened no
218
+ * pull request, and when the one it opened has had its head branch deleted (the usual sequel to
219
+ * a merge), which is the same tree under its surviving name.
220
+ */
205
221
  readonly ref: v.StringSchema<undefined>;
206
222
  /** The head commit of `ref` at read time, or null when it could not be resolved. */
207
223
  readonly commit: v.NullableSchema<v.StringSchema<undefined>, undefined>;
@@ -229,4 +245,138 @@ export declare const publicServiceSpecSchema: v.ObjectSchema<{
229
245
  }, undefined>, undefined>;
230
246
  }, undefined>;
231
247
  export type PublicServiceSpec = v.InferOutput<typeof publicServiceSpecSchema>;
248
+ /**
249
+ * How the presence anchor resolved for a RUN's spec, for a caller that got a `200`.
250
+ *
251
+ * {@link publicSpecAnchorSchema} plus `not_read`, which is a fact about the RUN rather than about
252
+ * the repository and therefore cannot occur on the service-scoped read:
253
+ *
254
+ * - `not_read` — nothing was read. The run's spec read is gated on a tester having reported, so
255
+ * that the tree served is the one the verdicts were made against; before that point the
256
+ * platform has consulted no tree, which is exactly what `requirements.spec: "not_read"` on the
257
+ * same run's outcome summary already says. `provenance` is null, because there is no snapshot
258
+ * to name.
259
+ *
260
+ * A separate picklist rather than a fourth member on the service one: `not_read` is unreachable
261
+ * there, and an enum carrying a value its endpoint can never answer is a state consumers write
262
+ * dead branches for.
263
+ */
264
+ export declare const publicRunSpecAnchorSchema: v.PicklistSchema<["present", "absent", "unparsed", "not_read"], undefined>;
265
+ export type PublicRunSpecAnchor = v.InferOutput<typeof publicRunSpecAnchorSchema>;
266
+ /**
267
+ * The spec ONE RUN was judged against, as `/api/v1` serves it.
268
+ *
269
+ * The sibling of {@link publicServiceSpecSchema} rather than a flag on it, for the reason the
270
+ * internal pair already splits on: they answer different questions. The service read answers "what
271
+ * does this service require", from the repository's DEFAULT branch. This answers "what did this run
272
+ * rule on", from the branch the run pushed its work to, which is a different tree for as long as
273
+ * the pull request is open. A caller joining `requirements` rows on `/api/v1/runs/:runId/outcome`
274
+ * or `…/report` back to the criteria they were scored against needs THIS one: every requirement the
275
+ * run itself added is missing from the default branch, so the service read leaves each of those
276
+ * verdicts unjoinable.
277
+ *
278
+ * Same body as the service read (the tree, the Gherkin, the issues, the caps), because it is the
279
+ * same document read at a different ref, and two wire shapes over one artifact are two things to
280
+ * keep in step. What differs is the key (`runId`), the fourth {@link publicRunSpecAnchorSchema}
281
+ * state, and a nullable `provenance`.
282
+ */
283
+ export declare const publicRunSpecSchema: v.ObjectSchema<{
284
+ /** The run this spec was read for, echoed so a response stands alone. */
285
+ readonly runId: v.StringSchema<undefined>;
286
+ /**
287
+ * What the RUN's branch holds where the spec should be, or `not_read` when the platform has
288
+ * consulted no tree for this run yet. `spec` is non-null exactly when this is `present`.
289
+ */
290
+ readonly anchor: v.PicklistSchema<["present", "absent", "unparsed", "not_read"], undefined>;
291
+ /** The structured tree, or null when `anchor` is not `present`. */
292
+ readonly spec: v.NullableSchema<v.ObjectSchema<{
293
+ readonly summary: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>, "">;
294
+ readonly modules: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
295
+ readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>]>;
296
+ readonly summary: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>, "">;
297
+ readonly groups: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
298
+ readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>]>;
299
+ readonly summary: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>, "">;
300
+ readonly requirements: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
301
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
302
+ readonly title: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 120, undefined>]>;
303
+ readonly statement: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 4000, undefined>]>;
304
+ readonly kind: v.PicklistSchema<["functional", "nonfunctional", "constraint"], undefined>;
305
+ readonly priority: v.PicklistSchema<["must", "should", "could"], undefined>;
306
+ readonly state: v.OptionalSchema<v.PicklistSchema<["aspirational", "established"], undefined>, "aspirational">;
307
+ readonly sourceBlockIds: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>, undefined>, readonly []>;
308
+ readonly acceptance: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
309
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
310
+ readonly given: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>;
311
+ readonly when: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>;
312
+ readonly outcome: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>;
313
+ }, undefined>, undefined>, readonly []>;
314
+ }, undefined>, undefined>, readonly []>;
315
+ readonly rules: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
316
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>;
317
+ readonly rule: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 4000, undefined>]>;
318
+ readonly rationale: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MaxLengthAction<string, 2000, undefined>]>, "">;
319
+ readonly sourceBlockIds: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 200, undefined>]>, undefined>, readonly []>;
320
+ }, undefined>, undefined>, readonly []>;
321
+ }, undefined>, undefined>, readonly []>;
322
+ }, undefined>, undefined>, readonly []>;
323
+ readonly service: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 120, undefined>]>, "">;
324
+ }, undefined>, undefined>;
325
+ /** The rendered Gherkin, one entry per `.feature` file. */
326
+ readonly features: v.ArraySchema<v.ObjectSchema<{
327
+ /** The owning module's display name. */
328
+ readonly module: v.StringSchema<undefined>;
329
+ /** The feature/group display name. */
330
+ readonly group: v.StringSchema<undefined>;
331
+ /** Repo-relative path of the `.feature` file. */
332
+ readonly path: v.StringSchema<undefined>;
333
+ /** The Gherkin, clamped to {@link PUBLIC_SPEC_MAX_FEATURE_CHARS}. */
334
+ readonly content: v.StringSchema<undefined>;
335
+ /** Characters actually returned in `content`. */
336
+ readonly chars: v.NumberSchema<undefined>;
337
+ /** Characters the file holds in the repository, whatever was returned. */
338
+ readonly totalChars: v.NumberSchema<undefined>;
339
+ /** True when `chars < totalChars`. */
340
+ readonly truncated: v.BooleanSchema<undefined>;
341
+ }, undefined>, undefined>;
342
+ /**
343
+ * Where the tree was read from: the RUN's branch (its pull request's head while one is open, the
344
+ * repository default otherwise) and the commit it was at.
345
+ *
346
+ * Null exactly when `anchor` is `not_read`, and that is the whole reason it is nullable: there is
347
+ * no snapshot to name, and naming the branch anyway would imply a read that did not happen.
348
+ */
349
+ readonly provenance: v.NullableSchema<v.ObjectSchema<{
350
+ readonly provider: v.PicklistSchema<["github", "gitlab"], undefined>;
351
+ /** The repository's owner (org or user). */
352
+ readonly owner: v.StringSchema<undefined>;
353
+ /** The repository's name. */
354
+ readonly repo: v.StringSchema<undefined>;
355
+ /**
356
+ * The branch the spec was read from, named rather than implied because the two reads answer at
357
+ * different refs: the repository's default branch for a service read, and the branch the run
358
+ * pushed its work to for a run read. A run read names the default branch when the run opened no
359
+ * pull request, and when the one it opened has had its head branch deleted (the usual sequel to
360
+ * a merge), which is the same tree under its surviving name.
361
+ */
362
+ readonly ref: v.StringSchema<undefined>;
363
+ /** The head commit of `ref` at read time, or null when it could not be resolved. */
364
+ readonly commit: v.NullableSchema<v.StringSchema<undefined>, undefined>;
365
+ }, undefined>, undefined>;
366
+ /** Files the read could not fully account for. Capped at {@link PUBLIC_SPEC_MAX_ISSUES}. */
367
+ readonly issues: v.ArraySchema<v.ObjectSchema<{
368
+ readonly path: v.StringSchema<undefined>;
369
+ readonly kind: v.PicklistSchema<["read_failed", "unparsed", "partial", "unread"], undefined>;
370
+ readonly dropped: v.OptionalSchema<v.NullableSchema<v.NumberSchema<undefined>, undefined>, 0>;
371
+ }, undefined>, undefined>;
372
+ /** Every cap that bit. Empty when nothing was left out. */
373
+ readonly truncations: v.ArraySchema<v.ObjectSchema<{
374
+ readonly section: v.PicklistSchema<["requirements", "rules", "acceptance", "features", "issues"], undefined>;
375
+ /** How many rows the response carries. */
376
+ readonly shown: v.NumberSchema<undefined>;
377
+ /** How many rows the spec holds. */
378
+ readonly total: v.NumberSchema<undefined>;
379
+ }, undefined>, undefined>;
380
+ }, undefined>;
381
+ export type PublicRunSpec = v.InferOutput<typeof publicRunSpecSchema>;
232
382
  //# sourceMappingURL=public-spec.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-spec.d.ts","sourceRoot":"","sources":["../src/public-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AA8C5B,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,OAAQ,CAAA;AAEjD,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,OAAQ,CAAA;AAE1C;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,OAAQ,CAAA;AAE/C,4EAA4E;AAC5E,eAAO,MAAM,6BAA6B,MAAM,CAAA;AAEhD,uEAAuE;AACvE,eAAO,MAAM,6BAA6B,QAAS,CAAA;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,UAAY,CAAA;AAE5D;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAA;AAEzC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,0BAA0B;;IAErC,4CAA4C;;IAE5C,6BAA6B;;IAE7B,0EAA0E;;IAE1E,oFAAoF;;aAEpF,CAAA;AACF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,0BAA0B,CAAC,CAAA;AAEnF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B;IACtC,wCAAwC;;IAExC,sCAAsC;;IAEtC,iDAAiD;;IAEjD,qEAAqE;;IAErE,iDAAiD;;IAEjD,0EAA0E;;IAE1E,sCAAsC;;aAEtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAErF,6FAA6F;AAC7F,eAAO,MAAM,iCAAiC,4FAM5C,CAAA;AACF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iCAAiC,CAAC,CAAA;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B;;IAErC,0CAA0C;;IAE1C,oCAAoC;;aAEpC,CAAA;AACF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,0BAA0B,CAAC,CAAA;AAEnF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,sBAAsB,gEAAgD,CAAA;AACnF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;IAClC,uFAAuF;;IAEvF;;;OAGG;;IAEH;;;;;OAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEH,6FAA6F;;QAzF7F,wCAAwC;;QAExC,sCAAsC;;QAEtC,iDAAiD;;QAEjD,qEAAqE;;QAErE,iDAAiD;;QAEjD,0EAA0E;;QAE1E,sCAAsC;;;;;QA/BtC,4CAA4C;;QAE5C,6BAA6B;;QAE7B,0EAA0E;;QAE1E,oFAAoF;;;IAyGpF;;;;;;;OAOG;;;;;;IAEH,2DAA2D;;;QAhE3D,0CAA0C;;QAE1C,oCAAoC;;;aAgEpC,CAAA;AACF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,uBAAuB,CAAC,CAAA"}
1
+ {"version":3,"file":"public-spec.d.ts","sourceRoot":"","sources":["../src/public-spec.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,10 @@ import * as v from 'valibot';
2
2
  import { vcsProviderSchema } from './routes/auth.js';
3
3
  import { readSpecDocSchema, specReadIssueSchema } from './spec.js';
4
4
  // ---------------------------------------------------------------------------
5
- // The public read of a service's in-repo SPECIFICATION (`GET /api/v1/services/:serviceId/spec`).
5
+ // The public reads of the in-repo SPECIFICATION: a service's, from the repository's default branch
6
+ // (`GET /api/v1/services/:serviceId/spec`), and a run's, from the branch that run pushed its work
7
+ // to (`GET /api/v1/runs/:runId/spec`). Everything below describes the first; the second carries the
8
+ // same body at a different ref, and {@link publicRunSpecSchema} states what it changes and why.
6
9
  //
7
10
  // The spec is the platform's requirements truth: structured requirement items with a MoSCoW
8
11
  // priority, an `aspirational ⇄ established` lifecycle state and Gherkin-shaped acceptance
@@ -86,6 +89,10 @@ export const PUBLIC_SPEC_MAX_ISSUES = 200;
86
89
  * than the one named. A null means the head could not be resolved at all: the tree below is still
87
90
  * what the branch held, we simply cannot name the commit.
88
91
  *
92
+ * Shared by both reads, which is why `ref` is the field a caller must actually look at rather than
93
+ * assume: WHICH branch each one answers is the distinction between them (see
94
+ * {@link publicRunSpecSchema}).
95
+ *
89
96
  * There is no `directory` here, and its absence is the fact: the `spec/` tree is anchored at the
90
97
  * REPOSITORY ROOT, so two services carved out of one monorepo share one spec. Naming a
91
98
  * subdirectory would imply a scoping the reader does not apply.
@@ -96,7 +103,13 @@ export const publicSpecProvenanceSchema = v.object({
96
103
  owner: v.string(),
97
104
  /** The repository's name. */
98
105
  repo: v.string(),
99
- /** The branch the spec was read from: the repository's default branch. */
106
+ /**
107
+ * The branch the spec was read from, named rather than implied because the two reads answer at
108
+ * different refs: the repository's default branch for a service read, and the branch the run
109
+ * pushed its work to for a run read. A run read names the default branch when the run opened no
110
+ * pull request, and when the one it opened has had its head branch deleted (the usual sequel to
111
+ * a merge), which is the same tree under its surviving name.
112
+ */
100
113
  ref: v.string(),
101
114
  /** The head commit of `ref` at read time, or null when it could not be resolved. */
102
115
  commit: v.nullable(v.string()),
@@ -205,4 +218,63 @@ export const publicServiceSpecSchema = v.object({
205
218
  /** Every cap that bit. Empty when nothing was left out. */
206
219
  truncations: v.array(publicSpecTruncationSchema),
207
220
  });
221
+ /**
222
+ * How the presence anchor resolved for a RUN's spec, for a caller that got a `200`.
223
+ *
224
+ * {@link publicSpecAnchorSchema} plus `not_read`, which is a fact about the RUN rather than about
225
+ * the repository and therefore cannot occur on the service-scoped read:
226
+ *
227
+ * - `not_read` — nothing was read. The run's spec read is gated on a tester having reported, so
228
+ * that the tree served is the one the verdicts were made against; before that point the
229
+ * platform has consulted no tree, which is exactly what `requirements.spec: "not_read"` on the
230
+ * same run's outcome summary already says. `provenance` is null, because there is no snapshot
231
+ * to name.
232
+ *
233
+ * A separate picklist rather than a fourth member on the service one: `not_read` is unreachable
234
+ * there, and an enum carrying a value its endpoint can never answer is a state consumers write
235
+ * dead branches for.
236
+ */
237
+ export const publicRunSpecAnchorSchema = v.picklist(['present', 'absent', 'unparsed', 'not_read']);
238
+ /**
239
+ * The spec ONE RUN was judged against, as `/api/v1` serves it.
240
+ *
241
+ * The sibling of {@link publicServiceSpecSchema} rather than a flag on it, for the reason the
242
+ * internal pair already splits on: they answer different questions. The service read answers "what
243
+ * does this service require", from the repository's DEFAULT branch. This answers "what did this run
244
+ * rule on", from the branch the run pushed its work to, which is a different tree for as long as
245
+ * the pull request is open. A caller joining `requirements` rows on `/api/v1/runs/:runId/outcome`
246
+ * or `…/report` back to the criteria they were scored against needs THIS one: every requirement the
247
+ * run itself added is missing from the default branch, so the service read leaves each of those
248
+ * verdicts unjoinable.
249
+ *
250
+ * Same body as the service read (the tree, the Gherkin, the issues, the caps), because it is the
251
+ * same document read at a different ref, and two wire shapes over one artifact are two things to
252
+ * keep in step. What differs is the key (`runId`), the fourth {@link publicRunSpecAnchorSchema}
253
+ * state, and a nullable `provenance`.
254
+ */
255
+ export const publicRunSpecSchema = v.object({
256
+ /** The run this spec was read for, echoed so a response stands alone. */
257
+ runId: v.string(),
258
+ /**
259
+ * What the RUN's branch holds where the spec should be, or `not_read` when the platform has
260
+ * consulted no tree for this run yet. `spec` is non-null exactly when this is `present`.
261
+ */
262
+ anchor: publicRunSpecAnchorSchema,
263
+ /** The structured tree, or null when `anchor` is not `present`. */
264
+ spec: v.nullable(readSpecDocSchema),
265
+ /** The rendered Gherkin, one entry per `.feature` file. */
266
+ features: v.array(publicSpecFeatureFileSchema),
267
+ /**
268
+ * Where the tree was read from: the RUN's branch (its pull request's head while one is open, the
269
+ * repository default otherwise) and the commit it was at.
270
+ *
271
+ * Null exactly when `anchor` is `not_read`, and that is the whole reason it is nullable: there is
272
+ * no snapshot to name, and naming the branch anyway would imply a read that did not happen.
273
+ */
274
+ provenance: v.nullable(publicSpecProvenanceSchema),
275
+ /** Files the read could not fully account for. Capped at {@link PUBLIC_SPEC_MAX_ISSUES}. */
276
+ issues: v.array(specReadIssueSchema),
277
+ /** Every cap that bit. Empty when nothing was left out. */
278
+ truncations: v.array(publicSpecTruncationSchema),
279
+ });
208
280
  //# sourceMappingURL=public-spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-spec.js","sourceRoot":"","sources":["../src/public-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAElE,8EAA8E;AAC9E,iGAAiG;AACjG,EAAE;AACF,4FAA4F;AAC5F,0FAA0F;AAC1F,gGAAgG;AAChG,iGAAiG;AACjG,2FAA2F;AAC3F,0FAA0F;AAC1F,iGAAiG;AACjG,uFAAuF;AACvF,EAAE;AACF,kCAAkC;AAClC,EAAE;AACF,mGAAmG;AACnG,kGAAkG;AAClG,8FAA8F;AAC9F,gGAAgG;AAChG,6FAA6F;AAC7F,kGAAkG;AAClG,4CAA4C;AAC5C,oGAAoG;AACpG,iGAAiG;AACjG,kGAAkG;AAClG,gGAAgG;AAChG,kGAAkG;AAClG,8FAA8F;AAC9F,8FAA8F;AAC9F,eAAe;AACf,iGAAiG;AACjG,iGAAiG;AACjG,kGAAkG;AAClG,iGAAiG;AACjG,mGAAmG;AACnG,uEAAuE;AACvE,EAAE;AACF,gGAAgG;AAChG,oGAAoG;AACpG,iGAAiG;AACjG,oEAAoE;AACpE,8EAA8E;AAE9E,iFAAiF;AACjF,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAA;AAEjD,iFAAiF;AACjF,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAA;AAE1C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,CAAA;AAE/C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAA;AAEhD,uEAAuE;AACvE,MAAM,CAAC,MAAM,6BAA6B,GAAG,MAAM,CAAA;AAEnD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,SAAS,CAAA;AAE5D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA;AAEzC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,QAAQ,EAAE,iBAAiB;IAC3B,4CAA4C;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,6BAA6B;IAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,0EAA0E;IAC1E,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,oFAAoF;IACpF,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CAC/B,CAAC,CAAA;AAGF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,wCAAwC;IACxC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,sCAAsC;IACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,iDAAiD;IACjD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,qEAAqE;IACrE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,iDAAiD;IACjD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,0EAA0E;IAC1E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,sCAAsC;IACtC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;CACvB,CAAC,CAAA;AAGF,6FAA6F;AAC7F,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC1D,cAAc;IACd,OAAO;IACP,YAAY;IACZ,UAAU;IACV,QAAQ;CACT,CAAC,CAAA;AAGF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,OAAO,EAAE,iCAAiC;IAC1C,0CAA0C;IAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,oCAAoC;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAA;AAGF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;AAGnF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,uFAAuF;IACvF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB;;;OAGG;IACH,MAAM,EAAE,sBAAsB;IAC9B;;;;;OAKG;IACH,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IACnC,6FAA6F;IAC7F,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC;IAC9C,UAAU,EAAE,0BAA0B;IACtC;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACpC,2DAA2D;IAC3D,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC;CACjD,CAAC,CAAA"}
1
+ {"version":3,"file":"public-spec.js","sourceRoot":"","sources":["../src/public-spec.ts"],"names":[],"mappings":"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"}
@@ -107,4 +107,114 @@ export declare const getPublicServiceSpecContract: {
107
107
  } & {
108
108
  readonly minScope: "read";
109
109
  };
110
+ /**
111
+ * The specification ONE RUN was judged against, read from the branch that run pushed its work to.
112
+ *
113
+ * The sibling of {@link getPublicServiceSpecContract}, and the reason it is a sibling rather than a
114
+ * query parameter is the reason the internal pair already splits: they answer different questions,
115
+ * and a caller that asked the first while meaning the second got a document missing exactly the
116
+ * requirements the run had added. Every verdict naming one of those landed as unjoinable.
117
+ *
118
+ * `read` scope, and addressed under `/api/v1/runs/:runId/*` beside `…/report` and `…/outcome`, so
119
+ * the requirement ids on those two and the criteria they were scored against are three GETs on one
120
+ * key rather than a repository clone.
121
+ */
122
+ export declare const getPublicRunSpecContract: {
123
+ readonly method: "get";
124
+ readonly requestPathParamsSchema: import("valibot").ObjectSchema<{
125
+ runId: import("valibot").StringSchema<undefined>;
126
+ }, undefined> & import("@toad-contracts/core").StandardObjectKeysV1<unknown, unknown>;
127
+ readonly pathResolver: ({ runId }: {
128
+ runId: string;
129
+ }) => string;
130
+ readonly responsesByStatusCode: {
131
+ readonly '4xx': import("valibot").ObjectSchema<{
132
+ readonly error: import("valibot").ObjectSchema<{
133
+ readonly code: import("valibot").StringSchema<undefined>;
134
+ readonly message: import("valibot").StringSchema<undefined>;
135
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
136
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
137
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
138
+ readonly message: import("valibot").StringSchema<undefined>;
139
+ }, undefined>, undefined>, undefined>;
140
+ }, undefined>;
141
+ }, undefined>;
142
+ readonly '5xx': import("valibot").ObjectSchema<{
143
+ readonly error: import("valibot").ObjectSchema<{
144
+ readonly code: import("valibot").StringSchema<undefined>;
145
+ readonly message: import("valibot").StringSchema<undefined>;
146
+ readonly details: import("valibot").OptionalSchema<import("valibot").UnknownSchema, undefined>;
147
+ readonly issues: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
148
+ readonly path: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
149
+ readonly message: import("valibot").StringSchema<undefined>;
150
+ }, undefined>, undefined>, undefined>;
151
+ }, undefined>;
152
+ }, undefined>;
153
+ readonly 200: import("valibot").ObjectSchema<{
154
+ readonly runId: import("valibot").StringSchema<undefined>;
155
+ readonly anchor: import("valibot").PicklistSchema<["present", "absent", "unparsed", "not_read"], undefined>;
156
+ readonly spec: import("valibot").NullableSchema<import("valibot").ObjectSchema<{
157
+ readonly summary: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>, "">;
158
+ readonly modules: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
159
+ readonly name: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>;
160
+ readonly summary: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>, "">;
161
+ readonly groups: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
162
+ readonly name: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>;
163
+ readonly summary: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>, "">;
164
+ readonly requirements: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
165
+ readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 200, undefined>]>;
166
+ readonly title: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>;
167
+ readonly statement: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 4000, undefined>]>;
168
+ readonly kind: import("valibot").PicklistSchema<["functional", "nonfunctional", "constraint"], undefined>;
169
+ readonly priority: import("valibot").PicklistSchema<["must", "should", "could"], undefined>;
170
+ readonly state: import("valibot").OptionalSchema<import("valibot").PicklistSchema<["aspirational", "established"], undefined>, "aspirational">;
171
+ readonly sourceBlockIds: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 200, undefined>]>, undefined>, readonly []>;
172
+ readonly acceptance: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
173
+ readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 200, undefined>]>;
174
+ readonly given: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>;
175
+ readonly when: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>;
176
+ readonly outcome: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>;
177
+ }, undefined>, undefined>, readonly []>;
178
+ }, undefined>, undefined>, readonly []>;
179
+ readonly rules: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
180
+ readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 200, undefined>]>;
181
+ readonly rule: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 4000, undefined>]>;
182
+ readonly rationale: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000, undefined>]>, "">;
183
+ readonly sourceBlockIds: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 200, undefined>]>, undefined>, readonly []>;
184
+ }, undefined>, undefined>, readonly []>;
185
+ }, undefined>, undefined>, readonly []>;
186
+ }, undefined>, undefined>, readonly []>;
187
+ readonly service: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").TrimAction, import("valibot").MaxLengthAction<string, 120, undefined>]>, "">;
188
+ }, undefined>, undefined>;
189
+ readonly features: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
190
+ readonly module: import("valibot").StringSchema<undefined>;
191
+ readonly group: import("valibot").StringSchema<undefined>;
192
+ readonly path: import("valibot").StringSchema<undefined>;
193
+ readonly content: import("valibot").StringSchema<undefined>;
194
+ readonly chars: import("valibot").NumberSchema<undefined>;
195
+ readonly totalChars: import("valibot").NumberSchema<undefined>;
196
+ readonly truncated: import("valibot").BooleanSchema<undefined>;
197
+ }, undefined>, undefined>;
198
+ readonly provenance: import("valibot").NullableSchema<import("valibot").ObjectSchema<{
199
+ readonly provider: import("valibot").PicklistSchema<["github", "gitlab"], undefined>;
200
+ readonly owner: import("valibot").StringSchema<undefined>;
201
+ readonly repo: import("valibot").StringSchema<undefined>;
202
+ readonly ref: import("valibot").StringSchema<undefined>;
203
+ readonly commit: import("valibot").NullableSchema<import("valibot").StringSchema<undefined>, undefined>;
204
+ }, undefined>, undefined>;
205
+ readonly issues: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
206
+ readonly path: import("valibot").StringSchema<undefined>;
207
+ readonly kind: import("valibot").PicklistSchema<["read_failed", "unparsed", "partial", "unread"], undefined>;
208
+ readonly dropped: import("valibot").OptionalSchema<import("valibot").NullableSchema<import("valibot").NumberSchema<undefined>, undefined>, 0>;
209
+ }, undefined>, undefined>;
210
+ readonly truncations: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
211
+ readonly section: import("valibot").PicklistSchema<["requirements", "rules", "acceptance", "features", "issues"], undefined>;
212
+ readonly shown: import("valibot").NumberSchema<undefined>;
213
+ readonly total: import("valibot").NumberSchema<undefined>;
214
+ }, undefined>, undefined>;
215
+ }, undefined>;
216
+ };
217
+ } & {
218
+ readonly minScope: "read";
219
+ };
110
220
  //# sourceMappingURL=public-spec.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-spec.d.ts","sourceRoot":"","sources":["../../src/routes/public-spec.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQxC,CAAA"}
1
+ {"version":3,"file":"public-spec.d.ts","sourceRoot":"","sources":["../../src/routes/public-spec.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQxC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQpC,CAAA"}
@@ -1,15 +1,17 @@
1
1
  import { defineApiContract } from '@toad-contracts/valibot';
2
- import { publicServiceSpecSchema } from '../public-spec.js';
2
+ import { publicRunSpecSchema, publicServiceSpecSchema } from '../public-spec.js';
3
3
  import { errorResponses, singleStringParam, withMinScope } from './_shared.js';
4
4
  // ---------------------------------------------------------------------------
5
- // The public SPEC read: absolute `/api/v1` path, authenticated in-controller by a public-API key.
6
- // The wire shape and the reasoning behind it live in `../public-spec.ts`; the honesty contract the
7
- // controller implements (four outcomes, never folded) is in `PublicSpecController`.
5
+ // The public SPEC reads: absolute `/api/v1` paths, authenticated in-controller by a public-API key.
6
+ // The wire shapes and the reasoning behind them live in `../public-spec.ts`; the honesty contract
7
+ // the controller implements (the outcomes, never folded) is in `PublicSpecController`.
8
8
  //
9
- // Addressed under `/api/v1/services/:serviceId/*`, beside `…/tasks`, because a spec is a fact about
10
- // a SERVICE. The `serviceId` is the board service-frame id every other endpoint on this surface
11
- // already uses, and it resolves through the same board read, so a key can only ever name a service
12
- // of its own workspace.
9
+ // Each is addressed under the resource the question is ABOUT, which is why there are two of them
10
+ // rather than one with a `ref` parameter. The service read is a fact about a SERVICE and sits
11
+ // beside `…/tasks`; the `serviceId` is the board service-frame id every other endpoint on this
12
+ // surface already uses, and it resolves through the same board read, so a key can only ever name a
13
+ // service of its own workspace. The run read is a fact about a RUN and sits beside `…/report` and
14
+ // `…/outcome`, so criterion to evidence is three GETs on one key.
13
15
  // ---------------------------------------------------------------------------
14
16
  /**
15
17
  * The service's in-repo specification: the structured requirement tree, the rendered Gherkin, and
@@ -28,4 +30,22 @@ export const getPublicServiceSpecContract = withMinScope('read', defineApiContra
28
30
  pathResolver: ({ serviceId }) => `/api/v1/services/${serviceId}/spec`,
29
31
  responsesByStatusCode: { 200: publicServiceSpecSchema, ...errorResponses },
30
32
  }));
33
+ /**
34
+ * The specification ONE RUN was judged against, read from the branch that run pushed its work to.
35
+ *
36
+ * The sibling of {@link getPublicServiceSpecContract}, and the reason it is a sibling rather than a
37
+ * query parameter is the reason the internal pair already splits: they answer different questions,
38
+ * and a caller that asked the first while meaning the second got a document missing exactly the
39
+ * requirements the run had added. Every verdict naming one of those landed as unjoinable.
40
+ *
41
+ * `read` scope, and addressed under `/api/v1/runs/:runId/*` beside `…/report` and `…/outcome`, so
42
+ * the requirement ids on those two and the criteria they were scored against are three GETs on one
43
+ * key rather than a repository clone.
44
+ */
45
+ export const getPublicRunSpecContract = withMinScope('read', defineApiContract({
46
+ method: 'get',
47
+ requestPathParamsSchema: singleStringParam('runId'),
48
+ pathResolver: ({ runId }) => `/api/v1/runs/${runId}/spec`,
49
+ responsesByStatusCode: { 200: publicRunSpecSchema, ...errorResponses },
50
+ }));
31
51
  //# sourceMappingURL=public-spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"public-spec.js","sourceRoot":"","sources":["../../src/routes/public-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE9E,8EAA8E;AAC9E,kGAAkG;AAClG,mGAAmG;AACnG,oFAAoF;AACpF,EAAE;AACF,oGAAoG;AACpG,gGAAgG;AAChG,mGAAmG;AACnG,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CACtD,MAAM,EACN,iBAAiB,CAAC;IAChB,MAAM,EAAE,KAAK;IACb,uBAAuB,EAAE,iBAAiB,CAAC,WAAW,CAAC;IACvD,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,oBAAoB,SAAS,OAAO;IACrE,qBAAqB,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,GAAG,cAAc,EAAE;CAC3E,CAAC,CACH,CAAA"}
1
+ {"version":3,"file":"public-spec.js","sourceRoot":"","sources":["../../src/routes/public-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAChF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE9E,8EAA8E;AAC9E,oGAAoG;AACpG,kGAAkG;AAClG,uFAAuF;AACvF,EAAE;AACF,iGAAiG;AACjG,8FAA8F;AAC9F,+FAA+F;AAC/F,mGAAmG;AACnG,kGAAkG;AAClG,kEAAkE;AAClE,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CACtD,MAAM,EACN,iBAAiB,CAAC;IAChB,MAAM,EAAE,KAAK;IACb,uBAAuB,EAAE,iBAAiB,CAAC,WAAW,CAAC;IACvD,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,oBAAoB,SAAS,OAAO;IACrE,qBAAqB,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,GAAG,cAAc,EAAE;CAC3E,CAAC,CACH,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,YAAY,CAClD,MAAM,EACN,iBAAiB,CAAC;IAChB,MAAM,EAAE,KAAK;IACb,uBAAuB,EAAE,iBAAiB,CAAC,OAAO,CAAC;IACnD,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,gBAAgB,KAAK,OAAO;IACzD,qBAAqB,EAAE,EAAE,GAAG,EAAE,mBAAmB,EAAE,GAAG,cAAc,EAAE;CACvE,CAAC,CACH,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/contracts",
3
- "version": "0.286.0",
3
+ "version": "0.287.0",
4
4
  "description": "Valibot wire contract shared between the Agent Architecture Board frontend and backend.",
5
5
  "repository": {
6
6
  "type": "git",