@sun-asterisk/sungen 3.2.14 → 3.2.16-beta.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/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +167 -51
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
- package/dist/dashboard/snapshot-builder.js +3 -46
- package/dist/dashboard/snapshot-builder.js.map +1 -1
- package/dist/dashboard/templates/index.html +1 -1
- package/dist/exporters/feature-parser.js +1 -1
- package/dist/exporters/feature-parser.js.map +1 -1
- package/dist/exporters/locale-variants.d.ts +38 -0
- package/dist/exporters/locale-variants.d.ts.map +1 -0
- package/dist/exporters/locale-variants.js +159 -0
- package/dist/exporters/locale-variants.js.map +1 -0
- package/dist/exporters/matrix/build.d.ts +36 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -0
- package/dist/exporters/matrix/build.js +267 -0
- package/dist/exporters/matrix/build.js.map +1 -0
- package/dist/exporters/matrix/export.d.ts +47 -0
- package/dist/exporters/matrix/export.d.ts.map +1 -0
- package/dist/exporters/matrix/export.js +136 -0
- package/dist/exporters/matrix/export.js.map +1 -0
- package/dist/exporters/matrix/fingerprint.d.ts +20 -0
- package/dist/exporters/matrix/fingerprint.d.ts.map +1 -0
- package/dist/exporters/matrix/fingerprint.js +83 -0
- package/dist/exporters/matrix/fingerprint.js.map +1 -0
- package/dist/exporters/matrix/gates.d.ts +21 -0
- package/dist/exporters/matrix/gates.d.ts.map +1 -0
- package/dist/exporters/matrix/gates.js +258 -0
- package/dist/exporters/matrix/gates.js.map +1 -0
- package/dist/exporters/matrix/map-loader.d.ts +22 -0
- package/dist/exporters/matrix/map-loader.d.ts.map +1 -0
- package/dist/exporters/matrix/map-loader.js +173 -0
- package/dist/exporters/matrix/map-loader.js.map +1 -0
- package/dist/exporters/matrix/render-csv.d.ts +8 -0
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -0
- package/dist/exporters/matrix/render-csv.js +69 -0
- package/dist/exporters/matrix/render-csv.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +17 -0
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -0
- package/dist/exporters/matrix/render-xlsx.js +298 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -0
- package/dist/exporters/matrix/types.d.ts +153 -0
- package/dist/exporters/matrix/types.d.ts.map +1 -0
- package/dist/exporters/matrix/types.js +15 -0
- package/dist/exporters/matrix/types.js.map +1 -0
- package/dist/exporters/scenario-merger.js +1 -1
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/spec-parser.js +1 -1
- package/dist/exporters/spec-parser.js.map +1 -1
- package/dist/exporters/xlsx-report-builder.d.ts +1 -1
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.js +3 -3
- package/dist/exporters/xlsx-report-builder.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +3 -11
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +11 -1
- package/dist/generators/test-generator/code-generator.js +1 -1
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +4 -1
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +3 -0
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +6 -0
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +41 -2
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/harness/annotation-overrides.d.ts +4 -1
- package/dist/harness/annotation-overrides.d.ts.map +1 -1
- package/dist/harness/annotation-overrides.js +5 -2
- package/dist/harness/annotation-overrides.js.map +1 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +6 -1
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability.d.ts +25 -0
- package/dist/harness/capability.d.ts.map +1 -1
- package/dist/harness/capability.js +44 -2
- package/dist/harness/capability.js.map +1 -1
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +5 -0
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +1 -1
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +118 -120
- package/dist/orchestrator/templates/ai-src/config/claude.md +1 -1
- package/dist/orchestrator/templates/ai-src/config/copilot.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +43 -7
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +1 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md +8 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -0
- package/dist/orchestrator/templates/specs-test-data.ts +13 -4
- package/package.json +4 -4
- package/src/cli/commands/delivery.ts +199 -71
- package/src/dashboard/snapshot-builder.ts +11 -61
- package/src/dashboard/templates/index.html +1 -1
- package/src/exporters/feature-parser.ts +1 -1
- package/src/exporters/locale-variants.ts +157 -0
- package/src/exporters/matrix/build.ts +294 -0
- package/src/exporters/matrix/export.ts +124 -0
- package/src/exporters/matrix/fingerprint.ts +49 -0
- package/src/exporters/matrix/gates.ts +284 -0
- package/src/exporters/matrix/map-loader.ts +142 -0
- package/src/exporters/matrix/render-csv.ts +71 -0
- package/src/exporters/matrix/render-xlsx.ts +289 -0
- package/src/exporters/matrix/types.ts +176 -0
- package/src/exporters/scenario-merger.ts +1 -1
- package/src/exporters/spec-parser.ts +1 -1
- package/src/exporters/xlsx-report-builder.ts +3 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +3 -11
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +11 -1
- package/src/generators/test-generator/code-generator.ts +1 -1
- package/src/generators/test-generator/diagnostics.ts +4 -1
- package/src/generators/test-generator/step-mapper.ts +43 -2
- package/src/harness/annotation-overrides.ts +5 -2
- package/src/harness/audit.ts +7 -2
- package/src/harness/capability.ts +53 -3
- package/src/harness/quality-gates.ts +4 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +1 -1
- package/src/orchestrator/templates/ai-src/commands/delivery.md +118 -120
- package/src/orchestrator/templates/ai-src/config/claude.md +1 -1
- package/src/orchestrator/templates/ai-src/config/copilot.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +43 -7
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +1 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md +8 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -0
- package/src/orchestrator/templates/specs-test-data.ts +13 -4
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* Shared annotation-override grammar for precondition annotations (`@query`/`@api`).
|
|
3
3
|
*
|
|
4
4
|
* Parses `name(a={{x}},b="lit",c=3)` overrides into a map of JS expressions, e.g.
|
|
5
|
-
* `{ a: "testData.
|
|
5
|
+
* `{ a: "testData.raw('x')", b: "\"lit\"", c: "3" }`. Used by the DB and API capability drivers'
|
|
6
6
|
* precondition codegen; lives in core so both drivers can share it. Gherkin tags carry no whitespace,
|
|
7
7
|
* so values are single tokens — flows thread a prior response via a whole-value ref, e.g.
|
|
8
8
|
* `@api:get_profile(token={{login.body.token}})`, with the auth scheme declared in the catalog header.
|
|
9
|
+
* A `{{ref}}` override binds into a typed sink (DB query param, JSON request body), so it resolves
|
|
10
|
+
* via `testData.raw()` (native type, still interpolates embedded refs) rather than `get()`
|
|
11
|
+
* (Gherkin-text stringify) — a numeric override otherwise reaches the DB/API as a JSON string.
|
|
9
12
|
*/
|
|
10
13
|
export function parseQueryOverrides(raw?: string): Record<string, string> {
|
|
11
14
|
const out: Record<string, string> = {};
|
|
@@ -18,7 +21,7 @@ export function parseQueryOverrides(raw?: string): Record<string, string> {
|
|
|
18
21
|
if (!key) continue;
|
|
19
22
|
const v = val.match(/^\{\{\s*([^}]+?)\s*\}\}$/);
|
|
20
23
|
const q = val.match(/^["'](.*)["']$/);
|
|
21
|
-
if (v) out[key] = `testData.
|
|
24
|
+
if (v) out[key] = `testData.raw(${JSON.stringify(v[1])})`;
|
|
22
25
|
else if (q) out[key] = JSON.stringify(q[1]);
|
|
23
26
|
else if (/^-?\d+(?:\.\d+)?$/.test(val)) out[key] = val;
|
|
24
27
|
else out[key] = JSON.stringify(val);
|
package/src/harness/audit.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from './sensors';
|
|
18
18
|
import { loadFlowScenarios } from './flow-check';
|
|
19
19
|
import { manualReasonMismatches, MANUAL_REASONS, buildPlan } from './capability-plan';
|
|
20
|
-
import { readCapabilities } from './capability';
|
|
20
|
+
import { readCapabilities, verificationScopeFindings } from './capability';
|
|
21
21
|
import { readIntent, projectRootFromScreenDir, IntentProfile } from './intent';
|
|
22
22
|
import { getProvenance, Provenance } from './provenance';
|
|
23
23
|
import { specCoverage, SpecCoverageResult, parseSpecClauses } from './spec-coverage';
|
|
@@ -129,7 +129,8 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
129
129
|
discoverAndRegisterCapabilities();
|
|
130
130
|
// The active platform (web | mobile | …) activates its own capability for scoring + sensor routing.
|
|
131
131
|
// `web` has no capability of its own → scoringCap stays the default `ui` (byte-identical).
|
|
132
|
-
const
|
|
132
|
+
const capProfile = readCapabilities(projectRootFromScreenDir(screenDir));
|
|
133
|
+
const platform = capProfile.platform;
|
|
133
134
|
const defaultCap = capabilityRegistry.defaultCapabilityId();
|
|
134
135
|
const scoringCapId = scoringCapabilityFor(catalogScreenName, defaultCap, platform);
|
|
135
136
|
const scoringCap = scoringCapId ? capabilityRegistry.get(scoringCapId) : undefined;
|
|
@@ -223,6 +224,10 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
|
|
|
223
224
|
for (const c of flowCredits) {
|
|
224
225
|
findings.push(`COVERED-VIA-FLOW: critical theme "${c.theme}" is not covered on this screen but is deeply covered by flow "${c.flow}" — cross-screen depth correctly owned by the flow, so it is credited (not a screen gap). Verify with \`sungen flow-check\`.`);
|
|
225
226
|
}
|
|
227
|
+
// Verification-scope (advisory): API/DB verification the project's recorded test type never asked for.
|
|
228
|
+
for (const v of verificationScopeFindings(featureText, fs.existsSync(viewpointPath) ? fs.readFileSync(viewpointPath, 'utf-8') : '', capProfile)) {
|
|
229
|
+
findings.push(`VERIFICATION-OUT-OF-SCOPE (${v.layer}): this unit ${v.message}`);
|
|
230
|
+
}
|
|
226
231
|
for (const g of gate.gaps) {
|
|
227
232
|
if (g.status === 'shallow') {
|
|
228
233
|
findings.push(`GATE: critical theme "${g.theme}" is covered only by SHALLOW scenarios (no data assertion) → deepen with \`... with {{value}}\` / \`table ... with {{value}}\` (count @manual cross-screen too).`);
|
|
@@ -15,9 +15,55 @@ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
|
15
15
|
export interface CapabilityProfile {
|
|
16
16
|
platform?: string; // web | mobile | … (the runtime adapter)
|
|
17
17
|
enabled: string[]; // driver ids enabled for this project
|
|
18
|
+
/**
|
|
19
|
+
* Which VERIFICATION layers this project's test scope uses — the recorded "test type"
|
|
20
|
+
* (`ui` = E2E-only; add `api` / `db` when the project also verifies via API/DB). Explicit here wins;
|
|
21
|
+
* when absent it is DERIVED from `enabled` (ui always; api if the api driver is on; db if db is on).
|
|
22
|
+
* Generation and the audit use it so an E2E-only project does not get @api/@query verification it
|
|
23
|
+
* never asked for.
|
|
24
|
+
*/
|
|
25
|
+
verification?: string[];
|
|
18
26
|
source: 'capabilities.yaml' | 'absent';
|
|
19
27
|
}
|
|
20
28
|
|
|
29
|
+
export type VerifyLayer = 'ui' | 'api' | 'db';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Effective verification scope = the recorded "test type". Explicit `verification` wins; otherwise
|
|
33
|
+
* derived from the enabled drivers. `ui` is always in scope (every project observes the UI/E2E result).
|
|
34
|
+
*/
|
|
35
|
+
export function verificationScope(profile: CapabilityProfile): Set<VerifyLayer> {
|
|
36
|
+
if (profile.verification?.length) {
|
|
37
|
+
const s = new Set<VerifyLayer>(['ui']);
|
|
38
|
+
for (const v of profile.verification) if (v === 'api' || v === 'db' || v === 'ui') s.add(v);
|
|
39
|
+
return s;
|
|
40
|
+
}
|
|
41
|
+
const s = new Set<VerifyLayer>(['ui']);
|
|
42
|
+
if (profile.enabled.includes('api')) s.add('api');
|
|
43
|
+
if (profile.enabled.includes('db')) s.add('db');
|
|
44
|
+
return s;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface VerifyScopeFinding { layer: 'api' | 'db'; message: string; }
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Flag API/DB verification that is OUT OF the project's recorded scope: a unit whose scenarios use
|
|
51
|
+
* `@api`/`@requires:api` (or `@query`/`@requires:db`) while the project is not API/DB-testing AND the
|
|
52
|
+
* viewpoint never asked for that layer. Deterministic; advisory only (a nudge, never a hard gate).
|
|
53
|
+
*/
|
|
54
|
+
export function verificationScopeFindings(featureText: string, viewpointText: string, profile: CapabilityProfile): VerifyScopeFinding[] {
|
|
55
|
+
const scope = verificationScope(profile);
|
|
56
|
+
const vp = (viewpointText || '').toLowerCase();
|
|
57
|
+
const out: VerifyScopeFinding[] = [];
|
|
58
|
+
if (/@api\b|@requires:\s*api\b/.test(featureText) && !scope.has('api') && !/\bapi\b/.test(vp)) {
|
|
59
|
+
out.push({ layer: 'api', message: 'uses @api / @requires:api verification, but this project is not API-testing (capabilities `enabled` has no `api`) and the viewpoint does not request API verification. Keep the oracle UI-observable, OR record API in scope (capabilities `verification: [ui, api]` or `sungen capability add api`). Reserve API/DB verify for the ≤20% of effects with no UI observation.' });
|
|
60
|
+
}
|
|
61
|
+
if (/@query\b|@requires:\s*db\b/.test(featureText) && !scope.has('db') && !/\b(database|db)\b/.test(vp)) {
|
|
62
|
+
out.push({ layer: 'db', message: 'uses @query / @requires:db verification, but this project is not DB-testing (capabilities `enabled` has no `db`) and the viewpoint does not request DB verification. Keep the oracle UI-observable, OR record DB in scope (capabilities `verification: [ui, db]` or `sungen capability add db`). Reserve API/DB verify for the ≤20% of effects with no UI observation.' });
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
21
67
|
export interface DriverMeta {
|
|
22
68
|
id: string;
|
|
23
69
|
kind: 'platform' | 'capability';
|
|
@@ -41,6 +87,7 @@ export function readCapabilities(cwd: string): CapabilityProfile {
|
|
|
41
87
|
return {
|
|
42
88
|
platform: typeof y.platform === 'string' ? y.platform : undefined,
|
|
43
89
|
enabled: Array.isArray(y.enabled) ? y.enabled.map(String) : [],
|
|
90
|
+
verification: Array.isArray(y.verification) ? y.verification.map(String) : undefined,
|
|
44
91
|
source: 'capabilities.yaml',
|
|
45
92
|
};
|
|
46
93
|
} catch {
|
|
@@ -48,14 +95,17 @@ export function readCapabilities(cwd: string): CapabilityProfile {
|
|
|
48
95
|
}
|
|
49
96
|
}
|
|
50
97
|
|
|
51
|
-
export function writeCapabilities(cwd: string, profile: { platform?: string; enabled: string[] }): string {
|
|
98
|
+
export function writeCapabilities(cwd: string, profile: { platform?: string; enabled: string[]; verification?: string[] }): string {
|
|
52
99
|
const p = capabilitiesPath(cwd);
|
|
53
100
|
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
54
101
|
const body =
|
|
55
102
|
'# Sungen capability profile — which runtime/drivers this project uses.\n' +
|
|
56
103
|
'# platform: the runtime adapter (web → Playwright, mobile → Appium). No default.\n' +
|
|
57
|
-
'# enabled: drivers turned on (added via `sungen capability add <driver>`).\n
|
|
58
|
-
|
|
104
|
+
'# enabled: drivers turned on (added via `sungen capability add <driver>`).\n' +
|
|
105
|
+
'# verification: the TEST TYPE — which layers this project verifies (`ui` = E2E only; add `api`/`db`\n' +
|
|
106
|
+
'# only if the project actually verifies via API/Database). Absent → derived from `enabled`.\n' +
|
|
107
|
+
'# This keeps an E2E-only project from getting @api/@query verification it never asked for.\n\n' +
|
|
108
|
+
stringifyYaml({ platform: profile.platform, enabled: profile.enabled, ...(profile.verification ? { verification: profile.verification } : {}) });
|
|
59
109
|
fs.writeFileSync(p, body, 'utf-8');
|
|
60
110
|
return p;
|
|
61
111
|
}
|
|
@@ -174,6 +174,10 @@ export interface OwnershipResult { duplicates: { scenario: string; flow: string
|
|
|
174
174
|
|
|
175
175
|
/** Scenarios whose step-skeleton also appears in a sibling flow feature → duplicate ownership. */
|
|
176
176
|
export function crossArtifactOwnership(screenDir: string, scenarios: ScenarioInfo[]): OwnershipResult {
|
|
177
|
+
// A behavior's ownership is judged from the screen side; flow/api units are the owners, so the
|
|
178
|
+
// gate does not apply to them. Without this guard, auditing qa/flows/<x>, qa/api/<x>, or
|
|
179
|
+
// qa/api/flows/<x> resolves flowsRoot to the unit's own parent and every scenario self-matches.
|
|
180
|
+
if (path.basename(path.dirname(screenDir)) !== 'screens') return { duplicates: [] };
|
|
177
181
|
const duplicates: { scenario: string; flow: string }[] = [];
|
|
178
182
|
// screenDir = <root>/qa/screens/<name>; flows live at <root>/qa/flows/*/features/*.feature
|
|
179
183
|
const flowsRoot = path.resolve(screenDir, '..', '..', 'flows');
|
|
@@ -22,7 +22,7 @@ If `spec_figma.md` exists OR the user provides a Figma URL for the PAT flow:
|
|
|
22
22
|
|
|
23
23
|
## Platform detection (do this FIRST)
|
|
24
24
|
|
|
25
|
-
Read `qa/capabilities.yaml` and check the `platform` field.
|
|
25
|
+
Read `qa/capabilities.yaml` and check the `platform` field — **and the verification scope** (`verification:` if set, else derived from `enabled`: `ui` always; `api`/`db` only if that driver is on). This is the project's recorded **test type**: an **E2E/UI-only** project (no `api`/`db`) must NOT get `@api`/`@query`/`@requires:api|db` verification unless the test-viewpoint explicitly asks for it — keep oracles UI-observable, and cap any in-scope API/DB-in-E2E verification at the **≤20% band** (see `sungen-tc-generation` → "Respect the project's verification scope"). `sungen audit` flags `VERIFICATION-OUT-OF-SCOPE`.
|
|
26
26
|
|
|
27
27
|
- If `platform: mobile` → the visual-capture step (Step 3, "Auto-detect visual source") uses the **`sungen-capture-mobile`** skill (Appium MCP live capture) **instead of** the web `sungen-capture` (figma/live). Scenarios use mobile gesture vocabulary from `sungen-mobile-gestures` (tap, swipe, long-press — not click/hover) and `accessibility-id`-first selectors; mobile-specific steps (permission dialogs, clipboard, geolocation) are valid Gherkin, not errors. The `Background:` is a **navigation recipe** (see `add-screen --reach`), not a URL path. Everything else — viewpoints, `sungen-tc-generation`, the harness/audit loop — is platform-agnostic and unchanged.
|
|
28
28
|
- If `platform: web` or field absent → follow the **web path** (all steps below, unchanged) — Figma/live capture via `sungen-capture` as documented in Step 3.
|
|
@@ -1,146 +1,144 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: delivery
|
|
3
|
-
description: "Export Gherkin
|
|
4
|
-
argument-hint: "[
|
|
3
|
+
description: "Export the Test Case & Coverage Matrix (review/manual/customer deliverable) from Gherkin + Playwright results. --legacy exports the classic per-scenario CSV/XLSX."
|
|
4
|
+
argument-hint: "[name...] [--env <locale>] [--legacy] (omit names for all; --env for locale-specific export)"
|
|
5
5
|
order: 50
|
|
6
|
-
claude-tools: "Bash, Read, AskUserQuestion"
|
|
6
|
+
claude-tools: "Bash, Read, Write, AskUserQuestion"
|
|
7
7
|
copilot-tools: "[read, execute, edit, vscode/askQuestions]"
|
|
8
|
-
codex-trigger: "Run when the user asks to EXPORT or deliver test cases
|
|
8
|
+
codex-trigger: "Run when the user asks to EXPORT or deliver test cases for QA hand-off. Final step. Do NOT use for creating or running tests."
|
|
9
9
|
---
|
|
10
10
|
## Role
|
|
11
11
|
|
|
12
|
-
You are a **QA Test Delivery Engineer**.
|
|
12
|
+
You are a **QA Test Delivery Engineer**. The deterministic `sungen delivery` CLI does all parsing,
|
|
13
|
+
gating, and rendering. Your job is (1) invoking it, (2) **proposing the Delivery Map** when a unit
|
|
14
|
+
does not have one yet — the one semantic step the CLI cannot do — and (3) walking the user through
|
|
15
|
+
review → approve → official render.
|
|
16
|
+
|
|
17
|
+
## The two delivery modes
|
|
18
|
+
|
|
19
|
+
- **Matrix (default)** — the Test Case & Coverage Matrix: one row per *delivery item* (one target +
|
|
20
|
+
one test intent + one oracle family), with each Gherkin scenario / `@cases` row preserved as a
|
|
21
|
+
collapsible *coverage variant* sub-row. No numbered step dumps. This is the reviewable /
|
|
22
|
+
manually-executable / customer-facing standard.
|
|
23
|
+
- **Legacy (`--legacy`, alias `--full`)** — the classic per-scenario-steps workbook (BM-2-901-13).
|
|
24
|
+
Use it when the user asks for the old format or a project is mid-engagement on it.
|
|
13
25
|
|
|
14
26
|
## Parameters
|
|
15
27
|
|
|
16
28
|
Parse from `$ARGUMENTS`:
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
{{^cap parallel-subagents}}
|
|
21
|
-
- **names** — zero or more screen/flow names. Empty → CLI processes all targets in `qa/screens/` + `qa/flows/`.
|
|
22
|
-
{{/cap}}
|
|
23
|
-
- **`--env <locale>`** — optional. Sets `SUNGEN_ENV=<locale>` for the run so the CLI merges `<name>.<locale>.yaml` over the base test-data and writes `<name>-testcases.<locale>.csv` / `.xlsx`. Accept `--locale <locale>` as an alias.
|
|
24
|
-
|
|
25
|
-
If `--env` is passed but no value follows, ask the user which locale to use.
|
|
29
|
+
- **names** — zero or more screen/flow/api names. Empty → all targets.
|
|
30
|
+
- **`--env <locale>`** — sets `SUNGEN_ENV=<locale>` for the run (accept `--locale` as alias).
|
|
31
|
+
- **`--legacy` / `--full`** — pass through to the CLI and skip the map flow entirely.
|
|
26
32
|
|
|
27
33
|
## Steps
|
|
28
34
|
|
|
29
|
-
### 1.
|
|
30
|
-
|
|
31
|
-
{{#cap parallel-subagents}}
|
|
32
|
-
Run via Bash (single command, no extra parsing). Prefer the local `./bin/sungen.js` when it exists — the sungen monorepo ships local-only features the global npm package doesn't have yet (multi-sheet locale aggregation, `.<env>` filename suffix, locale-aware step rendering). Fall back to `npx sungen` in downstream projects.
|
|
33
|
-
{{/cap}}
|
|
34
|
-
{{^cap parallel-subagents}}
|
|
35
|
-
Run via Bash (single command, no extra parsing):
|
|
36
|
-
{{/cap}}
|
|
35
|
+
### 1. Run the CLI once
|
|
37
36
|
|
|
38
37
|
```bash
|
|
39
|
-
# No env — local-first dispatcher:
|
|
40
|
-
{{#cap parallel-subagents}}
|
|
41
|
-
[ -x ./bin/sungen.js ] && ./bin/sungen.js delivery <screens> || npx sungen delivery <screens>
|
|
42
|
-
{{/cap}}
|
|
43
|
-
{{^cap parallel-subagents}}
|
|
44
38
|
[ -x ./bin/sungen.js ] && ./bin/sungen.js delivery <names> || npx sungen delivery <names>
|
|
45
|
-
{{/cap}}
|
|
46
|
-
|
|
47
|
-
# Locale-specific:
|
|
48
|
-
{{#cap parallel-subagents}}
|
|
49
|
-
[ -x ./bin/sungen.js ] && SUNGEN_ENV=<locale> ./bin/sungen.js delivery <screens> || SUNGEN_ENV=<locale> npx sungen delivery <screens>
|
|
50
|
-
{{/cap}}
|
|
51
|
-
{{^cap parallel-subagents}}
|
|
52
|
-
[ -x ./bin/sungen.js ] && SUNGEN_ENV=<locale> ./bin/sungen.js delivery <names> || SUNGEN_ENV=<locale> npx sungen delivery <names>
|
|
53
|
-
{{/cap}}
|
|
54
39
|
```
|
|
40
|
+
(prepend `SUNGEN_ENV=<locale>` when `--env` was given; append `--legacy` when requested — then skip
|
|
41
|
+
to step 5.)
|
|
42
|
+
|
|
43
|
+
Three outcomes per target:
|
|
44
|
+
- **Rendered** → done, go to step 5.
|
|
45
|
+
- **"no delivery map"** → go to step 2 (propose it).
|
|
46
|
+
- **Gate findings / "not approved"** → go to step 4 (review & approve).
|
|
47
|
+
|
|
48
|
+
### 2. Propose the Delivery Map (only when missing or the user asks to regroup)
|
|
49
|
+
|
|
50
|
+
Read the unit's `.feature` (and `requirements/spec.md` for target naming). Write
|
|
51
|
+
`qa/<screens|flows|api>/<unit>/delivery/<unit>.map.yaml`:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
version: 1
|
|
55
|
+
unit: <unit>
|
|
56
|
+
groups:
|
|
57
|
+
- id: DI-<TARGET>-<THEME> # stable kebab id, never renumbered
|
|
58
|
+
target: login.email # ONE target: field/component dot-path, flow phrase, or METHOD /path
|
|
59
|
+
intent: <one behavior/rule this item verifies>
|
|
60
|
+
oracle: <the shared observable Pass/Fail statement>
|
|
61
|
+
category: normal | abnormal | security | nfr
|
|
62
|
+
review: proposed # ALWAYS proposed — only QA approval flips it
|
|
63
|
+
variants: [VP-VAL-001-B, VP-VAL-001-S] # VP-ids; bare id on a @cases scenario = all its rows
|
|
64
|
+
dispositions: # scenarios intentionally NOT delivered as test cases
|
|
65
|
+
VP-DATA-000: { as: excluded, reason: data-setup checklist }
|
|
66
|
+
# as: excluded | blocked | covered_elsewhere | accepted_risk
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Grouping rules (the aggregation signature):**
|
|
70
|
+
- One group = **one target + one intent + one oracle family**. When unsure, keep items separate —
|
|
71
|
+
the gates and QA decide, never guess-merge.
|
|
72
|
+
- MAY share a group (become coverage dimensions): equivalence partitions, boundary values,
|
|
73
|
+
different data (`@cases` rows), a different trigger with the same oracle (blur vs submit),
|
|
74
|
+
locales.
|
|
75
|
+
- MUST split: different target, intent, oracle family, category, execution mode (`@manual` vs
|
|
76
|
+
auto), test layer (`@api`/`@query`), or priority tag; sequence-sensitive flows (re-Given/When
|
|
77
|
+
after a Then) stay solo.
|
|
78
|
+
- Every scenario must land in exactly one group **or** one disposition (Gate B enforces 100%
|
|
79
|
+
disposition). Data-setup blocks (`@manual:data-setup`) → `excluded`; SPEC-GAP placeholders →
|
|
80
|
+
`blocked`.
|
|
81
|
+
|
|
82
|
+
Then validate and fix any ERROR findings:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
[ -x ./bin/sungen.js ] && ./bin/sungen.js delivery <unit> --check || npx sungen delivery <unit> --check
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Present the grouping for review
|
|
89
|
+
|
|
90
|
+
Show the user a compact summary: item count vs variant count, the groups (id · target · intent ·
|
|
91
|
+
variant count), dispositions, and every remaining `review`-level finding (oracle-shape /
|
|
92
|
+
precondition heuristics — these are exactly what QA must confirm). Then `AskUserQuestion`:
|
|
93
|
+
|
|
94
|
+
- **Approve all groups** (Recommended when the findings look right)
|
|
95
|
+
- **Adjust the grouping** — user names the groups to change; edit the map, re-run `--check`, re-present.
|
|
96
|
+
- **Preview draft first** — `sungen delivery <unit> --preview` (DRAFT watermark), then re-ask.
|
|
97
|
+
- **Cancel**
|
|
98
|
+
|
|
99
|
+
### 4. Approve + official render
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
[ -x ./bin/sungen.js ] && ./bin/sungen.js delivery <unit> --approve || npx sungen delivery <unit> --approve
|
|
103
|
+
[ -x ./bin/sungen.js ] && ./bin/sungen.js delivery <unit> || npx sungen delivery <unit>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`--approve` stamps scenario fingerprints into the map — if the `.feature` changes later, Gate E
|
|
107
|
+
flips the affected groups back to review (drift). Approved + unchanged groups render without
|
|
108
|
+
re-asking.
|
|
109
|
+
|
|
110
|
+
### 5. Show summary + offer next steps
|
|
55
111
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
The CLI handles:
|
|
65
|
-
{{#cap parallel-subagents}}
|
|
66
|
-
- Scope detection (all screens + flows vs specific)
|
|
67
|
-
{{/cap}}
|
|
68
|
-
{{^cap parallel-subagents}}
|
|
69
|
-
- Scope detection (all screens + flows vs specific names)
|
|
70
|
-
- Auto-detect: `qa/flows/<name>/` → flow, `qa/screens/<name>/` → screen
|
|
71
|
-
{{/cap}}
|
|
72
|
-
- Pre-flight source checks with colorful output
|
|
73
|
-
- Parsing `.feature`, `.spec.ts`, `test-data.yaml` (+ `<name>.<env>.yaml` overlay when `SUNGEN_ENV` is set), and per-target `<name>-test-result[.<env>].json`
|
|
74
|
-
- Generating CSV/XLSX at `qa/deliverables/<name>-testcases[.<env>].csv` / `.xlsx`
|
|
75
|
-
- Printing summary table
|
|
76
|
-
|
|
77
|
-
### 2. Handle pre-flight failures (if CLI exits non-zero)
|
|
78
|
-
|
|
79
|
-
{{#cap parallel-subagents}}
|
|
80
|
-
If the CLI exits with blocking issues, it will have already printed a clear table showing exactly what's missing per screen.
|
|
81
|
-
{{/cap}}
|
|
82
|
-
{{^cap parallel-subagents}}
|
|
83
|
-
If the CLI exits with blocking issues, it will have already printed a clear table showing exactly what's missing per target.
|
|
84
|
-
{{/cap}}
|
|
85
|
-
|
|
86
|
-
Use `AskUserQuestion` to offer next steps:
|
|
87
|
-
|
|
88
|
-
**Options:**
|
|
89
|
-
- **Fix missing sources** (Recommended) — Print the suggested commands from CLI output and stop. User will run those commands manually, then re-invoke `/sungen:delivery`.
|
|
90
|
-
{{#cap parallel-subagents}}
|
|
91
|
-
- **Continue with available screens** — Re-run as `npx sungen delivery <screens> --continue-on-missing` to skip screens with blocking issues.
|
|
92
|
-
{{/cap}}
|
|
93
|
-
{{^cap parallel-subagents}}
|
|
94
|
-
- **Continue with available targets** — Re-run as `npx sungen delivery <names> --continue-on-missing` to skip targets with blocking issues.
|
|
95
|
-
{{/cap}}
|
|
96
|
-
- **Cancel** — Exit.
|
|
97
|
-
|
|
98
|
-
### 3. Show summary + offer next steps (on success)
|
|
99
|
-
|
|
100
|
-
Forward the CLI's summary table to the user verbatim. Then use `AskUserQuestion`:
|
|
101
|
-
|
|
102
|
-
- **Open a specific CSV** — Help user inspect one of the exported files with Read tool.
|
|
103
|
-
{{#cap parallel-subagents}}
|
|
104
|
-
- **Run tests to refresh results** — Suggest `/sungen:run-test <screen>` to update `test-results/results.json`, then re-run delivery.
|
|
105
|
-
- **Export another screen** — User can run `/sungen:delivery <other-screen>`.
|
|
106
|
-
{{/cap}}
|
|
107
|
-
{{^cap parallel-subagents}}
|
|
108
|
-
- **Run tests to refresh results** — Suggest `/sungen-run-test <name>` to update test results, then re-run delivery.
|
|
109
|
-
- **Export another target** — User can run `/sungen-delivery <other-name>`.
|
|
110
|
-
{{/cap}}
|
|
111
|
-
- **Done** — Exit.
|
|
112
|
+
Forward the CLI summary verbatim (Items = review rows; **Variants = execution units — progress is
|
|
113
|
+
counted in variants, never items**). Then `AskUserQuestion`:
|
|
114
|
+
|
|
115
|
+
- **Open the workbook** — inspect `qa/deliverables/<unit>-testcases.xlsx` (Testcases sheet:
|
|
116
|
+
collapse outline level 1 for the customer view; Coverage sheet: target × category grid + gaps).
|
|
117
|
+
- **Run tests to refresh results** — `/sungen:run-test <unit>`, then re-run delivery.
|
|
118
|
+
- **Export the legacy workbook too** — `sungen delivery <unit> --legacy`.
|
|
119
|
+
- **Done**
|
|
112
120
|
|
|
113
121
|
## Important notes
|
|
114
122
|
|
|
115
|
-
- **Do NOT parse
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- **
|
|
123
|
+
- **Do NOT parse/duplicate what the CLI computes** — gates recompute mode/layer/priority/oracle
|
|
124
|
+
shapes from the `.feature`; the map only carries the semantic fields (target/intent/oracle/
|
|
125
|
+
category/grouping).
|
|
126
|
+
- **Never write `review: approved` yourself** — only `--approve` after the user agreed. Proposing
|
|
127
|
+
with `review: approved` defeats the QA review this format exists for.
|
|
128
|
+
- **Do NOT modify feature/test-data files during delivery** — read-only except the map file.
|
|
129
|
+
- The map is committed and stable: adding a group never renumbers others; deleting scenarios →
|
|
130
|
+
update the map (Gate B lists exactly what's unmapped/stale).
|
|
119
131
|
|
|
120
|
-
## CLI
|
|
132
|
+
## CLI reference
|
|
121
133
|
|
|
122
134
|
```
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
[--skip-preflight] Skip pre-flight checks (not recommended)
|
|
130
|
-
{{#cap parallel-subagents}}
|
|
131
|
-
[--continue-on-missing] Skip screens with blocking misses
|
|
132
|
-
{{/cap}}
|
|
133
|
-
{{^cap parallel-subagents}}
|
|
134
|
-
[--continue-on-missing] Skip targets with blocking misses
|
|
135
|
-
{{/cap}}
|
|
136
|
-
|
|
137
|
-
# Locale-aware export (env var, not a CLI flag):
|
|
138
|
-
{{#cap parallel-subagents}}
|
|
139
|
-
SUNGEN_ENV=<locale> sungen delivery [screens...]
|
|
140
|
-
{{/cap}}
|
|
141
|
-
{{^cap parallel-subagents}}
|
|
142
|
-
SUNGEN_ENV=<locale> sungen delivery [names...]
|
|
143
|
-
{{/cap}}
|
|
144
|
-
→ reads <name>.<locale>.yaml overlay, picks <name>-test-result.<locale>.json,
|
|
145
|
-
writes <name>-testcases.<locale>.csv / .xlsx
|
|
135
|
+
sungen delivery [names...] # matrix (default; needs the map)
|
|
136
|
+
--check # gates only — validate the map, write nothing
|
|
137
|
+
--approve [DI-a,DI-b] # flip proposed→approved (+ stamp fingerprints); all groups when bare
|
|
138
|
+
--preview # render despite review findings (DRAFT watermark)
|
|
139
|
+
--legacy | --full # classic per-scenario workbook (no map needed)
|
|
140
|
+
--skip-preflight | --continue-on-missing | --env <env> # as before
|
|
146
141
|
```
|
|
142
|
+
|
|
143
|
+
Outputs: `qa/deliverables/<unit>-testcases.xlsx` (Testcases + Coverage sheets) + `.csv`
|
|
144
|
+
(flat, `Level` column `item|variant`). Legacy mode writes the classic files instead.
|
|
@@ -30,7 +30,7 @@ You generate 3 files for sungen — a Gherkin compiler that produces Playwright
|
|
|
30
30
|
| `/sungen:create-data-test <name>` | Generate standardized test-data (valid/boundary/invalid + CHK trace) from the Data Factory catalog; no name = all units (asks to confirm) |
|
|
31
31
|
| `/sungen:review <name>` | Score syntax, coverage, viewpoint quality (auto-detects screen or flow) |
|
|
32
32
|
| `/sungen:run-test <name>` | Generate `selectors.yaml`, compile, run, auto-fix (auto-detects screen or flow) |
|
|
33
|
-
| `/sungen:delivery [name...]` | Export
|
|
33
|
+
| `/sungen:delivery [name...]` | Export the Test Case & Coverage Matrix (review/manual/customer deliverable; `--legacy` = classic CSV; all screens if no arg) |
|
|
34
34
|
| `/sungen:locale <name> <locale>` | Bootstrap i18n for a screen — audit selectors, detect locale switch, generate overlay (run before `/sungen:run-test --env <locale>`) |
|
|
35
35
|
|
|
36
36
|
**Screen path:** add-screen → create-test → review → run-test → delivery.
|
|
@@ -30,7 +30,7 @@ You generate 3 files for sungen — a Gherkin compiler that produces Playwright
|
|
|
30
30
|
| `/sungen-create-data-test <name>` | Generate standardized test-data (valid/boundary/invalid + CHK trace) from the Data Factory catalog; no name = all units (asks to confirm) |
|
|
31
31
|
| `/sungen-review <name>` | Score syntax, coverage, viewpoint quality (auto-detects screen or flow) |
|
|
32
32
|
| `/sungen-run-test <name>` | Generate `selectors.yaml`, compile, run, auto-fix (auto-detects screen or flow) |
|
|
33
|
-
| `/sungen-delivery [name...]` | Export
|
|
33
|
+
| `/sungen-delivery [name...]` | Export the Test Case & Coverage Matrix (review/manual/customer deliverable; `--legacy` = classic CSV; all screens if no arg) |
|
|
34
34
|
| `/sungen-locale <name> <locale>` | Bootstrap i18n for a screen — audit selectors, detect locale switch, generate overlay (run before `/sungen-run-test --env <locale>`) |
|
|
35
35
|
|
|
36
36
|
**Screen path:** add-screen → create-test → review → run-test → delivery.
|
|
@@ -1,21 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sungen-delivery
|
|
3
|
-
description: 'Export
|
|
3
|
+
description: 'Export the Test Case & Coverage Matrix (or the legacy per-scenario CSV) from Gherkin + Playwright results. Auto-loaded by delivery command.'
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
Export test cases from Sungen
|
|
9
|
+
Export test cases from Sungen units to the QA deliverable. Two modes:
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
- **Matrix (default)** — the **Test Case & Coverage Matrix**: one row per *delivery item* (one
|
|
12
|
+
target + one test intent + one oracle family); scenarios / `@cases` rows stay as collapsible
|
|
13
|
+
*coverage variant* sub-rows. Built for review, manual execution, customer hand-off, and
|
|
14
|
+
reporting — no numbered step dumps.
|
|
15
|
+
- **Legacy (`--legacy`/`--full`)** — the classic per-scenario BM-2-901-13 workbook (documented
|
|
16
|
+
in the second half of this skill; unchanged).
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
**This skill delegates all heavy work to the `sungen delivery` CLI.** The CLI is the single source
|
|
19
|
+
of truth for parsing + gating. The AI's only semantic contribution is **proposing the Delivery
|
|
20
|
+
Map** (grouping) — everything else is: invoke the CLI, show output verbatim, help on failures.
|
|
16
21
|
|
|
17
22
|
---
|
|
18
23
|
|
|
24
|
+
## Matrix mode — the Delivery Map
|
|
25
|
+
|
|
26
|
+
`qa/<screens|flows|api>/<unit>/delivery/<unit>.map.yaml` — committed, AI-proposed
|
|
27
|
+
(`review: proposed`), gate-validated, QA-approved (`sungen delivery --approve` stamps scenario
|
|
28
|
+
fingerprints). Schema + grouping rules live in the delivery command instructions; the normative
|
|
29
|
+
spec is `docs/spec/delivery-coverage-matrix-spec.md`.
|
|
30
|
+
|
|
31
|
+
**Gates** (CLI `--check`): A source (VP-ids unique, oracle present, Background setup-only) ·
|
|
32
|
+
B mapping (every scenario in exactly one group XOR one disposition) · C aggregation (mode/layer/
|
|
33
|
+
priority recomputed and equal within a group — heuristic oracle-shape/precondition mismatches are
|
|
34
|
+
review-level, silenced once approved and unchanged) · D executability (precondition · condition+
|
|
35
|
+
data · trigger · oracle all renderable; every `{{var}}` resolves) · E drift (fingerprint mismatch
|
|
36
|
+
→ back to review) · G review state (proposed groups block the official render; `--preview` renders
|
|
37
|
+
a DRAFT watermark).
|
|
38
|
+
|
|
39
|
+
**Workbook**: `Testcases` sheet (parent rows + outline-level-1 variant sub-rows — collapse for the
|
|
40
|
+
customer view, expand to execute; result roll-up failed→blocked→not_run→partial→passed, counts like
|
|
41
|
+
`7/8 Passed · 1 Failed`) + `Coverage` sheet (target × category grid with explicit `—` gaps,
|
|
42
|
+
dispositions, generation manifest). CSV is flat with a `Level` column (`item`/`variant`).
|
|
43
|
+
`delivery_item_count` ≠ progress — variants are the execution metric.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Legacy mode (--legacy / --full)
|
|
48
|
+
|
|
19
49
|
## Architecture
|
|
20
50
|
|
|
21
51
|
```
|
|
@@ -85,7 +115,13 @@ The `.xlsx` leads with an **`Overview`** roll-up sheet, then splits the test cas
|
|
|
85
115
|
- **`Auto`** — automatable test cases (`Auto` + `Not compiled`).
|
|
86
116
|
- **`Manual`** — `@manual` test cases (always present, header-only when there are none).
|
|
87
117
|
|
|
88
|
-
Multi-locale
|
|
118
|
+
Multi-locale: `Overview` + one **`<LOCALE> Auto`** sheet per locale + a single shared **`Manual`** sheet (manual TCs are locale-invariant). The **CSV stays one file with every row** — the `Testcase type` column distinguishes Auto vs Manual. The Overview lists every detail sheet, so each locale's counts appear on its own row.
|
|
119
|
+
|
|
120
|
+
**Which result files become locale sheets — locales are DECLARED, never guessed.** A result-file suffix (`<name>-test-result.<X>.json`) is a locale ONLY when `X` is listed in `qa/capabilities.yaml` `locales:` (written by `/sungen:locale`), or — when delivering with `--env <E>` / `SUNGEN_ENV=<E>` — when `X = <E>-<locale>`. Every delivery mixes results of ONE environment:
|
|
121
|
+
- `sungen delivery login` → base results + bare declared locales (`ja`); `dev`/`stg` suffixes are IGNORED with a hint (`→ sungen delivery login --env dev`)
|
|
122
|
+
- `sungen delivery login --env dev` → `dev` results as base + `dev-ja` sheets; everything else ignored
|
|
123
|
+
- `--env ja` (SUNGEN_ENV=<locale> convention) → that locale's run IS the base, labeled JA
|
|
124
|
+
The base sheet label comes from `base_locale:` (default **EN**). Undeclared env suffixes NEVER fabricate locale sheets — a project without `locales:` always gets one clean `Auto` sheet. Mobile per-OS suffixes (`android`, `ios.ja`, …) are exempt and keep the per-OS files; their Test Data column merges the after-OS tail overlay (`ios.ja` → `<name>.ja.yaml`), matching what the runtime merged.
|
|
89
125
|
|
|
90
126
|
---
|
|
91
127
|
|
|
@@ -94,6 +94,7 @@ needs any of these, it is a **finding for QA** — surface it in the run summary
|
|
|
94
94
|
| `SG-W007` | Browser-alert handler step written AFTER an action — listener registers too late, the dialog auto-dismisses silently | Use the compound form `click [X] button and accept [OK] alert` (preferred), or move the alert step before the trigger |
|
|
95
95
|
| `SG-W008` | `@manual` scenario incomplete in either direction: (a) HAS Gherkin steps but NO `Then` — a dangling `When` is invalid Gherkin, comments can NOT substitute; (b) documentation-style (NO steps) but its comments lack numbered action lines and/or a labeled oracle line — prose paragraphs / rationale-only comments export EMPTY Steps + Expected cells | Two valid shapes only: complete the Gherkin with a `Then`, or write the FULL procedure in the `# Tester verifies:` block as NUMBERED lines — action steps first (`1. <action>`), then labeled `Observable:`/`Oracle:`/`Expected:` lines (the number is what fills Steps, the label is what fills Expected results) |
|
|
96
96
|
| `SG-W009` | test-data references `${QA_<NAME>}` (a SECRET env ref) but the name is declared in neither `.env.qa` nor `.env.qa.example` — the test throws "environment variable not set" the moment the key is used. (Only the `${QA_*}` shape is checked; any other `${...}` is literal data and never flagged.) | Add `QA_<NAME>=<value>` to `.env.qa` (gitignored) and list the NAME in `.env.qa.example` (the committed checklist). See `qa/TEST-DATA-GUIDE.md` |
|
|
97
|
+
| `SG-W010` | A row step's `[Ref]` looks POSITIONAL (`First…`/`Last…`/`Top…`/`nth`) but has no selectors.yaml entry — the label is display-only, so the step checks existence ANYWHERE in the table; an ordering/sort-stability rule would pass even when the row moved | Declare the row in selectors.yaml (a `type: locator` value RELATIVE to the table, e.g. `first contact row:` → `value: 'tbody tr:first-child'`) — the step then asserts `toContainText` on that exact row. This is a selectors.yaml-only fix — allowed inside the run-test auto-fix loop |
|
|
97
98
|
|
|
98
99
|
### Runtime error → `Test data "<key>" references ${QA_*} but the environment variable is not set`
|
|
99
100
|
|
|
@@ -127,6 +127,14 @@ User see [Table] table match data:
|
|
|
127
127
|
|
|
128
128
|
Row scope: `see [Ref] row in [Table] table with {{v}}` enters scope. Subsequent `see [Col] column with {{v}}` checks cell in that row. Use `table match data:` for multi-row verification.
|
|
129
129
|
|
|
130
|
+
**[Ref] of a row step is a display label UNLESS declared in selectors.yaml.** Without an entry the step checks the value exists in ANY row — a name like `[First Contact Row]` does NOT position the row, and an ordering rule would pass even when the row moved (SG-W010 warns on positional-looking undeclared labels). To assert a POSITION, declare the row (a `type: locator` value RELATIVE to the table):
|
|
131
|
+
```yaml
|
|
132
|
+
first contact row:
|
|
133
|
+
type: locator
|
|
134
|
+
value: 'tbody tr:first-child'
|
|
135
|
+
```
|
|
136
|
+
→ compiles to `expect(table.locator('tbody tr:first-child')).toContainText(v)` — the exact row must hold the value — and still enters row scope for `[Col] column` checks.
|
|
137
|
+
|
|
130
138
|
### Database verification (optional Data Driver)
|
|
131
139
|
|
|
132
140
|
Read-only DB-state checks. **Prefer named queries** — SQL lives in `qa/screens/<screen>/database/queries.yaml` (reviewed once, parameterized). Invoke with the `@query:<name>` annotation; it binds the result rows to `{{name}}`, then assert with `expect`:
|
|
@@ -66,7 +66,7 @@ Use these when repairing GATE/DEPTH findings for the hard viewpoints (cart/detai
|
|
|
66
66
|
2. **Stop when** `gateStatus == PASS` AND `findings` empty — or budget exhausted.
|
|
67
67
|
3. **Never fake a pass.** A shallow `see [Cart] page` does not satisfy `cart-correctness`. If a gap is genuinely cross-screen or needs capabilities the DSL lacks (e.g. capture an element value to compare elsewhere), **report it as a residual gap / flow item** instead of forcing a green gate.
|
|
68
68
|
4. **EP/data families are OK.** A `duplicates` cluster with `sameDataLikely=false` is an intentional equivalence-partition family (e.g. many invalid-email cases) — keep it; only collapse `sameDataLikely=true` exact duplicates.
|
|
69
|
-
5. **Advisory findings — surface, don't gate.** `MANUAL-REASON-MISMATCH` → fix the scenario's `@manual:Mx` code (so the planner recommends the right driver) during repair. `CAPABILITY-SUGGESTION` → **present it to the user as a next-step option** (e.g. "N @manual could be automated — `sungen capability add api db`?"), **recommend-only — never auto-install**. Neither fails the gate.
|
|
69
|
+
5. **Advisory findings — surface, don't gate.** `MANUAL-REASON-MISMATCH` → fix the scenario's `@manual:Mx` code (so the planner recommends the right driver) during repair. `CAPABILITY-SUGGESTION` → **present it to the user as a next-step option** (e.g. "N @manual could be automated — `sungen capability add api db`?"), **recommend-only — never auto-install**. `VERIFICATION-OUT-OF-SCOPE (api|db)` → the unit uses `@api`/`@query`/`@requires:api|db` verification the project's recorded **test type** never opted into (E2E/UI-only per `capabilities.yaml`, and the viewpoint doesn't ask for it). During repair: **rewrite the oracle to be UI-observable** (or downgrade the deep check to an `(optional deep check: …)` note); only keep the API/DB verification if the project genuinely tests that layer — then record it (`verification: [ui, api]` / `sungen capability add`). Keep API/DB-in-E2E to the ≤20% band. Neither of these fails the gate.
|
|
70
70
|
|
|
71
71
|
## Discovery / fallback tree (when input is limited)
|
|
72
72
|
|
|
@@ -34,6 +34,14 @@ Take a screen/flow whose `selectors/*.yaml` and `.feature` files were authored a
|
|
|
34
34
|
1. `selectors/<feature>.yaml` — hardcoded `name`/`value` replaced with `{{var}}`
|
|
35
35
|
2. `test-data/<feature>.yaml` — base locale, complete with all new keys
|
|
36
36
|
3. `test-data/<feature>.<locale>.yaml` — overlay with only the keys that change
|
|
37
|
+
4. **`qa/capabilities.yaml` — DECLARE the locale** (required since 3.2.15): append the code to `locales:` and set `base_locale:` (language of the base test-data; tool default is `en`). Delivery/dashboard treat ONLY declared codes as locales — undeclared result-file suffixes are assumed to be ENVIRONMENTS (dev/staging) and excluded from locale sheets:
|
|
38
|
+
```yaml
|
|
39
|
+
platform: web
|
|
40
|
+
enabled: [web]
|
|
41
|
+
base_locale: en # or vi/ja — whatever the base test-data is written in
|
|
42
|
+
locales: [ja] # append every bootstrapped locale here
|
|
43
|
+
```
|
|
44
|
+
Env × locale combos use the compound `SUNGEN_ENV=<env>-<locale>` (e.g. `staging-ja`, overlay `<feature>.staging-ja.yaml`) — the locale segment LAST; delivery recognizes it when the tail matches a declared locale.
|
|
37
45
|
4. (Optional) `selectors/<feature>.yaml` Pages block updated when locale uses URL prefix or query param
|
|
38
46
|
|
|
39
47
|
After this skill finishes, `sungen run-test <name> --env <locale>` Just Works.
|
|
@@ -328,6 +328,7 @@ Security: [S1 – admin only]
|
|
|
328
328
|
Gate (`SG-W008`, both directions): a `@manual` with Gherkin steps but no `Then` fires — comments (even labeled `Oracle:` lines) can NOT substitute for the missing `Then`. A `@manual` with NO steps ALSO fires when its comments lack ≥1 numbered action line + ≥1 labeled `Observable:`/`Oracle:`/`Expected:` line — prose paragraphs and rationale-only comments export EMPTY Steps/Expected cells.
|
|
329
329
|
In shape A the observable/oracle lines MUST carry their **label** (`Observable:` / `Oracle:` / `Expected:`) — the delivery parser extracts Expected results **by label**; unlabeled prose all lands in the Steps column and the Expected cell exports EMPTY. And the numbered action steps MUST precede them — without the actions the tester has an oracle but no procedure.
|
|
330
330
|
**Oracle layer must match the unit** — a screen-unit manual defaults to a **UI oracle**: phrase the expected as what the tester SEES (on-screen message, list/table state after reload). If the business effect IS UI-observable, do NOT cite API responses or DB state as the oracle — "server rejects the request" is verified by *the error message on screen + no new row after reload*, not by reading the API response. Only when the effect has NO UI observation (mail content, stored hash, request count, response-body leak) may the oracle use another layer — then: (a) put the **layer label inside the line**: `Oracle: UI — …` / `Oracle: API — …` / `Oracle: DB — …` so QA knows the tooling needed from the deliverable alone; (b) tag `@manual:M2` so the capability planner recommends the api/db driver; (c) prefer the automation-ready `@requires:api`/`@query` form when the steps are expressible. A deep engineering check may ride along as `(optional deep check: …)` appended to the UI oracle — it must never REPLACE a UI-observable oracle.
|
|
331
|
+
**Respect the project's VERIFICATION SCOPE (the recorded test type).** Read `qa/capabilities.yaml` — the effective scope is `verification:` if set, else derived from `enabled` (`ui` always; `api`/`db` only if that driver is on). If the project is **E2E/UI-only** (no `api`/`db`) **and the test-viewpoint does not ask for API/DB verification**, do **NOT** author `@api`/`@query`/`@requires:api|db` verification — keep the oracle **UI-observable**, or leave the deep check as an `(optional deep check: …)` note. Author API/DB verification only when the scope (or an explicit viewpoint) calls for it, and even then keep the API/DB-in-E2E combination to a **≤20% band** of scenarios (the effects with no UI observation) — never the default. `sungen audit` reports `VERIFICATION-OUT-OF-SCOPE` when a unit uses API/DB verify the project never opted into.
|
|
331
332
|
Use this comment shape:
|
|
332
333
|
```gherkin
|
|
333
334
|
@high @manual
|