---
name: ba-audit-cross-dimension
description: >
  Cross-dimension coherence audit of one `.smartstack/ba/` module — verifies that
  data-model fields with state semantics have matching business rules, use cases
  and screens, that use-case actors exist in RBAC, that screen entity refs
  resolve, that a kanban is a view of its list and not its own section, that
  transition-captured attributes are not asked at creation, that a dated child
  can be born, and that a 360 related tab onto a ≥ confidentiel entity
  (lib/ba-sensitivity) carries its backticked permission AND its list target —
  the « first 4 attributes » fallback is the leak (XD-001..009). Reads the
  module's `entité.md`, `règles-métier.md`,
  `use-case.md`, `rbac.md` and its section `screen.md` files together, writes a
  verdict to `_audit/cross-dimension.md`. Run after the per-dimension audits or as
  part of pre-dev readiness.
allowed-tools: [Read, Write, Glob, Grep, Bash]  # Bash: the audit-ba engine (deterministic mechanical rules)
---

# ba-audit-cross-dimension — Cross-dimension coherence audit

You audit ONE business module of a `.smartstack/ba/` project for coherence
**between** its dimensions (data model ↔ rules ↔ use cases ↔ screens ↔ RBAC) and
write a verdict file. The rules are unchanged from the SmartStack convention; only
the I/O is file-based. This audit is inherently cross-doc — a single dimension in
isolation cannot tell you whether a state field is missing its transition rule, so
you read several docs of the module together and cross-check them.

## Deterministic engine — how this audit runs

The MECHANICAL rules of this dimension are evaluated by the shared `audit-ba`
CLI (see `/ba-audit-run`) — **never by reading the corpus yourself, never by
spawning per-module subagents** (the 394M-token incident shape). Your only
job here is the judgment residue.

1. **Run the engine, scoped to this dimension**:

   ```bash
   npx --prefer-offline tsx skills/business-analyse/audit-run/cli/audit-ba/index.ts \
     --spec '{"baRoot":".smartstack/ba","scope":{"app":"<APP>","module":"<MODULE>"},"dimensions":["cross-dimension"]}'
   ```

2. **Exit 3 = parsing suspect -> STOP.** A control counter disagrees with the
   parser (`report.parseControl.perDoc`): fix the doc's form or report the
   parser bug, then re-run. Never « complete by hand » — no green verdict may
   be born from a silent parser.
3. **Arbitrate** (optional) the `report.judgmentAdvisory[]` entries — internal to the application, an advisory review that never blocks, capped at `warn` (XD-002, XD-008) from its `question` + `excerpts` ONLY (they are complete by contract — needing more is a CLI bug to report, never a license to read the corpus). Write the decisions JSON to the scratchpad and re-run with `\"judgments\":\"<path>\"` — the CLI merges, consumes the pending items and rewrites the verdict itself (you never write verdict markdown).
4. **Chat summary** (3-6 lines, business terms): the PARSE TOTALS (say the
   counts — that is how a « 0 erreur » stays verifiable), err/warn counts,
   remaining judgments, and the fix skill each finding names.

The CLI writes the verdict to `.smartstack/ba/<APP>/<MODULE>/_audit/cross-dimension.md`
(existing format — anchor, `Verdict :` header, emoji sections; `0 err` =
pass for the downstream gate). The rule texts below remain the AUTHORITATIVE
spec — the CLI registry is drift-tested against them.

## Rules

State semantics, throughout: an attribute carries **state semantics** when its
name contains `status`, `state`, `phase` or `step`, **or** its type is an `enum`
whose values look like a lifecycle (e.g. `NOUVELLE/GAGNEE/PERDUE`,
`DRAFT/APPROVED/REJECTED`). Identify these per entity first, then apply XD-001..003.

### XD-001 — State fields have transition rules
- `warn` if a state field is missing a transition rule; `ok` if covered.
- Check: for each entity attribute with state semantics, verify at least one
  business rule of type `state-transition` (or whose condition governs the
  status/state change) references that entity. List the uncovered entities.
- Why it matters: without a transition rule the allowed status changes are
  undefined — FluentValidation has nothing to enforce and the UI cannot gate
  illegal transitions.
- Fix: `/ba-create-business-rules`.

### XD-002 — State fields have corresponding use cases
- `warn` if a state field has no use case describing its change; `ok` if covered;
  a **judgment** when a candidate use case exists without the mechanical proof.
- Check: for each entity with a state field, at least one use case must be
  **linked** to the entity AND **move** its state.
  - **Linked** — the use case's code is listed in the entity's `**Traçabilité**`
    (the BA's own declaration), or the entity name appears in its title or main
    flow. The traceability is what makes the rule independent of the language:
    an entity's technical name (`Memo`) never appears in a prose written in the
    client's vocabulary (« pense-bête »).
  - **Moves the state** — its title names a status action (`change`, `update`,
    `transition`, `approve`, `reject`, `validate`, `cancel`, `close`, `archive`,
    `suspend`, `activate` and their French stems), **or** it tells a move — a
    FROM and a TO: its **Préconditions** cite a declared state value and its
    **Postconditions** cite another one (`A_FAIRE` before, `TRAITE` after).
    Values are matched as whole tokens, accent- and case-folded. A creation
    (« créé au statut `A_FAIRE` », no starting state) SETS a status, it does not
    move one: it is a candidate, never a proof.
- Three outcomes per entity:
  1. a linked use case moves the state → covered;
  2. a linked use case only **cites** a state value (title, flows, conditions)
     → **judgment** (`maxSeverity: warn`): a consultation or a filter cites a
     status too, so the engine asks instead of guessing. One pending item per
     module, listing each entity with its candidate use cases — name in the
     decision's `evidence` the entities that stay uncovered;
  3. no linked use case cites any state → `warn`. List the uncovered entities.
- Why it matters: a status that nothing in the use cases ever moves is dead state;
  the workflow behind it was never specified.
- Fix: `/ba-create-use-case` — state the status in the use case's Préconditions
  and Postconditions. Never rewrite a title to carry the entity's technical name.

### XD-003 — Workflow entities have Kanban or workflow screens
- `warn` if an entity with a lifecycle of **≥ 3 states** has no workflow screen;
  `ok` if covered, or if no entity reaches the threshold.
- Check: for each entity whose state field declares **at least 3 values**, at
  least one screen of type `SmartKanban` (or an equivalent workflow board) should
  bind that entity — authored as a second screen in the entity's `*-list` section
  (see XD-006), not its own section. List the uncovered entities.
- The threshold is the one `/ba-create-screen` authors against
  (`levels/kanban-screens.md`, `references/type-mapping.md`) — one number,
  `KANBAN_MIN_STATES` in `lib/page-spec-kanban.ts`. Below it a board stays
  **allowed**, never required: a two-value status (`ACTIF/RETIRE`) is a toggle,
  not a workflow, and a rule demanding a board for it would demand the very
  screen its own fix skill tells the BA not to write.
- Why it matters: lifecycle entities are best operated on a board; otherwise users
  have no view that surfaces the workflow.
- Fix: `/ba-create-screen`.

### XD-004 — Use-case actors exist in RBAC
- `warn` if a use-case primary actor has no permission in the module; `ok` if all
  matched.
- Check: for each use case's primary actor code, verify it appears in the module's
  `rbac.md` with at least one permission entry (or is referenced by a business
  rule for the module). List the orphan actor codes.
- Why it matters: an actor that performs use cases but holds no permission cannot
  actually be authorised to do anything — the RBAC matrix is incomplete.
- Fix: `/ba-create-rbac`.

### XD-005 — Screen entity references match the data model
- `err` on a broken reference; `ok` if all valid.
- Check: for each screen that binds an entity, verify the referenced entity code
  exists in the module's `entité.md`. List the broken references (screen → entity).
- Mirror of SCR-003 — the SAME predicate (`screen-blocks.unresolvedEntityRefs`),
  never a second implementation: skip `SmartDashboard` / `SmartAppHome` /
  `SmartModuleHome` / `SmartSectionHome` whatever their `Entité` line says
  (they aggregate via widgets; the template writes `— (chaque widget porte la
  sienne)`). The two rules can never disagree on a screen.
- Why it matters: a screen pointing at a non-existent entity cannot be scaffolded —
  it breaks downstream page generation.
- Fix: `/ba-create-data-model` (add the missing entity) or `/ba-create-screen`
  (correct the screen's binding), depending on which side is wrong.

### XD-006 — A Kanban is a representation, never a section
- `err` when a `SmartKanban` is NOT co-located with a `SmartListView` of the SAME
  entity in the SAME section (i.e. the kanban stands as the sole/primary screen of
  its own section). A section must denote a business workspace; "kanban / board /
  pipeline" is a presentation, not a business concept, so it must never define a
  section.
- Check: build the module index (entity → list of {section, SmartComponent type}).
  For each `SmartKanban` bound to entity E in section S_k, require a `SmartListView`
  bound to E in that SAME section S_k. If E's `SmartListView` lives in another
  section S_l ≠ S_k, OR no `SmartListView` for E exists at all, flag the kanban —
  list its `SCR-…`, its section S_k, and the list section S_l it should join (if any).
- Why it matters: the generator renders the kanban as a viewMode of the list PAGE
  (one route `/…/list` with a Table ⇄ Kanban toggle, one permission, one section —
  the PRD folds the SmartKanban into the list pagespec). Splitting it
  into a `-board`/`-workflow`/`-pipeline` section fabricates a duplicate menu node, a
  duplicate permission and a duplicate route for one entity (the split SCR-010
  removes for filters), and the two views silently drift apart.
- Fix: `/ba-create-screen` — re-author the kanban inside E's `*-list` `screen.md` as
  a second screen (same entity, same permission, next `NNN`); if E has no list at
  all, add its `SmartListView` there first so the section is a real business
  workspace. Then drop the standalone `*-board` section via `/ba-create-menu`.

### XD-007 — Transition-captured attributes are not asked at creation
- `warn` when a create-serving form collects an attribute a workflow rule captures
  at a transition; `ok` otherwise.
- Check: parse every `- **Flow**` line of the module's `workflow`/`state-transition`
  rules and the linked custom actions' parameters (`payloadParameters[].field` ??
  `name`, else `workflowTransition.flowParameters`). For each entity attribute so
  captured, verify the entity's form screens either phase it (a `- **Cycle de vie**`
  bullet whose phase owns the field) or don't list it at all. List the offending
  (screen, field, transition) triples. Also verify, for every declared phase, that
  its statuses are enum values of the entity AND that ≥ 1 Flow line REACHES one of
  them (a phase gated on a status no transition produces can never open).
- Why it matters: a field the workflow captures later (an invoice's paymentDate on
  CREATE) duplicates the capture point and lets creation smuggle in state no
  transition ever validated — the guard/BR chain is bypassed at birth.
- Fix: `/ba-create-screen` (add the `- **Cycle de vie**` bullet or remove the field
  from the create surface); a status no Flow reaches → `/ba-create-business-rules`.

## Output

Write `_audit/cross-dimension.md` per the doc-templates skeleton:
- Header `# Audit cross-dimension — <APP> / <MODULE>` + `_<date> · Verdict :
  <emoji> N warn · M err · K ok_`.
- `## ✅ Conforme`, `## ⚠️ Avertissements`, `## ❌ Bloquants` sections; one bullet
  per finding. For each `warn`/`err`: what's wrong (offending codes — entities,
  actors, screen/entity refs — in **bold**), why it matters, and a `→` fix naming
  the owning phase skill (`/ba-create-business-rules`, `/ba-create-use-case`,
  `/ba-create-screen`, `/ba-create-rbac` or `/ba-create-data-model`, per the rule).
- Rule codes (`XD-001`, …) stay **bold** so they remain greppable, but are
  explained in business terms — no label codes, no JSON.
- Re-Write the whole file each run (overwrite — it's a fresh verdict).

Then a 3–6 line chat summary in the user's language — business terms, not rule
codes. If any `err` (a broken screen → entity reference, or a kanban modeled as its
own section), state clearly that the module's coherence must be fixed before moving on.

## Used by the readiness orchestrator

`/ba-audit-pre-dev` runs every dimension and aggregates the verdicts. When invoked
by it, still write `_audit/cross-dimension.md` as usual — the orchestrator reads
these files.

### XD-008 — A dated child has a birth for its FIRST period
- **Severity**: warn, ok otherwise.
- Check: an entity carrying a PERIOD pair (`StartDate`/`EndDate`,
  `ValidFrom`/`ValidTo`, `DateDebut`/`DateFin` in `entité.md`) that the
  screens expose only as a list / related tab, whose ONLY creating action is a
  renewal/transition (`reconduct`/`renew`/`transfer`/`changer`), leaves the
  FIRST period unbornable: opening a vehicle's first registration required
  « changer de canton », its first site attachment « le transférer » — the
  data take-on had to lie about the act it performed. Add the initial creation
  action (or a form) alongside the transition.
- Fix: `/ba-create-screen` — an explicit « ouvrir la première période » action
  or a creation form on the child.

### XD-009 — A 360 tab onto a sensitive entity is declared, never derived
- **Severity**: `err` when a declared related tab (`- **Onglet lié « … »**`
  bullet of a module screen) targets an entity resolving ≥ `confidentiel`
  (`lib/ba-sensitivity.resolveEntitySensitivity` on the TARGET's `entité.md`,
  full tree — a scoped run still sees the other application) and the bullet
  lacks its backticked permission, or — unless `affichage summary` (a band
  cartouche) — its `→ SCR-…` list target; `ok` otherwise (vacuously when no
  tab targets a sensitive entity).
- Why both: the tab's data path is gated by the permission the bullet names
  (`lib/page-spec-related-tabs` defaults it to the target's `read` — on a
  sensitive target the BA writes it, consciously); and when the target has
  no list pagespec, `derive-related-tabs-data` falls back on « the first 4
  attributes of entité.md » — on a payroll or a medical record THAT is the
  leak. The list screen decides which columns a 360 view shows; a judgment,
  never a fallback.
- Target resolution: the `app` token when written, else the relation graph
  (`findEntity`, own module preferred); an unresolved target is XD-005's /
  SCR's business, not an err here. Cross-application tabs are, in addition,
  an ACCESS request (CODE-009) when the target is sensitive.
- Fix: `/ba-create-screen` (ENRICH — write the permission and the `→ SCR-…`
  list target on the bullet; author the target list screen if it does not
  exist yet). `lib/remediation` routes it there (lane `authoring`, the
  evidence names the skill) — the one cross-dimension rule with a single
  owner; the others stay `manual`.
