@sun-asterisk/sungen 3.2.11 → 3.2.12-beta.10

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 (51) hide show
  1. package/dist/capabilities/discover.d.ts.map +1 -1
  2. package/dist/capabilities/discover.js +5 -2
  3. package/dist/capabilities/discover.js.map +1 -1
  4. package/dist/cli/commands/capability.d.ts.map +1 -1
  5. package/dist/cli/commands/capability.js +44 -2
  6. package/dist/cli/commands/capability.js.map +1 -1
  7. package/dist/dashboard/templates/index.html +1 -1
  8. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  9. package/dist/exporters/csv-exporter.js +7 -2
  10. package/dist/exporters/csv-exporter.js.map +1 -1
  11. package/dist/exporters/feature-parser.d.ts.map +1 -1
  12. package/dist/exporters/feature-parser.js +15 -2
  13. package/dist/exporters/feature-parser.js.map +1 -1
  14. package/dist/exporters/json-exporter.d.ts.map +1 -1
  15. package/dist/exporters/json-exporter.js +10 -5
  16. package/dist/exporters/json-exporter.js.map +1 -1
  17. package/dist/exporters/result-variants.d.ts +23 -5
  18. package/dist/exporters/result-variants.d.ts.map +1 -1
  19. package/dist/exporters/result-variants.js +65 -9
  20. package/dist/exporters/result-variants.js.map +1 -1
  21. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  22. package/dist/exporters/test-data-resolver.js.map +1 -1
  23. package/dist/harness/capability.d.ts +1 -0
  24. package/dist/harness/capability.d.ts.map +1 -1
  25. package/dist/harness/capability.js.map +1 -1
  26. package/dist/harness/catalog/drivers.yaml +2 -1
  27. package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +111 -0
  28. package/dist/orchestrator/templates/ai-src/commands/create-test.md +3 -0
  29. package/dist/orchestrator/templates/ai-src/commands/run-test.md +1 -0
  30. package/dist/orchestrator/templates/ai-src/config/claude.md +3 -1
  31. package/dist/orchestrator/templates/ai-src/config/copilot.md +3 -1
  32. package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +213 -0
  33. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -0
  34. package/package.json +3 -2
  35. package/src/capabilities/discover.ts +5 -2
  36. package/src/cli/commands/capability.ts +40 -2
  37. package/src/dashboard/templates/index.html +1 -1
  38. package/src/exporters/csv-exporter.ts +7 -3
  39. package/src/exporters/feature-parser.ts +15 -2
  40. package/src/exporters/json-exporter.ts +10 -6
  41. package/src/exporters/result-variants.ts +68 -9
  42. package/src/exporters/test-data-resolver.ts +1 -0
  43. package/src/harness/capability.ts +1 -0
  44. package/src/harness/catalog/drivers.yaml +2 -1
  45. package/src/orchestrator/templates/ai-src/commands/create-data-test.md +111 -0
  46. package/src/orchestrator/templates/ai-src/commands/create-test.md +3 -0
  47. package/src/orchestrator/templates/ai-src/commands/run-test.md +1 -0
  48. package/src/orchestrator/templates/ai-src/config/claude.md +3 -1
  49. package/src/orchestrator/templates/ai-src/config/copilot.md +3 -1
  50. package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +213 -0
  51. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -0
@@ -0,0 +1,213 @@
1
+ ---
2
+ name: sungen-data-factory
3
+ description: 'Use when create-data-test (or create-test) needs standardized TEST DATA — valid/boundary/invalid values for input fields with CHK-* traceability. Drives the Data Factory catalog + the 4-source method. Invoke after reading spec.md, when authoring the field-map or filling test-data.'
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## What this skill does
8
+
9
+ Turn a screen/flow's fields into **standardized test data** — not guessed values. You author a
10
+ **field-map**; the deterministic `sungen data gen` expands it from the Data Factory **catalog**
11
+ (field-type + security + technique library) into valid / boundary / invalid values, each carrying a
12
+ `CHK-*` id that traces to the spec. Your judgment goes into *reading the spec correctly* and
13
+ *answering blind spots* — never into inventing values the catalog or the QA should own.
14
+
15
+ Data Factory is **bundled with core** (runtime-free) — no `capability add` needed; the `sungen data …`
16
+ CLI is available out of the box.
17
+
18
+ **Auto-detection (act on these, don't wait to be asked).** `sungen generate`/`sungen audit` now NOTICE
19
+ the work a unit needs, even before any field-map exists:
20
+ - **`DATA-FACTORY-UNSTANDARDIZED`** — the unit has input fields but no `qa/data-factory/<name>.fields.yaml`.
21
+ → author the field-map + `data gen` (this skill's main job).
22
+ - **`DATA-FACTORY-PRECONDITION-UNDECLARED`** — the spec describes a stateful precondition (a required
23
+ entity/state) but the test declares none. → **auto-draft a state-recipe** from the spec sentence, run
24
+ `sungen data state`, and weave its `@manual:data-setup` `Background`; confirm the drafted values with
25
+ the QA (`AskUserQuestion`) — never invent domain values.
26
+ When you see either finding, do the work rather than leaving it — that is what makes Sungen self-driving
27
+ instead of a toolbox the QA must operate.
28
+
29
+ ## The 4-source method (phuong-phap-tao-test-data.md)
30
+
31
+ Never invent values from memory. Cross-reference four sources — each covers the previous one's gap:
32
+
33
+ 1. **Spec validate rules** — required, format, min/max, business rules, and the **error/message code**
34
+ per rule. Defines the legal/illegal boundary. (Says the *law*, not every way to *break* it.)
35
+ 2. **Field-type catalog** — the accumulated "how this type breaks" knowledge (email/password/phone/
36
+ number/…). This is the Data Factory `common/` — it fills the "spec doesn't list every break" gap.
37
+ 3. **Design technique** — Boundary Value Analysis / Equivalence Partitioning / Decision Table / State
38
+ Transition — reduces the rule + candidates to a *minimal-but-sufficient* representative set.
39
+ 4. **DB mapping** — unique constraints, cross-entity dependency, real backend limits → precondition
40
+ data, not just a single input value.
41
+
42
+ Then classify every value into **Valid / Boundary / Invalid** (each invalid tagged with its error
43
+ code) and give it a `CHK-*` id for traceability.
44
+
45
+ ## The field-map — `qa/data-factory/<name>.fields.yaml`
46
+
47
+ Your main artifact. One entry per input field; the generator expands it:
48
+
49
+ ```yaml
50
+ screen: login # or flow: <name>
51
+ fields:
52
+ - name: email
53
+ type: email # a catalog field-type (see list below)
54
+ required: true
55
+ constraints: { maxLocal: 64, maxTotal: 254 } # the project's REAL limits from spec
56
+ errorMap: { M13: E1042, M02: E1001 } # catalog placeholder code → project's real code
57
+ - name: password
58
+ type: password
59
+ constraints: { minLength: 8, maxLength: 32 }
60
+ ```
61
+
62
+ **Catalog field-types** (P1): `email` · `password` · `phone` · `string` · `number-integer` ·
63
+ `number-float` · `currency` · `postcode` · `katakana` (JP). Security payload banks auto-append to a
64
+ field's invalid group via the type's `uses_security` (`sqli`, `xss`, `idor`, `broken-auth`, `upload`,
65
+ `input-validation`).
66
+
67
+ Rules:
68
+ - Pick the closest `type`; put the project's real numbers in `constraints` (they override the
69
+ catalog defaults).
70
+ - Map every `errorRef` placeholder (`M13`, `M39`, …) to the spec's real code via `errorMap`. Leave
71
+ one unmapped **only** if the spec has none — the lint flags it as an open point to confirm.
72
+ - **Complex forms:** a **group** field takes nested **`fields:`** (recursive; no `type` on the group → renders a nested object like `address.city`). A field whose rule depends on another takes **`dependsOn: { field, value }`** — recorded as a `_depends_on` note (the generator doesn't resolve the runtime condition; weave it into the scenario/`@cases`).
73
+ - Set **`unique: true`** on a field that must be fresh every run (register email/username, anything
74
+ that would clash with a record a previous run left behind). Its valid value then carries a runtime
75
+ `{{$timestamp}}` (email → `user+{{$timestamp}}@…`) so each run is unique — no cross-run cache
76
+ (which would make tests order-dependent/flaky). Prefer this over caching prior-run values. For
77
+ reusing a value produced earlier **within the same run** (register → then log in with it), bind it
78
+ via the scenario (`@dataFactory` recipe / `testData.bind`), not a cross-run cache.
79
+
80
+ ## No input fields → nothing to generate
81
+
82
+ Data Factory standardizes **field-level input data**. If a unit has no user-input fields or
83
+ parameters — a pure navigation, listing, or capture-compare flow — there is nothing to generate.
84
+ Report *"no input fields → nothing to generate"* and skip it; do **not** write an empty field-map.
85
+ Those scenarios are covered by the data create-test already produced, not by field-level test data.
86
+ (This is a correct outcome, not a gap — don't force a field-map to make the unit "processed".)
87
+
88
+ ## Blind spots — ask, never fabricate
89
+
90
+ If a field's type is **not** in the catalog — a business enum, a cross-entity constraint, a
91
+ project-specific data model — do **not** guess. Ask the QA (via `AskUserQuestion`) for: (1) the valid
92
+ set, (2) invalid / non-existent values, (3) the error code when wrong, (4) dependencies on other
93
+ fields. Record it in `qa/data-factory/project/<entity>.yaml` so it becomes reusable project catalog.
94
+ This is the core discipline: *common is never enough; when blind, think and ask — don't invent.*
95
+
96
+ ## Customizing the catalog — `.overwrite` (survives `sungen update`)
97
+
98
+ The shipped `common/` is a floor. Project rules go in `qa/data-factory/common.overwrite.yaml`,
99
+ deep-merged over the common (**later-wins**, keyed by `type` + data-point `id`) via three explicit
100
+ operations: **EXTEND** (a new `id` appends), **REPLACE** (same `id` wins; `constraints` merge
101
+ key-by-key), **DISABLE** (list ids under `disable:` to drop shipped cases that don't apply — a stale
102
+ target id warns). You can also override `security:` banks and `techniques:` the same way. `sungen
103
+ update` refreshes `common/` but never touches your overlay; a stale entry **warns you to prune it** —
104
+ it never edits your file. Nothing is silently overwritten: **`sungen data provenance`** (and a
105
+ `⟲ .overwrite →` line at `data gen`) shows exactly what your overlay changed, and each overlaid value
106
+ is tagged `via: .overwrite` in the test-data. Prefer a targeted `errorMap`/`constraints` in the
107
+ field-map for per-screen tweaks; use `.overwrite` only for rules that apply project-wide.
108
+
109
+ ## Bulk-import fixtures (CSV)
110
+
111
+ For CSV/Excel import or bulk-upload testing, `sungen data fixture --screen <name> [--rows N] [--invalid]`
112
+ turns the field-map into a fixture FILE under `qa/fixtures/`: `<name>.csv` (N valid rows; nested groups
113
+ → dotted headers; `unique` fields row-indexed) that should import cleanly, and — with `--invalid` —
114
+ `<name>.invalid.csv` (one seeded-bad row per field, **same columns as the valid file so a strict
115
+ importer fails on the data, not an extra column**) plus a **sidecar** `<name>.invalid.expected.yaml`
116
+ that says which 0-based row must be rejected and why (`field`, `chk`, `reason`, `expected_error`).
117
+ Reference the CSV from an `@api` upload (`files:`) or a UI file input, and assert row rejection against
118
+ the sidecar.
119
+
120
+ ## Verify before done — the phuong-phap §6 checklist
121
+
122
+ Run `sungen data lint` and clear it: every required field has **≥1 valid**, **boundary present**
123
+ (exact min/max, not only over-boundary) for bounded types, **≥1 invalid per rule** (not one generic
124
+ "wrong" value for many rules), no `UNRESOLVED` values, error codes mapped or explicitly left open.
125
+ Then `sungen data gen` writes the standardized `test-data/<name>.yaml`. Do not hand-edit the
126
+ generated values — change the field-map or `.overwrite` and re-run (determinism: same input → same
127
+ data).
128
+
129
+ Then run **`sungen data validate`** — the semantic check beyond coverage. It verifies each generated
130
+ value is *correct*, not just *present*: every `valid`/`boundary` value actually satisfies the
131
+ constraints and every synthesized `invalid` value actually violates them. A boundary is expanded to
132
+ **one case per point** (`min / min+1` → two cases; `< min` → min-1, below the minimum), each stamped
133
+ `expected: valid|invalid` in the output. Any `VALUE_NOT_VALID` error means a value labeled valid breaks
134
+ a constraint — fix the field-map/constraints and re-run. This is what stops the "structurally right but
135
+ semantically wrong" data (e.g. a "below minimum length" case that is actually long enough to pass).
136
+
137
+ **Applicability & profiles.** The generator only emits cases that apply, and reports the rest (never
138
+ silent). Set **`required: true|false`** correctly — an optional field drops the "empty (required)" case;
139
+ a numeric field with `min ≥ 0` drops the negative example. Security/injection payloads land in their own
140
+ **`adversarial:`** bucket, separate from `invalid:`. Dropped cases show up as `_not_applicable` in the
141
+ output + a `NOT_APPLICABLE` lint info. A `--profile` (`regression` default · `functional` · `smoke` ·
142
+ `security-min`) and `--locale`/`--channel`/`--sink` on `data gen|validate|lint` select a reduced set;
143
+ selection is deterministic. Prefer setting `required` in the field-map over disabling the empty case.
144
+
145
+ ## Domain / stateful preconditions (spec + viewpoint only — no DB/API)
146
+
147
+ Field values are not enough when a test needs a **business state first** — "a paid order of user A",
148
+ "a valid unused reset token ≤24h", "the session-storage buffer holds the entered values". Declare a
149
+ **state-recipe** in `qa/data-factory/recipes.yaml` under `resources:` — each resource has an `entity`,
150
+ a **`provenance`** (`prior-flow` | `fixture` | `client-storage` | `server-context` | `manual` |
151
+ `api` | `db`), optional `dependsOn`, `desiredState`, `lifecycle` (`reusable`/`consumable`/`expiring`/
152
+ `leased`/`mutable-state`/`unique-per-run`), and `with:` values — plus `bindings:` (`orderId: ${order.id}`).
153
+ **Auto-draft it — don't make the QA hand-write it.** When the spec describes a precondition (or you saw
154
+ a `PRECONDITION-UNDECLARED` finding), run **`sungen data state --scaffold <unit>`**: it drafts a recipe
155
+ skeleton from the spec's precondition sentences (one resource per signal, provenance guessed, entity
156
+ left as `TODO`). Then **fill each `entity` + `desiredState`/`bindings` from the spec and confirm the
157
+ domain specifics with the QA (`AskUserQuestion`)** — never invent domain values.
158
+
159
+ Run **`sungen data state`**: it validates the graph (cycles, dangling deps, bindings) and renders a
160
+ standardized **manual precondition** block — tagged **`@manual:data-setup`** when it can't be
161
+ auto-provisioned — to weave into the scenario's `Background`. **This works with only spec + viewpoint:
162
+ provenance is usually `prior-flow`/`fixture`/`manual`, NOT DB/API.** If a datasource is later added and
163
+ a resource uses `api`/`db` provenance (+ a `provider:` endpoint), the *same* recipe auto-provisions — no
164
+ rewrite. For a **journey where the same data flows across screens** (setup → confirmation → complete),
165
+ add `shared: { entity, screens: [...] }` so one dataset is used across all of them.
166
+
167
+ ## One QA-facing door: `/sungen:create-test`
168
+
169
+ QA never needs to remember which `sungen data …` sub-command to run. **`/sungen:create-test` is the
170
+ single entry** — it standardizes fields, validates, cross-checks, and drafts any stateful precondition
171
+ inline. The `sungen data gen|lint|validate|crosscheck|state|provenance|fixture` commands are the
172
+ **deterministic plumbing** the create-test loop (and CI) drives; run them directly only for a targeted
173
+ re-standardize. `/sungen:create-data-test` is the same pipeline on demand (re-standardize after editing
174
+ a field-map/`.overwrite`, or a unit authored before Data Factory) — not a step you must invoke after
175
+ create-test.
176
+
177
+ ## Cross-artifact check — testcase ↔ data agree
178
+
179
+ `data validate` checks the data alone; **`sungen data crosscheck`** checks the testcase and its data
180
+ AGREE: no dangling `{{var}}` (every referenced var has a value), a cross-screen `shared` dataset is
181
+ identical across the journey (confirmation shows what setup entered), and a declared state-precondition
182
+ is surfaced in the feature. Run it after the `.feature` exists; fix any `error`. Together
183
+ `data validate` + `data crosscheck` are the **Data Gate + Cross-artifact Gate** (the `data-only`
184
+ harness profile). Every `data gen` also stamps a `_fingerprint` (catalog+generator+context hash) so a
185
+ reader/cache can tell whether the inputs that produced the data changed.
186
+
187
+ ## Boundary completeness + trim
188
+
189
+ Boundary Value Analysis is **complete by construction**: for every bounded dimension in the field-map's
190
+ `constraints` — including ones the field-type's catalog didn't model (e.g. an **email `minLength`**) —
191
+ the generator auto-emits the full set **min-1 (invalid) · min · min+1 · max-1 · max · max+1 (invalid)**.
192
+ So a spec "email min 5" yields length 4 (invalid), 5, 6 — don't hand-add them. Text fields also carry a
193
+ **leading/trailing-whitespace** case (trim behaviour: the server must trim then accept, or reject per
194
+ spec — confirm). If `data validate`/the QA still finds a missing boundary, it means the constraint was
195
+ absent from the field-map — add it there.
196
+
197
+ ## Login / authentication screens — credential-state cases (experience)
198
+
199
+ A login screen is not just field-format validation. The catalog carries an **experience checklist**
200
+ (`auth-account-states`) of credential/account STATES a login must cover — each a scenario, most needing
201
+ a domain-state precondition (a seeded account in that state; declare it with a state-recipe →
202
+ `@manual:data-setup` Background):
203
+ - **active** (happy path) · **wrong-password** · **non-existent** (same generic error — anti-enumeration)
204
+ - **soft-deleted** (must NOT authenticate — real-world bug precedent) · **locked/suspended** ·
205
+ **unverified-email** · **password-expired** · **valid-with-surrounding-whitespace** (trim → accept).
206
+ When the unit is a login/auth screen, generate these as scenarios (confirm the exact outcome/message
207
+ code with the spec). Do not assume the outcome — ask the QA for states the spec doesn't pin.
208
+
209
+ ## Weaving into scenarios
210
+
211
+ When a `.feature` exists, express invalid/boundary sets as data-driven `Scenario Outline` + `Examples`
212
+ (`@cases`) referencing the values — see `sungen-gherkin-syntax`. This keeps one logic + many values
213
+ instead of copy-pasted scenarios, and each row carries its `CHK-*` id for traceability.
@@ -6,6 +6,7 @@ user-invocable: false
6
6
 
7
7
  ## ⚠️ Gotchas — read before generating
8
8
 
9
+ - **Field-level test-data follows the Data Factory standard — don't hand-invent values.** When the unit has input fields, the field values (valid / boundary / invalid + error codes) come from the **`sungen-data-factory`** catalog via a field-map + `sungen data gen` (create-test step 5.3), not free-form guessing. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. This skill still owns scenario structure, viewpoints, and non-field oracles.
9
10
  - **Write incrementally — never emit the whole suite in one response.** Build the `.feature` in batches via successive `Write`/`Edit` (≈10–15 scenarios per call). For **Full coverage**, write tier-by-tier: `Write` Tier 1 → `Edit` append Tier 2 → `Edit` append Tier 3.
10
11
  → One huge `Write` can exceed the model's output-token cap → `API Error: Claude's response exceeded the N output token maximum`. Single-pass full coverage only fits when `CLAUDE_CODE_MAX_OUTPUT_TOKENS ≥ 64000`; otherwise batch. Batching also lets the audit/reviewer run per batch — higher quality.
11
12