---
name: ba-audit-rules
description: >
  Audits the business rules of a `.smartstack/ba/` module — completeness,
  conflicts, redundancy, example quality, entity/UC references, per-ruleType
  edge-case coverage, and — at app/project scope only — cross-application
  similarity (warn) (BR-001..012). Reads `règles-métier.md` plus the module's
  `use-case.md` and `entité.md`, writes a verdict to `_audit/règles-métier.md`.
  Run after `/ba-create-business-rules` or as part of pre-dev readiness.
allowed-tools: [Read, Write, Glob, Grep, Bash]  # Bash: the audit-ba engine (deterministic mechanical rules)
---

# ba-audit-rules — Business Rules audit

You audit the business rules of a `.smartstack/ba/` module against the rules
below and write a verdict file. The rule set is unchanged from the SmartStack
convention; only the I/O is file-based.

## 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":["rules"]}'
   ```

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** every `report.judgmentNeeded[]` entry of this dimension (BR-012) 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/règles-métier.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.

## Gate dependencies

- **Upstream**: the use-cases phase must be ready before rules can be considered
  complete. If any UC in scope lacks a detailed main flow, this phase cannot
  complete — BR-009 emits `err` regardless of rule count.
- **Downstream**: the RBAC phase depends on this phase being ready (rules
  materialise access/ownership permissions).

## Scope

- **Module scope** (default): audit rules whose scope belongs to the target
  module. UCs are audited for UC → rule coverage within the same module.
- **Section scope**: restrict every check (BR-001..011) to rules whose section
  matches the selected section. BR-001 becomes "at least 1 rule for the selected
  section"; BR-007 becomes "every UC in the selected section has ≥1 linked rule".
  Read only the section's `règles-métier.md` and `use-case.md`.
- **Application / project scope**: rules from all descendant modules apply —
  **plus BR-012** (cross-application similarity, warn). BR-012 is the ONLY rule
  allowed to look at other applications, and it READS them only — it never
  audits, counts, or fixes their rules. At module/section scope, skip BR-012 —
  emit zero cross-app findings.
- Rules outside the active scope are out of scope. The verdict file lives at the
  audited module's `_audit/règles-métier.md`.

## Rules

### BR-001 — At least 1 business rule exists per module
- `err` if 0; `ok` if ≥ 1.
- Fix: `/ba-create-business-rules`.

### BR-002 — Rules carry complete examples (Level 2)
- `err` if any rule with examples is incomplete; `warn` if no examples at all on
  ≥1 rule; `ok` if all complete.
- **What to check**:
  1. Rules with no examples → `warn` — rule still at Level 1 shell stage.
  2. Rules with ≥1 example must have **≥1 valid + ≥1 invalid** → `err` if missing
     either side.
  3. Every example must have a non-empty given, when, then → `err` if any field
     blank.
  4. **Error-code rules only** (rule has a populated error code or error
     message — NOT to be confused with the optional `**Enforcement**` opt-out
     field, which names a non-scaffolded channel): invalid examples must have
     an expected error code OR expected
     error message → `err` if both missing. **Filter/visibility rules** (rule
     has no error code AND no error message, e.g. soft-delete guards,
     anonymisation filters, scope isolation) describe observable absence —
     invalid examples legitimately leave the expected error code and message
     empty. Do NOT flag these.
- Fix: `/ba-create-business-rules`.

### BR-003 — No conflicting rules (same condition, different outcomes)
- `err` if conflicts found; `ok` if none.
- Check: normalize conditions (lowercase, trim). Group by condition. If the same
  condition has different expressions → conflict.
- Fix: `/ba-create-business-rules`.

### BR-004 — No redundant rules (same condition AND same expression)
- `warn` if found; `ok` if none.
- Fix: `/ba-create-business-rules`.

### BR-005 — (relocated to DM-010 in `/ba-audit-data-model`)
Entity-reference validation moved to the data-model audit where the entity
catalogue is authoritative. No check here.

### BR-006 — All rules are linked to at least 1 use case
- `warn` if unlinked; `ok` if all linked.
- Direction: rule → UC. Complement of BR-007.
- Fix: `/ba-create-business-rules`.

### BR-007 — Every use case in scope is covered by ≥1 business rule
- `err` if UCs without rules; `ok` if every UC has ≥1 linked rule.
- Direction: UC → rule. Complement of BR-006.
- Check: for each UC in scope, count rules whose linked use cases contain the UC
  code. If 0 → UC is uncovered.
- Why `err` (not `warn`): a UC without rules cannot be vibecoded — the generated
  code would have no invariants, no validation, no failure paths. Downstream code
  generation breaks.
- Fix: `/ba-create-business-rules`.

### BR-008 — Examples cover the edge cases expected for the ruleType
- `warn` if obvious edge cases are missing for the ruleType; `ok` if covered.
- Reference: `create-business-rules` edge-case checklist by ruleType.
- Check per ruleType (minimum expected coverage — at least one example hitting each):

  | ruleType | Required edge cases (pick ≥2 of) |
  |----------|----------------------------------|
  | `validation` | null/empty, boundary (min/max length), format mismatch, case-insensitive dup |
  | `calculation` | zero, negative, rounding boundary, division by zero when applicable |
  | `state-transition` | illegal skip, reverse transition, terminal-state exit |
  | `ownership` | owner allowed, non-owner denied, manager/admin bypass |
  | `constraint` | at-limit boundary, just-above/below, null-vs-zero |
  | `derivation` | missing input (null component), recompute-on-update |
  | `workflow` | threshold boundary, delegation, timeout |
  | `integrity` | soft-deleted parent, cascade, orphaned child |
  | `cross-cutting` | batch operation, system/service account, retry |
  | `compliance` | retention expiry, retroactive policy change |
  | `access` | actor with permission, actor without permission |
  | `numbering` | sequence progression, per-tenant isolation, reset boundary, concurrent allocation (no duplicate) |

- How to detect coverage: scan each example's label, given, when, then for
  keywords from the expected list (case-insensitive). If fewer than 2 of the
  expected edge-case themes are matched → `warn`.
- Fix: `/ba-create-business-rules`.

### BR-009 — Upstream gate: every UC in scope must be detailed
- `err` if any UC in scope is not detailed; `ok` if all detailed.
- **Why**: per the gate chain `actors → UCs → rules → permissions`, rules cannot
  be considered complete while use cases are still in progress. Without detailed
  main flows, rules have nothing concrete to constrain and any downstream code
  generation would produce empty validation paths.
- **Check**: a UC is "detailed" when it has ≥1 main-flow step. Read the module's
  `use-case.md` and collect every UC code in scope (module or section) whose main
  flow is empty.
- Fix: `/ba-create-business-rules` (and re-run `/ba-create-use-case` for the
  undetailed UCs).

### BR-010 — Numbering rules are fully specified
- `err` if a `numbering` rule misses its generation spec; `ok` if all complete or
  no `numbering` rule in scope.
- **Why**: a `numbering` rule drives a code/sequence allocator. Without a complete
  spec the generated numbering is ambiguous (wrong scope = collisions across
  tenants; missing reset = ever-growing counter; unknown gapless = wrong allocation
  mode, DB-locked gapless vs HiLo). The allocator itself is the socle's — a rule
  must never prescribe a counter table.
- **What to check**: for each rule with `Type: numbering`, its Condition/Expression
  must state all four — a **format** template built from the socle tokens only
  (`{SEQ:n}` required unless a `{FIELD|UPPER|LOWER|SLUG|INITIALS|ABBR:Champ}` token
  is present; `{YYYY}`/`{YY}`/`{MM}`/`{DD}`/`{TENANT}` for the rest — an invented
  token such as `{NNNN}` is rejected by the engine at every insert), a
  **sequence scope** (`tenant` / `global` — those two only), a **reset** period
  (`none` / `yearly` / `monthly` / `daily`), and whether it is **gapless**. A reset
  period MUST match a date token in the format (yearly ⇒ `{YY}`/`{YYYY}`). Examples
  must include ≥1 valid showing the sequence **progressing** and ≥1 invalid showing
  the **no-duplicate** (concurrency / cross-tenant) or **immutability** guarantee.
- **Code-pattern landing (conditional leg)**: when the module's `entité.md`
  exists, each `numbering` rule's target entity must carry the matching
  `**Code pattern**` line → **warn** here if missing (the blocking err is
  DM-017 check 6, which runs when both docs exist — a numbering rule without
  its codePattern is invisible to the whole dev chain: `ruleExemption`
  presumes the channel, DEV-API-022 never arms, the dev agent improvises an
  allocator). When `entité.md` does NOT exist yet (rules are Phase 4, the data
  model Phase 6), surface an explicit note "code-pattern landing not yet
  verifiable — entité.md absent (DM-017 check 6 will gate it)" — NEVER a
  silent skip.
- Skip when the module has no `numbering` rule.
- Fix: `/ba-create-business-rules`.

### BR-011 — Error codes carry the module prefix
- `err` when an enforcement rule's error code is not `lower.dotted` with >= 3
  segments starting with the module's code (`{module}.{entity}.{cas}`, e.g.
  `parc.vehicule.immat-unique`); `ok` otherwise.
- **Why**: error codes are the API's public error contract — they land verbatim
  in AC, generated tests and i18n keys. An unprefixed code (`amount-positive`,
  `immat-unique`) collides the day a second module coins the same case; on one
  client every PARC code shipped without its module segment and could no longer
  be namespaced after the fact.
- **What to check**: every rule of the enforcement pattern (error code present)
  matches the format and its first segment equals the module code. Filter /
  visibility rules (blank code by design) are exempt. Legacy `UPPER_SNAKE`
  codes = err, with the dotted equivalent proposed in the finding.
- Fix: `/ba-create-business-rules` (Level 2 — ELABORATE names the format).

### BR-012 — Cross-application rule similarity (app/project scope only)
- **Severity**: `warn` only — never `err`, never blocking (`/ba-audit-pre-dev`
  counts only `err` findings).
- **Gate**: apply ONLY when the audit scope is application or project. At
  module/section scope, skip — emit zero BR-012 findings.
- Compare the audited scope's rule titles and expressions against the `### BR-`
  headings (and `Expression` lines) of the OTHER applications (Grep;
  whole-token, case/accent-insensitive matching — never substring).
- **Contextual analysis REQUIRED** — a lexical hit is not a finding. TRUE
  duplicate: the same business constraint re-modelled on the same concept in
  two apps (the same discount-cap rule, the same retention policy). Contextually
  different: same words, different business object, threshold, or jurisdiction
  (a « montant plafonné » rule in SALES vs in EXPENSES is legitimate). Do NOT
  use a hardcoded whitelist — analyze the business semantics.
- Finding: written in the verdict of the module OWNING the flagged rule — cite
  both codes (local `BR-NNN` + foreign app/module + `BR-NNN`) and one line on
  the overlap. Fix: user arbitration (keep both, reword the local one, or
  consolidate by hand) — NEVER an edit of the other application's docs; there
  is no automated fix path.

## Output

Write `_audit/règles-métier.md` per the doc-templates skeleton:
- Header `# Audit règles métier — <APP> / <MODULE>` + `_<date> · Verdict :
  <emoji> N warn · M err · K ok_`.
- `## ✅ Conforme`, `## ⚠️ Avertissements`, `## ❌ Bloquants` sections; one bullet
  per finding. Keep rule codes (`BR-001`, …) **bold** so they stay greppable, but
  explain each in business terms. For `warn`/`err`: what's wrong (offending rule
  / UC codes **bold**), why it matters, and a `→` fix naming
  `/ba-create-business-rules`.
- 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`, state clearly that the rules 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/règles-métier.md` as usual — the orchestrator reads
these files.
