---
name: ba-create-test-data
description: >
  Phase 6.5 of business analysis (OPTIONAL, after the data model). Authors the
  module's business TEST DATASET — `jeu-de-test.md` — 5 to 8 realistic,
  FICTITIOUS rows per business entity, validated by the client with THEIR
  vocabulary (their vehicles, sites, statuses). One dataset, every consumer —
  the seed of dev/test/qual (the second seed tier, next to the setup rows of
  `**Valeurs initiales**`), the fixtures of the acceptance tests, the UAT, and
  a BA simulator that shows the client's own rows instead of hash noise.
  Conversational — reads entité.md, use-case.md, règles-métier.md and the
  client sources, proposes rows in 3 tiers, the client corrects, the skill
  writes the file and runs the deterministic checker. Rows are cited across
  modules by KEY, never copied. Run after `/ba-create-data-model`, before or
  after `/ba-create-screen`; audited by `/ba-audit-data-model` (DM-029..032).
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion]
---

# ba-create-test-data — The business test dataset (`jeu-de-test.md`)

You are a **business analyst** turning the data model into a dataset the
client RECOGNISES. Two seed tiers exist in a generated application, and this
skill owns the second:

| Tier | Source | Generated | Environments |
|---|---|---|---|
| **Setup** — rows the application needs to start | `- **Valeurs initiales**` on a reference entity (entité.md, `/ba-create-data-model`) | `{Module}ReferenceDataSeedDataProvider` | every environment |
| **Test dataset** — rows that let the deployed application be EXERCISED | `jeu-de-test.md` (this skill) | `{Module}TestDataSeedDataProvider`, guarded by `IsDevelopment() \|\| SmartStack:EnableDevSeeding` | dev (implicit), test (the key), qual on demand — **never preprod/prod** |

The dataset the clients forget is the one nobody can test with once the
application is deployed. This skill exists so that it is written ONCE, in the
client's words, and reaches every consumer: the seed, the acceptance-test
fixtures, the UAT, and any BA simulator (the same markdown table `Valeurs
initiales` uses — a reader that parses one parses the other).

## Doctrine (read first)

- **Fictitious, always.** People and companies are INVENTED — plausible for
  the domain, never copied from the client sources (nLPD / RGPD). No rule can
  check this mechanically; you can. The file's blockquote says it.
- **Optional, never a blocker.** A module without business entities (only
  reference tables) needs no dataset. `/ba-audit-data-model` DM-029 WARNS when
  a module with business entities has none — it never blocks.
- **Ownership: a row belongs to the module that owns the entity.** Another
  module CITES it by its key (or its display value), never by copy. Where the
  target lives is already written: the relation's `scope` in entité.md.
- **A reference table has NO block.** Its `**Valeurs initiales**` ARE its rows
  (setup tier) — cite them from the blocks that need them.
- **Fake nothing else.** No `Id` column (ids are generated at seed), no `Code`
  on a coded entity (the engine allocates it — unless the pattern says
  `surchargeable à la création`), no computed attribute.
- **The CLI is the checker, you are the author.** `derive-test-data --mode
  check` says every incoherence and, for an unresolved citation, the OWNER
  module. You write; it verifies. Never hand-fix the generated seed.

## Inputs you read

| File | What you take from it |
|---|---|
| `<APP>/<MODULE>/entité.md` | entities, attributes (types, enum values, requis/unique), relations with their `scope`, `**Affichage**`, `**Valeurs initiales**`, `**Code pattern**` |
| `<APP>/<MODULE>/**/use-case.md` | the situations the flows walk through — each main flow, alternative and exception deserves a row that makes it playable |
| `<APP>/<MODULE>/**/règles-métier.md` | `Cas valides` / `Cas invalides` (the examples the rules already name), `Flow` transitions (every status reached must be carried by a row) |
| `<APP>/acteur.md` | the actors — a `User` FK is cited by an actor (code or label) |
| `.smartstack/sources/` (via `create-sources/cli/search`) | the client's vocabulary — names of sites, categories, real-looking codes — NEVER real people or companies |
| other modules' `jeu-de-test.md` / `entité.md` | the rows you may cite (a `Client` of ANNUAIRE for a `Facture` of FACTURATION) |

## The file — `jeu-de-test.md` (module level, next to entité.md)

Grammar and the reference rules live in `business-analyse/_workflow/doc-templates.md`
(section `jeu-de-test.md`). The shape:

```markdown
<!-- ba:jeu-de-test level=module code=ANNUAIRE -->
# Jeu de test — CLIENT / ANNUAIRE
> Personnes et sociétés FICTIVES — aucune donnée réelle.
- **Date de référence** : 2026-09-15

### JT-001 — Client (ENT-001)
- **Clé** : `Nom`

| Nom | Organisation | TypeClient | Segment | Statut | Responsable | Note |
|-----|--------------|------------|---------|--------|-------------|------|
| Direction Marketing | ACME SA | Grand compte | Industrie | Actif | Commercial | BR-003 : nom ≠ raison sociale |
| Atelier Lausanne | Garage du Léman Sàrl | PME | Services | Archivé | BA-001-AC-001 | BR-004 : archivé, lecture seule |
```

- Heading STRICTLY `### JT-NNN — <Entité> (ENT-NNN)` — nothing after the
  parenthesis (the parsers refuse a suffix there).
- `- **Clé** : \`<Attribut>\`` is MANDATORY — the upsert key, the citation key,
  unique per tenant. Prefer the display attribute (`**Affichage**`).
- Columns = PascalCase attributes and FK relations (`TypeClient`,
  `TypeClientId` or the target entity's name). `Note` is reserved and ignored
  — use it to cite the BR / UC a row exists for.
- Enum values VERBATIM; dates absolute `AAAA-MM-JJ`, read relative to
  `**Date de référence**` (never "today"); booleans `oui` / `non`.
- 5 to 8 rows: enough to carry every status a Flow reaches, one edge case per
  rule, and the situations the use cases walk through.

### Citing another row — utilisateur, client, facture

The relation in entité.md says where the target lives; you cite accordingly:

| Relation scope | The cell carries | Resolved against |
|---|---|---|
| `same-module` | the target row's key or display value | this file, or the target's `**Valeurs initiales**` |
| `cross-module (APP/MOD)` | idem | `APP/MOD/jeu-de-test.md` (or its Valeurs initiales) — the OWNER's rows |
| `core` — `User` | an ACTOR code (`BA-001-AC-002`) or label (`Commercial`) | at seed: the actor's role → the module's test user |
| `core` — `TenantOrganisation` | its `Name` (fictitious) | at seed, by Name, retried at each startup |
| `core` — anything else | leave the cell empty | not resolvable in v1 |

A citation the owner cannot resolve is the OWNER's row to add: same
application → propose it there (you may append to that module's file with
the user's explicit validation — the file stays the owner's); another
application → report it, never write there.

## Procedure

1. **Scope.** Ask which application → module (one module per run). Read the
   inputs above. List the business entities (not lookup, no Valeurs initiales)
   and, for each, the FK relations and where each target lives.
2. **Draft.** For each business entity, draft 5-8 rows in THREE tiers
   (`lib/proposal-tiers` — Obligatoire / Suggestion / Élargissement):
   - *Obligatoire*: one row per status a Flow rule reaches, one per `Cas
     valide` the rules name, the rows the main flows of the use cases need;
   - *Suggestion*: the edge cases (`Cas invalides` that are still storable,
     an archived record, a nullable FK left empty, a boundary date);
   - *Élargissement*: variety for demos (several sites, a long name, accents).
   Every FK cell must cite an EXISTING row (owner dataset or Valeurs
   initiales) — check the target modules first; list what is missing.
3. **Validate with the client.** Show the tables; the client renames with
   THEIR vocabulary. Remind them: fictitious people and companies only.
4. **Write** `jeu-de-test.md` (marker, blockquote, `Date de référence`, one
   block per entity, key bullet, table).
5. **Check** — run the deterministic checker and read its report:
   ```bash
   npx --prefer-offline tsx skills/business-analyse/create-test-data/cli/derive-test-data/index.ts --spec '{"baRoot":".smartstack/ba","app":"<APP>","module":"<MODULE>","mode":"check"}'
   ```
   `report.issues[]` names every incoherence (`unknown-column`, `missing-key`,
   `enum-value` with the verbatim suggestion, `fk-unresolved` naming the owner
   module, `cycle`, `flow-status-missing`, …). Fix the file (or propose the
   owner's rows) and re-run until `totals.err` is 0. `status: absent` means
   the file was not written where the CLI looks.
6. **Hand-off.** Say what the dataset now feeds: Phase 1 of `/ba-develop`
   runs `--mode derive` and passes `testData[]` to `scaffold-seed`
   (`{Module}TestDataSeedDataProvider`, guarded); `/ba-audit-data-model`
   verifies it (DM-029..032); `audit-dev-data DEV-DAT-010` verifies the
   provider. Not wired into `/ba-loop` (a `--from-phase` run does not know
   phase 6.5): run it explicitly per module, in the BA order (a cited module
   first).

## Non-goals

- Never a row copied from a real customer file. Never real names.
- Never an `Id`, a `Code` on a coded entity, a computed value.
- Never a block on a reference table with `**Valeurs initiales**` (DM-031).
- Never edit another application's dataset — report the missing row.
- Never write the C# seed by hand — `scaffold-seed` generates it from the
  derived JSON, and DEV-DAT-010 checks it.
