@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.
Files changed (83) hide show
  1. package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.js +2 -1
  2. package/build/prompts/enhance-assertions/integrationAssertionsPrompt.js +2 -1
  3. package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -1
  4. package/build/prompts/enhance-assertions/sharedAssertionRules.js +57 -22
  5. package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +17 -9
  6. package/build/prompts/test-recommendation/diffExecutionPlan.js +0 -2
  7. package/build/prompts/test-recommendation/test-recommendation-prompt.js +11 -6
  8. package/build/prompts/testbot/testbot-prompts.js +19 -12
  9. package/build/recommendation/answers.d.ts +11 -7
  10. package/build/recommendation/answers.js +14 -10
  11. package/build/recommendation/pullRequestText.d.ts +18 -0
  12. package/build/recommendation/pullRequestText.js +31 -0
  13. package/build/recommendation/registerPlan.d.ts +9 -1
  14. package/build/recommendation/registerPlan.js +8 -1
  15. package/build/recommendation/runVerifiers.js +6 -0
  16. package/build/recommendation/types.d.ts +58 -0
  17. package/build/recommendation/verifierContracts.d.ts +108 -13
  18. package/build/recommendation/verifierContracts.js +147 -29
  19. package/build/recommendation/verifiers/coverage.d.ts +10 -0
  20. package/build/recommendation/verifiers/coverage.js +144 -22
  21. package/build/recommendation/verifiers/defects.d.ts +9 -0
  22. package/build/recommendation/verifiers/defects.js +117 -0
  23. package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +22 -0
  24. package/build/recommendation/verifiers/deliveredMatchesPlan.js +43 -0
  25. package/build/recommendation/verifiers/existingCoverage.js +53 -0
  26. package/build/recommendation/verifiers/expectedValueSourced.d.ts +14 -0
  27. package/build/recommendation/verifiers/expectedValueSourced.js +246 -0
  28. package/build/recommendation/verifiers/issueTraceability.d.ts +52 -0
  29. package/build/recommendation/verifiers/issueTraceability.js +197 -0
  30. package/build/recommendation/verifiers/requirementSourced.d.ts +2 -0
  31. package/build/recommendation/verifiers/requirementSourced.js +168 -0
  32. package/build/services/TestGenerationService.js +3 -1
  33. package/build/tools/code-refactor/codeReuseTool.js +1 -1
  34. package/build/tools/code-refactor/reuse-outcome.d.ts +1 -1
  35. package/build/tools/code-refactor/reuse-state.d.ts +85 -7
  36. package/build/tools/code-refactor/reuse-state.js +239 -34
  37. package/build/tools/code-refactor/utils-verify-gates.d.ts +5 -0
  38. package/build/tools/code-refactor/utils-verify-gates.js +103 -11
  39. package/build/tools/generate-tests/generateBatchScenarioRestTool.js +2 -1
  40. package/build/tools/submitReportTool.js +276 -39
  41. package/build/tools/test-management/actionsTool.js +5 -0
  42. package/build/tools/test-management/analyzeChangesTool.d.ts +53 -0
  43. package/build/tools/test-management/analyzeChangesTool.js +55 -2
  44. package/build/tools/test-management/registerTestPlanTool.d.ts +32 -17
  45. package/build/tools/test-management/registerTestPlanTool.js +105 -16
  46. package/build/types/ReuseOutcome.d.ts +73 -7
  47. package/build/types/TestAnalysis.d.ts +6 -0
  48. package/build/types/TestbotReport.d.ts +22 -4
  49. package/build/utils/AnalysisStateManager.d.ts +7 -1
  50. package/build/utils/AnalysisStateManager.js +5 -1
  51. package/build/utils/assertion-verify/api-shared-lints.js +118 -11
  52. package/build/utils/assertion-verify/format.js +2 -2
  53. package/build/utils/assertion-verify/helper-imports.d.ts +7 -0
  54. package/build/utils/assertion-verify/helper-imports.js +119 -27
  55. package/build/utils/assertion-verify/lint-types.d.ts +31 -2
  56. package/build/utils/assertion-verify/lint-types.js +66 -0
  57. package/build/utils/assertion-verify/metrics.d.ts +13 -0
  58. package/build/utils/assertion-verify/metrics.js +16 -0
  59. package/build/utils/assertion-verify/verify.d.ts +11 -6
  60. package/build/utils/assertion-verify/verify.js +56 -15
  61. package/build/utils/canonicalJson.d.ts +11 -0
  62. package/build/utils/canonicalJson.js +17 -0
  63. package/build/utils/utils-verify/action-key.d.ts +27 -0
  64. package/build/utils/utils-verify/action-key.js +292 -0
  65. package/build/utils/utils-verify/allow.d.ts +8 -1
  66. package/build/utils/utils-verify/allow.js +14 -1
  67. package/build/utils/utils-verify/call-sites.d.ts +76 -8
  68. package/build/utils/utils-verify/call-sites.js +256 -70
  69. package/build/utils/utils-verify/language-spec.d.ts +3 -2
  70. package/build/utils/utils-verify/parse.d.ts +22 -3
  71. package/build/utils/utils-verify/parse.js +123 -52
  72. package/build/utils/utils-verify/verify.d.ts +33 -3
  73. package/build/utils/utils-verify/verify.js +126 -12
  74. package/build/utils/workspaceAuth.d.ts +59 -19
  75. package/build/utils/workspaceAuth.js +228 -31
  76. package/package.json +1 -1
  77. package/plugin/prompts/generate-tests/execution-plan.md +3 -3
  78. package/plugin/prompts/generate-tests/generation.md +1 -0
  79. package/plugin/prompts/plan-tests.md +41 -15
  80. package/plugin/prompts/testbot-task1.md +3 -9
  81. package/build/prompts/testbot/planDeclarations.d.ts +0 -6
  82. package/build/prompts/testbot/planDeclarations.js +0 -9
  83. package/plugin/prompts/declaring-a-plan.md +0 -20
@@ -0,0 +1,2 @@
1
+ import { Verifier } from "../types.js";
2
+ export declare const requirementSourced: Verifier;
@@ -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
- * `rederiveReuseOutcome`), never read back from here.
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 `rederiveReuseOutcome` bail out,
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`, which does not block and reports the honest zero. So the
59
- * worst case degrades to the reporting half rather than to a run that produces
60
- * nothing which is what a bound would have been protecting against.
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
- /** The basename label a report row shows for a set of utils files. */
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 `undefined` when it fails outright.
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 rederiveReuseOutcome(record: ReuseRecord): Promise<ReuseOutcome | undefined>;
254
+ export declare function rederiveReuse(record: ReuseRecord): Promise<ReuseRederivation>;