@sun-asterisk/sungen 3.0.0-beta.74 → 3.0.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/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +17 -3
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +2 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +15 -0
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +8 -0
- package/dist/generators/test-generator/patterns/capture-patterns.d.ts +5 -0
- package/dist/generators/test-generator/patterns/capture-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/capture-patterns.js +33 -0
- package/dist/generators/test-generator/patterns/capture-patterns.js.map +1 -1
- package/dist/harness/audit.d.ts +5 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +13 -2
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/parse.d.ts +1 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +3 -0
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/provenance.d.ts +6 -0
- package/dist/harness/provenance.d.ts.map +1 -0
- package/dist/harness/provenance.js +65 -0
- package/dist/harness/provenance.js.map +1 -0
- package/dist/harness/sensors.d.ts +30 -0
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +122 -0
- package/dist/harness/sensors.js.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +12 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +12 -0
- package/package.json +3 -3
- package/src/cli/commands/audit.ts +13 -3
- package/src/generators/gherkin-parser/index.ts +17 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +8 -0
- package/src/generators/test-generator/patterns/capture-patterns.ts +38 -0
- package/src/harness/audit.ts +18 -4
- package/src/harness/parse.ts +4 -0
- package/src/harness/provenance.ts +33 -0
- package/src/harness/sensors.ts +189 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +12 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +12 -0
package/dist/harness/sensors.js
CHANGED
|
@@ -40,6 +40,8 @@ exports.dataThemesFor = dataThemesFor;
|
|
|
40
40
|
exports.coverageBalance = coverageBalance;
|
|
41
41
|
exports.duplicateClusters = duplicateClusters;
|
|
42
42
|
exports.traceability = traceability;
|
|
43
|
+
exports.taxonomyLint = taxonomyLint;
|
|
44
|
+
exports.claimProof = claimProof;
|
|
43
45
|
/**
|
|
44
46
|
* Harness Sensors — deterministic quality measurement over test-design artifacts.
|
|
45
47
|
* Each sensor returns a structured finding the Orchestrator/Repair loop can act on.
|
|
@@ -229,4 +231,124 @@ function traceability(scenarios, viewpoints) {
|
|
|
229
231
|
: 'Traceable.',
|
|
230
232
|
};
|
|
231
233
|
}
|
|
234
|
+
// Ordered by specificity; the first matching rule per scenario wins.
|
|
235
|
+
const CLAIM_RULES = [
|
|
236
|
+
{
|
|
237
|
+
claim: 'all/every/each',
|
|
238
|
+
title: /\b(all|every|each)\b/,
|
|
239
|
+
proof: /\bsee all\b/,
|
|
240
|
+
need: 'a `User see all …` assertion (every element, not one)',
|
|
241
|
+
hint: 'assert across all matched elements — for per-card structure use the all-card DSL (roadmap Q2).',
|
|
242
|
+
severity: 'fail',
|
|
243
|
+
// singular action presence under an "each/every" claim = partial proof
|
|
244
|
+
underproof: /\bsee \[[^\]]+\] (link|button)\b/,
|
|
245
|
+
underNeed: 'an all-card assertion for the claimed action (not single presence)',
|
|
246
|
+
underHint: 'the actions are asserted once, not per-card — wrap them with the all-card DSL `User see all [Card] contain [Action]` (roadmap Q2).',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
claim: 'only/belong-to',
|
|
250
|
+
title: /\b(only|belongs? to|exclusively)\b/,
|
|
251
|
+
proof: /\bsee all\b[^.]*\bcontain/,
|
|
252
|
+
need: 'all-match (`User see all … contains …`)',
|
|
253
|
+
hint: 'all displayed items must match the facet; "no items OUTSIDE" is UI-limited → verify via hybrid API/DB or mark @manual with reason.',
|
|
254
|
+
severity: 'warn',
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
claim: 'single/exactly-one',
|
|
258
|
+
title: /\b(a single|single|exactly one|just one|only one)\b/,
|
|
259
|
+
proof: /\bcount\b|\btable with\b|\bexactly\b|tohavecount/,
|
|
260
|
+
need: 'a count assertion (e.g. count is 1)',
|
|
261
|
+
hint: 'assert the quantity, not just presence.',
|
|
262
|
+
severity: 'fail',
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
claim: 'correct/matching/identity',
|
|
266
|
+
title: /\b(correct|matching|the same|same (product|name|price|value|item)|consistency|identity|lands? in|is the (product|item))\b/,
|
|
267
|
+
proof: /\bremember\b/,
|
|
268
|
+
need: 'capture + compare (`User remember … as {{v}}` then assert {{v}})',
|
|
269
|
+
hint: 'remember the value on the source, then assert it on the target (cross-screen → defer to a flow as @manual).',
|
|
270
|
+
severity: 'fail',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
claim: 'changes/toggles',
|
|
274
|
+
title: /\b(changes?|toggles?|updates?|reflects?|reopens?)\b/,
|
|
275
|
+
proof: /\bremember\b|\bis hidden\b/,
|
|
276
|
+
need: 'a state delta (before ≠ after, or a visible→hidden contrast)',
|
|
277
|
+
hint: 'capture the before-state and assert the after-state differs, or assert the visible/hidden transition.',
|
|
278
|
+
severity: 'warn',
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
claim: 'hidden/rejected/not-complete',
|
|
282
|
+
title: /\b(hidden|closed|dismiss(es|ed)?|does not|doesn't|not complete|rejected|inert)\b/,
|
|
283
|
+
proof: /\bis hidden\b|\bare hidden\b|message is hidden|not complete|\bhidden\b/,
|
|
284
|
+
need: 'a negative / hidden assertion (`… is hidden`)',
|
|
285
|
+
hint: 'assert the absence/hidden state that the title claims, not just an unrelated visible element.',
|
|
286
|
+
severity: 'fail',
|
|
287
|
+
},
|
|
288
|
+
];
|
|
289
|
+
const TAXONOMY_KNOWN = new Set(['LIST', 'PRODUCT', 'CART', 'FILTER', 'NAV', 'VAL', 'SEC']);
|
|
290
|
+
const CATEGORY_SIGNALS = [
|
|
291
|
+
{ cat: 'FILTER', re: /\b(categor(y|ies)|sub-?categor\w*|expand\w*|collaps\w*|\bfacet\b|filter\w*|belongs? to)\b/ },
|
|
292
|
+
{ cat: 'CART', re: /\b(add(ed|ing)? to cart|added (dialog|modal|message|confirmation)|cart (page|table|line|item)|view cart|continue shopping|quantit)\b/ },
|
|
293
|
+
{ cat: 'PRODUCT', re: /\b(product detail|product-detail|view product|product page|same product|product name and price|product identity|detail product)\b/ },
|
|
294
|
+
{ cat: 'LIST', re: /\b(product (list|grid)|featured product|product card|each (featured )?card|every (featured )?card)\b/ },
|
|
295
|
+
{ cat: 'NAV', re: /\b(navigates?|returns the user|redirect\w*|logo returns|menu navigates)\b/ },
|
|
296
|
+
{ cat: 'VAL', re: /\b(valid email|invalid\b|without (a |an )?@|without a domain|empty (email|input|field)|validation|required field)\b/ },
|
|
297
|
+
{ cat: 'SEC', re: /\b(xss|sql|injection|payload|without authentication|unauthenticated|\binert\b|tamper\w*|malformed|url parameter|query param\w*|falls? back|gracefull?y|without a crash|not[- ]found|\b404\b|special character|abuse)\b/ },
|
|
298
|
+
];
|
|
299
|
+
function taxonomyLint(scenarios) {
|
|
300
|
+
const mislabeled = [];
|
|
301
|
+
let checked = 0;
|
|
302
|
+
for (const s of scenarios) {
|
|
303
|
+
const cat = s.category;
|
|
304
|
+
if (!cat || !TAXONOMY_KNOWN.has(cat))
|
|
305
|
+
continue;
|
|
306
|
+
checked++;
|
|
307
|
+
const title = s.name.toLowerCase();
|
|
308
|
+
const matched = [...new Set(CATEGORY_SIGNALS.filter((c) => c.re.test(title)).map((c) => c.cat))];
|
|
309
|
+
if (matched.includes(cat))
|
|
310
|
+
continue; // title supports its own category → fine
|
|
311
|
+
const others = matched.filter((c) => c !== cat);
|
|
312
|
+
if (others.length === 1) { // unambiguous mismatch
|
|
313
|
+
const sig = CATEGORY_SIGNALS.find((c) => c.cat === others[0]);
|
|
314
|
+
const m = title.match(sig.re);
|
|
315
|
+
mislabeled.push({ name: s.name, current: cat, suggested: others[0], signal: m ? m[0] : others[0] });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { total: scenarios.length, checked, mislabeled };
|
|
319
|
+
}
|
|
320
|
+
function claimProof(scenarios, focus = 'functional') {
|
|
321
|
+
const measured = scenarios.filter((s) => !s.manual);
|
|
322
|
+
const unproven = [];
|
|
323
|
+
let withClaims = 0;
|
|
324
|
+
for (const s of measured) {
|
|
325
|
+
const title = s.name.toLowerCase();
|
|
326
|
+
const rule = CLAIM_RULES.find((r) => r.title.test(title));
|
|
327
|
+
if (!rule)
|
|
328
|
+
continue; // no claim → not measured
|
|
329
|
+
withClaims++;
|
|
330
|
+
if (!rule.proof.test(s.stepsText)) {
|
|
331
|
+
// proof shape entirely absent → fail at the rule's severity
|
|
332
|
+
unproven.push({ name: s.name, claim: rule.claim, need: rule.need, hint: rule.hint, severity: rule.severity });
|
|
333
|
+
}
|
|
334
|
+
else if (rule.underproof && rule.underproof.test(s.stepsText)) {
|
|
335
|
+
// right shape exists but only as a partial proof → warn
|
|
336
|
+
unproven.push({
|
|
337
|
+
name: s.name, claim: rule.claim,
|
|
338
|
+
need: rule.underNeed ?? rule.need,
|
|
339
|
+
hint: rule.underHint ?? rule.hint,
|
|
340
|
+
severity: 'warn',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const proven = withClaims - unproven.length;
|
|
345
|
+
const ratio = withClaims ? proven / withClaims : 1;
|
|
346
|
+
const threshold = DEPTH_THRESHOLDS[focus] ?? DEPTH_THRESHOLDS.functional;
|
|
347
|
+
const hasFail = unproven.some((u) => u.severity === 'fail');
|
|
348
|
+
let verdict = 'pass';
|
|
349
|
+
if (ratio < threshold) {
|
|
350
|
+
verdict = WARN_ONLY_FOCUS.has(focus) || !hasFail ? 'warn' : 'fail';
|
|
351
|
+
}
|
|
352
|
+
return { total: measured.length, withClaims, proven, unproven, ratio, focus, threshold, verdict };
|
|
353
|
+
}
|
|
232
354
|
//# sourceMappingURL=sensors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sensors.js","sourceRoot":"","sources":["../../src/harness/sensors.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sensors.js","sourceRoot":"","sources":["../../src/harness/sensors.ts"],"names":[],"mappings":"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"}
|
|
@@ -74,6 +74,18 @@ User switch to [T] frame | [main] frame
|
|
|
74
74
|
# 8. Page: User see [T] page
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
### Collection / all-card (P5)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
# Every element's TEXT matches a value (filter correctness, all items belong):
|
|
81
|
+
User see all [Result Product Name] text contains {{category_term}}
|
|
82
|
+
# Every CONTAINER holds a CHILD element (structural per-card proof — prove "each card has X"):
|
|
83
|
+
User see all [Product Card] contain [Product Name]
|
|
84
|
+
User see all [Product Card] contain [Add To Cart] button
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Use the all-card form whenever a title claims *every / each* card/row exposes something — a single `User see [Add To Cart] button` does NOT prove "each card" and the harness Claim-Proof gate will flag it.
|
|
88
|
+
|
|
77
89
|
### Table
|
|
78
90
|
|
|
79
91
|
```
|
|
@@ -74,6 +74,18 @@ User switch to [T] frame | [main] frame
|
|
|
74
74
|
# 8. Page: User see [T] page
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
### Collection / all-card (P5)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
# Every element's TEXT matches a value (filter correctness, all items belong):
|
|
81
|
+
User see all [Result Product Name] text contains {{category_term}}
|
|
82
|
+
# Every CONTAINER holds a CHILD element (structural per-card proof — prove "each card has X"):
|
|
83
|
+
User see all [Product Card] contain [Product Name]
|
|
84
|
+
User see all [Product Card] contain [Add To Cart] button
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Use the all-card form whenever a title claims *every / each* card/row exposes something — a single `User see [Add To Cart] button` does NOT prove "each card" and the harness Claim-Proof gate will flag it.
|
|
88
|
+
|
|
77
89
|
### Table
|
|
78
90
|
|
|
79
91
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sun-asterisk/sungen",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"copy-templates": "mkdir -p dist/generators/test-generator/adapters/playwright/templates/steps && mkdir -p dist/generators/test-generator/templates && mkdir -p dist/orchestrator/templates && mkdir -p dist/dashboard/templates && cp -r src/generators/test-generator/adapters/playwright/templates/*.hbs dist/generators/test-generator/adapters/playwright/templates/ 2>/dev/null || true && cp -r src/generators/test-generator/adapters/playwright/templates/steps dist/generators/test-generator/adapters/playwright/templates/ && cp src/generators/test-generator/templates/*.hbs dist/generators/test-generator/templates/ 2>/dev/null || true && cp -r src/orchestrator/templates/* dist/orchestrator/templates/ && cp src/dashboard/templates/index.html dist/dashboard/templates/index.html && mkdir -p dist/harness/catalog && cp src/harness/catalog/*.yaml dist/harness/catalog/",
|
|
13
13
|
"build:dashboard": "cd dashboard && npm install --silent && npm run build && cd .. && cp dashboard/dist/index.html src/dashboard/templates/index.html",
|
|
14
14
|
"dev": "tsx src/cli/index.ts",
|
|
15
|
-
"test": "tsx tests/golden/run.ts",
|
|
16
|
-
"test:update": "tsx tests/golden/run.ts --update",
|
|
15
|
+
"test": "tsx tests/golden/run.ts && tsx tests/audit/run.ts",
|
|
16
|
+
"test:update": "tsx tests/golden/run.ts --update && tsx tests/audit/run.ts --update",
|
|
17
17
|
"prepublishOnly": "npm run build:dashboard && npm run build"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
@@ -23,8 +23,10 @@ function render(r: AuditReport): void {
|
|
|
23
23
|
L('');
|
|
24
24
|
L(` Quality score (business-weighted): ${r.score.overall}/10 [Viewpoint Gate: ${r.gateStatus}]`);
|
|
25
25
|
L(` Intent: focus=${r.intent.focus} · depth threshold ${r.depth.threshold.toFixed(2)} (${r.intent.source})`);
|
|
26
|
+
L(` Provenance: sungen ${r.provenance.sungenVersion} · catalog ${r.provenance.catalogHash} (same here on every machine → same score)`);
|
|
26
27
|
L(` coverage ${bar(r.score.coverage)} ${(r.score.coverage * 100).toFixed(0)}%`);
|
|
27
28
|
L(` businessDepth ${bar(r.score.businessDepth)} ${(r.score.businessDepth * 100).toFixed(0)}% [${r.depth.verdict.toUpperCase()}]`);
|
|
29
|
+
L(` claimProof ${bar(r.claim.ratio)} ${(r.claim.ratio * 100).toFixed(0)}% [${r.claim.verdict.toUpperCase()}]`);
|
|
28
30
|
L(` balance ${bar(r.score.balance)} ${(r.score.balance * 100).toFixed(0)}%`);
|
|
29
31
|
L(` traceability ${bar(r.score.traceability)} ${(r.score.traceability * 100).toFixed(0)}%`);
|
|
30
32
|
L(` (${r.score.formula})`);
|
|
@@ -37,15 +39,23 @@ function render(r: AuditReport): void {
|
|
|
37
39
|
for (const s of r.depth.shallowBusinessCritical.slice(0, 8)) L(` ⚠ ${s.category}: ${s.name}`);
|
|
38
40
|
if (r.depth.shallowBusinessCritical.length > 8) L(` … +${r.depth.shallowBusinessCritical.length - 8} more`);
|
|
39
41
|
L('');
|
|
40
|
-
L(` ③
|
|
42
|
+
L(` ③ Claim-Proof — ${r.claim.proven}/${r.claim.withClaims} titled claims proven by steps [${r.claim.verdict.toUpperCase()}]`);
|
|
43
|
+
if (r.claim.unproven.length === 0) L(' ✓ every claim (all/only/single/correct/changes/hidden) is backed by an assertion');
|
|
44
|
+
for (const u of r.claim.unproven.slice(0, 8)) L(` ${u.severity === 'fail' ? '✗' : '⚠'} [${u.claim}] ${u.name} → needs ${u.need}`);
|
|
45
|
+
if (r.claim.unproven.length > 8) L(` … +${r.claim.unproven.length - 8} more`);
|
|
46
|
+
L('');
|
|
47
|
+
L(` ③·5 Taxonomy — ${r.taxonomy.mislabeled.length === 0 ? '✓ VP codes match scenario semantics' : `⚠ ${r.taxonomy.mislabeled.length} mislabel(s)`}`);
|
|
48
|
+
for (const m of r.taxonomy.mislabeled.slice(0, 6)) L(` ⚠ ${m.name} → VP-${m.current} reads as ${m.suggested} ("${m.signal}")`);
|
|
49
|
+
L('');
|
|
50
|
+
L(` ④ Coverage balance — ${r.balance.imbalanced ? '⚠ IMBALANCED' : '✓ balanced'}`);
|
|
41
51
|
L(` buckets: ${Object.entries(r.balance.byBucket).map(([k, v]) => `${k}=${v}`).join(' ')}`);
|
|
42
52
|
L('');
|
|
43
|
-
L(`
|
|
53
|
+
L(` ⑤ Duplicate — ${r.duplicates.clusters.length} same-shape cluster(s), ${r.duplicates.exactDuplicateCount} likely exact dup(s)`);
|
|
44
54
|
for (const c of r.duplicates.clusters.slice(0, 3)) {
|
|
45
55
|
L(` ${c.sameDataLikely ? '✗ exact' : '○ EP/data family'} (${c.scenarios.length}): ${c.scenarios.slice(0, 3).join(' | ')}${c.scenarios.length > 3 ? ' …' : ''}`);
|
|
46
56
|
}
|
|
47
57
|
L('');
|
|
48
|
-
L(`
|
|
58
|
+
L(` ⑥ Traceability — ${(r.trace.mappedRatio * 100).toFixed(0)}% scenarios linked to viewpoint-overview`);
|
|
49
59
|
L(` ${r.trace.note}`);
|
|
50
60
|
L('');
|
|
51
61
|
L(' ── Findings (Repair targets) ──');
|
|
@@ -18,6 +18,8 @@ export interface ParsedStep {
|
|
|
18
18
|
keyword: string; // Given, When, Then, And, But
|
|
19
19
|
text: string; // Original step text
|
|
20
20
|
selectorRef?: string; // Extracted selector reference like [auth-login.email]
|
|
21
|
+
childRef?: string; // Q2: second [ref] after "contain" — child element for all-card structural assertion
|
|
22
|
+
childElementType?: string; // Element type after the child [ref], e.g. "button" in "contain [Add To Cart] button"
|
|
21
23
|
dataRef?: string; // Extracted data reference like <valid_user.email>
|
|
22
24
|
value?: string; // Static value if any
|
|
23
25
|
elementType?: string; // Element type after [Selector] e.g., "button", "text", "link", "field"
|
|
@@ -173,12 +175,25 @@ export class GherkinParser {
|
|
|
173
175
|
if (selectorRef) {
|
|
174
176
|
const elementTypeMatch = text.match(/\]\s+([\w-]+)/);
|
|
175
177
|
elementType = elementTypeMatch ? elementTypeMatch[1].toLowerCase() : undefined;
|
|
178
|
+
// In "see all [Card] contain [Child]" the word after the first `]` is the
|
|
179
|
+
// connector "contain", not an element type — don't mistake it for one (Q2).
|
|
180
|
+
if (elementType && /^(contain|contains|include|includes)$/.test(elementType)) elementType = undefined;
|
|
176
181
|
} else {
|
|
177
182
|
// Extract final word if it's a known type (page, button, field, etc)
|
|
178
183
|
const finalWordMatch = text.match(/\b(page|button|field|link|text|checkbox|radio|select|dropdown|modal|dialog|drawer|message|error|warning|success|alert|table|list|list-item|listitem|row|search|option|slider|toggle|tab|breadcrumb|overlay|step|section|card|item|icon|image|header|label|badge|tooltip|tag|menuitem|cell|column|uploader|date-picker|key)\b$/i);
|
|
179
184
|
elementType = finalWordMatch ? finalWordMatch[1].toLowerCase() : undefined;
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
// Q2: a second [ref] after "contain"/"include" = the child element every container
|
|
188
|
+
// must hold, e.g. "see all [Product Card] contain [Add To Cart] button".
|
|
189
|
+
let childRef: string | undefined;
|
|
190
|
+
let childElementType: string | undefined;
|
|
191
|
+
const childMatch = text.match(/\b(?:contain|contains|include|includes)\s+\[([^\]]+)\]\s*([\w-]+)?/i);
|
|
192
|
+
if (childMatch) {
|
|
193
|
+
childRef = childMatch[1];
|
|
194
|
+
childElementType = childMatch[2] ? childMatch[2].toLowerCase() : undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
182
197
|
// Extract positional index from "[Element] field 3", "[Element] button 2", etc.
|
|
183
198
|
let nth = 0;
|
|
184
199
|
if (selectorRef && selectorMatch) {
|
|
@@ -202,6 +217,8 @@ export class GherkinParser {
|
|
|
202
217
|
keyword: step.keyword.trim(),
|
|
203
218
|
text: step.text, // Preserve original text (with parent scoping) for pattern matching
|
|
204
219
|
selectorRef,
|
|
220
|
+
childRef,
|
|
221
|
+
childElementType,
|
|
205
222
|
dataRef,
|
|
206
223
|
value,
|
|
207
224
|
elementType,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
const __cards_{{stepCounter}} = {{> locator}};
|
|
3
|
+
const __n_{{stepCounter}} = await __cards_{{stepCounter}}.count();
|
|
4
|
+
expect(__n_{{stepCounter}}, 'Expected at least one [{{selectorRef}}]').toBeGreaterThan(0);
|
|
5
|
+
for (let __i_{{stepCounter}} = 0; __i_{{stepCounter}} < __n_{{stepCounter}}; __i_{{stepCounter}}++) {
|
|
6
|
+
await expect({{#with child}}{{> locator}}{{/with}}, 'Every [{{selectorRef}}] must contain [{{childRef}}]').toBeVisible();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -13,6 +13,11 @@ import { StepPattern, StepTemplateData } from './types';
|
|
|
13
13
|
* 2. List: `User see all [Product Name] contain {{selected_category}}`
|
|
14
14
|
* → asserts EVERY matching element's text contains the value
|
|
15
15
|
* (e.g. all products belong to the selected category/brand).
|
|
16
|
+
*
|
|
17
|
+
* 3. All-card: `User see all [Product Card] contain [Add To Cart] button`
|
|
18
|
+
* → asserts EVERY container element holds the child element
|
|
19
|
+
* (structural per-card proof: every card has name/price/action).
|
|
20
|
+
* Roadmap Q2 — the fix for "each card exposes X" claims.
|
|
16
21
|
*/
|
|
17
22
|
export const capturePatterns: StepPattern[] = [
|
|
18
23
|
{
|
|
@@ -56,4 +61,37 @@ export const capturePatterns: StepPattern[] = [
|
|
|
56
61
|
},
|
|
57
62
|
priority: 34,
|
|
58
63
|
},
|
|
64
|
+
{
|
|
65
|
+
// Q2 — all-card structural assertion: every container holds the child element.
|
|
66
|
+
// Distinguished from `all-contain-assertion` by a second [ref] (childRef) and the
|
|
67
|
+
// ABSENCE of a value/data (which would make it a text-contains assertion instead).
|
|
68
|
+
name: 'all-contain-element',
|
|
69
|
+
matcher: (step: ParsedStep) =>
|
|
70
|
+
/\b(see|sees)\b/i.test(step.text) &&
|
|
71
|
+
/\ball\b/i.test(step.text) &&
|
|
72
|
+
/(contain|contains|include|includes)/i.test(step.text) &&
|
|
73
|
+
!!step.selectorRef && !!step.childRef && !step.value && !step.dataRef,
|
|
74
|
+
resolver: (step, context): StepTemplateData => {
|
|
75
|
+
const container = context.selectorResolver.resolveSelector(
|
|
76
|
+
step.selectorRef!, undefined, step.elementType, step.nth,
|
|
77
|
+
);
|
|
78
|
+
const child = context.selectorResolver.resolveSelector(
|
|
79
|
+
step.childRef!, undefined, step.childElementType, 0,
|
|
80
|
+
);
|
|
81
|
+
const sc = context.stepCounter;
|
|
82
|
+
return {
|
|
83
|
+
templateName: 'all-contain-element',
|
|
84
|
+
data: {
|
|
85
|
+
...container,
|
|
86
|
+
selectorRef: step.selectorRef,
|
|
87
|
+
childRef: step.childRef,
|
|
88
|
+
stepCounter: sc,
|
|
89
|
+
// Render the child RELATIVE to each container row via locator.hbs's parentLocator branch.
|
|
90
|
+
child: { ...child, parentLocator: `__cards_${sc}.nth(__i_${sc})` },
|
|
91
|
+
},
|
|
92
|
+
comment: `Assert all ${step.selectorRef} contain [${step.childRef}]`,
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
priority: 36,
|
|
96
|
+
},
|
|
59
97
|
];
|
package/src/harness/audit.ts
CHANGED
|
@@ -9,16 +9,19 @@
|
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
import { loadScenarios, parseViewpointOverview, ScenarioInfo, ViewpointEntry } from './parse';
|
|
11
11
|
import {
|
|
12
|
-
loadCatalog, viewpointGate, assertionDepth, dataThemesFor, coverageBalance, duplicateClusters, traceability,
|
|
13
|
-
GateResult, DepthResult, BalanceResult, DuplicateResult, TraceResult,
|
|
12
|
+
loadCatalog, viewpointGate, assertionDepth, dataThemesFor, coverageBalance, duplicateClusters, traceability, claimProof, taxonomyLint,
|
|
13
|
+
GateResult, DepthResult, BalanceResult, DuplicateResult, TraceResult, ClaimProofResult, TaxonomyResult,
|
|
14
14
|
} from './sensors';
|
|
15
15
|
import { readIntent, projectRootFromScreenDir, IntentProfile } from './intent';
|
|
16
|
+
import { getProvenance, Provenance } from './provenance';
|
|
16
17
|
|
|
17
18
|
export interface AuditReport {
|
|
18
19
|
screen: string;
|
|
19
20
|
scenarioCount: number;
|
|
20
21
|
gate: GateResult;
|
|
21
22
|
depth: DepthResult;
|
|
23
|
+
claim: ClaimProofResult;
|
|
24
|
+
taxonomy: TaxonomyResult;
|
|
22
25
|
balance: BalanceResult;
|
|
23
26
|
duplicates: DuplicateResult;
|
|
24
27
|
trace: TraceResult;
|
|
@@ -33,6 +36,7 @@ export interface AuditReport {
|
|
|
33
36
|
gateStatus: 'PASS' | 'FAIL';
|
|
34
37
|
findings: string[]; // human-actionable, what the Repair loop would target
|
|
35
38
|
intent: IntentProfile; // P3 — the intent profile that drove the thresholds
|
|
39
|
+
provenance: Provenance; // D1 — sungen version + catalog hash (diagnose cross-user score gaps)
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
@@ -47,6 +51,8 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
47
51
|
// P3 — intent profile from qa/context.md drives the depth threshold (focus).
|
|
48
52
|
const intent = readIntent(projectRootFromScreenDir(screenDir));
|
|
49
53
|
const depth = assertionDepth(scenarios, dataThemesFor(catalog, gate.pageType), intent.focus);
|
|
54
|
+
const claim = claimProof(scenarios, intent.focus);
|
|
55
|
+
const taxonomy = taxonomyLint(scenarios);
|
|
50
56
|
const balance = coverageBalance(scenarios);
|
|
51
57
|
const duplicates = duplicateClusters(scenarios);
|
|
52
58
|
const trace = traceability(scenarios, viewpoints);
|
|
@@ -78,6 +84,13 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
78
84
|
`add data assertions (\`... with {{value}}\`, \`see all ... contain {{v}}\`) or, if cross-screen, defer to a flow with @manual + reason.`,
|
|
79
85
|
);
|
|
80
86
|
}
|
|
87
|
+
for (const u of claim.unproven) {
|
|
88
|
+
const tag = u.severity === 'fail' ? 'CLAIM-UNPROVEN' : 'CLAIM-WEAK';
|
|
89
|
+
findings.push(`${tag}: "${u.name}" — title claims [${u.claim}] but steps lack ${u.need}. ${u.hint}`);
|
|
90
|
+
}
|
|
91
|
+
for (const m of taxonomy.mislabeled) {
|
|
92
|
+
findings.push(`VP-MISLABEL: "${m.name}" is coded VP-${m.current} but reads as ${m.suggested} (signal: "${m.signal}") → re-tag VP-${m.suggested}-NNN so the coverage matrix isn't skewed.`);
|
|
93
|
+
}
|
|
81
94
|
if (balance.imbalanced) {
|
|
82
95
|
findings.push(`BALANCE: ${balance.note} Stop expanding secondary viewpoints until business-core gaps are filled.`);
|
|
83
96
|
}
|
|
@@ -91,12 +104,12 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
91
104
|
// Gate now spans coverage (viewpoint themes) AND depth (data-correctness).
|
|
92
105
|
// A depth 'fail' (below the intent threshold) fails the gate; 'warn' does not.
|
|
93
106
|
const gateStatus: 'PASS' | 'FAIL' =
|
|
94
|
-
gate.gaps.length === 0 && depth.verdict !== 'fail' ? 'PASS' : 'FAIL';
|
|
107
|
+
gate.gaps.length === 0 && depth.verdict !== 'fail' && claim.verdict !== 'fail' ? 'PASS' : 'FAIL';
|
|
95
108
|
|
|
96
109
|
return {
|
|
97
110
|
screen: screenName,
|
|
98
111
|
scenarioCount: scenarios.length,
|
|
99
|
-
gate, depth, balance, duplicates, trace,
|
|
112
|
+
gate, depth, claim, taxonomy, balance, duplicates, trace,
|
|
100
113
|
score: {
|
|
101
114
|
overall: Math.round(overall * 10) / 10,
|
|
102
115
|
coverage: Math.round(coverage * 100) / 100,
|
|
@@ -108,5 +121,6 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
108
121
|
gateStatus,
|
|
109
122
|
findings,
|
|
110
123
|
intent,
|
|
124
|
+
provenance: getProvenance(),
|
|
111
125
|
};
|
|
112
126
|
}
|
package/src/harness/parse.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface ScenarioInfo {
|
|
|
28
28
|
shallow: boolean; // asserts only visibility/navigation (no data)
|
|
29
29
|
stepSkeleton: string; // normalized steps for duplicate clustering
|
|
30
30
|
haystack: string; // lowercase name + steps text (for keyword coverage)
|
|
31
|
+
stepsText: string; // lowercase steps ONLY (name excluded) — for claim-proof
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
// ---------- test-viewpoint.md ----------
|
|
@@ -98,11 +99,13 @@ function classifyScenario(sc: ParsedScenario): ScenarioInfo {
|
|
|
98
99
|
let hasData = false;
|
|
99
100
|
const skeletonParts: string[] = [];
|
|
100
101
|
const textParts: string[] = [sc.name];
|
|
102
|
+
const stepTextParts: string[] = [];
|
|
101
103
|
|
|
102
104
|
for (const step of sc.steps as ParsedStep[]) {
|
|
103
105
|
const kw = step.keyword.trim();
|
|
104
106
|
if (kw === 'Given' || kw === 'When' || kw === 'Then') last = kw;
|
|
105
107
|
textParts.push(step.text);
|
|
108
|
+
stepTextParts.push(step.text);
|
|
106
109
|
// normalized skeleton: keep [refs] (distinct targets = distinct tests),
|
|
107
110
|
// but neutralize {{vars}} and quoted values so EP/data families collapse.
|
|
108
111
|
const skel = step.text
|
|
@@ -132,6 +135,7 @@ function classifyScenario(sc: ParsedScenario): ScenarioInfo {
|
|
|
132
135
|
shallow,
|
|
133
136
|
stepSkeleton: skeletonParts.join(' | '),
|
|
134
137
|
haystack: textParts.join(' ').toLowerCase(),
|
|
138
|
+
stepsText: stepTextParts.join(' ').toLowerCase(),
|
|
135
139
|
};
|
|
136
140
|
}
|
|
137
141
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance stamp for deterministic reports (score-determinism D1).
|
|
3
|
+
*
|
|
4
|
+
* The audit score is a pure function of the project files + the bundled catalog.
|
|
5
|
+
* Stamping the sungen version + a catalog hash into the report lets two users who
|
|
6
|
+
* get different scores see IMMEDIATELY whether the cause is a version/catalog
|
|
7
|
+
* mismatch (the main residual source of cross-user variance) rather than a real
|
|
8
|
+
* difference in their test design.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import * as crypto from 'crypto';
|
|
13
|
+
|
|
14
|
+
export interface Provenance {
|
|
15
|
+
sungenVersion: string;
|
|
16
|
+
catalogHash: string; // sha256(universal-viewpoints.yaml), first 12 hex — the catalog that drives the score
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getProvenance(): Provenance {
|
|
20
|
+
let sungenVersion = 'unknown';
|
|
21
|
+
try {
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
23
|
+
if (pkg && typeof pkg.version === 'string') sungenVersion = pkg.version;
|
|
24
|
+
} catch { /* version stays 'unknown' */ }
|
|
25
|
+
|
|
26
|
+
let catalogHash = 'unknown';
|
|
27
|
+
try {
|
|
28
|
+
const cat = fs.readFileSync(path.join(__dirname, 'catalog', 'universal-viewpoints.yaml'), 'utf-8');
|
|
29
|
+
catalogHash = crypto.createHash('sha256').update(cat).digest('hex').slice(0, 12);
|
|
30
|
+
} catch { /* hash stays 'unknown' */ }
|
|
31
|
+
|
|
32
|
+
return { sungenVersion, catalogHash };
|
|
33
|
+
}
|