@vijaypjavvadi/bdd2pw 4.3.2 → 4.4.1
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 +223 -0
- package/README.md +66 -10
- package/dist/cli.js +83 -0
- package/dist/cli.js.map +1 -1
- package/dist/emitters/facade.d.ts +11 -0
- package/dist/emitters/facade.js +72 -0
- package/dist/emitters/facade.js.map +1 -1
- package/dist/http/schemas.d.ts +4 -4
- package/dist/index.js +30 -1
- package/dist/index.js.map +1 -1
- package/dist/llm/anthropicClient.d.ts +7 -0
- package/dist/llm/anthropicClient.js +11 -0
- package/dist/llm/anthropicClient.js.map +1 -1
- package/dist/llm/geminiClient.d.ts +2 -0
- package/dist/llm/geminiClient.js +6 -0
- package/dist/llm/geminiClient.js.map +1 -1
- package/dist/llm/llmStepMatcher.js +43 -4
- package/dist/llm/llmStepMatcher.js.map +1 -1
- package/dist/llm/openaiClient.d.ts +2 -0
- package/dist/llm/openaiClient.js +6 -0
- package/dist/llm/openaiClient.js.map +1 -1
- package/dist/llm/types.d.ts +14 -0
- package/dist/reports/coverage.d.ts +132 -0
- package/dist/reports/coverage.js +360 -0
- package/dist/reports/coverage.js.map +1 -0
- package/dist/reports/metaSidecar.d.ts +21 -0
- package/dist/reports/metaSidecar.js +20 -0
- package/dist/reports/metaSidecar.js.map +1 -1
- package/dist/reports/quarantineStats.d.ts +102 -0
- package/dist/reports/quarantineStats.js +319 -0
- package/dist/reports/quarantineStats.js.map +1 -0
- package/dist/transformers/stepMatcher.d.ts +10 -0
- package/dist/transformers/stepMatcher.js +59 -5
- package/dist/transformers/stepMatcher.js.map +1 -1
- package/dist/types.d.ts +60 -0
- package/package.json +1 -1
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* v4.4.0 Slice 2 — `bdd2pw coverage <repo>`.
|
|
4
|
+
*
|
|
5
|
+
* Reads the same set of artefacts Slice 1's `quarantine-stats`
|
|
6
|
+
* consumes, plus the healing telemetry, and turns "which rules fired
|
|
7
|
+
* in this repo" into a decision surface:
|
|
8
|
+
*
|
|
9
|
+
* - rule hit rate — which rules bound how many steps, ordered
|
|
10
|
+
* by use.
|
|
11
|
+
* - per-pack hit rate — how much each domain rule pack pulled its
|
|
12
|
+
* weight; a pack with no hits is a
|
|
13
|
+
* candidate for `domains: [...]` removal.
|
|
14
|
+
* - dead rules — every rule the current registry knows about
|
|
15
|
+
* that did NOT fire in this repo. Not a
|
|
16
|
+
* verdict on the rule — just a repo-scoped
|
|
17
|
+
* report.
|
|
18
|
+
* - promotion trail — candidate rules proposed from LLM bindings
|
|
19
|
+
* → which became real rules → which of
|
|
20
|
+
* those now fire. The loop closing is the
|
|
21
|
+
* number worth publishing.
|
|
22
|
+
* - heal pressure — locators that heal most often (from
|
|
23
|
+
* `artefacts/heal-events.jsonl`). A rule
|
|
24
|
+
* that binds and then always needs healing
|
|
25
|
+
* is worse than no rule.
|
|
26
|
+
*
|
|
27
|
+
* Report shape (both stdout and `<repo>/artefacts/coverage.json`):
|
|
28
|
+
*
|
|
29
|
+
* {
|
|
30
|
+
* "version": "<bdd2pw version>",
|
|
31
|
+
* "generatedAt": "<ISO-8601>",
|
|
32
|
+
* "repo": "<absolute path>",
|
|
33
|
+
* "sidecars": <int>,
|
|
34
|
+
* "totals": { scenarios: { ... }, steps: { ... } }, // shared with quarantine-stats
|
|
35
|
+
* "rules": {
|
|
36
|
+
* "hit": [{ ruleId, pack?, hitCount, sampleSteps: [ ... ] }, ...],
|
|
37
|
+
* "dead": [{ ruleId, pack? }, ...],
|
|
38
|
+
* },
|
|
39
|
+
* "packs": {
|
|
40
|
+
* "hit": { <packName>: { hitCount, ruleIdsFired: [ ... ] } },
|
|
41
|
+
* "dead": [ <packName>, ... ]
|
|
42
|
+
* },
|
|
43
|
+
* "promotions": { candidateStepsSurveyed, promoted, promotedStepTexts }, // shared with quarantine-stats
|
|
44
|
+
* "healPressure": [{ locatorKey, healCount, page?, name? }, ...],
|
|
45
|
+
* "missingArtefacts": [ "artefacts/heal-events.jsonl", ... ],
|
|
46
|
+
* "warnings": [ ... ]
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* The reader is best-effort. Missing artefacts are reported, not
|
|
50
|
+
* fatal. Exits non-zero only on a real I/O error against the repo
|
|
51
|
+
* root itself. The output shape is invariant with `quarantine-stats`
|
|
52
|
+
* where the fields overlap (`totals`, `promotions`) so a dashboard
|
|
53
|
+
* can read either without switching schemas.
|
|
54
|
+
*/
|
|
55
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
56
|
+
if (k2 === undefined) k2 = k;
|
|
57
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
58
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
59
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
60
|
+
}
|
|
61
|
+
Object.defineProperty(o, k2, desc);
|
|
62
|
+
}) : (function(o, m, k, k2) {
|
|
63
|
+
if (k2 === undefined) k2 = k;
|
|
64
|
+
o[k2] = m[k];
|
|
65
|
+
}));
|
|
66
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
67
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
68
|
+
}) : function(o, v) {
|
|
69
|
+
o["default"] = v;
|
|
70
|
+
});
|
|
71
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
72
|
+
var ownKeys = function(o) {
|
|
73
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
74
|
+
var ar = [];
|
|
75
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
76
|
+
return ar;
|
|
77
|
+
};
|
|
78
|
+
return ownKeys(o);
|
|
79
|
+
};
|
|
80
|
+
return function (mod) {
|
|
81
|
+
if (mod && mod.__esModule) return mod;
|
|
82
|
+
var result = {};
|
|
83
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
84
|
+
__setModuleDefault(result, mod);
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
})();
|
|
88
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
89
|
+
exports.analyseCoverage = analyseCoverage;
|
|
90
|
+
exports.renderCoverageTable = renderCoverageTable;
|
|
91
|
+
exports.renderSuggestRetire = renderSuggestRetire;
|
|
92
|
+
const fs = __importStar(require("fs-extra"));
|
|
93
|
+
const path = __importStar(require("path"));
|
|
94
|
+
const quarantineStats_1 = require("./quarantineStats");
|
|
95
|
+
async function analyseCoverage(opts) {
|
|
96
|
+
var _a;
|
|
97
|
+
const repo = path.resolve(opts.repo);
|
|
98
|
+
const missingArtefacts = [];
|
|
99
|
+
const warnings = [];
|
|
100
|
+
const sampleCap = opts.sampleStepsPerRule ?? 3;
|
|
101
|
+
const healTopN = opts.healPressureTopN ?? 10;
|
|
102
|
+
// 1) Shared totals + promotions — re-use Slice 1's aggregator so
|
|
103
|
+
// this and quarantine-stats always agree on the shared numbers.
|
|
104
|
+
// Write to a scratch path we discard; only the returned stats
|
|
105
|
+
// object matters here.
|
|
106
|
+
const scratch = path.join(repo, "artefacts", ".coverage-scratch.json");
|
|
107
|
+
const { stats } = await (0, quarantineStats_1.analyseQuarantineStats)({
|
|
108
|
+
repo,
|
|
109
|
+
version: opts.version,
|
|
110
|
+
outputPath: scratch,
|
|
111
|
+
});
|
|
112
|
+
await fs.remove(scratch).catch(() => { });
|
|
113
|
+
for (const w of stats.warnings)
|
|
114
|
+
warnings.push(w);
|
|
115
|
+
// 2) Walk sidecars for rule hits.
|
|
116
|
+
const hitByRule = new Map();
|
|
117
|
+
const testsDir = path.join(repo, "tests");
|
|
118
|
+
const sidecarFiles = [];
|
|
119
|
+
if (await fs.pathExists(testsDir)) {
|
|
120
|
+
await walkForSidecars(testsDir, sidecarFiles);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
missingArtefacts.push("tests/");
|
|
124
|
+
}
|
|
125
|
+
for (const file of sidecarFiles) {
|
|
126
|
+
let sidecar;
|
|
127
|
+
try {
|
|
128
|
+
sidecar = JSON.parse(await fs.readFile(file, "utf8"));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
continue; // Already warned in Slice 1's pass.
|
|
132
|
+
}
|
|
133
|
+
for (const scenario of sidecar.scenarios ?? []) {
|
|
134
|
+
for (const step of scenario.steps ?? []) {
|
|
135
|
+
if (step.rule && typeof step.rule === "object") {
|
|
136
|
+
const ruleId = step.rule.ruleId;
|
|
137
|
+
if (!ruleId)
|
|
138
|
+
continue;
|
|
139
|
+
let hit = hitByRule.get(ruleId);
|
|
140
|
+
if (!hit) {
|
|
141
|
+
hit = {
|
|
142
|
+
ruleId,
|
|
143
|
+
pack: step.rule.pack,
|
|
144
|
+
hitCount: 0,
|
|
145
|
+
sampleSteps: [],
|
|
146
|
+
};
|
|
147
|
+
hitByRule.set(ruleId, hit);
|
|
148
|
+
}
|
|
149
|
+
hit.hitCount += 1;
|
|
150
|
+
if (hit.sampleSteps.length < sampleCap && step.text) {
|
|
151
|
+
hit.sampleSteps.push(step.text);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// 3) Dead rules = every registry ruleId NOT in hitByRule.
|
|
158
|
+
const hitRuleIds = new Set(hitByRule.keys());
|
|
159
|
+
const deadRules = [];
|
|
160
|
+
for (const r of opts.registryRuleIds) {
|
|
161
|
+
if (!hitRuleIds.has(r.ruleId)) {
|
|
162
|
+
deadRules.push(r.pack ? { ruleId: r.ruleId, pack: r.pack } : { ruleId: r.ruleId });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// 4) Per-pack roll-up.
|
|
166
|
+
const packHits = {};
|
|
167
|
+
const packsSeen = new Set();
|
|
168
|
+
for (const r of opts.registryRuleIds) {
|
|
169
|
+
if (r.pack)
|
|
170
|
+
packsSeen.add(r.pack);
|
|
171
|
+
}
|
|
172
|
+
for (const [, hit] of hitByRule) {
|
|
173
|
+
if (!hit.pack)
|
|
174
|
+
continue;
|
|
175
|
+
const acc = (packHits[_a = hit.pack] ?? (packHits[_a] = { hitCount: 0, ruleIdsFired: [] }));
|
|
176
|
+
acc.hitCount += hit.hitCount;
|
|
177
|
+
if (!acc.ruleIdsFired.includes(hit.ruleId)) {
|
|
178
|
+
acc.ruleIdsFired.push(hit.ruleId);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const deadPacks = [];
|
|
182
|
+
for (const p of packsSeen) {
|
|
183
|
+
if (!packHits[p])
|
|
184
|
+
deadPacks.push(p);
|
|
185
|
+
}
|
|
186
|
+
deadPacks.sort();
|
|
187
|
+
// 5) Heal pressure — read artefacts/heal-events.jsonl and count
|
|
188
|
+
// `healed` / `heal_attempt` events per locator.
|
|
189
|
+
const healPath = path.join(repo, "artefacts", "heal-events.jsonl");
|
|
190
|
+
const pwHealPath = path.join(repo, ".pwheal", "heal-events.jsonl");
|
|
191
|
+
const healPressureMap = new Map();
|
|
192
|
+
const activeHealPath = (await fs.pathExists(healPath))
|
|
193
|
+
? healPath
|
|
194
|
+
: (await fs.pathExists(pwHealPath))
|
|
195
|
+
? pwHealPath
|
|
196
|
+
: undefined;
|
|
197
|
+
if (!activeHealPath) {
|
|
198
|
+
// Not an error — many repos don't run --self-healing. Note it.
|
|
199
|
+
missingArtefacts.push("artefacts/heal-events.jsonl (or .pwheal/heal-events.jsonl)");
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
try {
|
|
203
|
+
const raw = await fs.readFile(activeHealPath, "utf8");
|
|
204
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
205
|
+
const trimmed = line.trim();
|
|
206
|
+
if (!trimmed)
|
|
207
|
+
continue;
|
|
208
|
+
let ev;
|
|
209
|
+
try {
|
|
210
|
+
ev = JSON.parse(trimmed);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (ev.event !== "healed" && ev.event !== "heal_attempt")
|
|
216
|
+
continue;
|
|
217
|
+
const key = `${ev.page ?? "?"}.${ev.name ?? "?"}`;
|
|
218
|
+
let bucket = healPressureMap.get(key);
|
|
219
|
+
if (!bucket) {
|
|
220
|
+
bucket = { healCount: 0, page: ev.page, name: ev.name };
|
|
221
|
+
healPressureMap.set(key, bucket);
|
|
222
|
+
}
|
|
223
|
+
bucket.healCount += 1;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
warnings.push(`Could not read heal-events log: ${e instanceof Error ? e.message : String(e)}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const healPressure = Array.from(healPressureMap.entries())
|
|
231
|
+
.map(([locatorKey, v]) => ({ locatorKey, ...v }))
|
|
232
|
+
.sort((a, b) => b.healCount - a.healCount)
|
|
233
|
+
.slice(0, healTopN);
|
|
234
|
+
// 6) candidate-rules.jsonl awareness — record its absence as a
|
|
235
|
+
// missing artefact when nothing to promote and no file present.
|
|
236
|
+
const candidatesPath = path.join(repo, "artefacts", "candidate-rules.jsonl");
|
|
237
|
+
if (!(await fs.pathExists(candidatesPath))) {
|
|
238
|
+
missingArtefacts.push("artefacts/candidate-rules.jsonl");
|
|
239
|
+
}
|
|
240
|
+
const coverage = {
|
|
241
|
+
version: opts.version,
|
|
242
|
+
generatedAt: new Date().toISOString(),
|
|
243
|
+
repo,
|
|
244
|
+
sidecars: stats.totals.sidecars,
|
|
245
|
+
totals: stats.totals,
|
|
246
|
+
rules: {
|
|
247
|
+
hit: Array.from(hitByRule.values()).sort((a, b) => b.hitCount - a.hitCount),
|
|
248
|
+
dead: deadRules,
|
|
249
|
+
},
|
|
250
|
+
packs: {
|
|
251
|
+
hit: packHits,
|
|
252
|
+
dead: deadPacks,
|
|
253
|
+
},
|
|
254
|
+
promotions: stats.promotions,
|
|
255
|
+
healPressure,
|
|
256
|
+
missingArtefacts,
|
|
257
|
+
warnings,
|
|
258
|
+
};
|
|
259
|
+
const outputPath = opts.outputPath ?? path.join(repo, "artefacts", "coverage.json");
|
|
260
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
261
|
+
await fs.writeFile(outputPath, JSON.stringify(coverage, null, 2) + "\n", "utf8");
|
|
262
|
+
return { coverage, outputPath };
|
|
263
|
+
}
|
|
264
|
+
/** Depth-first walk for `.spec.meta.json` files. */
|
|
265
|
+
async function walkForSidecars(dir, out) {
|
|
266
|
+
let entries;
|
|
267
|
+
try {
|
|
268
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
for (const entry of entries) {
|
|
274
|
+
const full = path.join(dir, entry.name);
|
|
275
|
+
if (entry.isDirectory()) {
|
|
276
|
+
await walkForSidecars(full, out);
|
|
277
|
+
}
|
|
278
|
+
else if (entry.isFile() && entry.name.endsWith(".spec.meta.json")) {
|
|
279
|
+
out.push(full);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Human-readable one-page render. Separate from the JSON generator so
|
|
285
|
+
* tests can assert on the JSON shape without parsing text, and callers
|
|
286
|
+
* that want raw JSON pass `--json` at the CLI layer.
|
|
287
|
+
*/
|
|
288
|
+
function renderCoverageTable(cov) {
|
|
289
|
+
const lines = [];
|
|
290
|
+
lines.push(`bdd2pw coverage (v${cov.version})`);
|
|
291
|
+
lines.push(`repo: ${cov.repo}`);
|
|
292
|
+
lines.push(`generated: ${cov.generatedAt}`);
|
|
293
|
+
lines.push("");
|
|
294
|
+
lines.push(`sidecars: ${cov.sidecars} scenarios: ${cov.totals.scenarios.total} steps: ${cov.totals.steps.total}`);
|
|
295
|
+
lines.push("");
|
|
296
|
+
lines.push(`rules fired: ${cov.rules.hit.length} dead: ${cov.rules.dead.length}`);
|
|
297
|
+
const topRules = cov.rules.hit.slice(0, 10);
|
|
298
|
+
if (topRules.length > 0) {
|
|
299
|
+
lines.push("");
|
|
300
|
+
lines.push("top firing rules:");
|
|
301
|
+
for (const r of topRules) {
|
|
302
|
+
lines.push(` ${r.ruleId.padEnd(12)} ${String(r.hitCount).padStart(4)} ${r.pack ?? "core"}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const deadPacks = cov.packs.dead;
|
|
306
|
+
if (deadPacks.length > 0) {
|
|
307
|
+
lines.push("");
|
|
308
|
+
lines.push(`dead packs (no rule fired in this repo): ${deadPacks.join(", ")}`);
|
|
309
|
+
lines.push(` → drop from your domains: [...] to shrink the rule table (--suggest-retire prints the stanza).`);
|
|
310
|
+
}
|
|
311
|
+
if (cov.healPressure.length > 0) {
|
|
312
|
+
lines.push("");
|
|
313
|
+
lines.push("heal pressure (most healed locators):");
|
|
314
|
+
for (const h of cov.healPressure) {
|
|
315
|
+
lines.push(` ${h.locatorKey.padEnd(40)} ${h.healCount}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
lines.push("");
|
|
319
|
+
lines.push(`promotions: ${cov.promotions.promoted}/${cov.promotions.candidateStepsSurveyed} candidate step(s) now rule-bound`);
|
|
320
|
+
if (cov.missingArtefacts.length > 0) {
|
|
321
|
+
lines.push("");
|
|
322
|
+
lines.push("missing artefacts (report continued with what was present):");
|
|
323
|
+
for (const m of cov.missingArtefacts)
|
|
324
|
+
lines.push(` - ${m}`);
|
|
325
|
+
}
|
|
326
|
+
if (cov.warnings.length > 0) {
|
|
327
|
+
lines.push("");
|
|
328
|
+
lines.push("warnings:");
|
|
329
|
+
for (const w of cov.warnings)
|
|
330
|
+
lines.push(` - ${w}`);
|
|
331
|
+
}
|
|
332
|
+
return lines.join("\n") + "\n";
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Render the `--suggest-retire` stanza — a copyable block the user can
|
|
336
|
+
* paste into their bdd2pw config (or bench harness) to shrink the
|
|
337
|
+
* active rule table. Never edits anything itself.
|
|
338
|
+
*/
|
|
339
|
+
function renderSuggestRetire(cov) {
|
|
340
|
+
const lines = [];
|
|
341
|
+
lines.push("# `bdd2pw coverage --suggest-retire` — copy the block(s) you want to apply.");
|
|
342
|
+
lines.push("# Each entry is a rule or pack that did NOT fire in this repo. Removing");
|
|
343
|
+
lines.push("# them is safe here; it may not be safe across all your repos.");
|
|
344
|
+
lines.push("");
|
|
345
|
+
if (cov.packs.dead.length > 0) {
|
|
346
|
+
lines.push("# Domain packs to drop from ScaffoldOptions.domains:");
|
|
347
|
+
for (const p of cov.packs.dead) {
|
|
348
|
+
lines.push(`# - "${p}"`);
|
|
349
|
+
}
|
|
350
|
+
lines.push("");
|
|
351
|
+
}
|
|
352
|
+
if (cov.rules.dead.length > 0) {
|
|
353
|
+
lines.push("# Rules that never fired here (repo-scoped only; NOT a global verdict):");
|
|
354
|
+
for (const r of cov.rules.dead) {
|
|
355
|
+
lines.push(`# - ${r.ruleId}${r.pack ? ` (pack: ${r.pack})` : ""}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return lines.join("\n") + "\n";
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/reports/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,6 +39,27 @@ export interface MetaSidecarStep {
|
|
|
39
39
|
locator?: string;
|
|
40
40
|
/** Matcher name or method name when the binding has one. */
|
|
41
41
|
assertion?: string;
|
|
42
|
+
/**
|
|
43
|
+
* v4.4.0 — provenance. `null` when this step was bound by the LLM
|
|
44
|
+
* fallback; a `{ ruleId, pack? }` object when bound by the
|
|
45
|
+
* deterministic rule table. Absent only when the binding was
|
|
46
|
+
* emitted before v4.4 (old sidecars remain parseable).
|
|
47
|
+
*/
|
|
48
|
+
rule?: null | {
|
|
49
|
+
ruleId: string;
|
|
50
|
+
pack?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* v4.4.0 — populated iff this step was bound by the LLM fallback.
|
|
54
|
+
* Consumed by `bdd2pw quarantine-stats` and `bdd2pw coverage`.
|
|
55
|
+
*/
|
|
56
|
+
llm?: {
|
|
57
|
+
provider: "anthropic" | "openai" | "gemini";
|
|
58
|
+
model: string;
|
|
59
|
+
cached: boolean;
|
|
60
|
+
governance: "sanitised" | "skipped";
|
|
61
|
+
at: string;
|
|
62
|
+
};
|
|
42
63
|
}
|
|
43
64
|
export interface MetaSidecarScenario {
|
|
44
65
|
name: string;
|
|
@@ -80,6 +80,26 @@ function bindingsToMetaSteps(bindings) {
|
|
|
80
80
|
step.locator = b.assertion.locator;
|
|
81
81
|
step.assertion = b.assertion.matcher;
|
|
82
82
|
}
|
|
83
|
+
// v4.4.0 — provenance passthrough.
|
|
84
|
+
// LLM binding → `rule: null` + full `llm` block.
|
|
85
|
+
// Rule binding → `rule: { ruleId, pack? }`.
|
|
86
|
+
// No provenance (legacy binding) → both fields absent.
|
|
87
|
+
if (b.provenance?.source === "llm" && b.provenance.llm) {
|
|
88
|
+
step.rule = null;
|
|
89
|
+
step.llm = {
|
|
90
|
+
provider: b.provenance.llm.provider,
|
|
91
|
+
model: b.provenance.llm.model,
|
|
92
|
+
cached: b.provenance.llm.cached,
|
|
93
|
+
governance: b.provenance.llm.governance,
|
|
94
|
+
at: b.provenance.llm.at,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
else if (b.provenance?.source === "rule" && b.provenance.ruleId) {
|
|
98
|
+
step.rule = {
|
|
99
|
+
ruleId: b.provenance.ruleId,
|
|
100
|
+
...(b.provenance.pack ? { pack: b.provenance.pack } : {}),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
83
103
|
return step;
|
|
84
104
|
});
|
|
85
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metaSidecar.js","sourceRoot":"","sources":["../../src/reports/metaSidecar.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;
|
|
1
|
+
{"version":3,"file":"metaSidecar.js","sourceRoot":"","sources":["../../src/reports/metaSidecar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v4.4.0 Slice 1 — `bdd2pw quarantine-stats <repo>`.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates the LLM-provenance data written by v4.4.0's scaffold path
|
|
5
|
+
* (`*.spec.meta.json` sidecars + `artefacts/candidate-rules.jsonl`)
|
|
6
|
+
* into a per-feature / per-pack report. The point is to make the two
|
|
7
|
+
* lanes measurable:
|
|
8
|
+
*
|
|
9
|
+
* trusted lane — scenarios with NO `@llm-generated` tag; every
|
|
10
|
+
* step bound by the deterministic rule table.
|
|
11
|
+
* review lane — scenarios with the `@llm-generated` tag; at
|
|
12
|
+
* least one step bound by the LLM fallback.
|
|
13
|
+
*
|
|
14
|
+
* Report shape (both stdout and `artefacts/quarantine-stats.json`):
|
|
15
|
+
*
|
|
16
|
+
* {
|
|
17
|
+
* "version": "<bdd2pw version>",
|
|
18
|
+
* "generatedAt": "<ISO-8601>",
|
|
19
|
+
* "repo": "<absolute path>",
|
|
20
|
+
* "totals": {
|
|
21
|
+
* "sidecars": <int>,
|
|
22
|
+
* "scenarios": { "total": N, "llmGenerated": N, "deterministic": N },
|
|
23
|
+
* "steps": { "total": N, "byRule": N, "byLlm": N },
|
|
24
|
+
* "llmCacheHitShare": <0..1 | null>
|
|
25
|
+
* },
|
|
26
|
+
* "byFeature": [{ source, scenarios, steps }, ...],
|
|
27
|
+
* "promotions": {
|
|
28
|
+
* "candidateStepsSurveyed": <int>,
|
|
29
|
+
* "promoted": <int>,
|
|
30
|
+
* "promotedStepTexts": [ ... ]
|
|
31
|
+
* },
|
|
32
|
+
* "sidecarsScanned": ["<path>", ...]
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* The reader is best-effort — a malformed sidecar is skipped with a
|
|
36
|
+
* warning and does not crash the run. Only I/O failures on the repo
|
|
37
|
+
* root itself surface as non-zero exit codes; the report is not a gate.
|
|
38
|
+
*/
|
|
39
|
+
/** Top-level per-repo summary. */
|
|
40
|
+
export interface QuarantineStats {
|
|
41
|
+
version: string;
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
repo: string;
|
|
44
|
+
totals: {
|
|
45
|
+
sidecars: number;
|
|
46
|
+
scenarios: {
|
|
47
|
+
total: number;
|
|
48
|
+
llmGenerated: number;
|
|
49
|
+
deterministic: number;
|
|
50
|
+
};
|
|
51
|
+
steps: {
|
|
52
|
+
total: number;
|
|
53
|
+
byRule: number;
|
|
54
|
+
byLlm: number;
|
|
55
|
+
};
|
|
56
|
+
/** null when no LLM steps were recorded (avoids fake precision). */
|
|
57
|
+
llmCacheHitShare: number | null;
|
|
58
|
+
};
|
|
59
|
+
byFeature: {
|
|
60
|
+
source: string;
|
|
61
|
+
scenarios: {
|
|
62
|
+
total: number;
|
|
63
|
+
llmGenerated: number;
|
|
64
|
+
deterministic: number;
|
|
65
|
+
};
|
|
66
|
+
steps: {
|
|
67
|
+
total: number;
|
|
68
|
+
byRule: number;
|
|
69
|
+
byLlm: number;
|
|
70
|
+
};
|
|
71
|
+
}[];
|
|
72
|
+
promotions: {
|
|
73
|
+
candidateStepsSurveyed: number;
|
|
74
|
+
promoted: number;
|
|
75
|
+
promotedStepTexts: string[];
|
|
76
|
+
};
|
|
77
|
+
sidecarsScanned: string[];
|
|
78
|
+
warnings: string[];
|
|
79
|
+
}
|
|
80
|
+
export interface AnalyseQuarantineStatsOptions {
|
|
81
|
+
/** Repo root containing tests/, artefacts/. */
|
|
82
|
+
repo: string;
|
|
83
|
+
/** Package version to embed. Propagated from the CLI. */
|
|
84
|
+
version: string;
|
|
85
|
+
/** Optional override for the output path. Default: <repo>/artefacts/quarantine-stats.json. */
|
|
86
|
+
outputPath?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface AnalyseQuarantineStatsResult {
|
|
89
|
+
stats: QuarantineStats;
|
|
90
|
+
outputPath: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Walk `<repo>/tests/**\/*.spec.meta.json` and produce the aggregate
|
|
94
|
+
* report. Writes the JSON payload alongside the artefacts directory.
|
|
95
|
+
*/
|
|
96
|
+
export declare function analyseQuarantineStats(opts: AnalyseQuarantineStatsOptions): Promise<AnalyseQuarantineStatsResult>;
|
|
97
|
+
/**
|
|
98
|
+
* Human-readable one-page render. Kept separate from the report
|
|
99
|
+
* generation so tests can assert on the JSON shape without parsing
|
|
100
|
+
* text.
|
|
101
|
+
*/
|
|
102
|
+
export declare function renderQuarantineStatsTable(stats: QuarantineStats): string;
|