@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,168 @@
|
|
|
1
|
+
import { normalizeCategory } from "../../types/TestRecommendation.js";
|
|
2
|
+
import { REQUIREMENT_SOURCED_CONTRACT, fillPlaceholders } from "../verifierContracts.js";
|
|
3
|
+
import { normalizeCitedPath } from "./citedPath.js";
|
|
4
|
+
import { appearsIn, searchable } from "../pullRequestText.js";
|
|
5
|
+
/** Verifier 10. A change names where the agent read it, and the server reads the
|
|
6
|
+
* name back.
|
|
7
|
+
*
|
|
8
|
+
* `source` is the record of where a change came from, and the server holds the
|
|
9
|
+
* pull request's own words, so it reads the claim back against them: a `spec:` path
|
|
10
|
+
* has to name a file the checkout holds AND a file the pull request names, and a
|
|
11
|
+
* change read from the pull request has to quote words the pull request carries.
|
|
12
|
+
*
|
|
13
|
+
* A conflict is a disagreement between a requirement and the code. A change read
|
|
14
|
+
* off the diff IS the code, so there is no second side for it to disagree with.
|
|
15
|
+
*
|
|
16
|
+
* The plan tool always supplies the pull request: the testbot fetches its prompt
|
|
17
|
+
* from this same server, so the text is in the process. Both fields blank means
|
|
18
|
+
* the run had no title and no description. */
|
|
19
|
+
const { unsourced: UNSOURCED, unreadable: UNREADABLE, fromDiff: FROM_DIFF, noChange: NO_CHANGE, notNamed: NOT_NAMED, emptyPullRequest: EMPTY_PULL_REQUEST, notQuoted: NOT_QUOTED, unquoted: UNQUOTED, } = REQUIREMENT_SOURCED_CONTRACT.objections;
|
|
20
|
+
const CONFLICT_CATEGORY = "requirement_conflict";
|
|
21
|
+
function readSource(raw) {
|
|
22
|
+
const none = (kind) => ({ kind, file: "", citedAs: "" });
|
|
23
|
+
const source = typeof raw === "string" ? raw.trim() : "";
|
|
24
|
+
if (source.length === 0)
|
|
25
|
+
return none("unknown");
|
|
26
|
+
if (/^(pr-title|pr-description)$/i.test(source))
|
|
27
|
+
return none("pullRequest");
|
|
28
|
+
if (/^diff$/i.test(source))
|
|
29
|
+
return none("diff");
|
|
30
|
+
const named = /^spec:(.*)$/i.exec(source);
|
|
31
|
+
if (!named)
|
|
32
|
+
return none("unknown");
|
|
33
|
+
const citedAs = named[1]
|
|
34
|
+
.split(/[#§]/)[0]
|
|
35
|
+
.replace(/(?::\d+)+(?:-\d+)?$/, "")
|
|
36
|
+
.trim();
|
|
37
|
+
const file = normalizeCitedPath(citedAs);
|
|
38
|
+
// `spec:` with nothing after it names no file, so there is nothing to check and
|
|
39
|
+
// nothing to trust either.
|
|
40
|
+
return file ? { kind: "spec", file, citedAs } : none("unknown");
|
|
41
|
+
}
|
|
42
|
+
/** A source that stands for a requirement: the pull request, or a requirements file. */
|
|
43
|
+
const statesARequirement = (source) => source.kind === "pullRequest" || source.kind === "spec";
|
|
44
|
+
const text = (value) => (typeof value === "string" ? value.trim() : "");
|
|
45
|
+
const list = (value) => (Array.isArray(value) ? value : []);
|
|
46
|
+
export const requirementSourced = {
|
|
47
|
+
name: "requirementSourced",
|
|
48
|
+
run(registration, ctx) {
|
|
49
|
+
const changes = list(registration?.changes);
|
|
50
|
+
const plannedTests = list(registration?.plannedTests);
|
|
51
|
+
const objections = [];
|
|
52
|
+
const sourceById = new Map();
|
|
53
|
+
const quoteById = new Map();
|
|
54
|
+
const pullRequestText = searchable(ctx.pullRequest);
|
|
55
|
+
for (const change of changes) {
|
|
56
|
+
const changeId = text(change?.id) || "(unnamed)";
|
|
57
|
+
const written = text(change?.source);
|
|
58
|
+
const source = readSource(written);
|
|
59
|
+
if (text(change?.id)) {
|
|
60
|
+
sourceById.set(text(change.id), source);
|
|
61
|
+
quoteById.set(text(change.id), typeof change?.quote === "string" ? change.quote : undefined);
|
|
62
|
+
}
|
|
63
|
+
if (source.kind === "unknown") {
|
|
64
|
+
objections.push({
|
|
65
|
+
objectionId: `requirementSourced:unsourced:${changeId}`,
|
|
66
|
+
verifier: "requirementSourced",
|
|
67
|
+
message: fillPlaceholders(UNSOURCED.message, { change: changeId }),
|
|
68
|
+
evidence: `change ${changeId} states source \`${written || "(blank)"}\``,
|
|
69
|
+
suggestion: UNSOURCED.suggestion,
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (source.kind === "pullRequest") {
|
|
74
|
+
if (pullRequestText.length > 0)
|
|
75
|
+
continue;
|
|
76
|
+
objections.push({
|
|
77
|
+
objectionId: `requirementSourced:emptyPullRequest:${changeId}`,
|
|
78
|
+
verifier: "requirementSourced",
|
|
79
|
+
message: fillPlaceholders(EMPTY_PULL_REQUEST.message, { change: changeId }),
|
|
80
|
+
evidence: `change ${changeId} states source \`${written}\`; this run rendered its prompt with no title and no description`,
|
|
81
|
+
suggestion: EMPTY_PULL_REQUEST.suggestion,
|
|
82
|
+
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (source.kind !== "spec")
|
|
86
|
+
continue;
|
|
87
|
+
if (typeof ctx?.citedFileExists === "function" && !ctx.citedFileExists(source.file)) {
|
|
88
|
+
objections.push({
|
|
89
|
+
objectionId: `requirementSourced:unreadable:${changeId}`,
|
|
90
|
+
verifier: "requirementSourced",
|
|
91
|
+
message: fillPlaceholders(UNREADABLE.message, { change: changeId, source: written }),
|
|
92
|
+
evidence: `change ${changeId} states source \`${written}\`; ${source.file} is not a file in the run's repositories`,
|
|
93
|
+
suggestion: UNREADABLE.suggestion,
|
|
94
|
+
});
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// A requirements file the pull request never names is a file the agent found by
|
|
98
|
+
// looking through the repository, which is not reading a requirement.
|
|
99
|
+
if (appearsIn(pullRequestText, source.file) || appearsIn(pullRequestText, source.citedAs))
|
|
100
|
+
continue;
|
|
101
|
+
objections.push({
|
|
102
|
+
objectionId: `requirementSourced:notNamed:${changeId}`,
|
|
103
|
+
verifier: "requirementSourced",
|
|
104
|
+
message: fillPlaceholders(NOT_NAMED.message, { change: changeId, source: written }),
|
|
105
|
+
evidence: `change ${changeId} states source \`${written}\`; neither the title nor the description names ${source.file}`,
|
|
106
|
+
suggestion: NOT_NAMED.suggestion,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
for (const plannedTest of plannedTests) {
|
|
110
|
+
if (normalizeCategory(plannedTest?.scenario?.category) !== CONFLICT_CATEGORY)
|
|
111
|
+
continue;
|
|
112
|
+
const plannedTestId = text(plannedTest?.plannedTestId);
|
|
113
|
+
const named = plannedTestId ? { plannedTestId } : {};
|
|
114
|
+
// An id no change carries names nothing, so it says no more than citing
|
|
115
|
+
// nothing does. Both leave the requirement with no stated origin.
|
|
116
|
+
const cited = list(plannedTest?.declarations?.changes)
|
|
117
|
+
.map((changeId) => text(changeId))
|
|
118
|
+
.filter((changeId) => sourceById.has(changeId));
|
|
119
|
+
if (cited.length === 0) {
|
|
120
|
+
objections.push({
|
|
121
|
+
objectionId: `requirementSourced:noChange:${plannedTestId || "plan"}`,
|
|
122
|
+
verifier: "requirementSourced",
|
|
123
|
+
...named,
|
|
124
|
+
message: NO_CHANGE.message,
|
|
125
|
+
evidence: `planned test ${plannedTestId || "(unnamed)"} reports a requirement conflict and cites no change this plan declares`,
|
|
126
|
+
suggestion: NO_CHANGE.suggestion,
|
|
127
|
+
});
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (cited.some((changeId) => statesARequirement(sourceById.get(changeId)))) {
|
|
131
|
+
// The quote is what makes the claim checkable. One objection per test, on the
|
|
132
|
+
// first cited change that does not carry one the pull request holds.
|
|
133
|
+
const offending = cited.find((changeId) => {
|
|
134
|
+
if (sourceById.get(changeId)?.kind !== "pullRequest")
|
|
135
|
+
return false;
|
|
136
|
+
const quote = quoteById.get(changeId);
|
|
137
|
+
return quote === undefined || !appearsIn(pullRequestText, quote);
|
|
138
|
+
});
|
|
139
|
+
if (offending === undefined)
|
|
140
|
+
continue;
|
|
141
|
+
const quote = quoteById.get(offending);
|
|
142
|
+
const objection = quote === undefined ? UNQUOTED : NOT_QUOTED;
|
|
143
|
+
objections.push({
|
|
144
|
+
objectionId: `requirementSourced:notQuoted:${plannedTestId || "plan"}`,
|
|
145
|
+
verifier: "requirementSourced",
|
|
146
|
+
...named,
|
|
147
|
+
message: fillPlaceholders(objection.message, { change: offending }),
|
|
148
|
+
evidence: quote === undefined
|
|
149
|
+
? `planned test ${plannedTestId || "(unnamed)"} cites ${offending}, which states no \`quote\``
|
|
150
|
+
: `planned test ${plannedTestId || "(unnamed)"} cites ${offending}, whose quote \`${quote}\` is in neither the title nor the description`,
|
|
151
|
+
suggestion: objection.suggestion,
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
objections.push({
|
|
156
|
+
objectionId: `requirementSourced:fromDiff:${plannedTestId || "plan"}`,
|
|
157
|
+
verifier: "requirementSourced",
|
|
158
|
+
...named,
|
|
159
|
+
message: FROM_DIFF.message,
|
|
160
|
+
evidence: `planned test ${plannedTestId || "(unnamed)"} cites ${cited
|
|
161
|
+
.map((changeId) => `${changeId} (kind ${sourceById.get(changeId)?.kind})`)
|
|
162
|
+
.join(", ")}`,
|
|
163
|
+
suggestion: FROM_DIFF.suggestion,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return objections;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
@@ -438,7 +438,9 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
438
438
|
if (generateOptions.authHeader === undefined) {
|
|
439
439
|
try {
|
|
440
440
|
const repoPath = generateOptions.outputDir || process.cwd();
|
|
441
|
-
const resolved = await resolveAuthFromWorkspace(repoPath, generateOptions.authHeader, generateOptions.authScheme
|
|
441
|
+
const resolved = await resolveAuthFromWorkspace(repoPath, generateOptions.authHeader, generateOptions.authScheme,
|
|
442
|
+
// The directory the test is written into names the service it is for.
|
|
443
|
+
generateOptions.outputDir);
|
|
442
444
|
if (resolved) {
|
|
443
445
|
generateOptions.authHeader = resolved.authHeader;
|
|
444
446
|
if (resolved.authScheme !== undefined) {
|
|
@@ -31,7 +31,7 @@ const codeReuseSchema = z.object({
|
|
|
31
31
|
verify: z
|
|
32
32
|
.boolean()
|
|
33
33
|
.default(false)
|
|
34
|
-
.describe("Verify a previously refactored test instead of returning the reuse prompt. POM path (browser tests): checks the test's POM calls against source; requires the discovery pass — this tool called for the same testFile without `verify` — to have run first. SkyrampUtils path (every other test type): stages the shared utils file for the output commit, checks its invariants, and — when skyramp_modularization recorded a baseline for this spec — compares the delivered assertion count and page.on('pageerror') guard against that hand-out, rejecting a net loss (API helpers: one helper per method+path, status-code-only assertions, method+resource names; browser helpers: actions and structural waits only, intent names). Call it after the reuse edits are written; skyramp_enhance_assertions and skyramp_execute_test refuse until it has passed."),
|
|
34
|
+
.describe("Verify a previously refactored test instead of returning the reuse prompt. POM path (browser tests): checks the test's POM calls against source; requires the discovery pass — this tool called for the same testFile without `verify` — to have run first. SkyrampUtils path (every other test type): stages the shared utils file for the output commit, checks its invariants, and — when skyramp_modularization recorded a baseline for this spec — compares the delivered assertion count and page.on('pageerror') guard against that hand-out, rejecting a net loss (API helpers: one helper per method+path, status-code-only assertions, method+resource names; browser helpers: actions and structural waits only, intent names, one helper per action sequence; every family: one name is defined once per module, with one parameter count across modules). Call it after the reuse edits are written; skyramp_enhance_assertions and skyramp_execute_test refuse until it has passed."),
|
|
35
35
|
testType: z
|
|
36
36
|
.nativeEnum(TestType)
|
|
37
37
|
.optional()
|
|
@@ -21,7 +21,7 @@ export interface FlaggedMember {
|
|
|
21
21
|
* moment the spec changes — and it does change: the execution fix-up may restore
|
|
22
22
|
* `<testFile>.raw.bak` over the spec by plain `cp`, invisible to this tool. The
|
|
23
23
|
* counts and the decline list are therefore derived at report time (see
|
|
24
|
-
* `
|
|
24
|
+
* `rederiveReuse`), never read back from here.
|
|
25
25
|
*
|
|
26
26
|
* And keeping the two types disjoint makes the report boundary opt-IN. When the
|
|
27
27
|
* record extended the wire type, every field added here shipped to the
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { type VerifyResult } from "../../utils/pom-verify/index.js";
|
|
2
2
|
import { type ReuseOutcome, type ReuseRecord } from "./reuse-outcome.js";
|
|
3
3
|
import { type UtilsVerifyResult } from "../../utils/utils-verify/index.js";
|
|
4
|
+
import type { ReuseVerificationFailure } from "../../types/ReuseOutcome.js";
|
|
4
5
|
/**
|
|
5
6
|
* Record the tier-1 candidate count STEP 1 detected, plus the identity needed to
|
|
6
7
|
* re-derive the counts from the delivered spec later.
|
|
7
8
|
*
|
|
8
9
|
* The identity is written here and not only by {@link recordVerifyOutcome} because
|
|
9
10
|
* the verify pass is a call the agent decides whether to make. When it skips it,
|
|
10
|
-
* a record holding the candidate count alone makes `
|
|
11
|
+
* a record holding the candidate count alone makes `rederiveReuse` bail out,
|
|
11
12
|
* and the report states "N candidate POM files detected" with no reuse numbers —
|
|
12
13
|
* indistinguishable from a run where reuse was measured and simply not summarized.
|
|
13
14
|
* Recording it unconditionally is what makes the zero-reuse case reportable without
|
|
@@ -55,9 +56,11 @@ export declare function recordVerifyOutcome(testFile: string, r: VerifyResult, g
|
|
|
55
56
|
* NOT terminal. A PASS is always reachable in one edit plus one call (substitute the
|
|
56
57
|
* members, or document each candidate with a `// kept inline:` marker, which the gate
|
|
57
58
|
* accepts), and an agent that resolves neither can still walk past these tools to
|
|
58
|
-
* `skyramp_submit_report
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* `skyramp_submit_report`. That tool refuses a blocking verdict on the delivered
|
|
60
|
+
* files too, but its refusal is BOUNDED (`REUSE_SUBMIT_MAX_REFUSALS`): past the bound
|
|
61
|
+
* it accepts the report with the fault recorded in the row. So the worst case still
|
|
62
|
+
* degrades to the reporting half rather than to a run that produces nothing — which
|
|
63
|
+
* is what a bound here would have been protecting against.
|
|
61
64
|
*/
|
|
62
65
|
export declare function pendingReuseVerification(testFile: string, explicitStateFile?: string): Promise<string | undefined>;
|
|
63
66
|
/**
|
|
@@ -81,7 +84,17 @@ export declare function recordUtilsVerifyError(testFile: string, explicitStateFi
|
|
|
81
84
|
export declare function samePath(a: string, b: string): boolean;
|
|
82
85
|
/** Exported for retrofit-state: the same canonicalisation the records use. */
|
|
83
86
|
export declare function canonPath(p: string): string;
|
|
84
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* The label a report row shows for a set of utils files: each file's path relative
|
|
89
|
+
* to its repository root, posix-separated, joined with `, `.
|
|
90
|
+
*
|
|
91
|
+
* Repository-relative, never absolute — an absolute path carries the runner's
|
|
92
|
+
* temporary directory and means nothing to a customer. Not a basename either: a
|
|
93
|
+
* fullstack delivery writes one module per test directory under the same
|
|
94
|
+
* conventional name, and two rows labelled `skyrampUtils.ts` cannot be told apart
|
|
95
|
+
* (a renderer keyed on the label then merges them into one aggregate). Outside a
|
|
96
|
+
* repository, or for a file the root does not contain, the basename stands in.
|
|
97
|
+
*/
|
|
85
98
|
export declare function utilsFileLabel(files: string[]): string;
|
|
86
99
|
/** Verdict of one utils verify pass. The verdict alone is stored — counts and the
|
|
87
100
|
* file list are re-derived from the delivered files at report time. */
|
|
@@ -148,6 +161,64 @@ export declare function reuseChainSkipped(fileName: string, testType: string, re
|
|
|
148
161
|
testType: string;
|
|
149
162
|
language: string;
|
|
150
163
|
}> | undefined): Promise<true | undefined>;
|
|
164
|
+
/**
|
|
165
|
+
* A blocking reuse verdict measured on the DELIVERED files at report time — the
|
|
166
|
+
* same predicate the live `verify: true` pass refuses on, re-run on what ships.
|
|
167
|
+
*
|
|
168
|
+
* Verification is a one-time checkpoint on a file that keeps changing: the execution
|
|
169
|
+
* fix loop deletes a failing assertion after the gate recorded `passed`, and a
|
|
170
|
+
* post-verification full-file rewrite erases verified page-object reuse. Until this
|
|
171
|
+
* existed, the report re-derived the verdict, found the fault, wrote it into a field
|
|
172
|
+
* and shipped the work — the run committed the fault, detected it, disclosed it and
|
|
173
|
+
* delivered it. `skyramp_submit_report` refuses on this instead, and the agent
|
|
174
|
+
* repairs (or documents the decline) and resubmits.
|
|
175
|
+
*
|
|
176
|
+
* Only a BLOCKING verdict lands here. Advisories (`scenario-name`, untyped
|
|
177
|
+
* parameters, sibling inline call sites, single importers) never do: they are
|
|
178
|
+
* report-time signals whose number means something only on the final file, and
|
|
179
|
+
* they must stay free to be computed and reported at submit.
|
|
180
|
+
*/
|
|
181
|
+
export interface ReuseBlockingVerdict {
|
|
182
|
+
/** ABSOLUTE PATH of the spec the verdict is about — the refusal is agent-facing,
|
|
183
|
+
* and two specs sharing a basename (one per repository) must stay two verdicts. */
|
|
184
|
+
file: string;
|
|
185
|
+
/** The blocking kinds found, each with its count and detail — what the row ships
|
|
186
|
+
* with once the refusal bound is reached. */
|
|
187
|
+
failures: ReuseVerificationFailure[];
|
|
188
|
+
/** What failed and how to repair it — the text the live verify pass would have
|
|
189
|
+
* returned for the delivered file, so the remediation is the one the agent knows. */
|
|
190
|
+
detail: string;
|
|
191
|
+
/** The exact `skyramp_reuse_code` verify call to make after the repair, so the
|
|
192
|
+
* repaired files are re-checked. */
|
|
193
|
+
verifyCall: string;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* How many times skyramp_submit_report refuses a report over one spec's blocking
|
|
197
|
+
* verdict before accepting it with the fault recorded in the row.
|
|
198
|
+
*
|
|
199
|
+
* The refusal is a repair loop, and a repair loop at the last step of a run needs a
|
|
200
|
+
* terminal state (SKYR-4059: an unbounded loop destroyed verified work). Without one,
|
|
201
|
+
* an agent that cannot reach a pass — out of turns, or a `guard-removed` it cannot
|
|
202
|
+
* restore, which no marker documents away — delivers no report at all, and a
|
|
203
|
+
* customer with no pull request is a worse outcome than one with a disclosed fault.
|
|
204
|
+
* Two refusals cover the common case, where the repair is one edit and one verify
|
|
205
|
+
* call away; the third call ships the row with `verificationFailures` set.
|
|
206
|
+
*/
|
|
207
|
+
export declare const REUSE_SUBMIT_MAX_REFUSALS = 2;
|
|
208
|
+
/** What one report row's re-derivation established: the outcome to publish, and a
|
|
209
|
+
* blocking verdict when the delivered files fail the live check. */
|
|
210
|
+
export interface ReuseRederivation {
|
|
211
|
+
outcome: ReuseOutcome | undefined;
|
|
212
|
+
blocking?: ReuseBlockingVerdict;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* The reason behind a failed shared-helper verdict, one entry per blocking kind in
|
|
216
|
+
* the order the verifier found them. The verify pass had these in hand and dropped
|
|
217
|
+
* them after computing `ok`; without them a `failed` row is a verdict nobody can act
|
|
218
|
+
* on. The detail text is the verifier's own — for an assertion loss it carries the
|
|
219
|
+
* counts (baseline, delivered, in the test, in the helpers) that decided the verdict.
|
|
220
|
+
*/
|
|
221
|
+
export declare function verificationFailures(r: UtilsVerifyResult): ReuseVerificationFailure[];
|
|
151
222
|
/**
|
|
152
223
|
* Re-derive a recorded outcome from the spec as it stands NOW, so the report
|
|
153
224
|
* describes the delivered artifact rather than the state at verify time.
|
|
@@ -169,8 +240,15 @@ export declare function reuseChainSkipped(fileName: string, testType: string, re
|
|
|
169
240
|
*
|
|
170
241
|
* Returns the recorded outcome minus internals when re-derivation is impossible
|
|
171
242
|
* (no path recorded — now only the no-POM-layer path, which has no spec to measure
|
|
172
|
-
* and no candidates to contrast against), and
|
|
243
|
+
* and no candidates to contrast against), and no outcome when it fails outright.
|
|
173
244
|
* Failing closed matters: falling back to the recorded counts is exactly the false
|
|
174
245
|
* claim this exists to prevent.
|
|
246
|
+
*
|
|
247
|
+
* Beside the outcome comes the blocking verdict the delivered files earn under the
|
|
248
|
+
* live check — see {@link ReuseBlockingVerdict}. One measurement feeds both: the row
|
|
249
|
+
* the report publishes and the refusal `skyramp_submit_report` returns. That half
|
|
250
|
+
* fails OPEN like every reuse check: a re-derivation that throws yields no outcome
|
|
251
|
+
* and no verdict. A verifier that cannot run is not evidence against the file, and
|
|
252
|
+
* refusing a report on a malfunction would deliver nothing to the customer.
|
|
175
253
|
*/
|
|
176
|
-
export declare function
|
|
254
|
+
export declare function rederiveReuse(record: ReuseRecord): Promise<ReuseRederivation>;
|