@ivorycanvas/qamap 0.3.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/CHANGELOG.md +93 -0
- package/LICENSE +21 -0
- package/README.md +636 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +879 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +114 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +1 -0
- package/dist/context.js +126 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +32 -0
- package/dist/doctor.js +200 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domain-language.d.ts +25 -0
- package/dist/domain-language.js +655 -0
- package/dist/domain-language.js.map +1 -0
- package/dist/domains.d.ts +33 -0
- package/dist/domains.js +258 -0
- package/dist/domains.js.map +1 -0
- package/dist/e2e.d.ts +326 -0
- package/dist/e2e.js +6869 -0
- package/dist/e2e.js.map +1 -0
- package/dist/eval.d.ts +40 -0
- package/dist/eval.js +374 -0
- package/dist/eval.js.map +1 -0
- package/dist/flows.d.ts +32 -0
- package/dist/flows.js +246 -0
- package/dist/flows.js.map +1 -0
- package/dist/fs.d.ts +7 -0
- package/dist/fs.js +132 -0
- package/dist/fs.js.map +1 -0
- package/dist/github.d.ts +34 -0
- package/dist/github.js +183 -0
- package/dist/github.js.map +1 -0
- package/dist/history.d.ts +173 -0
- package/dist/history.js +247 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-suggestions.d.ts +67 -0
- package/dist/manifest-suggestions.js +673 -0
- package/dist/manifest-suggestions.js.map +1 -0
- package/dist/manifest.d.ts +212 -0
- package/dist/manifest.js +1607 -0
- package/dist/manifest.js.map +1 -0
- package/dist/qa.d.ts +53 -0
- package/dist/qa.js +361 -0
- package/dist/qa.js.map +1 -0
- package/dist/report.d.ts +5 -0
- package/dist/report.js +164 -0
- package/dist/report.js.map +1 -0
- package/dist/review.d.ts +31 -0
- package/dist/review.js +383 -0
- package/dist/review.js.map +1 -0
- package/dist/scanner.d.ts +3 -0
- package/dist/scanner.js +797 -0
- package/dist/scanner.js.map +1 -0
- package/dist/severity.d.ts +3 -0
- package/dist/severity.js +9 -0
- package/dist/severity.js.map +1 -0
- package/dist/test-evidence.d.ts +39 -0
- package/dist/test-evidence.js +303 -0
- package/dist/test-evidence.js.map +1 -0
- package/dist/test-plan.d.ts +35 -0
- package/dist/test-plan.js +573 -0
- package/dist/test-plan.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +27 -0
- package/dist/verify.js +244 -0
- package/dist/verify.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/docs/adoption.md +166 -0
- package/docs/agent-skill.md +94 -0
- package/docs/api-contracts.md +30 -0
- package/docs/assets/qamap-30s-demo.gif +0 -0
- package/docs/configuration.md +277 -0
- package/docs/e2e-output-examples.md +464 -0
- package/docs/ecosystem.md +41 -0
- package/docs/eval.md +52 -0
- package/docs/github-action.md +89 -0
- package/docs/manifest.md +350 -0
- package/docs/quickstart-demo.md +268 -0
- package/docs/release-validation.md +247 -0
- package/docs/releasing.md +112 -0
- package/docs/roadmap.md +67 -0
- package/docs/rules.md +28 -0
- package/docs/verify.md +44 -0
- package/package.json +80 -0
- package/schema/qamap-manifest.schema.json +323 -0
- package/schema/qamap.schema.json +58 -0
- package/skills/qamap-pr-qa/SKILL.md +81 -0
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EvalOptions, EvalResult } from "./eval.js";
|
|
2
|
+
import type { VerificationManifestMatch } from "./manifest.js";
|
|
3
|
+
import type { ReviewResult } from "./review.js";
|
|
4
|
+
import type { ScanOptions } from "./types.js";
|
|
5
|
+
export interface VerifyOptions extends EvalOptions {
|
|
6
|
+
scanOptions?: ScanOptions;
|
|
7
|
+
manifestPath?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface VerifyResult {
|
|
10
|
+
tool: {
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
};
|
|
14
|
+
root: string;
|
|
15
|
+
workspaceRoot?: string;
|
|
16
|
+
generatedAt: string;
|
|
17
|
+
base: string;
|
|
18
|
+
head: string;
|
|
19
|
+
review: ReviewResult;
|
|
20
|
+
evaluation: EvalResult;
|
|
21
|
+
verificationManifestPath?: string;
|
|
22
|
+
verificationManifestMatches: VerificationManifestMatch[];
|
|
23
|
+
recommendations: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare function verifyChange(rootInput: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
26
|
+
export declare function formatVerifyReport(result: VerifyResult): string;
|
|
27
|
+
export declare function formatMarkdownVerifyReport(result: VerifyResult): string;
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { evaluateChangeReadiness } from "./eval.js";
|
|
2
|
+
import { changedFilesRelativeToManifestRoot, loadVerificationManifest, matchVerificationManifest, } from "./manifest.js";
|
|
3
|
+
import { reviewProject } from "./review.js";
|
|
4
|
+
import { TOOL_NAME, VERSION } from "./version.js";
|
|
5
|
+
export async function verifyChange(rootInput, options = {}) {
|
|
6
|
+
const scanOptions = options.workspaceRoot
|
|
7
|
+
? { ...options.scanOptions, workspaceRoot: options.workspaceRoot }
|
|
8
|
+
: options.scanOptions;
|
|
9
|
+
const review = await reviewProject(rootInput, {
|
|
10
|
+
base: options.base,
|
|
11
|
+
head: options.head,
|
|
12
|
+
scanOptions,
|
|
13
|
+
});
|
|
14
|
+
const evaluation = await evaluateChangeReadiness(rootInput, {
|
|
15
|
+
base: options.base,
|
|
16
|
+
head: options.head,
|
|
17
|
+
workspaceRoot: options.workspaceRoot ?? scanOptions?.workspaceRoot,
|
|
18
|
+
includeWorkingTree: options.includeWorkingTree,
|
|
19
|
+
prBody: options.prBody,
|
|
20
|
+
prBodyFile: options.prBodyFile,
|
|
21
|
+
validationCommands: options.validationCommands,
|
|
22
|
+
});
|
|
23
|
+
const manifestRoot = evaluation.workspaceRoot ?? evaluation.root;
|
|
24
|
+
const verificationManifest = await loadVerificationManifest(manifestRoot, { manifestPath: options.manifestPath });
|
|
25
|
+
const manifestChangedFiles = changedFilesRelativeToManifestRoot(evaluation.changedFiles, evaluation.root, manifestRoot);
|
|
26
|
+
const verificationManifestMatches = matchVerificationManifest(verificationManifest, manifestChangedFiles);
|
|
27
|
+
return {
|
|
28
|
+
tool: {
|
|
29
|
+
name: TOOL_NAME,
|
|
30
|
+
version: VERSION,
|
|
31
|
+
},
|
|
32
|
+
root: evaluation.root,
|
|
33
|
+
workspaceRoot: evaluation.workspaceRoot,
|
|
34
|
+
generatedAt: new Date().toISOString(),
|
|
35
|
+
base: evaluation.base,
|
|
36
|
+
head: evaluation.head,
|
|
37
|
+
review,
|
|
38
|
+
evaluation,
|
|
39
|
+
verificationManifestPath: verificationManifest.path,
|
|
40
|
+
verificationManifestMatches,
|
|
41
|
+
recommendations: buildRecommendations(review, evaluation),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function formatVerifyReport(result) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
lines.push(`${result.tool.name} Verify`);
|
|
47
|
+
lines.push(`Root: ${result.root}`);
|
|
48
|
+
if (result.workspaceRoot) {
|
|
49
|
+
lines.push(`Workspace root: ${result.workspaceRoot}`);
|
|
50
|
+
}
|
|
51
|
+
lines.push(`Base: ${result.base}`);
|
|
52
|
+
lines.push(`Head: ${result.head}`);
|
|
53
|
+
lines.push(`Readiness: ${result.evaluation.score}/${result.evaluation.maxScore} (${result.evaluation.rating})`);
|
|
54
|
+
lines.push(`Changed files: ${result.evaluation.changedFiles.length}`);
|
|
55
|
+
lines.push(`New findings: ${result.review.newFindings.length}`);
|
|
56
|
+
lines.push(`Changed risky files: ${result.review.changedRiskyFindings.length}`);
|
|
57
|
+
if (result.verificationManifestPath) {
|
|
58
|
+
lines.push(`Verification manifest: ${result.verificationManifestPath}`);
|
|
59
|
+
lines.push(`Manifest recommendations: ${result.verificationManifestMatches.length}`);
|
|
60
|
+
}
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push("Verification gates:");
|
|
63
|
+
for (const check of result.evaluation.checks) {
|
|
64
|
+
lines.push(`- ${check.status.toUpperCase()} ${check.title}: ${check.score}/${check.maxScore} - ${check.reason}`);
|
|
65
|
+
}
|
|
66
|
+
if (result.evaluation.testPlanItems.length > 0) {
|
|
67
|
+
lines.push("");
|
|
68
|
+
lines.push("Suggested domain tests:");
|
|
69
|
+
for (const item of result.evaluation.testPlanItems) {
|
|
70
|
+
lines.push(`- ${item.title}: ${item.checks[0]}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (result.verificationManifestMatches.length > 0) {
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("Manifest recommendations:");
|
|
76
|
+
for (const match of result.verificationManifestMatches.slice(0, 8)) {
|
|
77
|
+
lines.push(`- ${match.name}: ${match.reason}`);
|
|
78
|
+
if (match.evidenceSources.length > 0) {
|
|
79
|
+
lines.push(` Evidence sources: ${match.evidenceSources.join(", ")}`);
|
|
80
|
+
}
|
|
81
|
+
lines.push(` Evidence: ${match.manifestPath}`);
|
|
82
|
+
lines.push(` If wrong: update ${match.updatePath}`);
|
|
83
|
+
if (match.nextActions.length > 0) {
|
|
84
|
+
lines.push(" Next actions:");
|
|
85
|
+
for (const action of match.nextActions.slice(0, 4)) {
|
|
86
|
+
lines.push(` - ${action}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (match.repairHints.length > 0) {
|
|
90
|
+
lines.push(" Repair hints:");
|
|
91
|
+
for (const hint of match.repairHints.slice(0, 4)) {
|
|
92
|
+
lines.push(` - ${hint}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (result.evaluation.suggestedCommands.length > 0) {
|
|
98
|
+
lines.push("");
|
|
99
|
+
lines.push("Suggested commands:");
|
|
100
|
+
for (const command of result.evaluation.suggestedCommands) {
|
|
101
|
+
lines.push(`- ${command}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (result.recommendations.length > 0) {
|
|
105
|
+
lines.push("");
|
|
106
|
+
lines.push("Next actions:");
|
|
107
|
+
for (const recommendation of result.recommendations) {
|
|
108
|
+
lines.push(`- ${recommendation}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return lines.join("\n");
|
|
112
|
+
}
|
|
113
|
+
export function formatMarkdownVerifyReport(result) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
lines.push("# QAMap Verify");
|
|
116
|
+
lines.push("");
|
|
117
|
+
lines.push(`- Root: \`${escapeMarkdownInline(result.root)}\``);
|
|
118
|
+
if (result.workspaceRoot) {
|
|
119
|
+
lines.push(`- Workspace root: \`${escapeMarkdownInline(result.workspaceRoot)}\``);
|
|
120
|
+
}
|
|
121
|
+
lines.push(`- Base: \`${escapeMarkdownInline(result.base)}\``);
|
|
122
|
+
lines.push(`- Head: \`${escapeMarkdownInline(result.head)}\``);
|
|
123
|
+
if (result.evaluation.includeWorkingTree) {
|
|
124
|
+
lines.push("- Includes working tree changes: yes");
|
|
125
|
+
}
|
|
126
|
+
lines.push(`- Readiness: **${result.evaluation.score}/${result.evaluation.maxScore}** (${result.evaluation.rating})`);
|
|
127
|
+
lines.push(`- Changed files: ${result.evaluation.changedFiles.length}`);
|
|
128
|
+
lines.push(`- New findings: ${result.review.newFindings.length}`);
|
|
129
|
+
lines.push(`- Changed risky files: ${result.review.changedRiskyFindings.length}`);
|
|
130
|
+
if (result.verificationManifestPath) {
|
|
131
|
+
lines.push(`- Verification manifest: \`${escapeMarkdownInline(result.verificationManifestPath)}\``);
|
|
132
|
+
lines.push(`- Manifest recommendations: ${result.verificationManifestMatches.length}`);
|
|
133
|
+
}
|
|
134
|
+
lines.push("");
|
|
135
|
+
lines.push("## Verification Gates");
|
|
136
|
+
lines.push("");
|
|
137
|
+
lines.push("| Gate | Status | Score | Reason |");
|
|
138
|
+
lines.push("| --- | --- | ---: | --- |");
|
|
139
|
+
for (const check of result.evaluation.checks) {
|
|
140
|
+
lines.push(`| ${escapeMarkdownCell(check.title)} | ${check.status} | ${check.score}/${check.maxScore} | ${escapeMarkdownCell(check.reason)} |`);
|
|
141
|
+
}
|
|
142
|
+
lines.push("");
|
|
143
|
+
lines.push("## Review Findings");
|
|
144
|
+
lines.push("");
|
|
145
|
+
if (result.review.newFindings.length === 0 && result.review.changedRiskyFindings.length === 0) {
|
|
146
|
+
lines.push("No new QAMap findings or changed risky files were introduced by this branch.");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
for (const finding of [...result.review.newFindings, ...result.review.changedRiskyFindings].slice(0, 12)) {
|
|
150
|
+
const fileSuffix = finding.file ? ` (${escapeMarkdownInline(finding.file)})` : "";
|
|
151
|
+
lines.push(`- \`${finding.id}\` **${escapeMarkdownInline(finding.title)}**${fileSuffix}`);
|
|
152
|
+
lines.push(` - ${escapeMarkdownInline(finding.message)}`);
|
|
153
|
+
lines.push(` - Fix: ${escapeMarkdownInline(finding.recommendation)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
lines.push("");
|
|
157
|
+
if (result.evaluation.testPlanItems.length > 0) {
|
|
158
|
+
lines.push("## Suggested Domain Tests");
|
|
159
|
+
lines.push("");
|
|
160
|
+
for (const [index, item] of result.evaluation.testPlanItems.entries()) {
|
|
161
|
+
lines.push(`### ${index + 1}. ${escapeMarkdownInline(item.title)}`);
|
|
162
|
+
lines.push("");
|
|
163
|
+
lines.push(item.reason);
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push("Checks:");
|
|
166
|
+
for (const check of item.checks) {
|
|
167
|
+
lines.push(`- ${escapeMarkdownInline(check)}`);
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (result.verificationManifestMatches.length > 0) {
|
|
173
|
+
lines.push("## Manifest Recommendations");
|
|
174
|
+
lines.push("");
|
|
175
|
+
lines.push("These recommendations come from `.qamap/manifest.yaml`. If they are wrong, update the manifest path shown below so future PRs get better suggestions.");
|
|
176
|
+
lines.push("");
|
|
177
|
+
for (const match of result.verificationManifestMatches.slice(0, 8)) {
|
|
178
|
+
lines.push(`### ${escapeMarkdownInline(match.name)} \`${escapeMarkdownInline(match.id)}\``);
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push(`- Kind: ${match.kind}`);
|
|
181
|
+
lines.push(`- Confidence: ${match.confidence}`);
|
|
182
|
+
lines.push(`- Why this was recommended: ${escapeMarkdownInline(match.reason)}`);
|
|
183
|
+
if (match.evidenceSources.length > 0) {
|
|
184
|
+
lines.push(`- Evidence sources: ${match.evidenceSources.map(escapeMarkdownInline).join(", ")}`);
|
|
185
|
+
}
|
|
186
|
+
lines.push(`- Manifest evidence: \`${escapeMarkdownInline(match.manifestPath)}\``);
|
|
187
|
+
lines.push(`- If this is wrong: update \`${escapeMarkdownInline(match.updatePath)}\``);
|
|
188
|
+
if (match.nextActions.length > 0) {
|
|
189
|
+
lines.push("- Next actions:");
|
|
190
|
+
for (const action of match.nextActions.slice(0, 4)) {
|
|
191
|
+
lines.push(` - ${escapeMarkdownInline(action)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (match.repairHints.length > 0) {
|
|
195
|
+
lines.push("- Repair hints:");
|
|
196
|
+
for (const hint of match.repairHints.slice(0, 4)) {
|
|
197
|
+
lines.push(` - ${escapeMarkdownInline(hint)}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (match.matchedFiles.length > 0) {
|
|
201
|
+
lines.push("- Matched files:");
|
|
202
|
+
for (const file of match.matchedFiles.slice(0, 8)) {
|
|
203
|
+
lines.push(` - \`${escapeMarkdownInline(file)}\``);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
lines.push("");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (result.evaluation.suggestedCommands.length > 0) {
|
|
210
|
+
lines.push("## Suggested Commands");
|
|
211
|
+
lines.push("");
|
|
212
|
+
for (const command of result.evaluation.suggestedCommands) {
|
|
213
|
+
lines.push(`- \`${escapeMarkdownInline(command)}\``);
|
|
214
|
+
}
|
|
215
|
+
lines.push("");
|
|
216
|
+
}
|
|
217
|
+
if (result.recommendations.length > 0) {
|
|
218
|
+
lines.push("## Next Actions");
|
|
219
|
+
lines.push("");
|
|
220
|
+
for (const recommendation of result.recommendations) {
|
|
221
|
+
lines.push(`- ${escapeMarkdownInline(recommendation)}`);
|
|
222
|
+
}
|
|
223
|
+
lines.push("");
|
|
224
|
+
}
|
|
225
|
+
return lines.join("\n");
|
|
226
|
+
}
|
|
227
|
+
function buildRecommendations(review, evaluation) {
|
|
228
|
+
return [
|
|
229
|
+
...reviewRecommendations(review),
|
|
230
|
+
...evaluation.recommendations,
|
|
231
|
+
].filter((recommendation, index, recommendations) => recommendations.indexOf(recommendation) === index);
|
|
232
|
+
}
|
|
233
|
+
function reviewRecommendations(review) {
|
|
234
|
+
return [...review.newFindings, ...review.changedRiskyFindings]
|
|
235
|
+
.map((finding) => finding.recommendation)
|
|
236
|
+
.filter((recommendation, index, recommendations) => recommendations.indexOf(recommendation) === index);
|
|
237
|
+
}
|
|
238
|
+
function escapeMarkdownInline(value) {
|
|
239
|
+
return value.replaceAll("`", "'");
|
|
240
|
+
}
|
|
241
|
+
function escapeMarkdownCell(value) {
|
|
242
|
+
return escapeMarkdownInline(value).replaceAll("|", "\\|").replace(/\s+/g, " ").trim();
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
package/docs/adoption.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Adopting QAMap
|
|
2
|
+
|
|
3
|
+
QAMap works best when teams treat it as the local QA pass for AI-assisted PRs, not as a replacement for review or security tooling.
|
|
4
|
+
|
|
5
|
+
## First Run
|
|
6
|
+
|
|
7
|
+
Start with the PR QA draft on a changed branch — no manifest, no config:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm dlx @ivorycanvas/qamap qa . --base origin/main --head HEAD
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For coding agents, request the compact machine-readable summary instead:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm dlx @ivorycanvas/qamap qa . --base origin/main --head HEAD --format agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
When the qa output looks useful, preview and then write the draft E2E files:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pnpm dlx @ivorycanvas/qamap e2e draft . --base origin/main --head HEAD --dry-run
|
|
23
|
+
pnpm dlx @ivorycanvas/qamap e2e draft . --base origin/main --head HEAD
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For a combined PR verification report with readiness gates, add `verify`:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
pnpm dlx @ivorycanvas/qamap verify . --base origin/main --head HEAD --pr-body-file pr-body.md
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
When developing QAMap itself from source:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
git clone https://github.com/IvoryCanvas/qamap.git
|
|
36
|
+
cd qamap
|
|
37
|
+
pnpm install
|
|
38
|
+
pnpm build
|
|
39
|
+
node dist/cli.js scan /path/to/repo
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Build A Verification Base
|
|
43
|
+
|
|
44
|
+
QAMap works best when the repository becomes the source of truth for verification language, not when every PR starts with a fresh prompt to an external agent.
|
|
45
|
+
|
|
46
|
+
Start with generated output, then promote only durable knowledge:
|
|
47
|
+
|
|
48
|
+
- keep generated run history local with `qamap history init .` and `--record-history`
|
|
49
|
+
- commit `.qamap/domains.yml` when the team agrees on product/domain names
|
|
50
|
+
- commit `.qamap/flows.yml` when the team agrees a journey is important enough to protect repeatedly
|
|
51
|
+
- keep draft E2E files reviewable until selectors, fixtures, assertions, and runner config make them real regression coverage
|
|
52
|
+
|
|
53
|
+
This gives teams a small lifecycle: observe a branch, review the proposed language and flows, promote the stable parts, then let the next branch reuse that context without another LLM call.
|
|
54
|
+
|
|
55
|
+
## Recommended Rollout
|
|
56
|
+
|
|
57
|
+
Start advisory, then tighten the gate once the findings are understood.
|
|
58
|
+
|
|
59
|
+
| Phase | Command | Goal |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| 1. PR QA draft | `qamap qa . --base origin/main --head HEAD` | Get the affected flow, suggested E2E/checklist draft, missing evidence, and PR checklist for a branch. |
|
|
62
|
+
| 2. Agent handoff | `qamap qa . --base origin/main --head HEAD --format agent` | Give coding agents the same decision content as compact JSON instead of a long report. |
|
|
63
|
+
| 3. E2E preview | `qamap e2e draft . --base origin/main --head HEAD --dry-run` | Preview generated draft paths, readiness, action items, and blockers before writing files. |
|
|
64
|
+
| 4. E2E apply | `qamap e2e draft . --base origin/main --head HEAD` | Write draft files once the preview looks useful enough to review. |
|
|
65
|
+
| 5. QA memory | `qamap manifest init .` (from the default branch) | Create `.qamap/manifest.yaml` so future PR recommendations reuse reviewed team QA language. |
|
|
66
|
+
| 6. Verify | `qamap verify . --base origin/main --head HEAD --pr-body-file pr-body.md` | Combine review findings, readiness score, suggested domain tests, and next actions. |
|
|
67
|
+
| 7. PR Action | `uses: IvoryCanvas/qamap@main` | Add annotations, a step summary, a test plan, eval, and a sticky PR comment. |
|
|
68
|
+
| 8. Guardrail baseline | `qamap scan .` | See repo-level AI agent risks (guardrails layer) without blocking work. |
|
|
69
|
+
| 9. High-risk gate | `qamap scan . --fail-on high` | Block obvious risks such as committed env files or unsafe scripts. |
|
|
70
|
+
| 10. Medium-risk gate | `qamap scan . --fail-on medium` | Require stronger agent guidance, tests, and workflow permissions. |
|
|
71
|
+
|
|
72
|
+
`doctor`, `review`, `test-plan`, `eval`, and `report` remain available for teams that want the individual reports behind `verify`.
|
|
73
|
+
|
|
74
|
+
## Monorepos
|
|
75
|
+
|
|
76
|
+
When scanning a package inside a larger workspace, pass the workspace root so QAMap can separate package-local risks from repository guardrails:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
qamap doctor services/offer --workspace-root . --format markdown
|
|
80
|
+
qamap scan services/offer --workspace-root . --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
With `--workspace-root`, QAMap reads package-local files such as `package.json`, `.env.*`, and MCP config from the package path. It reads repo-level guardrails such as `AGENTS.md`, `.github/workflows`, `LICENSE`, `SECURITY.md`, and `CONTRIBUTING.md` from the workspace root.
|
|
84
|
+
|
|
85
|
+
## What To Fix First
|
|
86
|
+
|
|
87
|
+
Fix high-severity findings before letting an agent work broadly in the repo.
|
|
88
|
+
|
|
89
|
+
1. Remove committed local environment files and rotate any exposed secrets.
|
|
90
|
+
2. Move publish, push, merge, and destructive scripts out of normal agent workflows.
|
|
91
|
+
3. Remove suspicious instruction text or fence it clearly as an example.
|
|
92
|
+
4. Narrow GitHub Actions permissions.
|
|
93
|
+
5. Add a real test command that agents and reviewers can run consistently.
|
|
94
|
+
|
|
95
|
+
## CI Guidance
|
|
96
|
+
|
|
97
|
+
For early rollout, fail only on high-severity findings:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
name: QAMap
|
|
101
|
+
|
|
102
|
+
on:
|
|
103
|
+
pull_request:
|
|
104
|
+
|
|
105
|
+
permissions:
|
|
106
|
+
contents: read
|
|
107
|
+
pull-requests: write
|
|
108
|
+
|
|
109
|
+
jobs:
|
|
110
|
+
qamap:
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
steps:
|
|
113
|
+
- uses: actions/checkout@v7
|
|
114
|
+
with:
|
|
115
|
+
fetch-depth: 0
|
|
116
|
+
- uses: IvoryCanvas/qamap@main
|
|
117
|
+
with:
|
|
118
|
+
mode: review
|
|
119
|
+
base: ${{ github.event.pull_request.base.sha }}
|
|
120
|
+
head: HEAD
|
|
121
|
+
fail-on: high
|
|
122
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
When the repository is stable, consider `--fail-on medium`.
|
|
126
|
+
|
|
127
|
+
For all inputs, see [github-action.md](github-action.md).
|
|
128
|
+
|
|
129
|
+
## Change Readiness Eval
|
|
130
|
+
|
|
131
|
+
For the most useful PR-facing report, start with `verify`:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
qamap verify . --base origin/main --head HEAD --pr-body-file pr-body.md --format markdown
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Use `qamap eval` when an AI-assisted branch looks plausible but reviewers need a faster way to decide what still needs human attention:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
qamap eval . --base origin/main --head HEAD --pr-body-file pr-body.md --format markdown
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The eval report scores validation commands, changed-test coverage, intent capture, risk explanation, generated domain test scenarios, and review size. A low score does not mean the code is wrong; it means the branch is expensive or risky to verify.
|
|
144
|
+
|
|
145
|
+
## Interpreting Findings
|
|
146
|
+
|
|
147
|
+
QAMap findings are meant to be explainable. Each finding includes:
|
|
148
|
+
|
|
149
|
+
- a rule id such as `QM009`
|
|
150
|
+
- severity
|
|
151
|
+
- file path when available
|
|
152
|
+
- message
|
|
153
|
+
- recommendation
|
|
154
|
+
- short evidence when safe to print
|
|
155
|
+
|
|
156
|
+
Prefer severity overrides over broad ignores when a rule is useful but too noisy for a specific repository.
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"severity": {
|
|
161
|
+
"QM007": "info"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Use `ignoreRules` only for findings that the team intentionally accepts.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# QAMap As A Local QA Skill
|
|
2
|
+
|
|
3
|
+
QAMap can be used as a small local tool that an AI coding agent runs before opening, updating, or finalizing a pull request.
|
|
4
|
+
|
|
5
|
+
The goal is not to replace a reviewer or claim QA passed. The goal is to remove the repeated setup question:
|
|
6
|
+
|
|
7
|
+
```txt
|
|
8
|
+
What user flow did this PR touch, what should be tested, and what evidence is missing?
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Recommended Agent Step
|
|
12
|
+
|
|
13
|
+
Run this before writing a PR body or asking for review. Agents should prefer the compact agent format — one minified JSON object (about 2 KB for a typical small PR) instead of a long report:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm dlx @ivorycanvas/qamap qa . --base origin/main --head HEAD --format agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The result carries `flows[]` (draft path, runnable status, entry route, steps, selectors), `requiredEvidence[]`, `requiredBootstrap[]`, `prChecklist[]`, and `commands[]` under `schema: qamap.qa`.
|
|
20
|
+
|
|
21
|
+
For a human-readable report, drop the flag; for installed projects write it to a file:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
pnpm exec qamap qa . --base origin/main --head HEAD --output QAMAP_QA.md
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The command writes no test files. It only previews the QA work that should be attached to the PR.
|
|
28
|
+
|
|
29
|
+
## Packaged Skill Template
|
|
30
|
+
|
|
31
|
+
QAMap ships a portable skill template at:
|
|
32
|
+
|
|
33
|
+
```txt
|
|
34
|
+
skills/qamap-pr-qa/SKILL.md
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use it when an agent surface supports local skill folders, instruction folders, or reusable workflow prompts. The template is intentionally vendor-neutral: it tells an agent when to run `qamap qa`, how to pick a base branch, what sections to copy into the PR, and when to suggest manifest repair.
|
|
38
|
+
|
|
39
|
+
After installing QAMap as a dev dependency, inspect the template:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
cat node_modules/qamap/skills/qamap-pr-qa/SKILL.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or from a cloned QAMap repository:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
cat skills/qamap-pr-qa/SKILL.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If your agent supports symlinked skills, point its skill directory at `skills/qamap-pr-qa`. If it only supports instruction text, copy the contents of `SKILL.md` into that system's reusable instruction format.
|
|
52
|
+
|
|
53
|
+
## What The Agent Should Do With The Output
|
|
54
|
+
|
|
55
|
+
Use the `PR Comment Draft` section as review context:
|
|
56
|
+
|
|
57
|
+
- affected flow
|
|
58
|
+
- recommended runner
|
|
59
|
+
- draft E2E or checklist path
|
|
60
|
+
- missing fixture, selector, assertion, runner, or validation evidence
|
|
61
|
+
- PR checklist items
|
|
62
|
+
|
|
63
|
+
If the command says a generated recommendation is wrong, do not keep re-prompting the agent with the same context. Update the repo-local manifest after human review:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
pnpm exec qamap manifest init .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then edit `.qamap/manifest.yaml` so future branches can reuse the corrected team QA language.
|
|
70
|
+
|
|
71
|
+
## Minimal Agent Instruction
|
|
72
|
+
|
|
73
|
+
```txt
|
|
74
|
+
Before finalizing a PR, run:
|
|
75
|
+
pnpm dlx @ivorycanvas/qamap qa . --base origin/main --head HEAD --format agent
|
|
76
|
+
|
|
77
|
+
Paste the affected flow, suggested E2E/checklist, missing evidence, and PR checklist into the PR body or review note.
|
|
78
|
+
If the recommendation is wrong, ask the maintainer which manifest domain, flow, anchor, or check should be corrected.
|
|
79
|
+
Do not treat QAMap output as proof that browser, device, API, or manual QA already passed.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Manifest Is An Upgrade, Not A Gate
|
|
83
|
+
|
|
84
|
+
First use should work without manifest setup. QAMap starts from PR diff and repo signals.
|
|
85
|
+
|
|
86
|
+
Add `.qamap/manifest.yaml` when the team wants higher precision:
|
|
87
|
+
|
|
88
|
+
- team-owned domain names
|
|
89
|
+
- critical user flows
|
|
90
|
+
- routes, files, components, APIs, or tests that anchor those flows
|
|
91
|
+
- success, failure, edge, contract, or visual checks
|
|
92
|
+
- preferred runner per flow
|
|
93
|
+
|
|
94
|
+
That makes QAMap closer to a repo-local QA memory layer instead of a one-off prompt.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# API Contract Source Of Truth
|
|
2
|
+
|
|
3
|
+
Frontend and backend teams often coordinate through API documents. That works best when the document is generated from a single contract source, not hand-maintained separately from code and client types.
|
|
4
|
+
|
|
5
|
+
QAMap looks for a narrow drift signal:
|
|
6
|
+
|
|
7
|
+
- Markdown or text docs that list HTTP endpoints in a method-plus-path form
|
|
8
|
+
- No machine-readable API contract source in the repository
|
|
9
|
+
|
|
10
|
+
When both are true, QAMap reports `QM013`.
|
|
11
|
+
|
|
12
|
+
## Accepted Contract Sources
|
|
13
|
+
|
|
14
|
+
QAMap currently treats these as machine-readable contract sources:
|
|
15
|
+
|
|
16
|
+
- OpenAPI or Swagger: `openapi.yaml`, `openapi.yml`, `openapi.json`, `swagger.yaml`, `swagger.yml`, `swagger.json`
|
|
17
|
+
- AsyncAPI: `asyncapi.yaml`, `asyncapi.yml`, `asyncapi.json`
|
|
18
|
+
- Protocol Buffers: `*.proto`, `buf.yaml`, `buf.gen.yaml`
|
|
19
|
+
- GraphQL SDL: `*.graphql`, `*.graphqls`, `schema.graphql`, `schema.graphqls`
|
|
20
|
+
|
|
21
|
+
## Why It Matters
|
|
22
|
+
|
|
23
|
+
AI coding agents can edit frontend clients, backend handlers, tests, and docs in the same pull request. If the API contract exists only as prose, agents and reviewers have a harder time knowing which representation is authoritative.
|
|
24
|
+
|
|
25
|
+
Prefer one source of truth that can generate docs, validation, mock servers, or client types. This keeps API design review close to the code and reduces drift between documentation and implementation.
|
|
26
|
+
|
|
27
|
+
## References
|
|
28
|
+
|
|
29
|
+
- [Why frontend developers design APIs](https://blog.gangnamunni.com/post/saas-why-do-frontend-developers-design-api)
|
|
30
|
+
- [Single source of truth](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%A7%84%EC%8B%A4_%EA%B3%B5%EA%B8%89%EC%9B%90)
|
|
Binary file
|