@sun-asterisk/sungen 3.2.21-beta.1 → 3.2.21-beta.3

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.
Files changed (40) hide show
  1. package/dist/cli/commands/delivery.d.ts +3 -0
  2. package/dist/cli/commands/delivery.d.ts.map +1 -1
  3. package/dist/cli/commands/delivery.js +8 -0
  4. package/dist/cli/commands/delivery.js.map +1 -1
  5. package/dist/cli/commands/inspect.d.ts +41 -0
  6. package/dist/cli/commands/inspect.d.ts.map +1 -0
  7. package/dist/cli/commands/inspect.js +134 -0
  8. package/dist/cli/commands/inspect.js.map +1 -0
  9. package/dist/cli/index.js +2 -0
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/exporters/matrix/build.d.ts +10 -0
  12. package/dist/exporters/matrix/build.d.ts.map +1 -1
  13. package/dist/exporters/matrix/build.js +38 -0
  14. package/dist/exporters/matrix/build.js.map +1 -1
  15. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  16. package/dist/exporters/matrix/render-xlsx.js +29 -1
  17. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  18. package/dist/exporters/matrix/types.d.ts +8 -0
  19. package/dist/exporters/matrix/types.d.ts.map +1 -1
  20. package/dist/exporters/matrix/types.js.map +1 -1
  21. package/dist/harness/audit.d.ts.map +1 -1
  22. package/dist/harness/audit.js +22 -1
  23. package/dist/harness/audit.js.map +1 -1
  24. package/dist/harness/flow-contract.d.ts +16 -0
  25. package/dist/harness/flow-contract.d.ts.map +1 -1
  26. package/dist/harness/flow-contract.js +26 -2
  27. package/dist/harness/flow-contract.js.map +1 -1
  28. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +10 -0
  29. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +25 -0
  30. package/package.json +3 -3
  31. package/src/cli/commands/delivery.ts +8 -2
  32. package/src/cli/commands/inspect.ts +128 -0
  33. package/src/cli/index.ts +2 -0
  34. package/src/exporters/matrix/build.ts +40 -0
  35. package/src/exporters/matrix/render-xlsx.ts +30 -1
  36. package/src/exporters/matrix/types.ts +8 -0
  37. package/src/harness/audit.ts +22 -1
  38. package/src/harness/flow-contract.ts +34 -2
  39. package/src/orchestrator/templates/ai-src/commands/add-flow.md +10 -0
  40. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +25 -0
@@ -1 +1 @@
1
- {"version":3,"file":"flow-contract.js","sourceRoot":"","sources":["../../src/harness/flow-contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"flow-contract.js","sourceRoot":"","sources":["../../src/harness/flow-contract.ts"],"names":[],"mappings":"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"}
@@ -88,6 +88,11 @@ qa/flows/${input:flow}/
88
88
 
89
89
  ### 1a. Define the flow's BOUNDARY, then its screens
90
90
 
91
+ > QA teams often call this level **System Test** — same thing: one fully-integrated business
92
+ > journey verified against the spec. Use whichever name the team knows; the boundary rules
93
+ > below are the ISTQB system-test design rules.
94
+
95
+
91
96
  A flow is the **smallest complete business action chain**: one clear trigger ending in ONE
92
97
  observable, valuable outcome. Before asking for screens, walk this checklist with the user —
93
98
  if 1, 3 or 8 fails, propose SPLITTING into separate flows:
@@ -127,6 +132,11 @@ outcome:
127
132
  value: "The customer has paid; the shop has a new order"
128
133
  phases: [HP, ER, EH] # journey phases (default); add UI only if the flow owns UI states
129
134
  stateful: cart # the mutated collection, if any — enables regression-depth dims
135
+ golden: true # optional — release-critical: Final Inspection expects @golden scenarios here
136
+ external: # optional — legs owned by another team/vendor (System INTEGRATION Testing)
137
+ - name: payment-gateway
138
+ owner: vendor-x
139
+ screens: [payment] # the flow namespaces that leg passes through
130
140
  ```
131
141
 
132
142
  **A filled contract is an INPUT to generation — never an output.** Like `test-viewpoint.md`,
@@ -603,6 +603,31 @@ error:
603
603
 
604
604
  ## Flow Test Generation
605
605
 
606
+ > **Terminology**: many QA teams call this level **System Test** (ISTQB: verify the fully
607
+ > integrated system against its specified requirements, designed around business
608
+ > processes/use cases). In sungen a *flow* is that system-test suite run through the real UI;
609
+ > its automation then serves as the regression suite on later runs. The names are
610
+ > interchangeable in conversation; the artifacts stay `qa/flows/<name>/`.
611
+
612
+ **Representative, not exhaustive (ISTQB system-test design rule).** A flow case takes ONE
613
+ representative input per branch — one valid value for the main flow, one error value that
614
+ triggers the exception branch and proves the journey recovers. The full equivalence/boundary
615
+ matrix belongs to the OWNING SCREEN (as `@cases` there), never re-run inside the flow: if the
616
+ screen already proved "the field rejects negatives", the flow only proves "the journey survives
617
+ one rejected input". `sungen audit` reports `FLOW-EXHAUSTIVE-INPUTS` when ≥3 same-shape flow
618
+ scenarios differ only in data. **Mocked dependencies**: a flow scenario using `@mock` is
619
+ delivered as *Pass (Mocked)* — verified handling logic, not the real dependency; the delivery's
620
+ External Dependency Tracking table lists it until re-verified real.
621
+
622
+ **Release selection & external legs**: when the contract declares `golden: true`, tag the
623
+ happy-path scenario(s) that prove the outcome with **`@golden`** — that is the set
624
+ `sungen inspect` (Final Inspection, Go/No-Go) runs before a release; `GOLDEN-MISSING` fires
625
+ until it exists, and a @golden scenario that passes only against mocks BLOCKS the release.
626
+ When the contract declares `external:` legs (another team/vendor's system), scenarios touching
627
+ those namespaces are the **System INTEGRATION** group — keep their oracles about the boundary
628
+ (contract/format/handoff), and expect `SIT-MOCK-ONLY` until they are re-verified real.
629
+
630
+
606
631
  > **Auto-detect**: if path is `qa/flows/<name>/` → use this section. Skip Steps 1–4 above.
607
632
 
608
633
  **Read `requirements/flow-contract.yaml` FIRST — it is the flow's boundary and the yardstick
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.2.21-beta.1",
3
+ "version": "3.2.21-beta.3",
4
4
  "description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -39,8 +39,8 @@
39
39
  "@babel/types": "^7.28.5",
40
40
  "@cucumber/gherkin": "^37.0.0",
41
41
  "@cucumber/messages": "^31.0.0",
42
- "@sungen/driver-data-factory": "3.2.21-beta.1",
43
- "@sungen/driver-ui": "3.2.21-beta.1",
42
+ "@sungen/driver-data-factory": "3.2.21-beta.3",
43
+ "@sungen/driver-ui": "3.2.21-beta.3",
44
44
  "chalk": "^5.6.2",
45
45
  "commander": "^14.0.2",
46
46
  "dotenv": "^17.2.3",
@@ -100,7 +100,7 @@ function listFeatureTargets(cwd: string, screen: string, kind: UnitKind): Delive
100
100
  .sort((a, b) => a.featureBaseName.localeCompare(b.featureBaseName));
101
101
  }
102
102
 
103
- function listAllTargets(cwd: string): DeliveryTarget[] {
103
+ export function listAllTargets(cwd: string): DeliveryTarget[] {
104
104
  const targets: DeliveryTarget[] = [];
105
105
  const scan = (kind: UnitKind, skip: (n: string) => boolean = () => false) => {
106
106
  const root = path.join(cwd, 'qa', qaParent(kind));
@@ -629,7 +629,7 @@ async function exportTarget(
629
629
  // Matrix export (Delivery v2 — the default; --legacy keeps the classic workbook)
630
630
  // ----------------------------------------------------------------------------
631
631
 
632
- function matrixPathsFor(cwd: string, target: DeliveryTarget): MatrixTargetPaths {
632
+ export function matrixPathsFor(cwd: string, target: DeliveryTarget): MatrixTargetPaths {
633
633
  const base = qaDir(cwd, target);
634
634
  const genBase = generatedDir(cwd, target);
635
635
  return {
@@ -690,6 +690,12 @@ async function exportMatrixTarget(
690
690
  }
691
691
 
692
692
  log(`${COLOR.bold}${paths.label}${COLOR.reset} — ${model.manifest.itemCount} delivery item(s), ${model.manifest.variantCount} coverage variant(s), state: ${model.manifest.approvalState}`);
693
+ {
694
+ const mocked = model.items.flatMap((it) => it.variants.filter((v) => v.mocked));
695
+ if (mocked.length > 0) {
696
+ log(` ${COLOR.yellow}MOCKED${COLOR.reset}: ${mocked.length} variant(s) verified against mocks (${mocked.slice(0, 4).map((v) => v.ref).join(', ')}${mocked.length > 4 ? ', …' : ''}) — Pass (Mocked) ≠ Pass (Real); see the External Dependency Tracking block on the Coverage sheet.`);
697
+ }
698
+ }
693
699
  if (model.perf) {
694
700
  const p = model.perf;
695
701
  const tone = p.pass ? COLOR.green : COLOR.yellow;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * `sungen inspect` — Final Inspection: the deterministic Go/No-Go view. (#580 P9)
3
+ *
4
+ * The QA practice this implements: ONCE per release, run only the release-critical
5
+ * (@golden) journeys on the real environment with real (masked) data, on FROZEN code,
6
+ * and answer one question — is this build safe to release? Not a place to find new
7
+ * bugs; a place to refuse a release that is not proven.
8
+ *
9
+ * Every ingredient already exists, this command only reads them:
10
+ * - selection : @golden scenarios (tags pass through to Playwright — `--grep @golden`)
11
+ * - results : the units' Playwright JSON runs (same source delivery reads)
12
+ * - freeze : the approved delivery map's fingerprints — Gate E drift = not frozen
13
+ * - honesty : a @golden variant verified against MOCKS blocks GO — Pass (Mocked)
14
+ * says nothing about the real dependency (External Dependency Tracking)
15
+ * - perf : the qa/perf.yaml verdict, when configured
16
+ *
17
+ * Exit code 0 = GO, 2 = NO-GO — CI-usable as a release gate.
18
+ */
19
+ import { Command } from 'commander';
20
+ import * as fs from 'fs';
21
+ import { listAllTargets, matrixPathsFor } from './delivery';
22
+ import { loadMatrixModel } from '../../exporters/matrix/export';
23
+
24
+ export interface UnitInspection {
25
+ unit: string;
26
+ approved: boolean;
27
+ frozen: boolean; // no Gate E drift against the approved fingerprints
28
+ goldenTotal: number;
29
+ goldenPassed: number;
30
+ goldenFailed: number;
31
+ goldenPending: number; // golden variants with no run result yet
32
+ goldenMocked: number; // golden variants verified only against mocks
33
+ perfPass: boolean | null; // null = no budget configured / no samples
34
+ reasons: string[]; // what blocks GO for this unit (empty = clean)
35
+ }
36
+
37
+ export interface ProjectInspection {
38
+ units: UnitInspection[];
39
+ goldenTotal: number;
40
+ verdict: 'GO' | 'NO-GO';
41
+ reasons: string[];
42
+ }
43
+
44
+ /** Pure aggregation over the delivery models — testable without the CLI. */
45
+ export function inspectProject(cwd: string): ProjectInspection {
46
+ const units: UnitInspection[] = [];
47
+ for (const target of listAllTargets(cwd)) {
48
+ const paths = matrixPathsFor(cwd, target);
49
+ if (!fs.existsSync(paths.mapFile)) continue; // no delivery map → not a delivered unit
50
+ const { model } = loadMatrixModel(paths);
51
+ if (!model) continue; // structural map errors surface in delivery
52
+
53
+ const variants = model.items.flatMap((it) => it.variants);
54
+ const golden = variants.filter((v) => v.golden);
55
+ if (golden.length === 0) continue; // Final Inspection reads only the golden set
56
+
57
+ const passed = golden.filter((v) => v.result?.status === 'passed');
58
+ const failed = golden.filter((v) => v.result && ['failed', 'timedOut', 'interrupted'].includes(v.result.status));
59
+ const pending = golden.filter((v) => !v.result);
60
+ const mocked = golden.filter((v) => v.mocked);
61
+ const approved = model.manifest.approvalState === 'approved';
62
+ const frozen = !model.findings.some((f) => f.gate === 'E');
63
+ const perfPass = model.perf ? model.perf.pass : null;
64
+
65
+ const reasons: string[] = [];
66
+ if (!approved) reasons.push('delivery map not approved');
67
+ if (!frozen) reasons.push('sources drifted since approval (not frozen — Gate E)');
68
+ if (failed.length) reasons.push(`${failed.length} golden variant(s) FAILED`);
69
+ if (pending.length) reasons.push(`${pending.length} golden variant(s) have no run result`);
70
+ if (mocked.length) reasons.push(`${mocked.length} golden variant(s) are mock-verified — Pass (Mocked) cannot release`);
71
+ if (perfPass === false) reasons.push('performance budget OVER (qa/perf.yaml)');
72
+
73
+ units.push({
74
+ unit: paths.label ?? target.name,
75
+ approved, frozen,
76
+ goldenTotal: golden.length,
77
+ goldenPassed: passed.length,
78
+ goldenFailed: failed.length,
79
+ goldenPending: pending.length,
80
+ goldenMocked: mocked.length,
81
+ perfPass,
82
+ reasons,
83
+ });
84
+ }
85
+
86
+ const goldenTotal = units.reduce((n, u) => n + u.goldenTotal, 0);
87
+ const reasons = units.flatMap((u) => u.reasons.map((r) => `${u.unit}: ${r}`));
88
+ if (goldenTotal === 0) reasons.push('no @golden scenario anywhere — nothing proves the release (tag the release-critical journeys)');
89
+ return { units, goldenTotal, verdict: reasons.length === 0 ? 'GO' : 'NO-GO', reasons };
90
+ }
91
+
92
+ export function registerInspectCommand(program: Command): void {
93
+ program
94
+ .command('inspect')
95
+ .description('Final Inspection: Go/No-Go over the @golden set — results, freeze, mocks, perf (exit 2 = NO-GO)')
96
+ .option('--json', 'Output the raw JSON report')
97
+ .action((options) => {
98
+ try {
99
+ const report = inspectProject(process.cwd());
100
+ if (options.json) {
101
+ console.log(JSON.stringify(report, null, 2));
102
+ } else {
103
+ const L = console.log;
104
+ L('');
105
+ L(`━━━ Final Inspection — ${report.goldenTotal} @golden variant(s) across ${report.units.length} unit(s) ━━━`);
106
+ L('');
107
+ for (const u of report.units) {
108
+ const ok = u.reasons.length === 0;
109
+ L(` ${ok ? '✓' : '✗'} ${u.unit} — golden ${u.goldenPassed}/${u.goldenTotal} passed` +
110
+ `${u.goldenMocked ? ` · ${u.goldenMocked} mocked` : ''}` +
111
+ `${u.perfPass === null ? '' : u.perfPass ? ' · perf PASS' : ' · perf OVER'}` +
112
+ ` · ${u.approved ? 'approved' : 'NOT approved'} · ${u.frozen ? 'frozen' : 'DRIFTED'}`);
113
+ for (const r of u.reasons) L(` • ${r}`);
114
+ }
115
+ L('');
116
+ L(` Verdict: ${report.verdict === 'GO' ? '✅ GO' : '⛔ NO-GO'}`);
117
+ for (const r of report.units.length === 0 ? report.reasons : (report.verdict === 'NO-GO' ? report.reasons.slice(0, 12) : [])) {
118
+ L(` • ${r}`);
119
+ }
120
+ L('');
121
+ }
122
+ if (report.verdict !== 'GO') process.exitCode = 2;
123
+ } catch (error) {
124
+ console.error('Error:', error instanceof Error ? error.message : error);
125
+ process.exit(1);
126
+ }
127
+ });
128
+ }
package/src/cli/index.ts CHANGED
@@ -15,6 +15,7 @@ import { registerFigmaCommand } from './commands/figma';
15
15
  import { registerAddFlowCommand } from './commands/add-flow';
16
16
  import { registerDashboardCommand } from './commands/dashboard';
17
17
  import { registerAuditCommand } from './commands/audit';
18
+ import { registerInspectCommand } from './commands/inspect';
18
19
  import { registerDepthLintCommand } from './commands/depth-lint';
19
20
  import { registerJourneyCommand } from './commands/journey';
20
21
  import { registerGateCommand } from './commands/gate';
@@ -63,6 +64,7 @@ async function main() {
63
64
  registerAddFlowCommand(program);
64
65
  registerDashboardCommand(program);
65
66
  registerAuditCommand(program);
67
+ registerInspectCommand(program);
66
68
  registerDepthLintCommand(program);
67
69
  registerJourneyCommand(program);
68
70
  registerGateCommand(program);
@@ -32,6 +32,8 @@ import {
32
32
  MAX_VARIANTS_PER_ITEM,
33
33
  } from './types';
34
34
  import { runGates } from './gates';
35
+ import { capabilityRegistry } from '../../capabilities/registry';
36
+ import { discoverAndRegisterCapabilities } from '../../capabilities/discover';
35
37
 
36
38
  // ---------------------------------------------------------------------------
37
39
  // Variant derivation
@@ -42,6 +44,27 @@ function normalizeShape(text: string): string {
42
44
  return text.replace(/\{\{[^}]*\}\}/g, '{{*}}').replace(/\s+/g, ' ').trim();
43
45
  }
44
46
 
47
+ /**
48
+ * Is this scenario verified against MOCKED responses, and against which named deps? (#580)
49
+ * The mock capability owns its grammar: prefer the registry's `annotations` + `detectsStep`
50
+ * (driver-mock exports isMockStep — install AND call-count forms); fall back to literal
51
+ * twins of that grammar when the driver is not installed on this machine.
52
+ */
53
+ export function detectMocked(tags: string[], stepTexts: string[]): { mocked: boolean; mockDeps: string[] } {
54
+ discoverAndRegisterCapabilities();
55
+ const cap = capabilityRegistry.get('mock');
56
+ const tagForms = cap?.annotations ?? ['@mock', '@network'];
57
+ const tagged = tags.some((t) => tagForms.some((a) => t === a || t.startsWith(`${a}:`)));
58
+ const isMockStep = cap?.detectsStep ?? ((t: string) =>
59
+ /\[[^\]]+\]\s+mock\s+is\s+active\b/i.test(t) ||
60
+ /\[[^\]]+\]\s+mock\s+called\s+(?:\{\{[^}]+\}\}|\d+)\s+times?\b/i.test(t));
61
+ const mockDeps = Array.from(new Set(stepTexts
62
+ .filter((t) => isMockStep(t))
63
+ .map((t) => (t.match(/\[([^\]]+)\]\s+mock\b/i) || [])[1])
64
+ .filter((x): x is string => Boolean(x))));
65
+ return { mocked: tagged || mockDeps.length > 0, mockDeps };
66
+ }
67
+
45
68
  function deriveLayers(tags: string[]): MatrixLayer[] {
46
69
  const layers = new Set<MatrixLayer>(['ui']);
47
70
  if (tags.some((t) => t === '@api' || t.startsWith('@api:') || t === '@requires:api')) layers.add('api');
@@ -178,12 +201,29 @@ export function deriveVariants(inputs: Pick<BuildInputs, 'feature' | 'merged' |
178
201
  ...(apiCallsAreTrigger ? [] : apiRequestLines),
179
202
  ]));
180
203
 
204
+ // Mocked-run detection (#580): a pass against a scripted response must never read as a
205
+ // pass against the real dependency. The GRAMMAR authority is the mock capability itself
206
+ // (driver-mock declares `annotations` and exports `detectsStep`) — consult it instead of
207
+ // re-writing its regexes here, so new tag/step forms are picked up automatically. The
208
+ // literal fallback keeps delivery honest on machines WITHOUT the driver installed
209
+ // (delivery reads only feature text + results, it never compiles). Background steps are
210
+ // scanned too — a Background install mocks every scenario in the feature, and the
211
+ // driver's own spec warns that per-scenario tracking misses them.
212
+ const scenarioStepTexts = [
213
+ ...inputs.feature.backgroundOrderedSteps.map((st) => st.text),
214
+ ...m.feature.orderedSteps.map((st) => st.text),
215
+ ];
216
+ const { mocked, mockDeps } = detectMocked(tags, scenarioStepTexts);
217
+
181
218
  const base = {
182
219
  vpId,
183
220
  vpCategory,
184
221
  priority: extractPriority(tags),
185
222
  mode: mode as 'auto' | 'manual',
186
223
  manualReason: manualReason(tags),
224
+ mocked,
225
+ ...(mockDeps.length ? { mockDeps } : {}),
226
+ golden: tags.includes('@golden'),
187
227
  layers: deriveLayers(tags),
188
228
  traces: tags.filter((t) => t.startsWith('@spec:')).map((t) => t.slice('@spec:'.length)),
189
229
  runtimeVars: [...runtimeVars],
@@ -224,7 +224,7 @@ function addMatrixSheet(wb: ExcelJS.Workbook, model: MatrixModel, sungenVersion?
224
224
  // parent's steps + these read as one continuous procedure.
225
225
  numbered(item.triggerDeltas[v.ref] ?? [], item.trigger.length + 1),
226
226
  expectedWithVerification(v.oracle, v.verification),
227
- v.mode === 'manual' ? `Manual${v.manualReason ? ` (${v.manualReason})` : ''}` : 'Auto',
227
+ v.mode === 'manual' ? `Manual${v.manualReason ? ` (${v.manualReason})` : ''}` : (v.mocked ? 'Auto · Mocked' : 'Auto'),
228
228
  v.traces.join(', '),
229
229
  variantState(v),
230
230
  isoDate(v.result?.startTime),
@@ -330,6 +330,35 @@ function addCoverageSheet(wb: ExcelJS.Workbook, model: MatrixModel, sungenVersio
330
330
  rowIdx += 2;
331
331
  }
332
332
 
333
+ // --- External Dependency Tracking (#580, ISTQB system-test practice): every case that
334
+ // ran against a MOCK is listed centrally. Its Result stays in the canonical vocabulary
335
+ // (the roll-up formulas depend on it); THIS table is where "Pass (Mocked) ≠ Pass (Real)"
336
+ // is visible — a case verified only against mocks is not Done until re-verified real.
337
+ {
338
+ const mockedVars = model.items.flatMap((it) => it.variants.filter((v) => v.mocked).map((v) => ({ it, v })));
339
+ if (mockedVars.length > 0) {
340
+ dataCell(ws.getRow(rowIdx).getCell(2), 'External Dependency Tracking — mock-verified cases (Pass here = Pass (Mocked), not Pass (Real))', { bold: true });
341
+ rowIdx++;
342
+ const hd = ws.getRow(rowIdx);
343
+ dataCell(hd.getCell(2), 'Variant');
344
+ dataCell(hd.getCell(3), 'Mocked dependency');
345
+ dataCell(hd.getCell(4), 'Delivery item');
346
+ dataCell(hd.getCell(5), 'Result');
347
+ dataCell(hd.getCell(8), 'Real-environment re-verify');
348
+ rowIdx++;
349
+ for (const { it, v } of mockedVars) {
350
+ const r = ws.getRow(rowIdx);
351
+ dataCell(r.getCell(2), v.ref);
352
+ dataCell(r.getCell(3), (v.mockDeps ?? []).join(', ') || '(scenario-level @mock)');
353
+ dataCell(r.getCell(4), it.id);
354
+ dataCell(r.getCell(5), variantState(v));
355
+ dataCell(r.getCell(8), '');
356
+ rowIdx++;
357
+ }
358
+ rowIdx++;
359
+ }
360
+ }
361
+
333
362
  // --- Requirement coverage (review §6): every requirement id gets ONE explicit status.
334
363
  if (model.requirements.length > 0) {
335
364
  dataCell(ws.getRow(rowIdx).getCell(2), 'Requirement coverage — every id has an explicit status', { bold: true });
@@ -92,6 +92,14 @@ export interface CoverageVariant {
92
92
  /** 'auto' | 'manual'; manual keeps its @manual:Mx reason. */
93
93
  mode: 'auto' | 'manual';
94
94
  manualReason?: string;
95
+ /** The scenario runs against MOCKED network responses (@mock / `[x] mock is active`) —
96
+ * a pass verifies the handling logic, not the real dependency (Pass (Mocked) ≠ Pass (Real),
97
+ * #580: ISTQB external-dependency tracking). */
98
+ mocked?: boolean;
99
+ /** Named mocked dependencies (`[name] mock is active` refs), for the tracking table. */
100
+ mockDeps?: string[];
101
+ /** Release-critical: tagged @golden — the Final Inspection set (`sungen inspect`, #580 P9). */
102
+ golden?: boolean;
95
103
  layers: MatrixLayer[];
96
104
  /** @spec:* requirement traces. */
97
105
  traces: string[];
@@ -169,7 +169,7 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
169
169
  const isUiFlowUnit = /^flows\//.test(catalogScreenName);
170
170
  const flowQ: FlowQualityResult = isUiFlowUnit
171
171
  ? flowQuality(screenDir, scenarios)
172
- : { hasContract: false, errors: [], outcomeProven: false, outcomeManualOnly: false, offGoal: [], offGoalRatio: 0, offGoalCategories: [], phases: [], phaseRatio: 1, handoffs: { total: 0, asserted: 0, ratio: 1 } };
172
+ : { hasContract: false, errors: [], outcomeProven: false, outcomeManualOnly: false, offGoal: [], offGoalRatio: 0, offGoalCategories: [], phases: [], phaseRatio: 1, handoffs: { total: 0, asserted: 0, ratio: 1 }, sit: [] };
173
173
  const gateCatalog = (flowQ.hasContract && !declaredPageType(viewpointText, catalog))
174
174
  ? { ...catalog, page_types: {} } as Catalog
175
175
  : catalog;
@@ -351,6 +351,15 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
351
351
  for (const ph of flowQ.phases.filter((p) => !p.covered || !p.automated)) {
352
352
  findings.push(`FLOW-PHASE-${ph.phase}-MISSING: journey phase ${ph.phase} (${ph.phase === 'HP' ? 'happy path proving the outcome' : ph.phase === 'ER' ? 'error recovery — validation must not trap the journey' : 'guards — direct access / back / refresh'}) is ${ph.covered ? 'covered only by @manual' : 'not covered'} → it does not count toward flowCoverage until automated.`);
353
353
  }
354
+ // #580 P10 — the QA matrix keeps System INTEGRATION cases (external-system legs)
355
+ // separate, and holds their exit criteria open while they are mock-verified only.
356
+ for (const x of flowQ.sit.filter((v) => v.mockOnly).slice(0, 4)) {
357
+ findings.push(`SIT-MOCK-ONLY: "${x.name}" touches the external system "${x.external}" but is verified only against mocks — Pass (Mocked) says nothing about the real vendor behaviour. Re-verify on the real dependency before calling it Done (the delivery's External Dependency Tracking table holds the checklist).`);
358
+ }
359
+ // #580 P9 — a release-critical flow must carry its Final-Inspection selection.
360
+ if (flowQ.contract!.golden && !/@golden\b/i.test(featureText)) {
361
+ findings.push(`GOLDEN-MISSING: the contract declares \`golden: true\` (release-critical) but no scenario is tagged @golden — Final Inspection (\`sungen inspect\`) will have nothing to run for this flow. Tag the happy-path scenario(s) that prove the outcome.`);
362
+ }
354
363
  if (flowQ.handoffs.total > 0 && flowQ.handoffs.ratio < 0.7) {
355
364
  findings.push(`FLOW-HANDOFF-SHALLOW: only ${flowQ.handoffs.asserted}/${flowQ.handoffs.total} cross-screen transitions are followed by an assertion in the new screen — carried state (the thing a flow exists to verify) is unproven at the handoff. businessDepth is capped until asserted.`);
356
365
  }
@@ -500,6 +509,18 @@ export function runAudit(screenDir: string, screenName: string): AuditReport {
500
509
  for (const d of ownership.duplicates.slice(0, 6)) {
501
510
  findings.push(`DUPLICATE-FLOW-OWNERSHIP: "${d.scenario}" has the same shape as a scenario in flow "${d.flow}" — keep one owner (screen-local vs flow); the other should only reference/set up.`);
502
511
  }
512
+ // #580 — the flow→screen half of the ownership rule (ISTQB system-test design:
513
+ // representative, not exhaustive). A flow's cases take ONE representative input per
514
+ // branch — one valid value on the main flow, one error value that triggers the
515
+ // exception flow. An EP/data-family cluster (≥3 same-shape scenarios differing only
516
+ // in data) inside a FLOW is the screen's validation matrix being re-run where it
517
+ // does not belong: the screen already proved the field rejects each class; the flow
518
+ // only has to prove the journey survives one of them. Advisory — never a gate.
519
+ if (isUiFlow) {
520
+ for (const c of duplicates.clusters.filter((x) => !x.sameDataLikely && x.scenarios.length >= 3).slice(0, 4)) {
521
+ findings.push(`FLOW-EXHAUSTIVE-INPUTS: ${c.scenarios.length} same-shape scenarios differ only in data (${c.scenarios.slice(0, 3).join(' | ')}${c.scenarios.length > 3 ? ' …' : ''}) — a system-test flow uses REPRESENTATIVE inputs (one valid + one that triggers the exception branch); the full EP/boundary matrix belongs to the owning screen (or a @cases dataset there). Keep one representative per branch here.`);
522
+ }
523
+ }
503
524
  for (const u of unsourced.slice(0, 6)) {
504
525
  findings.push(`UNSOURCEABLE-SCENARIO: "${u}" doesn't trace to any FR / viewpoint item — link it to a source, or tag it @exploration (not part of the official suite).`);
505
526
  }
@@ -40,6 +40,11 @@ export interface FlowContract {
40
40
  /** The mutated collection (cart, order, application …) — enables regression dims. */
41
41
  stateful?: string;
42
42
  budgets?: Record<string, number>;
43
+ /** External-system legs (owned by another team/vendor) — ISTQB System INTEGRATION Testing
44
+ * scope (#580 P10). Scenarios touching these namespaces are classified SIT. */
45
+ external?: Array<{ name: string; owner?: string; screens: string[] }>;
46
+ /** This flow is release-critical: Final Inspection expects a @golden scenario here (P9). */
47
+ golden?: boolean;
43
48
  }
44
49
 
45
50
  export interface FlowQualityResult {
@@ -60,6 +65,9 @@ export interface FlowQualityResult {
60
65
  phaseRatio: number;
61
66
  /** Cross-namespace transitions followed by an assertion / all transitions. */
62
67
  handoffs: { total: number; asserted: number; ratio: number };
68
+ /** ISTQB SIT classification (#580 P10): scenarios whose steps touch an external-system
69
+ * namespace declared in the contract's `external:` block. */
70
+ sit: Array<{ name: string; external: string; mockOnly: boolean }>;
63
71
  }
64
72
 
65
73
  const DEFAULT_PHASES = ['HP', 'ER', 'EH'];
@@ -100,6 +108,16 @@ export function loadFlowContract(unitDir: string): { contract: FlowContract | nu
100
108
  phases,
101
109
  stateful: raw.stateful !== undefined ? String(raw.stateful).toLowerCase() : undefined,
102
110
  budgets: (raw.budgets && typeof raw.budgets === 'object') ? raw.budgets as Record<string, number> : undefined,
111
+ external: Array.isArray(raw.external)
112
+ ? (raw.external as Array<Record<string, unknown>>)
113
+ .filter((e) => e && typeof e === 'object' && e.name)
114
+ .map((e) => ({
115
+ name: String(e.name),
116
+ owner: e.owner !== undefined ? String(e.owner) : undefined,
117
+ screens: Array.isArray(e.screens) ? (e.screens as unknown[]).map((x) => String(x).toLowerCase()) : [],
118
+ }))
119
+ : undefined,
120
+ golden: raw.golden === true,
103
121
  },
104
122
  errors: [],
105
123
  };
@@ -139,7 +157,7 @@ export function flowQuality(unitDir: string, scenarios: ScenarioInfo[]): FlowQua
139
157
  const neutral: FlowQualityResult = {
140
158
  hasContract: false, errors, outcomeProven: false, outcomeManualOnly: false,
141
159
  offGoal: [], offGoalRatio: 0, offGoalCategories: [],
142
- phases: [], phaseRatio: 1, handoffs: { total: 0, asserted: 0, ratio: 1 },
160
+ phases: [], phaseRatio: 1, handoffs: { total: 0, asserted: 0, ratio: 1 }, sit: [],
143
161
  };
144
162
  if (!contract) return neutral;
145
163
 
@@ -202,12 +220,26 @@ export function flowQuality(unitDir: string, scenarios: ScenarioInfo[]): FlowQua
202
220
  }
203
221
  const handoffs = { total, asserted, ratio: total ? asserted / total : 1 };
204
222
 
223
+ // --- SIT classification (#580 P10): a scenario whose steps touch an external-system
224
+ // namespace belongs to the System INTEGRATION group the QA matrix keeps separate. When
225
+ // that scenario is also verified only against mocks, its pass says nothing about the
226
+ // real vendor behaviour — the exit criteria the QA doc holds open (Pass (Mocked)).
227
+ const MOCK_STEP = /\[[^\]]+\]\s+mock\s+(?:is\s+active|called)\b/i;
228
+ const sit: FlowQualityResult['sit'] = [];
229
+ for (const leg of contract.external ?? []) {
230
+ const legScreens = new Set(leg.screens);
231
+ for (const s of scenarios) {
232
+ if (!namespacesInOrder(s).some((ns) => legScreens.has(ns))) continue;
233
+ sit.push({ name: s.name.slice(0, 80), external: leg.name, mockOnly: MOCK_STEP.test(s.stepsText) });
234
+ }
235
+ }
236
+
205
237
  return {
206
238
  hasContract: true, contract, errors: [],
207
239
  outcomeProven, outcomeManualOnly,
208
240
  offGoal: offGoalScenarios.map((s) => s.name.slice(0, 80)),
209
241
  offGoalRatio, offGoalCategories,
210
- phases, phaseRatio, handoffs,
242
+ phases, phaseRatio, handoffs, sit,
211
243
  };
212
244
  }
213
245
 
@@ -88,6 +88,11 @@ qa/flows/${input:flow}/
88
88
 
89
89
  ### 1a. Define the flow's BOUNDARY, then its screens
90
90
 
91
+ > QA teams often call this level **System Test** — same thing: one fully-integrated business
92
+ > journey verified against the spec. Use whichever name the team knows; the boundary rules
93
+ > below are the ISTQB system-test design rules.
94
+
95
+
91
96
  A flow is the **smallest complete business action chain**: one clear trigger ending in ONE
92
97
  observable, valuable outcome. Before asking for screens, walk this checklist with the user —
93
98
  if 1, 3 or 8 fails, propose SPLITTING into separate flows:
@@ -127,6 +132,11 @@ outcome:
127
132
  value: "The customer has paid; the shop has a new order"
128
133
  phases: [HP, ER, EH] # journey phases (default); add UI only if the flow owns UI states
129
134
  stateful: cart # the mutated collection, if any — enables regression-depth dims
135
+ golden: true # optional — release-critical: Final Inspection expects @golden scenarios here
136
+ external: # optional — legs owned by another team/vendor (System INTEGRATION Testing)
137
+ - name: payment-gateway
138
+ owner: vendor-x
139
+ screens: [payment] # the flow namespaces that leg passes through
130
140
  ```
131
141
 
132
142
  **A filled contract is an INPUT to generation — never an output.** Like `test-viewpoint.md`,
@@ -603,6 +603,31 @@ error:
603
603
 
604
604
  ## Flow Test Generation
605
605
 
606
+ > **Terminology**: many QA teams call this level **System Test** (ISTQB: verify the fully
607
+ > integrated system against its specified requirements, designed around business
608
+ > processes/use cases). In sungen a *flow* is that system-test suite run through the real UI;
609
+ > its automation then serves as the regression suite on later runs. The names are
610
+ > interchangeable in conversation; the artifacts stay `qa/flows/<name>/`.
611
+
612
+ **Representative, not exhaustive (ISTQB system-test design rule).** A flow case takes ONE
613
+ representative input per branch — one valid value for the main flow, one error value that
614
+ triggers the exception branch and proves the journey recovers. The full equivalence/boundary
615
+ matrix belongs to the OWNING SCREEN (as `@cases` there), never re-run inside the flow: if the
616
+ screen already proved "the field rejects negatives", the flow only proves "the journey survives
617
+ one rejected input". `sungen audit` reports `FLOW-EXHAUSTIVE-INPUTS` when ≥3 same-shape flow
618
+ scenarios differ only in data. **Mocked dependencies**: a flow scenario using `@mock` is
619
+ delivered as *Pass (Mocked)* — verified handling logic, not the real dependency; the delivery's
620
+ External Dependency Tracking table lists it until re-verified real.
621
+
622
+ **Release selection & external legs**: when the contract declares `golden: true`, tag the
623
+ happy-path scenario(s) that prove the outcome with **`@golden`** — that is the set
624
+ `sungen inspect` (Final Inspection, Go/No-Go) runs before a release; `GOLDEN-MISSING` fires
625
+ until it exists, and a @golden scenario that passes only against mocks BLOCKS the release.
626
+ When the contract declares `external:` legs (another team/vendor's system), scenarios touching
627
+ those namespaces are the **System INTEGRATION** group — keep their oracles about the boundary
628
+ (contract/format/handoff), and expect `SIT-MOCK-ONLY` until they are re-verified real.
629
+
630
+
606
631
  > **Auto-detect**: if path is `qa/flows/<name>/` → use this section. Skip Steps 1–4 above.
607
632
 
608
633
  **Read `requirements/flow-contract.yaml` FIRST — it is the flow's boundary and the yardstick