@skyramp/mcp 0.4.0 → 0.4.1-rc.2
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/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.js +2 -1
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.js +2 -1
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -1
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +57 -22
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +17 -9
- package/build/prompts/test-recommendation/diffExecutionPlan.js +0 -2
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +11 -6
- package/build/prompts/testbot/testbot-prompts.js +19 -12
- package/build/recommendation/answers.d.ts +11 -7
- package/build/recommendation/answers.js +14 -10
- package/build/recommendation/pullRequestText.d.ts +18 -0
- package/build/recommendation/pullRequestText.js +31 -0
- package/build/recommendation/registerPlan.d.ts +9 -1
- package/build/recommendation/registerPlan.js +8 -1
- package/build/recommendation/runVerifiers.js +6 -0
- package/build/recommendation/types.d.ts +58 -0
- package/build/recommendation/verifierContracts.d.ts +108 -13
- package/build/recommendation/verifierContracts.js +147 -29
- package/build/recommendation/verifiers/coverage.d.ts +10 -0
- package/build/recommendation/verifiers/coverage.js +144 -22
- package/build/recommendation/verifiers/defects.d.ts +9 -0
- package/build/recommendation/verifiers/defects.js +117 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +22 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.js +43 -0
- package/build/recommendation/verifiers/existingCoverage.js +53 -0
- package/build/recommendation/verifiers/expectedValueSourced.d.ts +14 -0
- package/build/recommendation/verifiers/expectedValueSourced.js +246 -0
- package/build/recommendation/verifiers/issueTraceability.d.ts +52 -0
- package/build/recommendation/verifiers/issueTraceability.js +197 -0
- package/build/recommendation/verifiers/requirementSourced.d.ts +2 -0
- package/build/recommendation/verifiers/requirementSourced.js +168 -0
- package/build/services/TestGenerationService.js +3 -1
- package/build/tools/code-refactor/codeReuseTool.js +1 -1
- package/build/tools/code-refactor/reuse-outcome.d.ts +1 -1
- package/build/tools/code-refactor/reuse-state.d.ts +85 -7
- package/build/tools/code-refactor/reuse-state.js +239 -34
- package/build/tools/code-refactor/utils-verify-gates.d.ts +5 -0
- package/build/tools/code-refactor/utils-verify-gates.js +103 -11
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +2 -1
- package/build/tools/submitReportTool.js +276 -39
- package/build/tools/test-management/actionsTool.js +5 -0
- package/build/tools/test-management/analyzeChangesTool.d.ts +53 -0
- package/build/tools/test-management/analyzeChangesTool.js +55 -2
- package/build/tools/test-management/registerTestPlanTool.d.ts +32 -17
- package/build/tools/test-management/registerTestPlanTool.js +105 -16
- package/build/types/ReuseOutcome.d.ts +73 -7
- package/build/types/TestAnalysis.d.ts +6 -0
- package/build/types/TestbotReport.d.ts +22 -4
- package/build/utils/AnalysisStateManager.d.ts +7 -1
- package/build/utils/AnalysisStateManager.js +5 -1
- package/build/utils/assertion-verify/api-shared-lints.js +118 -11
- package/build/utils/assertion-verify/format.js +2 -2
- package/build/utils/assertion-verify/helper-imports.d.ts +7 -0
- package/build/utils/assertion-verify/helper-imports.js +119 -27
- package/build/utils/assertion-verify/lint-types.d.ts +31 -2
- package/build/utils/assertion-verify/lint-types.js +66 -0
- package/build/utils/assertion-verify/metrics.d.ts +13 -0
- package/build/utils/assertion-verify/metrics.js +16 -0
- package/build/utils/assertion-verify/verify.d.ts +11 -6
- package/build/utils/assertion-verify/verify.js +56 -15
- package/build/utils/canonicalJson.d.ts +11 -0
- package/build/utils/canonicalJson.js +17 -0
- package/build/utils/utils-verify/action-key.d.ts +27 -0
- package/build/utils/utils-verify/action-key.js +292 -0
- package/build/utils/utils-verify/allow.d.ts +8 -1
- package/build/utils/utils-verify/allow.js +14 -1
- package/build/utils/utils-verify/call-sites.d.ts +76 -8
- package/build/utils/utils-verify/call-sites.js +256 -70
- package/build/utils/utils-verify/language-spec.d.ts +3 -2
- package/build/utils/utils-verify/parse.d.ts +22 -3
- package/build/utils/utils-verify/parse.js +123 -52
- package/build/utils/utils-verify/verify.d.ts +33 -3
- package/build/utils/utils-verify/verify.js +126 -12
- package/build/utils/workspaceAuth.d.ts +59 -19
- package/build/utils/workspaceAuth.js +228 -31
- package/package.json +1 -1
- package/plugin/prompts/generate-tests/execution-plan.md +3 -3
- package/plugin/prompts/generate-tests/generation.md +1 -0
- package/plugin/prompts/plan-tests.md +41 -15
- package/plugin/prompts/testbot-task1.md +3 -9
- package/build/prompts/testbot/planDeclarations.d.ts +0 -6
- package/build/prompts/testbot/planDeclarations.js +0 -9
- package/plugin/prompts/declaring-a-plan.md +0 -20
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The pull request's own title and description, as the run rendered its prompt with.
|
|
2
|
+
*
|
|
3
|
+
* IN PROCESS, never the state file: the prompt and the plan tool are registered on
|
|
4
|
+
* the same server, so the text is already here, and writing it would put the pull
|
|
5
|
+
* request's prose on disk once per registration for a reader in the same process.
|
|
6
|
+
*
|
|
7
|
+
* ONE SLOT, last write wins. A run renders the prompt once, and a second render is
|
|
8
|
+
* a second run whose text replaces the first. */
|
|
9
|
+
let recorded;
|
|
10
|
+
const asText = (value) => (typeof value === "string" ? value : "");
|
|
11
|
+
/** Called by every entry point that renders the testbot prompt, with the values it
|
|
12
|
+
* renders. */
|
|
13
|
+
export function recordPullRequestText(title, description) {
|
|
14
|
+
recorded = { title: asText(title), description: asText(description) };
|
|
15
|
+
}
|
|
16
|
+
/** UNDEFINED when this process never rendered the prompt — a caller that drives the
|
|
17
|
+
* tools directly, or a test. A check that reads the pull request stays silent then;
|
|
18
|
+
* it cannot tell an empty pull request from one it never saw. */
|
|
19
|
+
export function pullRequestText() {
|
|
20
|
+
return recorded;
|
|
21
|
+
}
|
|
22
|
+
export function clearPullRequestText() {
|
|
23
|
+
recorded = undefined;
|
|
24
|
+
}
|
|
25
|
+
/** The pull request as one searchable string. Whitespace runs fold to one space, so
|
|
26
|
+
* a quote wrapped across lines still matches the sentence it was taken from. */
|
|
27
|
+
export const searchable = (pr) => `${pr.title}\n${pr.description}`.replace(/\s+/g, " ").trim().toLowerCase();
|
|
28
|
+
export const appearsIn = (haystack, needle) => {
|
|
29
|
+
const folded = needle.replace(/\s+/g, " ").trim().toLowerCase();
|
|
30
|
+
return folded.length > 0 && haystack.includes(folded);
|
|
31
|
+
};
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import { Objection, ObjectionAnswer, PlanChange, PlanInput, PlannedTest, VerifyContext } from "./types.js";
|
|
1
|
+
import { Objection, ObjectionAnswer, PlanChange, PlanDefect, PlanInput, PlanMaintenance, PlannedTest, VerifyContext } from "./types.js";
|
|
2
2
|
/** The plan as stored for the run. Every registration produces one; the newest
|
|
3
3
|
* replaces the last. */
|
|
4
4
|
export interface Plan {
|
|
5
5
|
/** The changes the agent said the diff makes. Published in the report
|
|
6
6
|
* beside the tests delivered against each one. */
|
|
7
7
|
changes: PlanChange[];
|
|
8
|
+
/** The defects the code review found. skyramp_submit_report reads them to hold
|
|
9
|
+
* the report to the review: every one is an issue, and every issue names the
|
|
10
|
+
* test that proves it. */
|
|
11
|
+
defects: PlanDefect[];
|
|
8
12
|
plannedTests: PlannedTest[];
|
|
13
|
+
/** Existing tests this run edits instead of planning new ones. Stored because
|
|
14
|
+
* `coverage` counts the changes they cite, so a reader of the plan has to be
|
|
15
|
+
* able to see which coverage came from maintenance rather than a new test. */
|
|
16
|
+
maintains?: PlanMaintenance[];
|
|
9
17
|
/** Objections the agent answered, with the answers. */
|
|
10
18
|
answeredObjections: Array<{
|
|
11
19
|
objection: Objection;
|
|
@@ -53,12 +53,13 @@ export function registerPlan(registration, ctx, previous) {
|
|
|
53
53
|
const acknowledged = Array.isArray(registration.answers) ? registration.answers : [];
|
|
54
54
|
const plannedTests = Array.isArray(registration.plannedTests) ? registration.plannedTests : [];
|
|
55
55
|
const changes = Array.isArray(registration.changes) ? registration.changes : [];
|
|
56
|
+
const defects = Array.isArray(registration.defects) ? registration.defects : [];
|
|
56
57
|
const registrationNumber = storedRegistrationNumber(registration);
|
|
57
58
|
// The verifiers see the same normalised fields the STORED plan gets, not the raw
|
|
58
59
|
// registration: handing them the raw one let a malformed top-level field crash
|
|
59
60
|
// every check at once, giving eight `:crashed` objections and no real ones.
|
|
60
61
|
// Crash containment is for a malformed field INSIDE a planned test.
|
|
61
|
-
const verified = runPlanTimeVerifiers({ ...registration, plannedTests, changes, answers: acknowledged }, ctx);
|
|
62
|
+
const verified = runPlanTimeVerifiers({ ...registration, plannedTests, changes, defects, answers: acknowledged }, ctx);
|
|
62
63
|
const objections = [
|
|
63
64
|
...verified,
|
|
64
65
|
...unknownAnswerObjections(verified, acknowledged, {
|
|
@@ -107,7 +108,13 @@ export function registerPlan(registration, ctx, previous) {
|
|
|
107
108
|
: {}),
|
|
108
109
|
plan: {
|
|
109
110
|
changes,
|
|
111
|
+
defects,
|
|
110
112
|
plannedTests,
|
|
113
|
+
// Only when declared: the field is optional, and writing `[]` on every plan
|
|
114
|
+
// would change the stored shape of every run that maintains nothing.
|
|
115
|
+
...(Array.isArray(registration.maintains) && registration.maintains.length > 0
|
|
116
|
+
? { maintains: registration.maintains }
|
|
117
|
+
: {}),
|
|
111
118
|
answeredObjections,
|
|
112
119
|
unverifiedCloses,
|
|
113
120
|
openObjections,
|
|
@@ -6,7 +6,10 @@ import { expectedOutcomeAtPlanTime } from "./verifiers/expectedOutcome.js";
|
|
|
6
6
|
import { uiElementGrounded } from "./verifiers/uiElementGrounded.js";
|
|
7
7
|
import { screenRoute } from "./verifiers/screenRoute.js";
|
|
8
8
|
import { coverage } from "./verifiers/coverage.js";
|
|
9
|
+
import { expectedValueSourced } from "./verifiers/expectedValueSourced.js";
|
|
9
10
|
import { removedElementGuarded } from "./verifiers/removedElementGuarded.js";
|
|
11
|
+
import { requirementSourced } from "./verifiers/requirementSourced.js";
|
|
12
|
+
import { defects } from "./verifiers/defects.js";
|
|
10
13
|
/** Verifiers that need only the plan and the run's facts. The order is the order
|
|
11
14
|
* objections are reported in; it carries no priority. */
|
|
12
15
|
export const PLAN_TIME_VERIFIERS = [
|
|
@@ -18,7 +21,10 @@ export const PLAN_TIME_VERIFIERS = [
|
|
|
18
21
|
uiElementGrounded,
|
|
19
22
|
screenRoute,
|
|
20
23
|
coverage,
|
|
24
|
+
expectedValueSourced,
|
|
21
25
|
removedElementGuarded,
|
|
26
|
+
requirementSourced,
|
|
27
|
+
defects,
|
|
22
28
|
];
|
|
23
29
|
/** How a crashed verifier reads back. The id is the verifier's name plus a fixed
|
|
24
30
|
* word, so it stays stable across registrations and can be answered. */
|
|
@@ -23,6 +23,9 @@ export interface PlanChange {
|
|
|
23
23
|
id: string;
|
|
24
24
|
text: string;
|
|
25
25
|
source: string;
|
|
26
|
+
/** The requirement in the pull request's own words, when `source` names the pull
|
|
27
|
+
* request. Checked against the text the run rendered its prompt with. */
|
|
28
|
+
quote?: string;
|
|
26
29
|
/** Where a user or caller meets this change. Every change states it: an optional
|
|
27
30
|
* field the agent skips gives the check nothing to read. */
|
|
28
31
|
surfaces: Array<"api" | "page">;
|
|
@@ -34,8 +37,32 @@ export interface PlanChange {
|
|
|
34
37
|
value?: string | number | boolean | null;
|
|
35
38
|
absent?: true;
|
|
36
39
|
expect: "accept" | "reject";
|
|
40
|
+
/** What the response must carry when this case is sent. Declared here so the
|
|
41
|
+
* test asserts a value the plan decided, not the value the running app
|
|
42
|
+
* happened to return — the one source that always agrees with a defect. */
|
|
43
|
+
expectedValue?: string | number | boolean | null;
|
|
44
|
+
/** Where the agent read `expectedValue` OR `derived` — the check reads it for
|
|
45
|
+
* either one: `pr-description`, `spec:<path>`, `convention:<file:line>`, or
|
|
46
|
+
* `code`. */
|
|
47
|
+
expectedFrom?: string;
|
|
48
|
+
/** The rule the value follows from, in the source's words, when the source
|
|
49
|
+
* states a rule and not a value. Stands in for `expectedValue`: the test
|
|
50
|
+
* computes the number from what it sent, so nothing pins one the source
|
|
51
|
+
* never wrote. */
|
|
52
|
+
derived?: string;
|
|
37
53
|
}>;
|
|
38
54
|
}
|
|
55
|
+
/** One defect the code review found, as the agent read it. Nothing on the server
|
|
56
|
+
* parses the description or opens the file: the check reads the id, and a test
|
|
57
|
+
* that cites it and expects to fail is what proves it. */
|
|
58
|
+
export interface PlanDefect {
|
|
59
|
+
id: string;
|
|
60
|
+
file: string;
|
|
61
|
+
/** Advisory. Line numbers drift, so nothing checks it. */
|
|
62
|
+
line?: number;
|
|
63
|
+
description: string;
|
|
64
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
65
|
+
}
|
|
39
66
|
/** What a planned test states so a verifier has a checkable change. Kept in step with
|
|
40
67
|
* `declarationFieldsSchema`, which the plan tool asserts against this type. */
|
|
41
68
|
export interface PlannedTestDetails {
|
|
@@ -74,6 +101,9 @@ export interface PlannedTestDetails {
|
|
|
74
101
|
};
|
|
75
102
|
/** The ids of the declared changes this test proves. */
|
|
76
103
|
changes?: string[];
|
|
104
|
+
/** The ids of the declared defects this test proves. A test proves a defect
|
|
105
|
+
* only when it expects to fail; the defects check reads both. */
|
|
106
|
+
defects?: string[];
|
|
77
107
|
/** The state the mutated record is in before the mutation. Presence only. */
|
|
78
108
|
startState?: string;
|
|
79
109
|
/** UI planned tests only. `items` entries are COPIES of elements a capture of
|
|
@@ -100,10 +130,31 @@ export interface ObjectionAnswer {
|
|
|
100
130
|
* An objection about an untested change closes only with one of these. */
|
|
101
131
|
blocker?: string;
|
|
102
132
|
}
|
|
133
|
+
/** An existing test this run maintains instead of planning a new one, and the
|
|
134
|
+
* declared changes that maintenance covers. A removal already covered by a spec
|
|
135
|
+
* is maintained, not duplicated, so the plan needs a way to say "this change is
|
|
136
|
+
* tested by a file I am editing" — without it, `coverage:change:` is unanswerable
|
|
137
|
+
* for a correct maintenance decision, and it closes only with a `blocker`. */
|
|
138
|
+
export interface PlanMaintenance {
|
|
139
|
+
/** Repository-relative path of the existing test. Only its presence in the
|
|
140
|
+
* checkout is checked, the same rule `declarations.existingTests` follows. */
|
|
141
|
+
file: string;
|
|
142
|
+
/** The edit this run makes to it, in one sentence. */
|
|
143
|
+
differsBy: string;
|
|
144
|
+
/** The ids of the declared changes this maintenance covers. */
|
|
145
|
+
changes: string[];
|
|
146
|
+
}
|
|
103
147
|
export interface PlanInput {
|
|
104
148
|
/** The changes the diff makes. Each planned test cites the ones it tests. */
|
|
105
149
|
changes: PlanChange[];
|
|
150
|
+
/** The defects the code review found. Each planned test cites the ones it
|
|
151
|
+
* proves. Empty is a statement — the review found none — and draws an
|
|
152
|
+
* objection the agent answers. */
|
|
153
|
+
defects: PlanDefect[];
|
|
106
154
|
plannedTests: PlannedTest[];
|
|
155
|
+
/** Existing tests this run edits rather than replacing with new ones. Coverage
|
|
156
|
+
* counts the changes these cite, so a maintenance-only plan is a complete plan. */
|
|
157
|
+
maintains?: PlanMaintenance[];
|
|
107
158
|
answers: ObjectionAnswer[];
|
|
108
159
|
/** The tool owns this and overwrites whatever the caller sends. */
|
|
109
160
|
registrationNumber: number;
|
|
@@ -141,6 +192,13 @@ export interface VerifyContext {
|
|
|
141
192
|
/** Identifiers a rename replaced, empty when the diff renames nothing. Only the
|
|
142
193
|
* server pairs the two sides of a diff. */
|
|
143
194
|
retiredUiElements: RemovedUiElement[];
|
|
195
|
+
/** The pull request's title and description, as the run rendered its prompt with.
|
|
196
|
+
* The plan tool fills it from the process the prompt was rendered in. Both fields
|
|
197
|
+
* blank MEANS the run had no title and no description. */
|
|
198
|
+
pullRequest: {
|
|
199
|
+
title: string;
|
|
200
|
+
description: string;
|
|
201
|
+
};
|
|
144
202
|
/** Whether a cited path names a file in any of the run's repositories. Injected
|
|
145
203
|
* to keep the verifiers filesystem-free. */
|
|
146
204
|
citedFileExists(relativePath: string): boolean;
|
|
@@ -17,8 +17,6 @@ export interface ContractObjection {
|
|
|
17
17
|
export interface VerifierContract {
|
|
18
18
|
/** The verifier's own `Verifier.name`. */
|
|
19
19
|
readonly id: string;
|
|
20
|
-
/** What the registered plan has to carry for the check to have anything to read. */
|
|
21
|
-
readonly declarationFields: readonly string[];
|
|
22
20
|
/** One entry per message the verifier can emit, keyed by the case. A key naming a
|
|
23
21
|
* segment of the `objectionId` uses that segment's spelling. The keys are widened
|
|
24
22
|
* here so every contract satisfies the interface, while each contract is `as
|
|
@@ -31,7 +29,6 @@ export interface VerifierContract {
|
|
|
31
29
|
}
|
|
32
30
|
export declare const CHANGED_FILE_CONTRACT: {
|
|
33
31
|
readonly id: "changedFile";
|
|
34
|
-
readonly declarationFields: readonly ["declarations.changedFile", "declarations.screenEvidence.file"];
|
|
35
32
|
readonly objections: {
|
|
36
33
|
readonly notStated: {
|
|
37
34
|
readonly message: "This test does not state which changed file it targets.";
|
|
@@ -54,7 +51,6 @@ export declare const CHANGED_FILE_CONTRACT: {
|
|
|
54
51
|
};
|
|
55
52
|
export declare const SCREEN_ROUTE_CONTRACT: {
|
|
56
53
|
readonly id: "screenRoute";
|
|
57
|
-
readonly declarationFields: readonly ["declarations.elements.pageUrl", "declarations.screenEvidence.file", "declarations.changedFile"];
|
|
58
54
|
readonly objections: {
|
|
59
55
|
readonly mismatch: {
|
|
60
56
|
readonly message: "The page this UI test opens is not a page that renders the changed file it is about.";
|
|
@@ -69,7 +65,6 @@ export declare const SCREEN_ROUTE_CONTRACT: {
|
|
|
69
65
|
};
|
|
70
66
|
export declare const ENDPOINT_GROUNDED_CONTRACT: {
|
|
71
67
|
readonly id: "endpointGrounded";
|
|
72
|
-
readonly declarationFields: readonly ["steps[]", "testType", "declarations.routes"];
|
|
73
68
|
readonly objections: {
|
|
74
69
|
readonly uncited: {
|
|
75
70
|
readonly message: "A call this test makes cites no file that declares it.";
|
|
@@ -88,7 +83,6 @@ export declare const ENDPOINT_GROUNDED_CONTRACT: {
|
|
|
88
83
|
};
|
|
89
84
|
export declare const STATED_DIFFERENCE_CONTRACT: {
|
|
90
85
|
readonly id: "statedDifference";
|
|
91
|
-
readonly declarationFields: readonly ["steps[]", "testType", "scenarioName", "declarations.differsFrom"];
|
|
92
86
|
readonly objections: {
|
|
93
87
|
readonly unexplainedPair: {
|
|
94
88
|
readonly message: "Another planned test in this plan tests the same endpoint and neither says how they differ.";
|
|
@@ -107,18 +101,24 @@ export declare const STATED_DIFFERENCE_CONTRACT: {
|
|
|
107
101
|
};
|
|
108
102
|
export declare const EXISTING_COVERAGE_CONTRACT: {
|
|
109
103
|
readonly id: "existingCoverage";
|
|
110
|
-
readonly declarationFields: readonly ["declarations.existingTests"];
|
|
111
104
|
readonly objections: {
|
|
112
105
|
readonly citedTestMissing: {
|
|
113
106
|
readonly message: "This planned test names an existing test file that is not in the checkout.";
|
|
114
107
|
readonly suggestion: "Name the file repository-relative, spelled as the analysis lists it. Drop the entry if it names a test you did not read — naming none is an answer too.";
|
|
115
108
|
};
|
|
109
|
+
readonly maintainedTestMissing: {
|
|
110
|
+
readonly message: "`maintains` names an existing test file that is not in the checkout.";
|
|
111
|
+
readonly suggestion: "Name the file repository-relative, spelled as the analysis lists it. A maintenance entry is what makes its changes count as covered, so it has to name a file this run can edit.";
|
|
112
|
+
};
|
|
113
|
+
readonly maintainedUnknownChange: {
|
|
114
|
+
readonly message: "A `maintains` entry cites a change id that this plan does not declare.";
|
|
115
|
+
readonly suggestion: "Spell the change's `id` exactly as your own `changes` list gives it — the match is exact apart from surrounding space. Declare the change if it is missing.";
|
|
116
|
+
};
|
|
116
117
|
};
|
|
117
|
-
readonly suggestion: "Which existing tests did you read on this change,
|
|
118
|
+
readonly suggestion: "Which existing tests did you read on this change, how does this planned test differ from them, and which changes does the maintenance you are doing cover?";
|
|
118
119
|
};
|
|
119
120
|
export declare const EXPECTED_OUTCOME_CONTRACT: {
|
|
120
121
|
readonly id: "expectedOutcome";
|
|
121
|
-
readonly declarationFields: readonly ["category", "declarations.expected.outcome", "declarations.expected.why"];
|
|
122
122
|
readonly objections: {
|
|
123
123
|
readonly passInShouldFailCategory: {
|
|
124
124
|
readonly message: "This planned test is categorised \"{category}\" but expects to pass on the app as it stands.";
|
|
@@ -133,7 +133,6 @@ export declare const EXPECTED_OUTCOME_CONTRACT: {
|
|
|
133
133
|
};
|
|
134
134
|
export declare const UI_ELEMENT_GROUNDED_CONTRACT: {
|
|
135
135
|
readonly id: "uiElementGrounded";
|
|
136
|
-
readonly declarationFields: readonly ["testType", "steps[]", "declarations.elements.items", "declarations.elements.pageUrl", "declarations.asserts", "scenarioName", "description", "declarations.expected.why"];
|
|
137
136
|
readonly objections: {
|
|
138
137
|
readonly nogrounding: {
|
|
139
138
|
readonly message: "This UI test names no `elements.items`, so nothing says the elements it targets are on the page.";
|
|
@@ -156,11 +155,10 @@ export declare const UI_ELEMENT_GROUNDED_CONTRACT: {
|
|
|
156
155
|
};
|
|
157
156
|
export declare const COVERAGE_CONTRACT: {
|
|
158
157
|
readonly id: "coverage";
|
|
159
|
-
readonly declarationFields: readonly ["changes", "declarations.changes", "declarations.changedFile", "declarations.routes", "declarations.screenEvidence.file", "declarations.startState", "changes[].cases", "changes[].surfaces"];
|
|
160
158
|
readonly objections: {
|
|
161
159
|
readonly change: {
|
|
162
160
|
readonly message: "This declared change has no test in the plan.";
|
|
163
|
-
readonly suggestion: "Plan a test that exercises it. If this run cannot write one, answer it and set `blocker` to what stopped the run — a service that is not running, a paired branch that no longer exists, the one credential the run holds. An answer with no blocker leaves this open: a change nothing prevented a test from reaching takes the test. Coverage per file is the basic minimum; coverage per change is what the plan is judged by, so a file covered by a shape test still leaves the change it makes untested.";
|
|
161
|
+
readonly suggestion: "Plan a test that exercises it. If an existing test already covers it and this run edits that test rather than writing a new one, declare it in `maintains` with the file, what your edit changes, and this change's id — maintenance is coverage, and a duplicate spec beside the one you edited is the mistake. If this run cannot write one, answer it and set `blocker` to what stopped the run — a service that is not running, a paired branch that no longer exists, the one credential the run holds. An answer with no blocker leaves this open: a change nothing prevented a test from reaching takes the test. Coverage per file is the basic minimum; coverage per change is what the plan is judged by, so a file covered by a shape test still leaves the change it makes untested.";
|
|
164
162
|
};
|
|
165
163
|
readonly noChanges: {
|
|
166
164
|
readonly message: "The plan declares no changes, so nothing says what the pull request must make different.";
|
|
@@ -195,7 +193,6 @@ export declare const COVERAGE_CONTRACT: {
|
|
|
195
193
|
};
|
|
196
194
|
export declare const REMOVED_ELEMENT_GUARDED_CONTRACT: {
|
|
197
195
|
readonly id: "removedElementGuarded";
|
|
198
|
-
readonly declarationFields: readonly ["declarations.elements.items", "declarations.asserts"];
|
|
199
196
|
readonly objections: {
|
|
200
197
|
readonly missing: {
|
|
201
198
|
readonly message: "The diff removes `{element}` and no planned test says it is gone.";
|
|
@@ -208,6 +205,104 @@ export declare const REMOVED_ELEMENT_GUARDED_CONTRACT: {
|
|
|
208
205
|
};
|
|
209
206
|
readonly suggestion: "Does every element this diff removes have a planned test that asserts it is gone, and does no test claim a renamed identifier is gone?";
|
|
210
207
|
};
|
|
208
|
+
export declare const EXPECTED_VALUE_SOURCED_CONTRACT: {
|
|
209
|
+
readonly id: "expectedValueSourced";
|
|
210
|
+
readonly objections: {
|
|
211
|
+
readonly sourcedFromCode: {
|
|
212
|
+
readonly message: "This case expects a value it read from the code as it stands, so a defect in that code becomes what the test demands.";
|
|
213
|
+
readonly suggestion: "Read the value from the pull request title or description, from a requirements file the description names, or from a convention the application already follows elsewhere, and name that source. If none of them states it, leave `expectedValue` out and assert the shape instead.";
|
|
214
|
+
};
|
|
215
|
+
readonly missingSource: {
|
|
216
|
+
readonly message: "This case states an expected value and does not say where the value came from.";
|
|
217
|
+
readonly suggestion: "Set `expectedFrom` to `pr-title`, `pr-description`, `spec:<path>`, `convention:<file:line>` or `code`.";
|
|
218
|
+
};
|
|
219
|
+
readonly unreadableSource: {
|
|
220
|
+
readonly message: "This case names a file as the source of its expected value, and that file is not in the checkout.";
|
|
221
|
+
readonly suggestion: "Give the path as the repository spells it, from the repository root. If the file is not there, the value has no source: read it from the pull request title or description instead, or leave `expectedValue` out and assert the shape.";
|
|
222
|
+
};
|
|
223
|
+
readonly changedConvention: {
|
|
224
|
+
readonly message: "This case reads its expected value from a line this pull request writes, so the same change decides both the behaviour and what counts as correct.";
|
|
225
|
+
readonly suggestion: "Cite a file the pull request leaves alone, or read the value from the description or a requirements file. If the cited file is changed but has nothing to do with this case, say so as the answer.";
|
|
226
|
+
};
|
|
227
|
+
readonly quoteMissing: {
|
|
228
|
+
readonly message: "This case reads its value from the pull request, and its change does not quote the sentence that states the rule.";
|
|
229
|
+
readonly suggestion: "Put the sentence from the title or description on the change as `quote`, as written there. If that sentence states the rule and not the number, put the rule in `derived` and leave `expectedValue` out.";
|
|
230
|
+
};
|
|
231
|
+
readonly valueNotQuoted: {
|
|
232
|
+
readonly message: "This case reads its value from the pull request, and the pull request does not state this value.";
|
|
233
|
+
readonly suggestion: "Quote the sentence that states it, or, if the pull request states a rule, put the rule in `derived` and leave `expectedValue` out; the test computes the value from what it sent.";
|
|
234
|
+
};
|
|
235
|
+
readonly failWithoutValue: {
|
|
236
|
+
readonly message: "This test expects to fail, and no case on the changes it cites states the value it must assert.";
|
|
237
|
+
readonly suggestion: "Put the value the code does not return today on the case this test sends, as `expectedValue`, and name where you read it. If the source states a rule rather than a number, put the rule in `derived` instead. If no source states either, answer with what the test asserts instead and where that comes from.";
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
readonly suggestion: "Where does the correct value for this case come from?";
|
|
241
|
+
};
|
|
242
|
+
export declare const REQUIREMENT_SOURCED_CONTRACT: {
|
|
243
|
+
readonly id: "requirementSourced";
|
|
244
|
+
readonly objections: {
|
|
245
|
+
readonly unsourced: {
|
|
246
|
+
readonly message: "Change `{change}` does not name a source the plan accepts: `pr-title`, `pr-description`, `spec:<path>` or `diff`.";
|
|
247
|
+
readonly suggestion: "Set `source` on this change to `pr-title` or `pr-description`, to `spec:<path>` for the requirements file that states it, or to `diff`.";
|
|
248
|
+
};
|
|
249
|
+
readonly unreadable: {
|
|
250
|
+
readonly message: "Change `{change}` cites `{source}`, and the checkout holds no file at that path.";
|
|
251
|
+
readonly suggestion: "Cite the requirements file by the path the checkout holds, or name the source you actually read this change in.";
|
|
252
|
+
};
|
|
253
|
+
readonly fromDiff: {
|
|
254
|
+
readonly message: "This test reports a requirement conflict, and none of the changes it cites was read from the pull request or a requirements file.";
|
|
255
|
+
readonly suggestion: "Cite a change you read in the pull request or in a requirements file, or report this test as something other than a requirement conflict.";
|
|
256
|
+
};
|
|
257
|
+
readonly notNamed: {
|
|
258
|
+
readonly message: "Change `{change}` cites `{source}`, and the pull request names no such file.";
|
|
259
|
+
readonly suggestion: "Cite a file the title or description names. If neither names it, you read the change in the repository, so set `source` to `diff`.";
|
|
260
|
+
};
|
|
261
|
+
readonly emptyPullRequest: {
|
|
262
|
+
readonly message: "Change `{change}` says it was read from the pull request, and the pull request has no title or description.";
|
|
263
|
+
readonly suggestion: "Set `source` to `spec:<path>` for the requirements file that states this change, or to `diff` if only the code states it.";
|
|
264
|
+
};
|
|
265
|
+
readonly notQuoted: {
|
|
266
|
+
readonly message: "This test reports a requirement conflict, and change `{change}` quotes words the pull request does not carry.";
|
|
267
|
+
readonly suggestion: "Quote the requirement as the title or description spells it, word for word. If you cannot find those words there, the change came from somewhere else: say where in `source`.";
|
|
268
|
+
};
|
|
269
|
+
readonly unquoted: {
|
|
270
|
+
readonly message: "This test reports a requirement conflict, and change `{change}` does not quote the requirement.";
|
|
271
|
+
readonly suggestion: "Set `quote` on that change to the sentence in the title or description that states the requirement.";
|
|
272
|
+
};
|
|
273
|
+
readonly noChange: {
|
|
274
|
+
readonly message: "This test reports a requirement conflict and cites no change, so nothing says where the requirement came from.";
|
|
275
|
+
readonly suggestion: "Name in `changes` the change that states the requirement, or report this test as something other than a requirement conflict.";
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
readonly suggestion: "Does every change name where you read it, and does every requirement-conflict test cite a change that came from the pull request or a requirements file?";
|
|
279
|
+
};
|
|
280
|
+
export declare const DEFECTS_CONTRACT: {
|
|
281
|
+
readonly id: "defects";
|
|
282
|
+
readonly objections: {
|
|
283
|
+
readonly none: {
|
|
284
|
+
readonly message: "The plan declares no defects, so nothing says the code review happened before the plan.";
|
|
285
|
+
readonly suggestion: "Review the code that serves each change — the handler, the functions it calls to read or write data, the component and what it calls — and list each defect in `defects`. If the review found none, answer in one line what you read.";
|
|
286
|
+
};
|
|
287
|
+
readonly untested: {
|
|
288
|
+
readonly message: "This declared defect has no test in the plan.";
|
|
289
|
+
readonly suggestion: "Add a planned test that cites the defect in `defects` and sets `expected.outcome` to `fail`. A defect in a file this pull request touches gets the test whether or not this pull request introduced it. If something stopped this run from writing the test, answer it and set `blocker` to what stopped it.";
|
|
290
|
+
};
|
|
291
|
+
readonly expectedPass: {
|
|
292
|
+
readonly message: "Every test that cites this defect expects to pass, and a test that passes today proves nothing about a defect.";
|
|
293
|
+
readonly suggestion: "Assert what the fixed code returns, set `expected.outcome` to `fail` with `why`, or answer in one line why a passing test is the proof.";
|
|
294
|
+
};
|
|
295
|
+
readonly unknownId: {
|
|
296
|
+
readonly message: "A planned test cites a defect id that this plan does not declare.";
|
|
297
|
+
readonly suggestion: "Spell the defect's `id` exactly as your own `defects` list gives it — the match is exact apart from surrounding space. Declare the defect if it is missing.";
|
|
298
|
+
};
|
|
299
|
+
readonly conflictWithoutDefect: {
|
|
300
|
+
readonly message: "This test reports a requirement conflict and cites no defect.";
|
|
301
|
+
readonly suggestion: "List the conflict in `defects`: the file and line that contradict the requirement, and a description that quotes the requirement. Cite that id from this test.";
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
readonly suggestion: "Which planned test proves each defect the review found, and for one nothing proves, why does it need no test?";
|
|
305
|
+
};
|
|
211
306
|
/** Fills a contract sentence's `{placeholder}` spans from the run's or the
|
|
212
307
|
* planned test's own values. A placeholder with no value is left as written rather
|
|
213
308
|
* than blanked, so a missed key shows up as `{knob}` instead of reading as a gap
|