@sun-asterisk/sungen 3.2.12-beta.5 → 3.2.12-beta.7

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.
@@ -94,9 +94,17 @@ Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data gen --screen
94
94
 
95
95
  Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data validate --screen <name> || npx sungen data validate --screen <name>`. This is stronger than lint (coverage): it checks every generated value is **semantically** correct — each `valid`/`boundary` value actually satisfies the constraints, and each synthesized `invalid` value actually violates them (a value in the `valid` set that breaks `maxLength`, or a "below min" case that landed inside the range, is a `VALUE_NOT_VALID` error). Fix any `error`; `INVALID_LOOKS_VALID` warns are a prompt to confirm the value is invalid for a non-length reason (charset/format). Each generated value also carries an `expected: valid|invalid` field in the test-data for traceability.
96
96
 
97
+ ### 5.6 Domain / stateful preconditions (spec + viewpoint only — no DB/API needed)
98
+
99
+ If the spec describes a **stateful precondition** — an entity with relationships or a business state the test needs *before* it runs (e.g. "a paid order of user A", "a valid unused reset token ≤24h", "the session-storage buffer holds the entered values") — author a **state-recipe** in `qa/data-factory/recipes.yaml` under `resources:` (each with `entity`, `provenance`, `dependsOn`, `desiredState`, `lifecycle`, `with:` values; plus `bindings:`). Provenance is **not only api/db** — pick `prior-flow` / `fixture` / `client-storage` / `server-context` / `manual` (use `api`/`db` only when a datasource exists). Then run `data state --recipe <name>`: it validates the graph and renders a standardized **manual precondition** block (`@manual:data-setup` when it can't be auto-provisioned) to weave into the scenario's `Background`. This is the domain/stateful improvement that works with **only spec + viewpoint** — the testcase states the required state precisely instead of a vague note; it auto-provisions later if an api/db datasource is added (no rewrite). For a **journey where the same data flows across screens** (setup → confirmation → complete), declare a `shared: { entity, screens: [...] }` so one dataset is used across all of them (the Cross-artifact Gate then asserts they match).
100
+
101
+ ### 5.7 Cross-artifact check (testcase ↔ data agree)
102
+
103
+ Run (local-first): `… data crosscheck --screen <name>`. It verifies the testcase and its test-data agree: no dangling `{{var}}` (every referenced var has a value), any cross-screen **shared** dataset is identical across the journey, and a declared state-precondition is surfaced in the feature. Fix any `error`. This is the `data-only` harness profile — `data validate` (values correct) + `data crosscheck` (values match the test); together they are the deterministic Data Gate + Cross-artifact Gate.
104
+
97
105
  ### 6. Weave into scenarios (if create-test already ran)
98
106
 
99
- If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
107
+ If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Weave any `data state` precondition block into the `Background`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
100
108
 
101
109
  ## After running
102
110
 
@@ -167,7 +167,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
167
167
 
168
168
  **5d. Sequential fallback.** Use the single-context incremental path (Step 2: tier-by-tier `Write`/`Edit` batches) when: only **one** shard applies, **Copilot / no sub-agents**, or a constrained setup. Same output, just no speedup. **For flows**: `[Screen:Element]` namespace refs, test-data namespaced by phase, `@flow` tag.
169
169
 
170
- 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** Don't hand-invent per-field values — make them **standard**. For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + the spec's real `constraints` + `errorMap` placeholder→real code), then run (Bash, local-first) `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>` and `… data gen --screen <name>`, per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves your scenario/namespaced data), so it is safe to run here. Weave the standardized **boundary/invalid** sets into `@cases` (`Scenario Outline` + `Examples`) with `CHK-*` trace; keep the map's `errorMap`/`constraints` aligned to the spec. **This is the same standard as `/sungen:create-data-test`, applied inline — so you do NOT run that command separately afterwards.** A unit with **no input fields** (navigation / list / capture-compare) → **skip this step** (nothing to standardize).
170
+ 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** Don't hand-invent per-field values — make them **standard**. For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + the spec's real `constraints` + `errorMap` placeholder→real code), then run (Bash, local-first) `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>` and `… data gen --screen <name>`, per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves your scenario/namespaced data), so it is safe to run here. Weave the standardized **boundary/invalid** sets into `@cases` (`Scenario Outline` + `Examples`) with `CHK-*` trace; keep the map's `errorMap`/`constraints` aligned to the spec. Then run `… data validate --screen <name>` (values are semantically correct) and — once the `.feature` exists — `… data crosscheck --screen <name>` (testcase ↔ data agree: no dangling `{{var}}`, shared datasets identical); fix any `error`. If the spec has a **stateful precondition** (an entity/state the test needs first), author a state-recipe + run `… data state` and weave its `@manual:data-setup` `Background` block (see the `sungen-data-factory` skill — works with spec+viewpoint only, no DB/API). **This is the same standard as `/sungen:create-data-test`, applied inline — so you do NOT run that command separately afterwards.** A unit with **no input fields** (navigation / list / capture-compare) → **skip this step** (nothing to standardize).
171
171
 
172
172
  5.4. **Depth self-check (deterministic — run BEFORE the audit).** Run `sungen depth-lint --screen <name>` (Bash). It reuses the audit's businessDepth classifier and splits every shallow business-critical scenario into two actionable buckets — act on them now so the audit/repair loop doesn't burn rounds on depth:
173
173
  - **DEEPEN IN PLACE** — add a real value assertion to each (`User see all [X] contain {{v}}`, `User remember [X] as {{v}}` + `… with {{v}}`). The printed `template` is a **hint** keyed off the theme — apply judgment to the scenario's actual claim; do NOT paste a value assertion that doesn't fit (e.g. a carousel-visibility scenario should assert the product SET, not a price). If a flagged scenario is genuinely visibility/behavior (not data-correctness), that's an over-count — leave it and note it, never fake an assertion.
@@ -196,7 +196,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
196
196
  4. Follow the `sungen-tc-generation` skill for section identification, viewpoint generation, and output format. **For flows**, use the "Flow Test Generation" section in the skill. When requirements exist, use the "Requirements-Driven Generation" strategy. **For Tier 1**, apply the **Lightweight Guard** — verify required fields, validation rules, business rules, security checks, and key state transitions all have TCs after generation. **For Tier 2+**, **MUST** apply the full **Mapping Contract** — walk every `spec.md` section top-to-bottom and produce the indicated TCs per Table 1; handle `test-viewpoint.md` per Table 2. Do not silently skip sections. Present sections as a numbered list and let user pick.
197
197
  5. Generate or update `.feature` + `test-data.yaml` following `sungen-gherkin-syntax` and `sungen-tc-generation` skills. Generate **group-by-group** (one viewpoint group at a time, tier-by-tier `Write`/`Edit` batches) to stay under the output-token cap. **For flows**: use `[Screen:Element]` namespace format, namespace test-data by phase, add `@flow` tag. **If a scenario needs `@query` DB verification**, check the datasource `engine` first — unsupported engine → follow `sungen-gherkin-syntax` § "Unsupported DB engine — fallback" instead of authoring `@query` steps.
198
198
  > **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.
199
- 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
199
+ 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. Then `… data validate` (values correct) + `… data crosscheck` (testcase↔data agree); for a stateful precondition, author a state-recipe + `… data state` and weave its `@manual:data-setup` `Background` (works spec+viewpoint only). **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
200
200
  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.
201
201
  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.
202
202
  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.
@@ -100,8 +100,11 @@ field-map for per-screen tweaks; use `.overwrite` only for rules that apply proj
100
100
  For CSV/Excel import or bulk-upload testing, `sungen data fixture --screen <name> [--rows N] [--invalid]`
101
101
  turns the field-map into a fixture FILE under `qa/fixtures/`: `<name>.csv` (N valid rows; nested groups
102
102
  → dotted headers; `unique` fields row-indexed) that should import cleanly, and — with `--invalid` —
103
- `<name>.invalid.csv` (one seeded-bad row per field + a `_violation` column) for row-level rejection
104
- tests. Reference it from an `@api` upload (`files:`) or a UI file input.
103
+ `<name>.invalid.csv` (one seeded-bad row per field, **same columns as the valid file so a strict
104
+ importer fails on the data, not an extra column**) plus a **sidecar** `<name>.invalid.expected.yaml`
105
+ that says which 0-based row must be rejected and why (`field`, `chk`, `reason`, `expected_error`).
106
+ Reference the CSV from an `@api` upload (`files:`) or a UI file input, and assert row rejection against
107
+ the sidecar.
105
108
 
106
109
  ## Verify before done — the phuong-phap §6 checklist
107
110
 
@@ -128,6 +131,32 @@ output + a `NOT_APPLICABLE` lint info. A `--profile` (`regression` default · `f
128
131
  `security-min`) and `--locale`/`--channel`/`--sink` on `data gen|validate|lint` select a reduced set;
129
132
  selection is deterministic. Prefer setting `required` in the field-map over disabling the empty case.
130
133
 
134
+ ## Domain / stateful preconditions (spec + viewpoint only — no DB/API)
135
+
136
+ Field values are not enough when a test needs a **business state first** — "a paid order of user A",
137
+ "a valid unused reset token ≤24h", "the session-storage buffer holds the entered values". Declare a
138
+ **state-recipe** in `qa/data-factory/recipes.yaml` under `resources:` — each resource has an `entity`,
139
+ a **`provenance`** (`prior-flow` | `fixture` | `client-storage` | `server-context` | `manual` |
140
+ `api` | `db`), optional `dependsOn`, `desiredState`, `lifecycle` (`reusable`/`consumable`/`expiring`/
141
+ `leased`/`mutable-state`/`unique-per-run`), and `with:` values — plus `bindings:` (`orderId: ${order.id}`).
142
+ Run **`sungen data state`**: it validates the graph (cycles, dangling deps, bindings) and renders a
143
+ standardized **manual precondition** block — tagged **`@manual:data-setup`** when it can't be
144
+ auto-provisioned — to weave into the scenario's `Background`. **This works with only spec + viewpoint:
145
+ provenance is usually `prior-flow`/`fixture`/`manual`, NOT DB/API.** If a datasource is later added and
146
+ a resource uses `api`/`db` provenance (+ a `provider:` endpoint), the *same* recipe auto-provisions — no
147
+ rewrite. For a **journey where the same data flows across screens** (setup → confirmation → complete),
148
+ add `shared: { entity, screens: [...] }` so one dataset is used across all of them.
149
+
150
+ ## Cross-artifact check — testcase ↔ data agree
151
+
152
+ `data validate` checks the data alone; **`sungen data crosscheck`** checks the testcase and its data
153
+ AGREE: no dangling `{{var}}` (every referenced var has a value), a cross-screen `shared` dataset is
154
+ identical across the journey (confirmation shows what setup entered), and a declared state-precondition
155
+ is surfaced in the feature. Run it after the `.feature` exists; fix any `error`. Together
156
+ `data validate` + `data crosscheck` are the **Data Gate + Cross-artifact Gate** (the `data-only`
157
+ harness profile). Every `data gen` also stamps a `_fingerprint` (catalog+generator+context hash) so a
158
+ reader/cache can tell whether the inputs that produced the data changed.
159
+
131
160
  ## Weaving into scenarios
132
161
 
133
162
  When a `.feature` exists, express invalid/boundary sets as data-driven `Scenario Outline` + `Examples`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.2.12-beta.5",
3
+ "version": "3.2.12-beta.7",
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.12-beta.5",
43
- "@sungen/driver-ui": "3.2.12-beta.5",
42
+ "@sungen/driver-data-factory": "3.2.12-beta.7",
43
+ "@sungen/driver-ui": "3.2.12-beta.7",
44
44
  "chalk": "^5.6.2",
45
45
  "commander": "^14.0.2",
46
46
  "dotenv": "^17.2.3",
@@ -94,9 +94,17 @@ Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data gen --screen
94
94
 
95
95
  Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data validate --screen <name> || npx sungen data validate --screen <name>`. This is stronger than lint (coverage): it checks every generated value is **semantically** correct — each `valid`/`boundary` value actually satisfies the constraints, and each synthesized `invalid` value actually violates them (a value in the `valid` set that breaks `maxLength`, or a "below min" case that landed inside the range, is a `VALUE_NOT_VALID` error). Fix any `error`; `INVALID_LOOKS_VALID` warns are a prompt to confirm the value is invalid for a non-length reason (charset/format). Each generated value also carries an `expected: valid|invalid` field in the test-data for traceability.
96
96
 
97
+ ### 5.6 Domain / stateful preconditions (spec + viewpoint only — no DB/API needed)
98
+
99
+ If the spec describes a **stateful precondition** — an entity with relationships or a business state the test needs *before* it runs (e.g. "a paid order of user A", "a valid unused reset token ≤24h", "the session-storage buffer holds the entered values") — author a **state-recipe** in `qa/data-factory/recipes.yaml` under `resources:` (each with `entity`, `provenance`, `dependsOn`, `desiredState`, `lifecycle`, `with:` values; plus `bindings:`). Provenance is **not only api/db** — pick `prior-flow` / `fixture` / `client-storage` / `server-context` / `manual` (use `api`/`db` only when a datasource exists). Then run `data state --recipe <name>`: it validates the graph and renders a standardized **manual precondition** block (`@manual:data-setup` when it can't be auto-provisioned) to weave into the scenario's `Background`. This is the domain/stateful improvement that works with **only spec + viewpoint** — the testcase states the required state precisely instead of a vague note; it auto-provisions later if an api/db datasource is added (no rewrite). For a **journey where the same data flows across screens** (setup → confirmation → complete), declare a `shared: { entity, screens: [...] }` so one dataset is used across all of them (the Cross-artifact Gate then asserts they match).
100
+
101
+ ### 5.7 Cross-artifact check (testcase ↔ data agree)
102
+
103
+ Run (local-first): `… data crosscheck --screen <name>`. It verifies the testcase and its test-data agree: no dangling `{{var}}` (every referenced var has a value), any cross-screen **shared** dataset is identical across the journey, and a declared state-precondition is surfaced in the feature. Fix any `error`. This is the `data-only` harness profile — `data validate` (values correct) + `data crosscheck` (values match the test); together they are the deterministic Data Gate + Cross-artifact Gate.
104
+
97
105
  ### 6. Weave into scenarios (if create-test already ran)
98
106
 
99
- If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
107
+ If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Weave any `data state` precondition block into the `Background`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
100
108
 
101
109
  ## After running
102
110
 
@@ -167,7 +167,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
167
167
 
168
168
  **5d. Sequential fallback.** Use the single-context incremental path (Step 2: tier-by-tier `Write`/`Edit` batches) when: only **one** shard applies, **Copilot / no sub-agents**, or a constrained setup. Same output, just no speedup. **For flows**: `[Screen:Element]` namespace refs, test-data namespaced by phase, `@flow` tag.
169
169
 
170
- 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** Don't hand-invent per-field values — make them **standard**. For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + the spec's real `constraints` + `errorMap` placeholder→real code), then run (Bash, local-first) `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>` and `… data gen --screen <name>`, per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves your scenario/namespaced data), so it is safe to run here. Weave the standardized **boundary/invalid** sets into `@cases` (`Scenario Outline` + `Examples`) with `CHK-*` trace; keep the map's `errorMap`/`constraints` aligned to the spec. **This is the same standard as `/sungen:create-data-test`, applied inline — so you do NOT run that command separately afterwards.** A unit with **no input fields** (navigation / list / capture-compare) → **skip this step** (nothing to standardize).
170
+ 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** Don't hand-invent per-field values — make them **standard**. For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + the spec's real `constraints` + `errorMap` placeholder→real code), then run (Bash, local-first) `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>` and `… data gen --screen <name>`, per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves your scenario/namespaced data), so it is safe to run here. Weave the standardized **boundary/invalid** sets into `@cases` (`Scenario Outline` + `Examples`) with `CHK-*` trace; keep the map's `errorMap`/`constraints` aligned to the spec. Then run `… data validate --screen <name>` (values are semantically correct) and — once the `.feature` exists — `… data crosscheck --screen <name>` (testcase ↔ data agree: no dangling `{{var}}`, shared datasets identical); fix any `error`. If the spec has a **stateful precondition** (an entity/state the test needs first), author a state-recipe + run `… data state` and weave its `@manual:data-setup` `Background` block (see the `sungen-data-factory` skill — works with spec+viewpoint only, no DB/API). **This is the same standard as `/sungen:create-data-test`, applied inline — so you do NOT run that command separately afterwards.** A unit with **no input fields** (navigation / list / capture-compare) → **skip this step** (nothing to standardize).
171
171
 
172
172
  5.4. **Depth self-check (deterministic — run BEFORE the audit).** Run `sungen depth-lint --screen <name>` (Bash). It reuses the audit's businessDepth classifier and splits every shallow business-critical scenario into two actionable buckets — act on them now so the audit/repair loop doesn't burn rounds on depth:
173
173
  - **DEEPEN IN PLACE** — add a real value assertion to each (`User see all [X] contain {{v}}`, `User remember [X] as {{v}}` + `… with {{v}}`). The printed `template` is a **hint** keyed off the theme — apply judgment to the scenario's actual claim; do NOT paste a value assertion that doesn't fit (e.g. a carousel-visibility scenario should assert the product SET, not a price). If a flagged scenario is genuinely visibility/behavior (not data-correctness), that's an over-count — leave it and note it, never fake an assertion.
@@ -196,7 +196,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
196
196
  4. Follow the `sungen-tc-generation` skill for section identification, viewpoint generation, and output format. **For flows**, use the "Flow Test Generation" section in the skill. When requirements exist, use the "Requirements-Driven Generation" strategy. **For Tier 1**, apply the **Lightweight Guard** — verify required fields, validation rules, business rules, security checks, and key state transitions all have TCs after generation. **For Tier 2+**, **MUST** apply the full **Mapping Contract** — walk every `spec.md` section top-to-bottom and produce the indicated TCs per Table 1; handle `test-viewpoint.md` per Table 2. Do not silently skip sections. Present sections as a numbered list and let user pick.
197
197
  5. Generate or update `.feature` + `test-data.yaml` following `sungen-gherkin-syntax` and `sungen-tc-generation` skills. Generate **group-by-group** (one viewpoint group at a time, tier-by-tier `Write`/`Edit` batches) to stay under the output-token cap. **For flows**: use `[Screen:Element]` namespace format, namespace test-data by phase, add `@flow` tag. **If a scenario needs `@query` DB verification**, check the datasource `engine` first — unsupported engine → follow `sungen-gherkin-syntax` § "Unsupported DB engine — fallback" instead of authoring `@query` steps.
198
198
  > **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.
199
- 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
199
+ 5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. Then `… data validate` (values correct) + `… data crosscheck` (testcase↔data agree); for a stateful precondition, author a state-recipe + `… data state` and weave its `@manual:data-setup` `Background` (works spec+viewpoint only). **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
200
200
  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.
201
201
  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.
202
202
  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.
@@ -100,8 +100,11 @@ field-map for per-screen tweaks; use `.overwrite` only for rules that apply proj
100
100
  For CSV/Excel import or bulk-upload testing, `sungen data fixture --screen <name> [--rows N] [--invalid]`
101
101
  turns the field-map into a fixture FILE under `qa/fixtures/`: `<name>.csv` (N valid rows; nested groups
102
102
  → dotted headers; `unique` fields row-indexed) that should import cleanly, and — with `--invalid` —
103
- `<name>.invalid.csv` (one seeded-bad row per field + a `_violation` column) for row-level rejection
104
- tests. Reference it from an `@api` upload (`files:`) or a UI file input.
103
+ `<name>.invalid.csv` (one seeded-bad row per field, **same columns as the valid file so a strict
104
+ importer fails on the data, not an extra column**) plus a **sidecar** `<name>.invalid.expected.yaml`
105
+ that says which 0-based row must be rejected and why (`field`, `chk`, `reason`, `expected_error`).
106
+ Reference the CSV from an `@api` upload (`files:`) or a UI file input, and assert row rejection against
107
+ the sidecar.
105
108
 
106
109
  ## Verify before done — the phuong-phap §6 checklist
107
110
 
@@ -128,6 +131,32 @@ output + a `NOT_APPLICABLE` lint info. A `--profile` (`regression` default · `f
128
131
  `security-min`) and `--locale`/`--channel`/`--sink` on `data gen|validate|lint` select a reduced set;
129
132
  selection is deterministic. Prefer setting `required` in the field-map over disabling the empty case.
130
133
 
134
+ ## Domain / stateful preconditions (spec + viewpoint only — no DB/API)
135
+
136
+ Field values are not enough when a test needs a **business state first** — "a paid order of user A",
137
+ "a valid unused reset token ≤24h", "the session-storage buffer holds the entered values". Declare a
138
+ **state-recipe** in `qa/data-factory/recipes.yaml` under `resources:` — each resource has an `entity`,
139
+ a **`provenance`** (`prior-flow` | `fixture` | `client-storage` | `server-context` | `manual` |
140
+ `api` | `db`), optional `dependsOn`, `desiredState`, `lifecycle` (`reusable`/`consumable`/`expiring`/
141
+ `leased`/`mutable-state`/`unique-per-run`), and `with:` values — plus `bindings:` (`orderId: ${order.id}`).
142
+ Run **`sungen data state`**: it validates the graph (cycles, dangling deps, bindings) and renders a
143
+ standardized **manual precondition** block — tagged **`@manual:data-setup`** when it can't be
144
+ auto-provisioned — to weave into the scenario's `Background`. **This works with only spec + viewpoint:
145
+ provenance is usually `prior-flow`/`fixture`/`manual`, NOT DB/API.** If a datasource is later added and
146
+ a resource uses `api`/`db` provenance (+ a `provider:` endpoint), the *same* recipe auto-provisions — no
147
+ rewrite. For a **journey where the same data flows across screens** (setup → confirmation → complete),
148
+ add `shared: { entity, screens: [...] }` so one dataset is used across all of them.
149
+
150
+ ## Cross-artifact check — testcase ↔ data agree
151
+
152
+ `data validate` checks the data alone; **`sungen data crosscheck`** checks the testcase and its data
153
+ AGREE: no dangling `{{var}}` (every referenced var has a value), a cross-screen `shared` dataset is
154
+ identical across the journey (confirmation shows what setup entered), and a declared state-precondition
155
+ is surfaced in the feature. Run it after the `.feature` exists; fix any `error`. Together
156
+ `data validate` + `data crosscheck` are the **Data Gate + Cross-artifact Gate** (the `data-only`
157
+ harness profile). Every `data gen` also stamps a `_fingerprint` (catalog+generator+context hash) so a
158
+ reader/cache can tell whether the inputs that produced the data changed.
159
+
131
160
  ## Weaving into scenarios
132
161
 
133
162
  When a `.feature` exists, express invalid/boundary sets as data-driven `Scenario Outline` + `Examples`