@phamvuhoang/otto-core 0.29.0 → 0.31.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/dist/cli-help.d.ts +6 -0
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +7 -1
- package/dist/cli-help.js.map +1 -1
- package/dist/git.d.ts +7 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +20 -0
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/input-sharpness.d.ts +80 -0
- package/dist/input-sharpness.d.ts.map +1 -0
- package/dist/input-sharpness.js +125 -0
- package/dist/input-sharpness.js.map +1 -0
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +25 -0
- package/dist/inspect.js.map +1 -1
- package/dist/loop.d.ts +6 -0
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +94 -4
- package/dist/loop.js.map +1 -1
- package/dist/report-finalize.d.ts.map +1 -1
- package/dist/report-finalize.js +49 -1
- package/dist/report-finalize.js.map +1 -1
- package/dist/run-bin.d.ts.map +1 -1
- package/dist/run-bin.js +5 -0
- package/dist/run-bin.js.map +1 -1
- package/dist/run-report.d.ts +15 -0
- package/dist/run-report.d.ts.map +1 -1
- package/dist/run-report.js.map +1 -1
- package/dist/verification-evidence.d.ts +41 -0
- package/dist/verification-evidence.d.ts.map +1 -0
- package/dist/verification-evidence.js +184 -0
- package/dist/verification-evidence.js.map +1 -0
- package/dist/verification-matrix.d.ts +159 -0
- package/dist/verification-matrix.d.ts.map +1 -0
- package/dist/verification-matrix.js +337 -0
- package/dist/verification-matrix.js.map +1 -0
- package/package.json +1 -1
- package/templates/plan.md +2 -0
- package/templates/verify.md +41 -1
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification matrix (issue #181 P24, slice 1 — "make verification provable").
|
|
3
|
+
*
|
|
4
|
+
* A pure data model + scorer for the roadmap's verification-artifact matrix:
|
|
5
|
+
* each requirement (a plan task / acceptance criterion) paired with HOW it was
|
|
6
|
+
* checked, the concrete artifact that proves it (a `file:line`, a commit SHA, a
|
|
7
|
+
* command transcript, a screenshot path), the result, and a confidence. Today
|
|
8
|
+
* the `verify` stage emits this as free-form DONE/GAP/DEFERRED prose; P24 turns
|
|
9
|
+
* it into a structured matrix a maintainer can scan, and a "verification
|
|
10
|
+
* gallery" a non-engineer can accept/reject from.
|
|
11
|
+
*
|
|
12
|
+
* This slice is the substrate — the type, a summary scorer (counts, artifact
|
|
13
|
+
* coverage, an overall verdict), and a formatter that renders the matrix and
|
|
14
|
+
* surfaces failures / unproven requirements as explicit risks rather than
|
|
15
|
+
* burying them in logs. INERT on the loop: nothing here runs a stage or changes
|
|
16
|
+
* behavior; later P24 slices populate it from the verify stage and fold it into
|
|
17
|
+
* run reports + `otto-inspect`. Mirrors how the plan/context/report rubrics
|
|
18
|
+
* shipped pure-then-wired.
|
|
19
|
+
*/
|
|
20
|
+
const METHODS = new Set([
|
|
21
|
+
"test",
|
|
22
|
+
"command",
|
|
23
|
+
"visual",
|
|
24
|
+
"inspection",
|
|
25
|
+
"manual",
|
|
26
|
+
]);
|
|
27
|
+
const RESULTS = new Set([
|
|
28
|
+
"pass",
|
|
29
|
+
"fail",
|
|
30
|
+
"partial",
|
|
31
|
+
"deferred",
|
|
32
|
+
]);
|
|
33
|
+
const CONFIDENCES = new Set(["high", "medium", "low"]);
|
|
34
|
+
/**
|
|
35
|
+
* Whether a string is a *typed*, durable artifact reference that actually proves
|
|
36
|
+
* something — a `file:line` (or `file:line-range`), a path with a separator or a
|
|
37
|
+
* file extension (a transcript / screenshot / source file), or a 7–40 char commit
|
|
38
|
+
* SHA. A bare command (`node --test`), prose (`read the code`), or a placeholder
|
|
39
|
+
* (`TODO`) is NOT proof and returns false, so the coverage signal can't be earned
|
|
40
|
+
* by an unverifiable string (#181 review). Pure.
|
|
41
|
+
*/
|
|
42
|
+
export function isValidArtifactReference(ref) {
|
|
43
|
+
const r = ref.trim();
|
|
44
|
+
if (!r)
|
|
45
|
+
return false;
|
|
46
|
+
if (/\s/.test(r))
|
|
47
|
+
return false; // commands / prose carry whitespace
|
|
48
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(r))
|
|
49
|
+
return false; // URLs (scheme://)
|
|
50
|
+
if (/(?:^|[\\/])\.\.(?:[\\/]|$)/.test(r))
|
|
51
|
+
return false; // path traversal
|
|
52
|
+
if (/^[0-9a-f]{7,40}$/i.test(r))
|
|
53
|
+
return true; // commit SHA
|
|
54
|
+
if (/^[\w./\\-]+:\d+(?:-\d+)?$/.test(r))
|
|
55
|
+
return true; // file:line or file:line-range
|
|
56
|
+
return /[/\\]/.test(r) || /\.[A-Za-z0-9]{1,8}$/.test(r); // a path, or a file with an extension
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Whether an entry carries a *valid, typed* proving artifact. Syntactically valid
|
|
60
|
+
* (see {@link isValidArtifactReference}) AND not marked non-existent by the loop's
|
|
61
|
+
* filesystem/git validation (`artifactExists === false`). When `artifactExists` is
|
|
62
|
+
* undefined the syntax check stands alone — the pure scorer cannot touch the
|
|
63
|
+
* filesystem, so the loop sets `artifactExists` before this matters at runtime.
|
|
64
|
+
*/
|
|
65
|
+
function hasArtifact(e) {
|
|
66
|
+
return (Boolean(e.artifactPath) &&
|
|
67
|
+
isValidArtifactReference(e.artifactPath) &&
|
|
68
|
+
e.artifactExists !== false);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse an agent-emitted verification matrix (a JSON `VerificationEntry[]`,
|
|
72
|
+
* e.g. the `.otto-tmp/verify-matrix.json` the verify stage writes), keeping the
|
|
73
|
+
* parse diagnostics so a malformed/partial matrix is reported, not silently
|
|
74
|
+
* dropped (#181 review). Tolerant: never throws, drops any entry missing a
|
|
75
|
+
* non-empty `requirement` or carrying an unknown `method`/`result`, defaults an
|
|
76
|
+
* absent/invalid `confidence` to `medium`, and counts each dropped row. Non-array
|
|
77
|
+
* / malformed JSON ⇒ `{ entries: [], dropped: 0, parsed: false }`. Pure.
|
|
78
|
+
*/
|
|
79
|
+
export function parseVerificationMatrixWithDiagnostics(raw) {
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(raw);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return { entries: [], dropped: 0, parsed: false };
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(parsed))
|
|
88
|
+
return { entries: [], dropped: 0, parsed: false };
|
|
89
|
+
const entries = [];
|
|
90
|
+
let dropped = 0;
|
|
91
|
+
for (const item of parsed) {
|
|
92
|
+
const entry = coerceEntry(item);
|
|
93
|
+
if (entry)
|
|
94
|
+
entries.push(entry);
|
|
95
|
+
else
|
|
96
|
+
dropped += 1;
|
|
97
|
+
}
|
|
98
|
+
return { entries, dropped, parsed: true };
|
|
99
|
+
}
|
|
100
|
+
function coerceEntry(item) {
|
|
101
|
+
if (!item || typeof item !== "object")
|
|
102
|
+
return null;
|
|
103
|
+
const r = item;
|
|
104
|
+
const requirement = typeof r.requirement === "string" ? r.requirement.trim() : "";
|
|
105
|
+
if (!requirement)
|
|
106
|
+
return null;
|
|
107
|
+
if (typeof r.method !== "string" || !METHODS.has(r.method))
|
|
108
|
+
return null;
|
|
109
|
+
if (typeof r.result !== "string" || !RESULTS.has(r.result))
|
|
110
|
+
return null;
|
|
111
|
+
const confidence = typeof r.confidence === "string" && CONFIDENCES.has(r.confidence)
|
|
112
|
+
? r.confidence
|
|
113
|
+
: "medium";
|
|
114
|
+
return {
|
|
115
|
+
requirement,
|
|
116
|
+
method: r.method,
|
|
117
|
+
check: typeof r.check === "string" ? r.check : "",
|
|
118
|
+
...(typeof r.artifactPath === "string" && r.artifactPath
|
|
119
|
+
? { artifactPath: r.artifactPath }
|
|
120
|
+
: {}),
|
|
121
|
+
...(typeof r.beforePath === "string" && r.beforePath
|
|
122
|
+
? { beforePath: r.beforePath }
|
|
123
|
+
: {}),
|
|
124
|
+
result: r.result,
|
|
125
|
+
confidence,
|
|
126
|
+
...(typeof r.note === "string" && r.note ? { note: r.note } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Parse a verification matrix into valid entries (diagnostics discarded). Pure. */
|
|
130
|
+
export function parseVerificationMatrix(raw) {
|
|
131
|
+
return parseVerificationMatrixWithDiagnostics(raw).entries;
|
|
132
|
+
}
|
|
133
|
+
/** Whether a requirement is one we expect a concrete artifact for (i.e. not deferred). */
|
|
134
|
+
function isVerifiable(e) {
|
|
135
|
+
return e.result !== "deferred";
|
|
136
|
+
}
|
|
137
|
+
/** Tally a verification matrix into counts, artifact coverage, and a verdict. Pure. */
|
|
138
|
+
export function summarizeVerification(entries) {
|
|
139
|
+
const total = entries.length;
|
|
140
|
+
const pass = entries.filter((e) => e.result === "pass").length;
|
|
141
|
+
const fail = entries.filter((e) => e.result === "fail").length;
|
|
142
|
+
const partial = entries.filter((e) => e.result === "partial").length;
|
|
143
|
+
const deferred = entries.filter((e) => e.result === "deferred").length;
|
|
144
|
+
const verifiable = entries.filter(isVerifiable);
|
|
145
|
+
const withArtifact = entries.filter(hasArtifact).length;
|
|
146
|
+
const verifiableProven = verifiable.filter(hasArtifact).length;
|
|
147
|
+
// Vacuous truth: an all-deferred matrix (entries, but none verifiable) is fully
|
|
148
|
+
// covered — there is nothing left to prove (#181 review). An empty matrix has
|
|
149
|
+
// nothing measured, so coverage is 0.
|
|
150
|
+
const coverage = total === 0
|
|
151
|
+
? 0
|
|
152
|
+
: verifiable.length > 0
|
|
153
|
+
? verifiableProven / verifiable.length
|
|
154
|
+
: 1;
|
|
155
|
+
let verdict;
|
|
156
|
+
if (total === 0)
|
|
157
|
+
verdict = "empty";
|
|
158
|
+
else if (fail > 0)
|
|
159
|
+
verdict = "gaps";
|
|
160
|
+
else if (verifiable.length > 0 && verifiableProven === 0)
|
|
161
|
+
verdict = "unproven";
|
|
162
|
+
else if (coverage >= 1 && partial === 0)
|
|
163
|
+
verdict = "verified";
|
|
164
|
+
else
|
|
165
|
+
verdict = "partial";
|
|
166
|
+
return {
|
|
167
|
+
total,
|
|
168
|
+
pass,
|
|
169
|
+
fail,
|
|
170
|
+
partial,
|
|
171
|
+
deferred,
|
|
172
|
+
withArtifact,
|
|
173
|
+
coverage,
|
|
174
|
+
verdict,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Score a verification matrix against the roadmap's coverage bar (P24): every
|
|
179
|
+
* verifiable requirement must carry a valid artifact, none may fail, none may be
|
|
180
|
+
* left partial, and no rows may have been dropped during parsing. `dropped` rows
|
|
181
|
+
* are unknown requirements that cannot be assumed proven, so any drop FAILs the
|
|
182
|
+
* gate (#181 re-review). The `unproven`/`failed`/`incomplete` lists + `dropped`
|
|
183
|
+
* are exactly why the gate did not pass. Pure.
|
|
184
|
+
*/
|
|
185
|
+
export function scoreVerificationCoverage(entries, dropped = 0) {
|
|
186
|
+
const summary = summarizeVerification(entries);
|
|
187
|
+
return {
|
|
188
|
+
passed: summary.verdict === "verified" && dropped === 0,
|
|
189
|
+
coverage: summary.coverage,
|
|
190
|
+
unproven: entries
|
|
191
|
+
.filter((e) => isVerifiable(e) && !hasArtifact(e))
|
|
192
|
+
.map((e) => e.requirement),
|
|
193
|
+
failed: entries
|
|
194
|
+
.filter((e) => e.result === "fail")
|
|
195
|
+
.map((e) => e.requirement),
|
|
196
|
+
incomplete: entries
|
|
197
|
+
.filter((e) => e.result === "partial")
|
|
198
|
+
.map((e) => e.requirement),
|
|
199
|
+
dropped,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Render the verification-coverage gate as a report block (mirrors the emit-time
|
|
204
|
+
* legibility gate): a PASS/FAIL verdict, the artifact-backed coverage, and — on
|
|
205
|
+
* FAIL — the unproven/failed requirements plus how to clear them. Empty string
|
|
206
|
+
* for an empty matrix, so a run with no verification adds no gate. Pure.
|
|
207
|
+
*/
|
|
208
|
+
export function formatVerificationCoverageGate(entries, dropped = 0) {
|
|
209
|
+
if (entries.length === 0 && dropped === 0)
|
|
210
|
+
return "";
|
|
211
|
+
const g = scoreVerificationCoverage(entries, dropped);
|
|
212
|
+
const lines = [
|
|
213
|
+
"## Verification Coverage Gate",
|
|
214
|
+
"",
|
|
215
|
+
`Gate: **${g.passed ? "PASS" : "FAIL"}** — ${pct.format(g.coverage * 100)}% of verifiable requirements are artifact-backed.`,
|
|
216
|
+
];
|
|
217
|
+
if (!g.passed) {
|
|
218
|
+
if (g.dropped > 0) {
|
|
219
|
+
lines.push("", `Dropped ${g.dropped} malformed matrix row(s) — those requirements are unknown and unverified; fix the matrix.`);
|
|
220
|
+
}
|
|
221
|
+
if (g.failed.length > 0) {
|
|
222
|
+
lines.push("", `Failed: ${g.failed.join(", ")}.`);
|
|
223
|
+
}
|
|
224
|
+
if (g.incomplete.length > 0) {
|
|
225
|
+
lines.push("", `Incomplete (partial — finish or split): ${g.incomplete.join(", ")}.`);
|
|
226
|
+
}
|
|
227
|
+
if (g.unproven.length > 0) {
|
|
228
|
+
lines.push("", `Unproven (cite a valid artifact — \`file:line\`, a commit SHA, a transcript/screenshot path — or mark the requirement \`deferred\`): ${g.unproven.join(", ")}.`);
|
|
229
|
+
}
|
|
230
|
+
// A FAIL with no failed/incomplete/unproven items would be unexplained; make
|
|
231
|
+
// the residual reason explicit rather than leaving an empty gate (#181 review).
|
|
232
|
+
if (g.dropped === 0 &&
|
|
233
|
+
g.failed.length === 0 &&
|
|
234
|
+
g.incomplete.length === 0 &&
|
|
235
|
+
g.unproven.length === 0) {
|
|
236
|
+
lines.push("", "No requirement is fully proven, yet none is individually failed/partial/unproven — review the matrix.");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return lines.join("\n");
|
|
240
|
+
}
|
|
241
|
+
/** Path prefix of artifacts relocated into the run bundle (see
|
|
242
|
+
* `verification-evidence.ts`); only these resolve relative to report.md. */
|
|
243
|
+
export const BUNDLE_ARTIFACT_PREFIX = "verification/";
|
|
244
|
+
const IMAGE_RE = /\.(?:png|jpe?g|gif|webp|svg|avif)$/i;
|
|
245
|
+
/**
|
|
246
|
+
* A path safe to embed as a markdown image: it was actually copied into the
|
|
247
|
+
* physical run bundle by the impure layer (`bundled === true` — not a string
|
|
248
|
+
* prefix the agent could spoof) and has an image extension. So a rejected URL, an
|
|
249
|
+
* un-relocated path, or an agent-supplied `verification/…` masquerade is never
|
|
250
|
+
* emitted as an image (#181 boundary review).
|
|
251
|
+
*/
|
|
252
|
+
function embeddableImage(p, bundled) {
|
|
253
|
+
return (bundled === true &&
|
|
254
|
+
typeof p === "string" &&
|
|
255
|
+
!p.includes("..") &&
|
|
256
|
+
IMAGE_RE.test(p));
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Render the visual evidence (P24 visual half) as a markdown "Screenshot
|
|
260
|
+
* Evidence" section that *embeds* each `visual` entry's captured screenshot —
|
|
261
|
+
* a single image, or a before → after pair — so a non-engineer reading the run
|
|
262
|
+
* report sees the proof, not just a path. Only artifacts the impure layer actually
|
|
263
|
+
* **copied into the bundle** (`artifactBundled`/`beforeBundled`) and that are
|
|
264
|
+
* images are embedded; a visual check the environment could not render, or any
|
|
265
|
+
* unbundled/spoofed path, is left to the coverage gate to flag, never emitted as
|
|
266
|
+
* an image. Empty string when no embeddable visual evidence exists. Pure.
|
|
267
|
+
*/
|
|
268
|
+
export function formatVisualEvidence(entries) {
|
|
269
|
+
const visuals = entries.filter((e) => e.method === "visual" &&
|
|
270
|
+
embeddableImage(e.artifactPath, e.artifactBundled));
|
|
271
|
+
if (visuals.length === 0)
|
|
272
|
+
return "";
|
|
273
|
+
const lines = ["## Screenshot Evidence", ""];
|
|
274
|
+
for (const e of visuals) {
|
|
275
|
+
lines.push(`### ${e.requirement}`, "");
|
|
276
|
+
if (embeddableImage(e.beforePath, e.beforeBundled)) {
|
|
277
|
+
lines.push(`- Before: `);
|
|
278
|
+
lines.push(`- After: `);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
lines.push(``);
|
|
282
|
+
}
|
|
283
|
+
lines.push("");
|
|
284
|
+
}
|
|
285
|
+
return lines.join("\n").trimEnd();
|
|
286
|
+
}
|
|
287
|
+
const RESULT_MARK = {
|
|
288
|
+
pass: "✓",
|
|
289
|
+
fail: "✗",
|
|
290
|
+
partial: "~",
|
|
291
|
+
deferred: "·",
|
|
292
|
+
};
|
|
293
|
+
const pct = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
|
|
294
|
+
/** Collapse a (possibly multi-line) check to one bounded, fence-safe line. */
|
|
295
|
+
function oneLine(s, max = 80) {
|
|
296
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
297
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Render a verification matrix as a scannable report: a header verdict line, one
|
|
301
|
+
* row per requirement (mark · method · requirement · artifact), and an explicit
|
|
302
|
+
* **Risks** section listing every failed or unproven requirement so a reader
|
|
303
|
+
* cannot miss them. Pure.
|
|
304
|
+
*/
|
|
305
|
+
export function formatVerificationMatrix(entries) {
|
|
306
|
+
if (entries.length === 0) {
|
|
307
|
+
return "Verification: no verification recorded for this run.";
|
|
308
|
+
}
|
|
309
|
+
const s = summarizeVerification(entries);
|
|
310
|
+
const lines = [
|
|
311
|
+
`Verification: ${s.verdict} — ${s.pass}/${s.total} pass` +
|
|
312
|
+
(s.fail > 0 ? `, ${s.fail} fail` : "") +
|
|
313
|
+
(s.partial > 0 ? `, ${s.partial} partial` : "") +
|
|
314
|
+
(s.deferred > 0 ? `, ${s.deferred} deferred` : "") +
|
|
315
|
+
` · ${pct.format(s.coverage * 100)}% artifact-backed`,
|
|
316
|
+
];
|
|
317
|
+
for (const e of entries) {
|
|
318
|
+
const artifact = hasArtifact(e)
|
|
319
|
+
? ` → ${e.artifactPath}`
|
|
320
|
+
: e.artifactPath
|
|
321
|
+
? ` → ${e.artifactPath} (not a valid artifact)`
|
|
322
|
+
: " → (no artifact)";
|
|
323
|
+
const conf = e.confidence !== "high" ? ` [${e.confidence}]` : "";
|
|
324
|
+
const check = e.check ? ` · check: ${oneLine(e.check)}` : "";
|
|
325
|
+
lines.push(` ${RESULT_MARK[e.result]} ${e.method}: ${e.requirement}${conf}${artifact}${check}`);
|
|
326
|
+
}
|
|
327
|
+
const risks = entries.filter((e) => e.result === "fail" || (isVerifiable(e) && !hasArtifact(e)));
|
|
328
|
+
if (risks.length > 0) {
|
|
329
|
+
lines.push("", `Risks (${risks.length}):`);
|
|
330
|
+
for (const e of risks) {
|
|
331
|
+
const why = e.result === "fail" ? "failed" : "unproven (no valid artifact)";
|
|
332
|
+
lines.push(` - ${e.requirement} — ${why}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return lines.join("\n");
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=verification-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification-matrix.js","sourceRoot":"","sources":["../src/verification-matrix.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/templates/plan.md
CHANGED
package/templates/verify.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
You are VERIFYING, not implementing. The `<inputs>` block names a plan and PRD (conventionally file paths). `Read` them.
|
|
24
24
|
|
|
25
|
-
**Make NO commits and NO source edits.** You may read files and run the test/type suites. The only
|
|
25
|
+
**Make NO commits and NO source edits.** You may read files and run the test/type suites. The only files you may write are the verification report and matrix named below and any verification artifacts they cite (e.g. screenshots), all under the gitignored `.otto-tmp/` scratch dir — nothing else.
|
|
26
26
|
|
|
27
27
|
# RECONCILE
|
|
28
28
|
|
|
@@ -49,6 +49,46 @@ Write your report to `.otto-tmp/verify-report.md` using the `Write` tool (this p
|
|
|
49
49
|
|
|
50
50
|
@include:quality-report.md
|
|
51
51
|
|
|
52
|
+
# VERIFICATION MATRIX (MACHINE-READABLE)
|
|
53
|
+
|
|
54
|
+
Also write a structured verification matrix to `.otto-tmp/verify-matrix.json`
|
|
55
|
+
using the `Write` tool (gitignored scratch — this, the report above, and any
|
|
56
|
+
screenshot artifacts cited below are the only writes you may make). It is a JSON
|
|
57
|
+
array, one entry per plan task /
|
|
58
|
+
acceptance criterion you reconciled, so a maintainer (or a non-engineer) can scan
|
|
59
|
+
exactly what was proven and how:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
|
+
"requirement": "<the task / acceptance criterion>",
|
|
65
|
+
"method": "test | command | visual | inspection | manual",
|
|
66
|
+
"check": "<the exact command run, the assertion, or the visual checked>",
|
|
67
|
+
"artifactPath": "<proof: file:line, a commit SHA, a transcript/screenshot path; omit if none>",
|
|
68
|
+
"result": "pass | fail | partial | deferred",
|
|
69
|
+
"confidence": "high | medium | low"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Rules: one entry per task; `result` mirrors your DONE/GAP/DEFERRED classification
|
|
75
|
+
(`pass` = DONE, `fail`/`partial` = GAP, `deferred` = DEFERRED); always cite an
|
|
76
|
+
`artifactPath` when one exists (a `file:line`, the commit SHA that implements it,
|
|
77
|
+
or the suite command) — an entry with no artifact is an unproven claim and should
|
|
78
|
+
say so via `"confidence": "low"`. Use the real commands you ran; do not invent
|
|
79
|
+
proof. A malformed file is ignored, so prefer omitting a field to guessing.
|
|
80
|
+
|
|
81
|
+
**Visual evidence (opportunistic).** For a UI/web requirement, if a screenshot
|
|
82
|
+
tool and a renderable target (a running dev server or a static built artifact)
|
|
83
|
+
are actually available to you, capture a screenshot, save it under the gitignored
|
|
84
|
+
`.otto-tmp/` scratch dir, and emit a `"method": "visual"` entry whose
|
|
85
|
+
`artifactPath` is that screenshot path; for a before/after change set `beforePath`
|
|
86
|
+
to the prior-state screenshot and `artifactPath` to the new one. **Never fabricate
|
|
87
|
+
a screenshot or a path.** If you cannot render or capture the UI in this
|
|
88
|
+
environment, still emit the `visual` entry but **omit `artifactPath`** and set
|
|
89
|
+
`"confidence": "low"` — the coverage gate then reports the gap honestly instead of
|
|
90
|
+
claiming unproven visual proof.
|
|
91
|
+
|
|
52
92
|
# CROSS-RUN QUALITY SUMMARY (READ-ONLY)
|
|
53
93
|
|
|
54
94
|
Beyond _this_ run, give the maintainer a quality rollup **across** runs so they can
|