@suss/intent-ir 0.33.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/index.cjs +543 -214
- package/dist/index.d.cts +364 -104
- package/dist/index.d.ts +364 -104
- package/dist/index.js +516 -198
- package/package.json +3 -3
- package/schema/intent-doc.schema.json +430 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,98 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { EffectRelation, BoundaryBinding, TypeShape } from '@suss/ir-core';
|
|
3
|
+
export { TEST_TITLE_SEPARATOR } from '@suss/ir-core';
|
|
3
4
|
|
|
4
|
-
declare const IntentFindingKindSchema: z.ZodEnum<{
|
|
5
|
-
uncoveredOutcome: "uncoveredOutcome";
|
|
6
|
-
unimplementedBoundary: "unimplementedBoundary";
|
|
7
|
-
outcomeShapeMismatch: "outcomeShapeMismatch";
|
|
8
|
-
undeclaredOutcome: "undeclaredOutcome";
|
|
9
|
-
unkeyableBoundary: "unkeyableBoundary";
|
|
10
|
-
renamedBoundary: "renamedBoundary";
|
|
11
|
-
unreadInputField: "unreadInputField";
|
|
12
|
-
undeclaredInputRead: "undeclaredInputRead";
|
|
13
|
-
unlinkedScenario: "unlinkedScenario";
|
|
14
|
-
danglingScenarioLink: "danglingScenarioLink";
|
|
15
|
-
ambiguousScenarioLink: "ambiguousScenarioLink";
|
|
16
|
-
undescribedOutcome: "undescribedOutcome";
|
|
17
|
-
}>;
|
|
18
|
-
type IntentFindingKind = z.infer<typeof IntentFindingKindSchema>;
|
|
19
|
-
declare const IntentFindingSeveritySchema: z.ZodEnum<{
|
|
20
|
-
error: "error";
|
|
21
|
-
warning: "warning";
|
|
22
|
-
info: "info";
|
|
23
|
-
}>;
|
|
24
|
-
type IntentFindingSeverity = z.infer<typeof IntentFindingSeveritySchema>;
|
|
25
|
-
/** Which intent (and, when relevant, which outcome) a finding concerns. */
|
|
26
|
-
declare const IntentRefSchema: z.ZodObject<{
|
|
27
|
-
name: z.ZodString;
|
|
28
|
-
outcomeId: z.ZodOptional<z.ZodString>;
|
|
29
|
-
}, z.core.$strip>;
|
|
30
|
-
type IntentRef = z.infer<typeof IntentRefSchema>;
|
|
31
5
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
6
|
+
* The intent file format a team writes, or `suss infer` drafts. There
|
|
7
|
+
* are two top-level forms, told apart by `kind`:
|
|
8
|
+
*
|
|
9
|
+
* kind: boundary system intent: what one boundary should do, as
|
|
10
|
+
* outcomes named by id.
|
|
11
|
+
* kind: prd outcome intent: human scenarios (when / expect)
|
|
12
|
+
* that refer to system-intent outcomes by id.
|
|
13
|
+
*
|
|
14
|
+
* Boundaries reuse @suss/ir-core's vocabulary, so intent and behavior
|
|
15
|
+
* describe a boundary the same way. A transition says how it ends and
|
|
16
|
+
* what it did, as DESIGN.md explains. `intentDocToSummary` normalizes a
|
|
17
|
+
* document into the form the checker compares against code.
|
|
35
18
|
*/
|
|
36
|
-
declare const IntentFindingSuppressionSchema: z.ZodObject<{
|
|
37
|
-
reason: z.ZodString;
|
|
38
|
-
effect: z.ZodEnum<{
|
|
39
|
-
mark: "mark";
|
|
40
|
-
downgrade: "downgrade";
|
|
41
|
-
hide: "hide";
|
|
42
|
-
}>;
|
|
43
|
-
originalSeverity: z.ZodOptional<z.ZodEnum<{
|
|
44
|
-
error: "error";
|
|
45
|
-
warning: "warning";
|
|
46
|
-
info: "info";
|
|
47
|
-
}>>;
|
|
48
|
-
}, z.core.$strip>;
|
|
49
|
-
type IntentFindingSuppression = z.infer<typeof IntentFindingSuppressionSchema>;
|
|
50
|
-
declare const IntentFindingSchema: z.ZodObject<{
|
|
51
|
-
kind: z.ZodEnum<{
|
|
52
|
-
uncoveredOutcome: "uncoveredOutcome";
|
|
53
|
-
unimplementedBoundary: "unimplementedBoundary";
|
|
54
|
-
outcomeShapeMismatch: "outcomeShapeMismatch";
|
|
55
|
-
undeclaredOutcome: "undeclaredOutcome";
|
|
56
|
-
unkeyableBoundary: "unkeyableBoundary";
|
|
57
|
-
renamedBoundary: "renamedBoundary";
|
|
58
|
-
unreadInputField: "unreadInputField";
|
|
59
|
-
undeclaredInputRead: "undeclaredInputRead";
|
|
60
|
-
unlinkedScenario: "unlinkedScenario";
|
|
61
|
-
danglingScenarioLink: "danglingScenarioLink";
|
|
62
|
-
ambiguousScenarioLink: "ambiguousScenarioLink";
|
|
63
|
-
undescribedOutcome: "undescribedOutcome";
|
|
64
|
-
}>;
|
|
65
|
-
severity: z.ZodEnum<{
|
|
66
|
-
error: "error";
|
|
67
|
-
warning: "warning";
|
|
68
|
-
info: "info";
|
|
69
|
-
}>;
|
|
70
|
-
boundary: z.ZodString;
|
|
71
|
-
intent: z.ZodObject<{
|
|
72
|
-
name: z.ZodString;
|
|
73
|
-
outcomeId: z.ZodOptional<z.ZodString>;
|
|
74
|
-
}, z.core.$strip>;
|
|
75
|
-
code: z.ZodOptional<z.ZodString>;
|
|
76
|
-
scenario: z.ZodOptional<z.ZodObject<{
|
|
77
|
-
title: z.ZodOptional<z.ZodString>;
|
|
78
|
-
link: z.ZodOptional<z.ZodString>;
|
|
79
|
-
}, z.core.$strip>>;
|
|
80
|
-
message: z.ZodString;
|
|
81
|
-
suppressed: z.ZodOptional<z.ZodObject<{
|
|
82
|
-
reason: z.ZodString;
|
|
83
|
-
effect: z.ZodEnum<{
|
|
84
|
-
mark: "mark";
|
|
85
|
-
downgrade: "downgrade";
|
|
86
|
-
hide: "hide";
|
|
87
|
-
}>;
|
|
88
|
-
originalSeverity: z.ZodOptional<z.ZodEnum<{
|
|
89
|
-
error: "error";
|
|
90
|
-
warning: "warning";
|
|
91
|
-
info: "info";
|
|
92
|
-
}>>;
|
|
93
|
-
}, z.core.$strip>>;
|
|
94
|
-
}, z.core.$strip>;
|
|
95
|
-
type IntentFinding = z.infer<typeof IntentFindingSchema>;
|
|
96
19
|
|
|
97
20
|
declare const IntentSourceSchema: z.ZodDefault<z.ZodEnum<{
|
|
98
21
|
author: "author";
|
|
@@ -110,18 +33,25 @@ declare const IntentSourceSchema: z.ZodDefault<z.ZodEnum<{
|
|
|
110
33
|
*/
|
|
111
34
|
declare function blanksLeftEmpty(doc: unknown, failedFields: string[]): string[];
|
|
112
35
|
/**
|
|
113
|
-
* The same draft with a placeholder
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
36
|
+
* The same draft with a placeholder in each blank, so a reader that
|
|
37
|
+
* wants the parts a draft does state can validate it and get them. Code
|
|
38
|
+
* that fills blanks this way must not show the placeholders to anybody,
|
|
39
|
+
* since those words come from suss and not from the team.
|
|
117
40
|
*/
|
|
118
41
|
declare function fillBlanks(doc: unknown, blanks: string[]): unknown;
|
|
119
|
-
|
|
42
|
+
type AuthoredShape = {
|
|
120
43
|
type: z.infer<typeof PrimitiveTypeName> | "array" | "object";
|
|
121
44
|
items?: AuthoredShape | undefined;
|
|
122
45
|
properties?: Record<string, AuthoredShape> | undefined;
|
|
123
46
|
required?: string[] | undefined;
|
|
124
|
-
}
|
|
47
|
+
} | {
|
|
48
|
+
const: AuthoredConstant;
|
|
49
|
+
} | {
|
|
50
|
+
properties: Record<string, AuthoredShape>;
|
|
51
|
+
required?: string[] | undefined;
|
|
52
|
+
};
|
|
53
|
+
/** A literal a value has to equal, such as a finding kind or a flag that is always true. */
|
|
54
|
+
type AuthoredConstant = string | number | boolean | null;
|
|
125
55
|
declare const BodyShapeSchema: z.ZodUnion<readonly [z.ZodType<AuthoredShape, unknown, z.core.$ZodTypeInternals<AuthoredShape, unknown>>, z.ZodObject<{
|
|
126
56
|
properties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<AuthoredShape, unknown, z.core.$ZodTypeInternals<AuthoredShape, unknown>>>>;
|
|
127
57
|
required: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -434,8 +364,26 @@ type DeclaredEffect = Partial<Record<EffectRelation, string>> & {
|
|
|
434
364
|
fields?: string[];
|
|
435
365
|
/** What it picks the item out by. */
|
|
436
366
|
by?: string | string[];
|
|
367
|
+
/** The shape of what it writes, such as the report a command prints. */
|
|
368
|
+
shape?: BodyShape;
|
|
369
|
+
/**
|
|
370
|
+
* Where the value of a column under `fields` or `by` comes from, by
|
|
371
|
+
* column: `{ tenant_id: input.headers.x-tenant-id }`. Only a `results`
|
|
372
|
+
* line takes it.
|
|
373
|
+
*/
|
|
374
|
+
from?: Record<string, string>;
|
|
437
375
|
};
|
|
376
|
+
/** What a source written in `from` starts with. */
|
|
377
|
+
declare const INPUT_SOURCE_PREFIX = "input.";
|
|
378
|
+
/** An effect as a change list states one, which says nothing of sources. */
|
|
379
|
+
declare const EffectLineSchema: z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>;
|
|
380
|
+
/** A `results` line, which can also say where a column's value comes from. */
|
|
438
381
|
declare const EffectOutcomeSchema: z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>;
|
|
382
|
+
/** One `always` line: an effect, and the outcomes that do not have to have it. */
|
|
383
|
+
type DeclaredAlways = DeclaredEffect & {
|
|
384
|
+
except?: string[];
|
|
385
|
+
};
|
|
386
|
+
declare const AlwaysEffectSchema: z.ZodUnion<[z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>, ...z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>[]]>;
|
|
439
387
|
/** One clause of a structured `when`, or the sentence for a guard that maps to none. */
|
|
440
388
|
type WhenClause = string | ({
|
|
441
389
|
where?: string;
|
|
@@ -465,6 +413,7 @@ declare const BoundaryTransitionSchema: z.ZodObject<{
|
|
|
465
413
|
throws: z.ZodOptional<z.ZodPreprocess<z.ZodObject<{
|
|
466
414
|
errorType: z.ZodOptional<z.ZodString>;
|
|
467
415
|
}, z.core.$strip>>>;
|
|
416
|
+
exits: z.ZodOptional<z.ZodNumber>;
|
|
468
417
|
results: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>>>;
|
|
469
418
|
}, z.core.$strict>;
|
|
470
419
|
declare const BoundaryIntentSchema: z.ZodObject<{
|
|
@@ -696,14 +645,18 @@ declare const BoundaryIntentSchema: z.ZodObject<{
|
|
|
696
645
|
throws: z.ZodOptional<z.ZodPreprocess<z.ZodObject<{
|
|
697
646
|
errorType: z.ZodOptional<z.ZodString>;
|
|
698
647
|
}, z.core.$strip>>>;
|
|
648
|
+
exits: z.ZodOptional<z.ZodNumber>;
|
|
699
649
|
results: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>>>;
|
|
700
650
|
}, z.core.$strict>>;
|
|
651
|
+
always: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>, ...z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>[]]>>>;
|
|
701
652
|
}, z.core.$strict>;
|
|
702
653
|
declare const PrdScenarioSchema: z.ZodObject<{
|
|
703
654
|
title: z.ZodOptional<z.ZodString>;
|
|
704
655
|
when: z.ZodString;
|
|
705
656
|
expect: z.ZodString;
|
|
706
657
|
link: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
658
|
+
coveredBy: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
659
|
+
about: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
707
660
|
}, z.core.$strict>;
|
|
708
661
|
declare const PrdSchema: z.ZodObject<{
|
|
709
662
|
kind: z.ZodLiteral<"prd">;
|
|
@@ -720,6 +673,8 @@ declare const PrdSchema: z.ZodObject<{
|
|
|
720
673
|
when: z.ZodString;
|
|
721
674
|
expect: z.ZodString;
|
|
722
675
|
link: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
676
|
+
coveredBy: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
677
|
+
about: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
723
678
|
}, z.core.$strict>>;
|
|
724
679
|
}, z.core.$strict>;
|
|
725
680
|
declare const IntentDocSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -951,8 +906,10 @@ declare const IntentDocSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
951
906
|
throws: z.ZodOptional<z.ZodPreprocess<z.ZodObject<{
|
|
952
907
|
errorType: z.ZodOptional<z.ZodString>;
|
|
953
908
|
}, z.core.$strip>>>;
|
|
909
|
+
exits: z.ZodOptional<z.ZodNumber>;
|
|
954
910
|
results: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>>>;
|
|
955
911
|
}, z.core.$strict>>;
|
|
912
|
+
always: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>, ...z.ZodType<DeclaredAlways, unknown, z.core.$ZodTypeInternals<DeclaredAlways, unknown>>[]]>>>;
|
|
956
913
|
}, z.core.$strict>, z.ZodObject<{
|
|
957
914
|
kind: z.ZodLiteral<"prd">;
|
|
958
915
|
title: z.ZodString;
|
|
@@ -968,6 +925,8 @@ declare const IntentDocSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
968
925
|
when: z.ZodString;
|
|
969
926
|
expect: z.ZodString;
|
|
970
927
|
link: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
928
|
+
coveredBy: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
929
|
+
about: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
971
930
|
}, z.core.$strict>>;
|
|
972
931
|
}, z.core.$strict>], "kind">;
|
|
973
932
|
type IntentDoc = z.infer<typeof IntentDocSchema>;
|
|
@@ -997,26 +956,79 @@ declare const PrimitiveTypeName: z.ZodEnum<{
|
|
|
997
956
|
}>;
|
|
998
957
|
type PrimitiveTypeName = z.infer<typeof PrimitiveTypeName>;
|
|
999
958
|
|
|
959
|
+
/**
|
|
960
|
+
* How a PRD scenario spells the test that covers it, the way the test
|
|
961
|
+
* runner prints it. vitest and RSpec write the file, each describe or
|
|
962
|
+
* context title, then the test's own title, joined with ` > `. pytest
|
|
963
|
+
* prints a node id, the file, any class, then the test function, joined
|
|
964
|
+
* with `::`. Both come apart into the same file and title path, and a
|
|
965
|
+
* test unit's name is that title path joined with ` > `, so one lookup
|
|
966
|
+
* serves every runner.
|
|
967
|
+
*/
|
|
968
|
+
|
|
969
|
+
/** What separates the file, a class and a test function in a pytest node id. */
|
|
970
|
+
declare const NODE_ID_SEPARATOR = "::";
|
|
971
|
+
/** One `coveredBy` entry, split into the test file and its title path. */
|
|
972
|
+
interface CoveringTestSpelling {
|
|
973
|
+
/** The entry as the author wrote it. */
|
|
974
|
+
spelledAs: string;
|
|
975
|
+
/** The test file, with the workspace in front when the author wrote one. */
|
|
976
|
+
file: string;
|
|
977
|
+
/** The suite titles, outermost first, then the test's own title. Empty when the entry has none. */
|
|
978
|
+
titles: string[];
|
|
979
|
+
}
|
|
980
|
+
declare function toCoveringTest(spelledAs: string): CoveringTestSpelling;
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* The normalized intent form the checker compares against behavioral
|
|
984
|
+
* summaries.
|
|
985
|
+
*
|
|
986
|
+
* The authoring schema is built to be easy to write, and this form is
|
|
987
|
+
* built to be easy to check: boundaries as @suss/ir-core
|
|
988
|
+
* `BoundaryBinding`s, body shapes as `TypeShape`s, and one flat
|
|
989
|
+
* outcome list per boundary intent.
|
|
990
|
+
*/
|
|
991
|
+
|
|
1000
992
|
/**
|
|
1001
993
|
* How a boundary outcome ends. `effect` is an outcome that declares
|
|
1002
994
|
* only what it did, which is what a queue consumer or a table writer
|
|
1003
995
|
* has to say instead of a status.
|
|
1004
996
|
*/
|
|
1005
|
-
type IntentOutcomeKind = "response" | "return" | "throw" | "effect";
|
|
997
|
+
type IntentOutcomeKind = "response" | "return" | "throw" | "exit" | "effect";
|
|
1006
998
|
/** One effect an outcome has, in the verbs `suss ask` asks with. */
|
|
1007
999
|
interface IntentEffect {
|
|
1008
1000
|
does: EffectRelation;
|
|
1009
|
-
/** The boundary it reaches, as the author
|
|
1001
|
+
/** The boundary it reaches, as the author wrote it. */
|
|
1010
1002
|
names: string;
|
|
1011
1003
|
/** The columns it touches. Empty when the doc states none. */
|
|
1012
1004
|
fields: string[];
|
|
1013
1005
|
/** What it picks the item out by. Empty when the doc states none. */
|
|
1014
1006
|
by: string[];
|
|
1007
|
+
/** The shape of what it writes, when the doc states one. */
|
|
1008
|
+
shape?: TypeShape;
|
|
1009
|
+
/** Where the value of each column the doc gives a source for comes from. */
|
|
1010
|
+
from?: IntentValueSource[];
|
|
1011
|
+
}
|
|
1012
|
+
/** Where a `results` line says one column's value comes from. */
|
|
1013
|
+
interface IntentValueSource {
|
|
1014
|
+
/** The column, one the line lists under `fields` or `by`. */
|
|
1015
|
+
column: string;
|
|
1016
|
+
/** The path off the boundary's input: `input.headers.x-tenant-id` is `["headers", "x-tenant-id"]`. */
|
|
1017
|
+
path: string[];
|
|
1015
1018
|
}
|
|
1016
1019
|
/**
|
|
1017
|
-
*
|
|
1018
|
-
*
|
|
1019
|
-
*
|
|
1020
|
+
* An effect every transition producing a declared outcome has. A
|
|
1021
|
+
* `results` line is satisfied by one transition; this is satisfied only
|
|
1022
|
+
* when none of them lacks it.
|
|
1023
|
+
*/
|
|
1024
|
+
interface IntentAlways {
|
|
1025
|
+
effect: IntentEffect;
|
|
1026
|
+
/** The outcome ids whose transitions do not have to have it. */
|
|
1027
|
+
except: string[];
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* One clause of what a branch turned on. The checker compares a clause
|
|
1031
|
+
* whose subject is a boundary, and the rest are kept for a reader.
|
|
1020
1032
|
*/
|
|
1021
1033
|
interface IntentCondition {
|
|
1022
1034
|
/** The boundary the guard read, when the clause says one. */
|
|
@@ -1029,14 +1041,14 @@ interface IntentCondition {
|
|
|
1029
1041
|
said: string;
|
|
1030
1042
|
}
|
|
1031
1043
|
interface IntentOutcome {
|
|
1032
|
-
/**
|
|
1044
|
+
/** The id the author gave the outcome, which PRD scenarios link to. */
|
|
1033
1045
|
id: string;
|
|
1034
1046
|
/** What the branch turned on, as one line, for a reader. */
|
|
1035
1047
|
when: string;
|
|
1036
1048
|
/** The same, clause by clause, for the checker to compare. */
|
|
1037
1049
|
conditions: IntentCondition[];
|
|
1038
1050
|
kind: IntentOutcomeKind;
|
|
1039
|
-
/**
|
|
1051
|
+
/** The REST status code of a `response` outcome, or the exit code of an `exit` one. */
|
|
1040
1052
|
status: number | null;
|
|
1041
1053
|
/** Response / return body shape, when declared. */
|
|
1042
1054
|
body: TypeShape | null;
|
|
@@ -1067,6 +1079,8 @@ interface BoundaryIntentSummary {
|
|
|
1067
1079
|
/** Empty for a doc with no `receives` block, which states nothing about the input. */
|
|
1068
1080
|
receives: IntentInputField[];
|
|
1069
1081
|
outcomes: IntentOutcome[];
|
|
1082
|
+
/** Empty for a doc with no `always` block. */
|
|
1083
|
+
always: IntentAlways[];
|
|
1070
1084
|
}
|
|
1071
1085
|
interface PrdScenarioSummary {
|
|
1072
1086
|
title: string | null;
|
|
@@ -1076,6 +1090,10 @@ interface PrdScenarioSummary {
|
|
|
1076
1090
|
expect: string;
|
|
1077
1091
|
/** Qualified outcome refs (`<intent-name>.<outcome-id>`); empty when unlinked. */
|
|
1078
1092
|
link: string[];
|
|
1093
|
+
/** The tests the scenario lists as covering it. Empty when it lists none. */
|
|
1094
|
+
coveredBy: CoveringTestSpelling[];
|
|
1095
|
+
/** What a covering test has to reach. Empty means the PRD's linked boundaries. */
|
|
1096
|
+
about: string[];
|
|
1079
1097
|
}
|
|
1080
1098
|
interface PrdSummary {
|
|
1081
1099
|
kind: "prd";
|
|
@@ -1089,5 +1107,247 @@ type IntentSummary = BoundaryIntentSummary | PrdSummary;
|
|
|
1089
1107
|
declare function intentDocToSummary(doc: IntentDoc): IntentSummary;
|
|
1090
1108
|
declare function toBoundaryBinding(boundary: Boundary): BoundaryBinding;
|
|
1091
1109
|
declare function toReceives(boundary: Boundary): IntentInputField[];
|
|
1110
|
+
/** One `results` line, or a change list's effect, in the form the checker compares. */
|
|
1111
|
+
declare function toIntentEffect(declared: DeclaredEffect): IntentEffect;
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* The change list: the behavior changes an agent says it will make for
|
|
1115
|
+
* one request, written before it edits anything.
|
|
1116
|
+
*
|
|
1117
|
+
* It takes the boundary intent vocabulary line by line. A subject is a
|
|
1118
|
+
* boundary spelled the way `suss ask` spells it, or an effect written the
|
|
1119
|
+
* way a `results` line is. Each entry adds one verb, `adds`, `removes` or
|
|
1120
|
+
* `changes`, and leaves out `when`, `purpose` and `audience`, which an
|
|
1121
|
+
* agent cannot know before it has written the code. `explained` lists the
|
|
1122
|
+
* changes the agent made without being asked and keeps, each with why.
|
|
1123
|
+
*
|
|
1124
|
+
* The CLI compares a list with two readings of the code and says which
|
|
1125
|
+
* entries are done, and which changes nobody asked for.
|
|
1126
|
+
*/
|
|
1127
|
+
|
|
1128
|
+
declare const VERBS: readonly ["adds", "removes", "changes"];
|
|
1129
|
+
type ChangeVerb = (typeof VERBS)[number];
|
|
1130
|
+
declare const ChangeEntrySchema: z.ZodObject<{
|
|
1131
|
+
asked: z.ZodOptional<z.ZodString>;
|
|
1132
|
+
note: z.ZodOptional<z.ZodString>;
|
|
1133
|
+
adds: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1134
|
+
removes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1135
|
+
changes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1136
|
+
outcomes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodEnum<{
|
|
1137
|
+
returns: "returns";
|
|
1138
|
+
throws: "throws";
|
|
1139
|
+
}>, z.ZodObject<{
|
|
1140
|
+
throws: z.ZodString;
|
|
1141
|
+
}, z.core.$strict>]>>>;
|
|
1142
|
+
at: z.ZodOptional<z.ZodString>;
|
|
1143
|
+
}, z.core.$strict>;
|
|
1144
|
+
declare const ExplainedEntrySchema: z.ZodObject<{
|
|
1145
|
+
why: z.ZodString;
|
|
1146
|
+
adds: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1147
|
+
removes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1148
|
+
changes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1149
|
+
outcomes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodEnum<{
|
|
1150
|
+
returns: "returns";
|
|
1151
|
+
throws: "throws";
|
|
1152
|
+
}>, z.ZodObject<{
|
|
1153
|
+
throws: z.ZodString;
|
|
1154
|
+
}, z.core.$strict>]>>>;
|
|
1155
|
+
at: z.ZodOptional<z.ZodString>;
|
|
1156
|
+
}, z.core.$strict>;
|
|
1157
|
+
declare const ChangeListSchema: z.ZodObject<{
|
|
1158
|
+
asked: z.ZodOptional<z.ZodString>;
|
|
1159
|
+
changes: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1160
|
+
asked: z.ZodOptional<z.ZodString>;
|
|
1161
|
+
note: z.ZodOptional<z.ZodString>;
|
|
1162
|
+
adds: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1163
|
+
removes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1164
|
+
changes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1165
|
+
outcomes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodEnum<{
|
|
1166
|
+
returns: "returns";
|
|
1167
|
+
throws: "throws";
|
|
1168
|
+
}>, z.ZodObject<{
|
|
1169
|
+
throws: z.ZodString;
|
|
1170
|
+
}, z.core.$strict>]>>>;
|
|
1171
|
+
at: z.ZodOptional<z.ZodString>;
|
|
1172
|
+
}, z.core.$strict>>>;
|
|
1173
|
+
explained: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1174
|
+
why: z.ZodString;
|
|
1175
|
+
adds: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1176
|
+
removes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1177
|
+
changes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<[z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>, ...z.ZodType<DeclaredEffect, unknown, z.core.$ZodTypeInternals<DeclaredEffect, unknown>>[]]>]>>;
|
|
1178
|
+
outcomes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodEnum<{
|
|
1179
|
+
returns: "returns";
|
|
1180
|
+
throws: "throws";
|
|
1181
|
+
}>, z.ZodObject<{
|
|
1182
|
+
throws: z.ZodString;
|
|
1183
|
+
}, z.core.$strict>]>>>;
|
|
1184
|
+
at: z.ZodOptional<z.ZodString>;
|
|
1185
|
+
}, z.core.$strict>>>;
|
|
1186
|
+
}, z.core.$strict>;
|
|
1187
|
+
type ChangeList = z.infer<typeof ChangeListSchema>;
|
|
1188
|
+
type ChangeEntry = z.infer<typeof ChangeEntrySchema>;
|
|
1189
|
+
type ExplainedEntry = z.infer<typeof ExplainedEntrySchema>;
|
|
1190
|
+
/** What an entry is about: a boundary by its spelling, or an effect. */
|
|
1191
|
+
type ChangeSubject = {
|
|
1192
|
+
kind: "boundary";
|
|
1193
|
+
names: string;
|
|
1194
|
+
} | {
|
|
1195
|
+
kind: "effect";
|
|
1196
|
+
effect: IntentEffect;
|
|
1197
|
+
};
|
|
1198
|
+
/** An outcome an entry lists, in the terms the intent checker compares. */
|
|
1199
|
+
type ChangeOutcome = Pick<IntentOutcome, "kind" | "status" | "errorType">;
|
|
1200
|
+
interface IntentChange {
|
|
1201
|
+
verb: ChangeVerb;
|
|
1202
|
+
subject: ChangeSubject;
|
|
1203
|
+
outcomes: ChangeOutcome[];
|
|
1204
|
+
/** The boundary an effect happens at. Null means any boundary. */
|
|
1205
|
+
at: string | null;
|
|
1206
|
+
/** The developer's words that asked for the entry: its own quote, or else the list's. */
|
|
1207
|
+
asked: string | null;
|
|
1208
|
+
note: string | null;
|
|
1209
|
+
}
|
|
1210
|
+
interface ExplainedChange {
|
|
1211
|
+
verb: ChangeVerb;
|
|
1212
|
+
subject: ChangeSubject;
|
|
1213
|
+
outcomes: ChangeOutcome[];
|
|
1214
|
+
at: string | null;
|
|
1215
|
+
why: string;
|
|
1216
|
+
}
|
|
1217
|
+
interface ChangeListSummary {
|
|
1218
|
+
asked: string | null;
|
|
1219
|
+
changes: IntentChange[];
|
|
1220
|
+
explained: ExplainedChange[];
|
|
1221
|
+
}
|
|
1222
|
+
/** A change list, or each place where it does not fit the schema. */
|
|
1223
|
+
type ParsedChangeList = {
|
|
1224
|
+
ok: true;
|
|
1225
|
+
list: ChangeListSummary;
|
|
1226
|
+
} | {
|
|
1227
|
+
ok: false;
|
|
1228
|
+
problems: Array<{
|
|
1229
|
+
path: string;
|
|
1230
|
+
message: string;
|
|
1231
|
+
}>;
|
|
1232
|
+
};
|
|
1233
|
+
/** Validates a change list that is already parsed from YAML or JSON, and converts it. */
|
|
1234
|
+
declare function parseChangeList(raw: unknown): ParsedChangeList;
|
|
1235
|
+
declare function changeListToSummary(list: ChangeList): ChangeListSummary;
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* The findings the intent checker emits.
|
|
1239
|
+
*
|
|
1240
|
+
* A behavioral `Finding` compares two peers, a provider and a consumer,
|
|
1241
|
+
* each with a source location. An intent finding checks coverage from
|
|
1242
|
+
* one side: the team declared something, and the question is whether
|
|
1243
|
+
* the code does it. Intent is identified by a name and an outcome id,
|
|
1244
|
+
* with no file or range, so an intent finding has its own fields, and
|
|
1245
|
+
* PRD scenario findings add to them.
|
|
1246
|
+
*/
|
|
1247
|
+
|
|
1248
|
+
declare const IntentFindingKindSchema: z.ZodEnum<{
|
|
1249
|
+
uncoveredOutcome: "uncoveredOutcome";
|
|
1250
|
+
unimplementedBoundary: "unimplementedBoundary";
|
|
1251
|
+
outcomeShapeMismatch: "outcomeShapeMismatch";
|
|
1252
|
+
undeclaredOutcome: "undeclaredOutcome";
|
|
1253
|
+
unkeyableBoundary: "unkeyableBoundary";
|
|
1254
|
+
renamedBoundary: "renamedBoundary";
|
|
1255
|
+
pathWithoutEffect: "pathWithoutEffect";
|
|
1256
|
+
valueFromElsewhere: "valueFromElsewhere";
|
|
1257
|
+
unreadInputField: "unreadInputField";
|
|
1258
|
+
undeclaredInputRead: "undeclaredInputRead";
|
|
1259
|
+
unlinkedScenario: "unlinkedScenario";
|
|
1260
|
+
danglingScenarioLink: "danglingScenarioLink";
|
|
1261
|
+
ambiguousScenarioLink: "ambiguousScenarioLink";
|
|
1262
|
+
missingCoveringTest: "missingCoveringTest";
|
|
1263
|
+
testMissesSubject: "testMissesSubject";
|
|
1264
|
+
coveringTestSkipped: "coveringTestSkipped";
|
|
1265
|
+
undescribedOutcome: "undescribedOutcome";
|
|
1266
|
+
}>;
|
|
1267
|
+
type IntentFindingKind = z.infer<typeof IntentFindingKindSchema>;
|
|
1268
|
+
declare const IntentFindingSeveritySchema: z.ZodEnum<{
|
|
1269
|
+
error: "error";
|
|
1270
|
+
warning: "warning";
|
|
1271
|
+
info: "info";
|
|
1272
|
+
}>;
|
|
1273
|
+
type IntentFindingSeverity = z.infer<typeof IntentFindingSeveritySchema>;
|
|
1274
|
+
/** Which intent (and, when relevant, which outcome) a finding concerns. */
|
|
1275
|
+
declare const IntentRefSchema: z.ZodObject<{
|
|
1276
|
+
name: z.ZodString;
|
|
1277
|
+
outcomeId: z.ZodOptional<z.ZodString>;
|
|
1278
|
+
}, z.core.$strip>;
|
|
1279
|
+
type IntentRef = z.infer<typeof IntentRefSchema>;
|
|
1280
|
+
/**
|
|
1281
|
+
* The annotation the `.sussignore` pipeline adds to a matched finding.
|
|
1282
|
+
* It stays structurally identical to the behavioral
|
|
1283
|
+
* `Finding.suppressed`, so @suss/ir-core's shared suppression pipeline
|
|
1284
|
+
* works on both.
|
|
1285
|
+
*/
|
|
1286
|
+
declare const IntentFindingSuppressionSchema: z.ZodObject<{
|
|
1287
|
+
reason: z.ZodString;
|
|
1288
|
+
effect: z.ZodEnum<{
|
|
1289
|
+
mark: "mark";
|
|
1290
|
+
downgrade: "downgrade";
|
|
1291
|
+
hide: "hide";
|
|
1292
|
+
}>;
|
|
1293
|
+
originalSeverity: z.ZodOptional<z.ZodEnum<{
|
|
1294
|
+
error: "error";
|
|
1295
|
+
warning: "warning";
|
|
1296
|
+
info: "info";
|
|
1297
|
+
}>>;
|
|
1298
|
+
}, z.core.$strip>;
|
|
1299
|
+
type IntentFindingSuppression = z.infer<typeof IntentFindingSuppressionSchema>;
|
|
1300
|
+
declare const IntentFindingSchema: z.ZodObject<{
|
|
1301
|
+
kind: z.ZodEnum<{
|
|
1302
|
+
uncoveredOutcome: "uncoveredOutcome";
|
|
1303
|
+
unimplementedBoundary: "unimplementedBoundary";
|
|
1304
|
+
outcomeShapeMismatch: "outcomeShapeMismatch";
|
|
1305
|
+
undeclaredOutcome: "undeclaredOutcome";
|
|
1306
|
+
unkeyableBoundary: "unkeyableBoundary";
|
|
1307
|
+
renamedBoundary: "renamedBoundary";
|
|
1308
|
+
pathWithoutEffect: "pathWithoutEffect";
|
|
1309
|
+
valueFromElsewhere: "valueFromElsewhere";
|
|
1310
|
+
unreadInputField: "unreadInputField";
|
|
1311
|
+
undeclaredInputRead: "undeclaredInputRead";
|
|
1312
|
+
unlinkedScenario: "unlinkedScenario";
|
|
1313
|
+
danglingScenarioLink: "danglingScenarioLink";
|
|
1314
|
+
ambiguousScenarioLink: "ambiguousScenarioLink";
|
|
1315
|
+
missingCoveringTest: "missingCoveringTest";
|
|
1316
|
+
testMissesSubject: "testMissesSubject";
|
|
1317
|
+
coveringTestSkipped: "coveringTestSkipped";
|
|
1318
|
+
undescribedOutcome: "undescribedOutcome";
|
|
1319
|
+
}>;
|
|
1320
|
+
severity: z.ZodEnum<{
|
|
1321
|
+
error: "error";
|
|
1322
|
+
warning: "warning";
|
|
1323
|
+
info: "info";
|
|
1324
|
+
}>;
|
|
1325
|
+
boundary: z.ZodString;
|
|
1326
|
+
intent: z.ZodObject<{
|
|
1327
|
+
name: z.ZodString;
|
|
1328
|
+
outcomeId: z.ZodOptional<z.ZodString>;
|
|
1329
|
+
}, z.core.$strip>;
|
|
1330
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1331
|
+
scenario: z.ZodOptional<z.ZodObject<{
|
|
1332
|
+
title: z.ZodOptional<z.ZodString>;
|
|
1333
|
+
link: z.ZodOptional<z.ZodString>;
|
|
1334
|
+
coveredBy: z.ZodOptional<z.ZodString>;
|
|
1335
|
+
}, z.core.$strip>>;
|
|
1336
|
+
message: z.ZodString;
|
|
1337
|
+
suppressed: z.ZodOptional<z.ZodObject<{
|
|
1338
|
+
reason: z.ZodString;
|
|
1339
|
+
effect: z.ZodEnum<{
|
|
1340
|
+
mark: "mark";
|
|
1341
|
+
downgrade: "downgrade";
|
|
1342
|
+
hide: "hide";
|
|
1343
|
+
}>;
|
|
1344
|
+
originalSeverity: z.ZodOptional<z.ZodEnum<{
|
|
1345
|
+
error: "error";
|
|
1346
|
+
warning: "warning";
|
|
1347
|
+
info: "info";
|
|
1348
|
+
}>>;
|
|
1349
|
+
}, z.core.$strip>>;
|
|
1350
|
+
}, z.core.$strip>;
|
|
1351
|
+
type IntentFinding = z.infer<typeof IntentFindingSchema>;
|
|
1092
1352
|
|
|
1093
|
-
export { ACCEPTS_NULL, type AuthoredBoundary, type AuthoredInputField, type AuthoredReceives, type AuthoredRestReceives, type AuthoredShape, type BodyShape, BodyShapeSchema, type Boundary, type BoundaryIntent, type BoundaryIntentSummary, BoundarySchema, type BoundaryTransition, type EffectOutcome, type IntentCondition, type IntentDoc, IntentDocSchema, type IntentEffect, type IntentFinding, type IntentFindingKind, IntentFindingKindSchema, IntentFindingSchema, type IntentFindingSeverity, IntentFindingSeveritySchema, type IntentFindingSuppression, IntentFindingSuppressionSchema, type IntentInputField, type IntentOutcome, type IntentOutcomeKind, type IntentRef, IntentRefSchema, type IntentSource, IntentSourceSchema, type IntentSummary, type Prd, type PrdScenario, type PrdScenarioSummary, type PrdSummary, PrimitiveTypeName, type When, type WhenClause, blanksLeftEmpty, fillBlanks, intentDocToSummary, toBoundaryBinding, toReceives };
|
|
1353
|
+
export { ACCEPTS_NULL, AlwaysEffectSchema, type AuthoredBoundary, type AuthoredConstant, type AuthoredInputField, type AuthoredReceives, type AuthoredRestReceives, type AuthoredShape, type BodyShape, BodyShapeSchema, type Boundary, type BoundaryIntent, type BoundaryIntentSummary, BoundarySchema, type BoundaryTransition, type ChangeEntry, type ChangeList, ChangeListSchema, type ChangeListSummary, type ChangeOutcome, type ChangeSubject, type ChangeVerb, type CoveringTestSpelling, type DeclaredAlways, type DeclaredEffect, EffectLineSchema, type EffectOutcome, EffectOutcomeSchema, type ExplainedChange, type ExplainedEntry, INPUT_SOURCE_PREFIX, type IntentAlways, type IntentChange, type IntentCondition, type IntentDoc, IntentDocSchema, type IntentEffect, type IntentFinding, type IntentFindingKind, IntentFindingKindSchema, IntentFindingSchema, type IntentFindingSeverity, IntentFindingSeveritySchema, type IntentFindingSuppression, IntentFindingSuppressionSchema, type IntentInputField, type IntentOutcome, type IntentOutcomeKind, type IntentRef, IntentRefSchema, type IntentSource, IntentSourceSchema, type IntentSummary, type IntentValueSource, NODE_ID_SEPARATOR, type ParsedChangeList, type Prd, type PrdScenario, type PrdScenarioSummary, type PrdSummary, PrimitiveTypeName, type When, type WhenClause, blanksLeftEmpty, changeListToSummary, fillBlanks, intentDocToSummary, parseChangeList, toBoundaryBinding, toCoveringTest, toIntentEffect, toReceives };
|