@sun-asterisk/sungen 3.2.2-beta.13 → 3.2.2-beta.17

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 (47) hide show
  1. package/dist/cli/commands/journey.d.ts.map +1 -1
  2. package/dist/cli/commands/journey.js +19 -1
  3. package/dist/cli/commands/journey.js.map +1 -1
  4. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  5. package/dist/generators/test-generator/code-generator.js +10 -6
  6. package/dist/generators/test-generator/code-generator.js.map +1 -1
  7. package/dist/harness/audit.d.ts.map +1 -1
  8. package/dist/harness/audit.js +7 -0
  9. package/dist/harness/audit.js.map +1 -1
  10. package/dist/harness/journey.d.ts +20 -0
  11. package/dist/harness/journey.d.ts.map +1 -1
  12. package/dist/harness/journey.js +75 -0
  13. package/dist/harness/journey.js.map +1 -1
  14. package/dist/harness/quality-gates.d.ts +13 -0
  15. package/dist/harness/quality-gates.d.ts.map +1 -1
  16. package/dist/harness/quality-gates.js +23 -0
  17. package/dist/harness/quality-gates.js.map +1 -1
  18. package/dist/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +12 -0
  19. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +12 -1
  20. package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +1 -1
  21. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +1 -0
  22. package/dist/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +6 -3
  23. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +11 -7
  24. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +3 -1
  25. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +1 -1
  26. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +1 -0
  27. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +6 -3
  28. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +11 -7
  29. package/dist/orchestrator/templates/playwright.config.ts +7 -4
  30. package/package.json +3 -3
  31. package/src/cli/commands/journey.ts +15 -2
  32. package/src/generators/test-generator/code-generator.ts +10 -6
  33. package/src/harness/audit.ts +8 -1
  34. package/src/harness/journey.ts +89 -0
  35. package/src/harness/quality-gates.ts +20 -0
  36. package/src/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +12 -0
  37. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +12 -1
  38. package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +1 -1
  39. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +1 -0
  40. package/src/orchestrator/templates/ai-instructions/claude-skill-error-mapping.md +6 -3
  41. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +11 -7
  42. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +3 -1
  43. package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +1 -1
  44. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +1 -0
  45. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-error-mapping.md +6 -3
  46. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +11 -7
  47. package/src/orchestrator/templates/playwright.config.ts +7 -4
@@ -42,6 +42,26 @@ export function isolationRisk(featureText: string, stateful: boolean): boolean {
42
42
  return !/@cleanup:cart\b|@isolate\b|empty cart|fresh (?:browser )?context|new context/i.test(featureText);
43
43
  }
44
44
 
45
+ /**
46
+ * #414 — the complement of isolationRisk. Per-scenario isolation is the DEFAULT now, so untagged
47
+ * suites can't cascade. `@serial` opts INTO a shared-page `test.describe.serial` suite, whose
48
+ * Playwright semantics SKIP every test after the first failure. That is correct ONLY for a genuinely
49
+ * stateful ordered sequence; for INDEPENDENT scenarios — each re-establishing its own start state via
50
+ * a navigating Background — `@serial` buys no correctness, only a cascade that *masks* failures (one
51
+ * early red turns the rest into greens-by-omission). Returns the scenario count when `@serial` should
52
+ * be dropped (the default isolation is safer), else 0.
53
+ *
54
+ * Conservative on purpose — only fires on `@serial` suites whose every scenario provably restarts (a
55
+ * `Background` that navigates `on [..] page`), so a real stateful sequence keeps its `@serial`.
56
+ */
57
+ export function serialCascadeRisk(featureText: string, scenarioCount: number): number {
58
+ if (!/@serial\b/i.test(featureText)) return 0; // isolated by default → no cascade
59
+ if (scenarioCount < 8) return 0; // small blast radius — not worth the churn
60
+ const navBackground = /Background:[\s\S]*?\bon \[[^\]]+\] page\b/i.test(featureText);
61
+ if (!navBackground) return 0; // no per-scenario reset → genuinely stateful; @serial is right
62
+ return scenarioCount;
63
+ }
64
+
45
65
  export function downstreamScope(specText: string, scenarios: ScenarioInfo[]): DownstreamResult {
46
66
  const routes = downstreamRoutes(specText);
47
67
  const underCovered: { route: string; slug: string }[] = [];
@@ -26,6 +26,18 @@ You are an **independent Senior QA Reviewer**. You did **not** write these tests
26
26
  - **Idempotency uses the DB oracle.** A "no double-charge / exactly once" claim is proven by `@concurrent` + a `@query` count, not HTTP status alone (status can lie under a race).
27
27
  - **Auth negatives** exist for protected mutations (401/403), not just the happy path.
28
28
 
29
+ ## Lens mode (parallel review — #410)
30
+
31
+ If the invoking prompt contains a line `LENS: <name>`, review **only that lens** and go *deeper* on it — ignore the other lenses' items (a sibling agent owns each). Diversity beats one blurred pass: each lens is a distinct failure mode, and a focused reviewer catches what a do-everything pass skims. The lenses map to the checks above:
32
+
33
+ - `LENS: correctness` → items **1** (title ↔ steps proof; negative / "does-not-happen" contrast) + **2** (observable, non-tautological `Then`).
34
+ - `LENS: depth` → item **3** (business-critical scenarios assert DATA, not visibility/nav).
35
+ - `LENS: manual` → item **4** (`@manual` genuinely unautomatable; flag `MANUAL-AUTOMATABLE` / cross-screen-should-be-a-flow).
36
+ - `LENS: traceability` → item **5** (meaning-level duplicates, missing criticals, `VP-` ids aligned to the viewpoint-overview).
37
+ - `LENS: api` → item **6** (API-only units: prove-the-effect, error matrix, self-clean flows, idempotency via DB oracle, auth negatives).
38
+
39
+ With **no** `LENS:` line, review **all** lenses in one pass (the single-agent / Copilot fallback). The output format is identical either way; the orchestrator dedupes the merged issues by `[scenario id]` + problem.
40
+
29
41
  ## Output (do NOT edit any file)
30
42
  Return a concise verdict:
31
43
 
@@ -32,6 +32,17 @@ Parse **name** from `$ARGUMENTS`. If missing, ask the user.
32
32
 
33
33
  **Auto-detect context**: check if `qa/api/<name>/` or `qa/api/flows/<name>/` exists → **API unit mode** (below). Else if `qa/flows/<name>/` → flow mode. Else `qa/screens/<name>/` → screen mode. This determines paths, generation strategy, and CLI commands.
34
34
 
35
+ ## Multi-unit fan-out (`--all` or several names)
36
+
37
+ If `$ARGUMENTS` is `--all` (or lists several units), generate them **concurrently** — generation parallelises across independent units, but **human review stays serial** (you can't judge N boards at once).
38
+
39
+ 1. **Discover + dedup.** List units with `sungen journey --all` (screens + flows + api). Skip units already `✅ signed off`; target the rest.
40
+ 2. **Budget the fan-out.** `N = clamp(unit_count, 1, min(16, cores-2))`, and scale per-unit depth to context budget (S4): on a tight (~200k) budget run fewer at once / Tier-1 only. The orchestrator holds only the **roll-up summary**, never each unit's full sources.
41
+ 3. **Fan out — one sub-agent per unit.** Spawn the **`sungen-generator`**-style flow per unit via the Task tool (`subagent_type: sungen-discovery` for reading, then generate), each running the **full per-unit loop in isolation** (steps 1-6 below: discover → generate → depth-lint → audit → gate). Each agent sees only its unit's slice and returns a one-line status (unit · gate · score · review-queue count). **Copilot has no sub-agents → do the units sequentially**, same output.
42
+ 4. **Roll up + review serially.** Run `sungen journey --all` and present the table. Then walk the user through the units **one at a time** in the board's order (open-obligations first), presenting each unit's own `sungen journey --screen <unit>` review queue, until each is signed off. Never batch sign-offs.
43
+
44
+ (For a single unit, ignore this section and follow the steps below.)
45
+
35
46
  ## API unit mode (driver-api)
36
47
 
37
48
  If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps below: `sungen context --area <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --area <name>` gate + the `sungen-reviewer` sub-agent + repair loop to businessDepth ≥ 0.7** → record + trace. Then jump to the "Converge" next-step options (recommend `/sungen:run-test <name>`). The capture / viewpoint-group / selector steps do **not** apply.
@@ -104,7 +115,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
104
115
 
105
116
  5.5. **Quality gate & repair (harness — always run, do NOT skip).** Follow the `sungen-harness-audit` skill:
106
117
  - Run `sungen audit --screen <name>` (Bash) and read `gateStatus` + `findings` (deterministic, structural).
107
- - **Independent semantic review.** **Claude Code:** spawn the **`sungen-reviewer`** sub-agent (Task tool, `subagent_type: sungen-reviewer`) it judges what the gate can't (does each scenario's steps PROVE its title/viewpoint, observable Thens, business-critical assertion depth) and returns `VERDICT` + `ISSUES` with concrete fixes. **Merge its NEEDS-REPAIR issues with the audit findings.** (Copilot / no sub-agents: run the same review inline using the `sungen-reviewer` criteria.)
118
+ - **Independent semantic review — multi-lens (#410).** **Claude Code:** fan out the `sungen-reviewer` sub-agent **once per lens, in parallel** (Task tool, `subagent_type: sungen-reviewer`), passing a `LENS: <name>` line in each prompt `correctness`, `depth`, `traceability`, `manual` (+ `api` for an API unit). Each lens reviews only its failure mode and goes deeper than one blurred pass would. **Merge all lenses' NEEDS-REPAIR issues, dedupe by `[scenario id]` + problem, then merge with the audit findings.** (Copilot / no sub-agents: run the lenses **sequentially** with the same criteria still more thorough than one pass; same merge. A single all-lens pass is the fallback when budget is tight.)
108
119
  - Repair **both** the audit findings and the reviewer issues (budget 3 rounds), then re-audit:
109
120
  - **Repair runs single-agent by default** (it edits the one `.feature` — concurrent edits to the same file conflict, and BALANCE/dedup needs whole-suite context). **Exception:** a finding that is purely **additive new coverage** (GATE missing-theme → generate scenarios for an uncovered theme) is just more shards — fan it out as `sungen-generator` sub-agent(s) (new disjoint `VP-` prefix) and merge, exactly like Step 5b. Findings that **edit existing** scenarios (DEPTH/BALANCE/TRACE) stay serial.
110
121
  - If the gate FAILs or there are findings, **repair** (budget 3 rounds), then re-audit:
@@ -29,7 +29,7 @@ You are an **independent QA Reviewer** running in a **fresh context** — you di
29
29
  1. **Enumerate feature files** — glob `<base>/<name>/features/*.feature` (main + any sub-features). If none → `/sungen:create-test` first.
30
30
  2. **Run the harness (source of truth) — do NOT re-score with a separate rubric:**
31
31
  - `sungen audit --screen <name>` (Bash) → gate status, business-weighted score, findings, gaps (coverage / assertion-depth / balance / duplicate / traceability).
32
- - **`sungen-reviewer`** sub-agent (Task tool, `subagent_type: sungen-reviewer`) → semantic verdict the gate can't see (do steps prove the title, observable Then, @manual justified). Copilot/no-sub-agents: apply the `sungen-reviewer` criteria inline.
32
+ - **`sungen-reviewer`** sub-agent (Task tool, `subagent_type: sungen-reviewer`) → semantic verdict the gate can't see (do steps prove the title, observable Then, @manual justified). **Multi-lens (#410):** fan it out in parallel one per lens — `correctness`, `depth`, `traceability`, `manual` (+ `api`) — via a `LENS: <name>` line, and merge + dedupe the verdicts. Copilot/no-sub-agents: walk the lenses inline (sequential), same merge.
33
33
  - `sungen script-check --screen <name>` (Bash) → is the generated spec a 1:1 of the Gherkin (only if a spec exists; flags hand-edit / stale drift).
34
34
  3. **Unified scorecard** — present ONE report per feature, anchored on the harness signals (the `sungen-tc-review` 7 dimensions are a *presentation layer* over these, not a competing score):
35
35
 
@@ -135,6 +135,7 @@ If the unit is **api-first**, skip every selector/capture phase (an API test has
135
135
  6. **Phase 2 — Priority Wave**: Run all `@high` scenarios. Fix only failures from this wave. Max 2 attempts. Shared selectors fixed here cascade to later phases.
136
136
  7. **Phase 3 — Full Run**: Run all tests. Fix only **new** failures (elements unique to `@normal`/`@low`). Max 1 attempt. Don't loop on low-priority failures.
137
137
  8. **Phase 4 — Regression**: One final full run. Report results. No more fix loops.
138
+ - **⚠️ Read SKIPPED as MASKED, not passed (#414).** Suites are **per-scenario isolated by default** (`test.describe` + a fresh page each scenario, run sequentially via `workers: 1`) — a failure isolates, every scenario runs. **But an `@serial` suite** (`test.describe.serial`, shared page) **skips every test after the first failure** — so "5 passed, 1 failed, 51 skipped" means **51 never ran**, not 51 OK. If you see that, the feature is `@serial`: unless it's a genuinely stateful ordered sequence, **remove `@serial`, regenerate, and re-run** (the default isolation runs them all). `sungen audit` flags this as **SERIAL-CASCADE-RISK**. Never report an `@serial` run with many skips as green.
138
139
  9. **Integrity check & trace (always run after the final run).**
139
140
  - `sungen script-check --screen <name>` — verify the generated spec is a **1:1** of the Gherkin (every non-@manual scenario ↔ one `test()`, no drift). If it reports **DRIFT** (spec hand-edited or stale), re-run `sungen generate --screen <name>` so the spec matches the feature, then re-run — **never hand-edit the generated spec** (auto-fix must edit `selectors.yaml`, not the `.spec.ts`).
140
141
  - `sungen ledger record --screen <name> --step run --ms <elapsed>` (record this run), then **present the journey board** — `sungen journey --screen <name>` — as the human-facing close-out: **📍 you-are-here**, the **obligation checklist** (now including automation), and **especially the 🔎 Review queue** with its per-item anchors 〔`VP-id · file:line`〕 (*review what / where*) plus any **candidate bugs left FAILING by the source-of-truth rule** (#387). Then `sungen trace --screen <name>` for the process map + bottlenecks. The board's **→ Next** tells the user whether they can sign off & deliver.
@@ -26,9 +26,12 @@ Then choose the fix from the patterns below.
26
26
  `.feature` + `test-data.yaml` + `spec.md` are the **oracle**. The **live page is NOT** — it may be the thing that's broken. A failing test is not automatically a test to "make pass". Classify first:
27
27
 
28
28
  - **Selector-resolution failure** (element not found / wrong locator / strict-mode / wrong element type) → the test looked in the wrong place. **Fix the locator in `selectors.yaml`** (re-snapshot, copy the exact accessible name). Legit auto-fix.
29
- - **Assertion-value failure** (element FOUND, but observed value ≠ expected) → STOP and ask: *is the TEST wrong, or is the APP wrong?*
30
- - Expected value/rule is wrong **relative to `spec.md`** (typo, stale test-data) → fix `test-data.yaml`/`.feature` so it matches the **spec** never the live page.
31
- - App behaviour contradicts `spec.md` (spec says X, app shows Y) **CANDIDATE BUG**. **Report it** (let the test FAIL / surface to the QA in the run summary). **NEVER** change the expected value, loosen the rule, weaken the assertion (`toHaveText`→`toContainText` to dodge a mismatch), edit `.feature`, or edit the generated `.spec.ts` to make it pass.
29
+ - **Assertion-value failure** (element FOUND, but observed value ≠ expected) → STOP and ask the decisive question: ***does `spec.md` PIN this exact value?***
30
+ - **Spec PINS the value and live contradicts it** (spec mandates X, app shows Y) → **CANDIDATE BUG**. **Report it** (let the test FAIL / surface it in the run summary). **NEVER** change the expected, loosen the rule, weaken the assertion (`toHaveText`→`toContainText`), shrink a boundary (`>8`→`>=6`), or edit `.feature`/`.spec.ts` to pass.
31
+ - **Spec does NOT pin the exact string, and your expected was your own transcription/guess** (whitespace, casing, punctuation, or a label the spec only *describes* narratively) while the live value is the legitimate, spec-consistent truth → **accuracy fix (allowed):** set `test-data.yaml`/`.feature` to the **real** value. This is *not* weakening the claim is unchanged. (test-11 example: the hero `<h1>` renders `AutomationExercise`; the spec says "the Automation Exercise logo" but pins no exact string → fix `hero_title` to `"AutomationExercise"`, don't leave it failing.)
32
+ - Expected is wrong **relative to a value `spec.md` DOES state** (a typo vs the spec) → fix to the **spec** value, never the live page.
33
+
34
+ > **Accuracy fix vs weakening — the line:** an *accuracy fix* makes the expected match a spec-consistent reality the spec didn't pin (cosmetic: whitespace/casing/label), meaning preserved. *Weakening* changes the **oracle** to dodge a real discrepancy (loosen the matcher, shrink a boundary, substring-hide a wrong value, or match a value that contradicts the spec). **If the spec pins it, or you're unsure → treat as a bug and leave it failing.** Don't launder a real defect as an "accuracy fix".
32
35
 
33
36
  > **Cardinal sin (do NOT do this):** a `password > 8 chars` rule fails on a 6-char input → "fix" it to `>= 6` so the test passes. The logic is now meaningless. A failing assertion is a **finding**, not a chore.
34
37
 
@@ -206,7 +206,8 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
206
206
  | `@cleanup:scroll` | Auto-cleanup: scroll to top after each test (cleanupPage) |
207
207
  | `@cleanup:storage` | Auto-cleanup: clear sessionStorage after each test (cleanupPage) |
208
208
  | `@screenshot:on-failure` | Auto-capture screenshot when test fails (base.ts fixture) |
209
- | `@parallel` | Opt-out: fresh page per test instead of serial default (for independent scenarios) |
209
+ | `@serial` | Opt-IN to a shared-page serial suite (`test.describe.serial`) for a genuinely STATEFUL ordered sequence (scenario N depends on N-1). Default is per-scenario isolation. ⚠️ a failure skips the rest. |
210
+ | `@parallel` | Isolation (same as default) + a hint that the suite is safe to run with multiple workers / `fullyParallel`. |
210
211
  | `@beforeAll` | Hook: runs once before all tests → `test.beforeAll()` |
211
212
  | `@afterEach` | Hook: runs after each test → `test.afterEach()` (custom cleanup) |
212
213
  | `@afterAll` | Hook: runs once after all tests → `test.afterAll()` |
@@ -274,18 +275,21 @@ npx playwright test --grep "@high" # only high priority
274
275
  npx playwright test --grep "@smoke|@high" # smoke OR high
275
276
  ```
276
277
 
277
- ### Serial vs Parallel (test execution mode)
278
+ ### Isolation vs Serial (test execution mode)
278
279
 
279
- **Default: serial** — `test.describe.serial()` with shared page. Background runs once in `beforeAll`. Fail skip remaining.
280
+ **Default: per-scenario isolation** — `test.describe()` with a **fresh page per scenario** (Background runs as `beforeEach`). A failure **isolates** — every scenario still runs (no skip-cascade). The scaffolded `playwright.config.ts` runs `workers: 1` (sequential), so an isolated suite has no cross-test contention on a live site. This is right for the vast majority of screens (independent checks that each re-navigate).
280
281
 
281
- **`@parallel` opt-out** — `test.describe()` with fresh page per test. Background runs as `beforeEach`. Use when scenarios are truly independent (validation rules, permission tests).
282
+ **`@serial` opt-in** — `test.describe.serial()` with a **shared page** (Background runs once in `beforeAll`). Use ONLY for a genuinely **stateful ordered sequence** where scenario N depends on N-1's state. ⚠️ A failure **skips every remaining scenario** (Playwright can't trust the shared page after a failure) — so one early red MASKS the rest. `sungen audit` emits **SERIAL-CASCADE-RISK** if an `@serial` suite's scenarios are actually independent.
283
+
284
+ **`@parallel`** — isolation (same as the default) plus a signal that the suite is safe to run with multiple workers; raise `workers` / set `fullyParallel: true` in `playwright.config.ts` for speed once your target tolerates concurrency.
282
285
 
283
286
  | Mode | Generated | Page | Background | On fail |
284
287
  |---|---|---|---|---|
285
- | Serial (default) | `test.describe.serial()` | Shared | `beforeAll` (1 goto) | Skip remaining |
286
- | `@parallel` | `test.describe()` | Fresh per test | `beforeEach` (N goto) | Continue |
288
+ | **Isolated (default)** | `test.describe()` | Fresh per scenario | `beforeEach` (N goto) | **Continue (isolated)** |
289
+ | `@serial` (stateful opt-in) | `test.describe.serial()` | Shared | `beforeAll` (1 goto) | Skip remaining ⚠️ |
290
+ | `@parallel` | `test.describe()` | Fresh per scenario | `beforeEach` | Continue (+ may multi-worker) |
287
291
 
288
- **`@parallel` is required** when a feature has multiple auth groups (e.g., `@auth:user` + `@no-auth` scenarios). Serial mode uses one shared browser context and cannot mix auth roles. The compiler will error if `@parallel` is missing in this case.
292
+ Multiple auth groups (e.g. `@auth:user` + `@no-auth`) work under the default isolation (each group sets its own `storageState`). Only `@serial` shares one context and cannot mix auth roles.
289
293
 
290
294
  ### `@flow` tag (E2E cross-screen testing)
291
295
 
@@ -27,6 +27,8 @@ You are a **Senior QA Engineer**. You structure test cases by viewpoint categori
27
27
 
28
28
  **Auto-detect context**: check if `qa/api/<name>/` or `qa/api/flows/<name>/` exists → **API unit mode** (below). Else if `qa/flows/<name>/` → flow mode (base path: `qa/flows/<name>/`). Else `qa/screens/<name>/` → screen mode (base path: `qa/screens/<name>/`).
29
29
 
30
+ **Multi-unit (`--all` or several names):** Copilot has no sub-agents, so process units **sequentially** — `sungen journey --all` to list + skip already-signed-off units, then run the full per-unit loop for each. After all are generated, present the `sungen journey --all` roll-up and review **one unit at a time** (open-obligations first; each unit's own `sungen journey --screen <unit>` queue) until signed off. Same output as the Claude fan-out, no speedup.
31
+
30
32
  ## API unit mode (driver-api)
31
33
 
32
34
  If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps: `sungen context --area <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --area <name>` gate + reviewer + repair loop to businessDepth ≥ 0.7** → record + trace. Then recommend `/sungen-run-test <name>`. The capture / viewpoint-group / selector steps do **not** apply.
@@ -75,7 +77,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
75
77
  > **No parallel fan-out here.** Copilot has no sub-agents, so generation is sequential (the Claude Code variant fans out one `sungen-generator` per viewpoint group and merges). Same output, no speedup.
76
78
  > **Load lazily (budget, S4).** Per group, load **only** the one matching `sungen-viewpoint` group file + the relevant `spec.md` section(s) — never all five groups or the whole spec. On a tight (~200k) budget, write smaller tier-by-tier batches and keep prior batches on disk; this is what keeps generation inside a non-1M context.
77
79
  5.4. **Depth self-check (deterministic — BEFORE the audit).** Run `sungen depth-lint --screen ${input:name}`. It splits every shallow business-critical scenario into **DEEPEN IN PLACE** (add a real value assertion — the printed `template` is a theme-keyed hint, apply judgment to the actual claim; never fake one onto a visibility/behavior scenario) and **CROSS-SCREEN** (route to a flow / tag `@manual:Mx` + reason — removes it from the depth denominator honestly). Act on both, re-run until `deepen` is empty (or only honest over-counts remain), THEN gate. Lifts first-pass `businessDepth` mechanically instead of via 2–3 repair rounds.
78
- 5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria (does each scenario's steps PROVE its title/viewpoint? observable Thens? business-critical assertion depth?). Merge both sets of issues; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass.
80
+ 5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria. Copilot has no sub-agents, so walk the **lenses sequentially** (#410) `correctness` (steps PROVE the title? observable, non-tautological Thens? negative-claim contrast?), `depth` (business-critical scenarios assert DATA, not visibility), `traceability` (meaning-level dups, missing criticals, VP-ids aligned), `manual` (each `@manual` genuinely unautomatable, not a cross-screen cop-out), `api` (API units only) — going deeper per lens than one blurred pass. Merge all lenses' issues (dedupe by `[scenario id]` + problem) with the audit findings; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass.
79
81
  5.5b. **Phase gate (boundary — do NOT skip).** Run `sungen gate --screen ${input:name} --phase create` (exit 2 = HALT): every required obligation (spec · coverage · depth · trace) must be **satisfied or explicitly waived**. On **HALT**, keep repairing within budget; a genuinely-accepted gap → `sungen journey --screen ${input:name} --waive <OB> --reason "..."` (reason mandatory). Do **not** converge (step 6) past a HALT without a fix or a reasoned waiver.
80
82
  5.6. **Record.** `sungen manifest --screen ${input:name}`. Ledger **each phase** (not just repair) — pick one `runId` at the start and pass it so `trace`/`ledger report` show THIS run, not a mix: `sungen ledger record --screen ${input:name} --run <runId> --step <discovery|viewpoint|gherkin|audit|repair:N> --ms <elapsed>`. On re-run, start with `sungen manifest --screen ${input:name} --diff` and only regenerate changed sections.
81
83
  6. **Converge — show the journey board first, then the trace.** First run `sungen journey --screen ${input:name}` and present the board: **📍 you-are-here**, the **obligation checklist** (what must still be true), and **especially the 🔎 Review queue** — each item carries an IDE-jumpable anchor 〔`VP-id · file:line`〕 that tells the user *what to review and where*. End with the board's **→ Next**. Then run `sungen trace --screen ${input:name}` for the process map (phases + repair rounds), bottlenecks, audit score + gate + residual gaps. Then offer next steps based on which tier was just generated:
@@ -32,7 +32,7 @@ You are an **independent QA Reviewer** — you did not author these tests. You d
32
32
  1. **Enumerate** `<base>/${input:name}/features/*.feature`. If none → `/sungen-create-test` first.
33
33
  2. **Run the harness (source of truth) — no separate rubric:**
34
34
  - `sungen audit --screen ${input:name}` → gate, business-weighted score, findings, gaps.
35
- - Apply the **`sungen-reviewer` criteria inline** → semantic verdict (do steps prove the title? observable Then? business-critical depth? @manual justified?).
35
+ - Apply the **`sungen-reviewer` criteria inline** → semantic verdict (do steps prove the title? observable Then? business-critical depth? @manual justified?). Walk the **lenses sequentially** (#410) — `correctness`, `depth`, `traceability`, `manual` (+ `api`) — deeper per lens than one pass, then merge + dedupe by `[scenario id]` + problem.
36
36
  - `sungen script-check --screen ${input:name}` → spec is 1:1 with the Gherkin (flags hand-edit / stale drift; only if a spec exists).
37
37
  3. **Unified scorecard** per feature, anchored on harness signals (the `sungen-tc-review` 7 dimensions are a presentation layer, not a competing score):
38
38
  ```
@@ -128,6 +128,7 @@ If the unit is **api-first**, skip every selector/capture phase (an API test has
128
128
  6. **Phase 2 — Priority Wave**: Run all `@high` scenarios. Fix only failures from this wave. Max 2 attempts. Shared selectors fixed here cascade to later phases.
129
129
  7. **Phase 3 — Full Run**: Run all tests. Fix only **new** failures (elements unique to `@normal`/`@low`). Max 1 attempt. Don't loop on low-priority failures.
130
130
  8. **Phase 4 — Regression**: One final full run. Report results. No more fix loops.
131
+ - **⚠️ SKIPPED ≠ passed (#414).** Suites are **per-scenario isolated by default** (failures isolate, all run). An **`@serial`** suite (`test.describe.serial`, shared page) **skips every test after the first failure** — "5 passed / 1 failed / 51 skipped" = 51 never ran. If you see that and the suite isn't a genuinely stateful sequence, **remove `@serial`, regenerate, re-run**. `sungen audit` flags it as **SERIAL-CASCADE-RISK**. Don't report an `@serial` run with many skips as green.
131
132
  9. **Integrity & trace (always run after the final run).** `sungen script-check --screen <name>` — verify the spec is a **1:1** of the Gherkin; if **DRIFT**, re-run `sungen generate --screen <name>` (never hand-edit the `.spec.ts` — auto-fix edits `selectors.yaml`). Then `sungen ledger record --screen <name> --step run --ms <elapsed>` and **present the journey board** — `sungen journey --screen <name>` — as the human-facing close-out: **📍 you-are-here**, the **obligation checklist**, and **especially the 🔎 Review queue** with per-item anchors 〔`VP-id · file:line`〕 (*review what / where*) plus any candidate bugs left FAILING by the source-of-truth rule (#387). Then `sungen trace --screen <name>` for the process map + bottlenecks; the board's **→ Next** says whether to sign off & deliver.
132
133
  9b. **Phase gate (boundary — do NOT skip).** `sungen gate --screen <name> --phase run` (exit 2 = HALT): run-boundary obligations (incl. automation) must be **satisfied or explicitly waived**. On HALT, classify per `sungen-error-mapping` § Source of truth (#387): selector-resolution failure → fix `selectors.yaml` + re-run; assertion-vs-spec failure → **report as a candidate bug / leave it FAIL** (never weaken to pass); accepted gap → `sungen journey --screen <name> --waive <OB> --reason "..."`. Don't declare "done" past a HALT without a fix, a reported bug, or a reasoned waiver.
133
134
  10. **Capability-pending offer (consent-gated).** If `sungen audit` reports `AUTOMATION-READY-PENDING` (or `@requires:<cap>` tests are skipped "requires …"), offer: *"N scenario(s) are automation-ready — enable `<cap>` to run them? (`sungen capability add <cap>`)"*. Only on the user's yes, run `sungen capability add <cap>` + re-run; on no, leave skipped (not failures, not manual). **Never auto-install.**
@@ -26,9 +26,12 @@ Then choose the fix from the patterns below.
26
26
  `.feature` + `test-data.yaml` + `spec.md` are the **oracle**. The **live page is NOT** — it may be the thing that's broken. A failing test is not automatically a test to "make pass". Classify first:
27
27
 
28
28
  - **Selector-resolution failure** (element not found / wrong locator / strict-mode / wrong element type) → the test looked in the wrong place. **Fix the locator in `selectors.yaml`** (re-snapshot, copy the exact accessible name). Legit auto-fix.
29
- - **Assertion-value failure** (element FOUND, but observed value ≠ expected) → STOP and ask: *is the TEST wrong, or is the APP wrong?*
30
- - Expected value/rule is wrong **relative to `spec.md`** (typo, stale test-data) → fix `test-data.yaml`/`.feature` so it matches the **spec** never the live page.
31
- - App behaviour contradicts `spec.md` (spec says X, app shows Y) **CANDIDATE BUG**. **Report it** (let the test FAIL / surface to the QA in the run summary). **NEVER** change the expected value, loosen the rule, weaken the assertion (`toHaveText`→`toContainText` to dodge a mismatch), edit `.feature`, or edit the generated `.spec.ts` to make it pass.
29
+ - **Assertion-value failure** (element FOUND, but observed value ≠ expected) → STOP and ask the decisive question: ***does `spec.md` PIN this exact value?***
30
+ - **Spec PINS the value and live contradicts it** (spec mandates X, app shows Y) → **CANDIDATE BUG**. **Report it** (let the test FAIL). **NEVER** change the expected, loosen the rule, weaken the assertion (`toHaveText`→`toContainText`), shrink a boundary (`>8`→`>=6`), or edit `.feature`/`.spec.ts` to pass.
31
+ - **Spec does NOT pin the exact string, and your expected was your own transcription/guess** (whitespace, casing, punctuation, or a label the spec only *describes* narratively) while the live value is the legitimate, spec-consistent truth **accuracy fix (allowed):** set `test-data.yaml`/`.feature` to the **real** value — *not* weakening, the claim is unchanged. (e.g. hero `<h1>` renders `AutomationExercise`; spec says "the Automation Exercise logo" but pins no string → fix `hero_title` to `"AutomationExercise"`, don't leave it failing.)
32
+ - Expected is wrong **relative to a value `spec.md` DOES state** (typo vs the spec) → fix to the **spec** value, never the live page.
33
+
34
+ > **Accuracy fix vs weakening — the line:** an *accuracy fix* matches a spec-consistent reality the spec didn't pin (cosmetic, meaning preserved). *Weakening* changes the **oracle** to dodge a real discrepancy. **If the spec pins it, or you're unsure → treat as a bug and leave it failing.**
32
35
 
33
36
  > **Cardinal sin (do NOT do this):** a `password > 8 chars` rule fails on a 6-char input → "fix" it to `>= 6` so the test passes. The logic is now meaningless. A failing assertion is a **finding**, not a chore.
34
37
 
@@ -206,7 +206,8 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
206
206
  | `@cleanup:scroll` | Auto-cleanup: scroll to top after each test (cleanupPage) |
207
207
  | `@cleanup:storage` | Auto-cleanup: clear sessionStorage after each test (cleanupPage) |
208
208
  | `@screenshot:on-failure` | Auto-capture screenshot when test fails (base.ts fixture) |
209
- | `@parallel` | Opt-out: fresh page per test instead of serial default (for independent scenarios) |
209
+ | `@serial` | Opt-IN to a shared-page serial suite (`test.describe.serial`) for a genuinely STATEFUL ordered sequence (scenario N depends on N-1). Default is per-scenario isolation. ⚠️ a failure skips the rest. |
210
+ | `@parallel` | Isolation (same as default) + a hint that the suite is safe to run with multiple workers / `fullyParallel`. |
210
211
  | `@beforeAll` | Hook: runs once before all tests → `test.beforeAll()` |
211
212
  | `@afterEach` | Hook: runs after each test → `test.afterEach()` (custom cleanup) |
212
213
  | `@afterAll` | Hook: runs once after all tests → `test.afterAll()` |
@@ -274,18 +275,21 @@ npx playwright test --grep "@high" # only high priority
274
275
  npx playwright test --grep "@smoke|@high" # smoke OR high
275
276
  ```
276
277
 
277
- ### Serial vs Parallel (test execution mode)
278
+ ### Isolation vs Serial (test execution mode)
278
279
 
279
- **Default: serial** — `test.describe.serial()` with shared page. Background runs once in `beforeAll`. Failskip remaining.
280
+ **Default: per-scenario isolation** — `test.describe()` with a **fresh page per scenario** (Background runs as `beforeEach`). A failure **isolates** — every scenario still runs (no skip-cascade). The scaffolded `playwright.config.ts` runs `workers: 1` (sequential) no cross-test contention on a live site. Right for the vast majority of screens.
280
281
 
281
- **`@parallel` opt-out** — `test.describe()` with fresh page per test. Background runs as `beforeEach`. Use when scenarios are truly independent (validation rules, permission tests).
282
+ **`@serial` opt-in** — `test.describe.serial()` with a **shared page** (Background once in `beforeAll`). Use ONLY for a genuinely **stateful ordered sequence** (scenario N depends on N-1). ⚠️ a failure **skips every remaining scenario** → one early red MASKS the rest. `sungen audit` emits **SERIAL-CASCADE-RISK** if an `@serial` suite is actually independent.
283
+
284
+ **`@parallel`** — isolation (same as default) + a signal it's safe to run with multiple workers; raise `workers` / `fullyParallel` for speed once the target tolerates concurrency.
282
285
 
283
286
  | Mode | Generated | Page | Background | On fail |
284
287
  |---|---|---|---|---|
285
- | Serial (default) | `test.describe.serial()` | Shared | `beforeAll` (1 goto) | Skip remaining |
286
- | `@parallel` | `test.describe()` | Fresh per test | `beforeEach` (N goto) | Continue |
288
+ | **Isolated (default)** | `test.describe()` | Fresh per scenario | `beforeEach` (N goto) | **Continue (isolated)** |
289
+ | `@serial` (stateful opt-in) | `test.describe.serial()` | Shared | `beforeAll` (1 goto) | Skip remaining ⚠️ |
290
+ | `@parallel` | `test.describe()` | Fresh per scenario | `beforeEach` | Continue (+ may multi-worker) |
287
291
 
288
- **`@parallel` is required** when a feature has multiple auth groups (e.g., `@auth:user` + `@no-auth` scenarios). Serial mode uses one shared browser context and cannot mix auth roles. The compiler will error if `@parallel` is missing in this case.
292
+ Multiple auth groups (`@auth:user` + `@no-auth`) work under the default isolation (each sets its own `storageState`). Only `@serial` shares one context and cannot mix auth roles.
289
293
 
290
294
  ### `@flow` tag (E2E cross-screen testing)
291
295
 
@@ -37,14 +37,17 @@ export default defineConfig({
37
37
  testDir: './specs/generated',
38
38
  /* Output directory for test artifacts (screenshots, videos, traces). */
39
39
  outputDir: './test-results',
40
- /* Run tests in files in parallel */
41
- fullyParallel: true,
40
+ /* Sequential by default. Scenarios are per-scenario ISOLATED (each test gets a fresh page), so a
41
+ failure never cascades — but we run one-at-a-time (workers: 1) so a heavy live site isn't hit by
42
+ concurrent workers (which causes flaky timeouts / ad-consent races). Once your suite is stable
43
+ and your target tolerates concurrency, raise `workers` (and set `fullyParallel: true`) for speed. */
44
+ fullyParallel: false,
42
45
  /* Fail the build on CI if you accidentally left test.only in the source code. */
43
46
  forbidOnly: !!process.env.CI,
44
47
  /* Retry on CI only */
45
48
  retries: process.env.CI ? 2 : 0,
46
- /* Opt out of parallel tests on CI. */
47
- workers: process.env.CI ? 1 : 2,
49
+ /* One worker sequential execution, no cross-test contention on the target site. */
50
+ workers: 1,
48
51
  /* Global timeout per test */
49
52
  timeout: 15_000,
50
53
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */