---
name: 'BUSINESS-RULES: Audit'
description: Run the business-rules catalog audit (structural + semantic tensions).
category: Business Rules
tags: [business-rules, audit, drift, semantic]
---

Audit the business-rules catalog. Two parts run back-to-back in the same session:

1. **Structural** — handled by `scripts/business-rules/audit.ts`. Counts, drift, outstanding assumptions, cross-BC pointers.
2. **Semantic** — handled by Claude in the continuation of this session. Pairwise tension analysis between rules to detect latent contradictions, undeclared derogations, and exceptions not marked as such.

This follows the same script + LLM continuation pattern as `/business-rules:promote`: the script automates what is deterministic; Claude does what requires reasoning. No SDK, no API key, no scheduled job.

---

**Input**: Optional flags forwarded to the structural script:

- `--json` → machine-consumable JSON for the structural report only.
- A bounded-context name (e.g., `production-planning`) to scope the semantic part to a single BC.

**Steps**

1. **Run the structural audit**

   ```bash
   npx tsx scripts/business-rules/audit.ts
   ```

   Or for JSON:

   ```bash
   npx tsx scripts/business-rules/audit.ts --json > /tmp/audit.json
   ```

   The script reports four sections:

   - **A) Health** — counts, BCs covered, estimated catalog size in tokens, size bucket.
   - **B) Drift** — `Implementa` paths missing, orphan citations in code, zombie rules (active but uncited).
   - **C) Outstanding assumptions** — `[VERIFICAR]` and `[ASUNCIÓN]` markers older than 30 days.
   - **D) Cross-BC pointers** — rules listing multiple `bounded_contexts` whose pointer entries are missing in the non-owning BC's catalog files.

   Exit codes: 0 (clean), 2 (warnings present). The structural report is the input for step 2 (Claude needs the rule counts to decide whether the semantic sweep is warranted).

2. **Semantic tension sweep (Claude continues here)**

   Skip this step in any of these cases:
   - Total active + proposed rules == 0 (catalog empty).
   - Total active rules == 0 (only proposed scaffolds present, nothing to compare semantically).
   - The user explicitly asked for a structural-only audit (`--structural-only` flag, or said so in the prompt).

   Otherwise, perform the pairwise semantic analysis:

   a. **Load the index**

      Read `cliter/business-rules-index.json`. Build the working set as the union of `state: active` and `state: proposed` rules (skip derogated). If the user passed a bounded-context name as argument, filter the working set to rules whose `bounded_contexts` array contains it.

   b. **Pair rules to compare**

      Generate pairs (A, B) where A and B share at least one of: `bounded_contexts`, `aggregates`, or a `keywords` entry. Do NOT compare every rule against every other — that explodes quadratically and most pairs are orthogonal by construction. The shared-attribute heuristic catches the pairs that have any chance of tension.

      If the working set is large (>40 rules) and the bucket from step 1 is `WARN` or `SOFT_ERROR`, ask the user whether to proceed with the full sweep or scope it (e.g., "this will compare ~120 pairs across 3 BCs; do you want to filter to one BC first?").

   c. **Read each pair's body**

      For every pair, read the rule body from the `filePath` in the index. The body is what carries the actual semantic content (Enunciado, table of cases, cascade diagrams). Frontmatter and the index alone are not enough.

   d. **Classify the pair**

      For each pair, produce:
      - **Verdict**: `contradiction` | `extension` | `orthogonal` | `needs-review`.
      - **Confidence**: `0.0`–`1.0`.
      - **Explanation**: one or two sentences in Spanish describing the tension (or its absence).

      Definitions:
      - `contradiction` — the rules cannot both hold simultaneously without one explicitly derogating or excepting the other. Report all of these.
      - `extension` — one rule extends the other (e.g., a more specific case). Report only if confidence < 0.7 (i.e., uncertain whether it's a clean extension or a hidden tension).
      - `orthogonal` — independent concerns. Do not report.
      - `needs-review` — too ambiguous to classify automatically. Report.

   e. **Print the semantic section**

      Append section **E) Semantic tensions** to the structural report:

      ```
      E) TENSIONES SEMÁNTICAS
        Pares analizados:    <N>
        Pares reportados:    <M>  (contradicciones <c>, needs-review <r>, extensiones dudosas <e>)

        - [BR-XXX-YYY-001] vs [BR-XXX-YYY-002] — contradiction (0.85)
          <one-sentence explanation in Spanish>

        - ...
      ```

      If no tensions are reported, print: `✓ Sin tensiones semánticas detectadas (analizados <N> pares).`

3. **Decide on actions**

   For each finding, decide:

   - **Structural**:
     - Missing `Implementa` paths → either the code was renamed (update the rule) or the rule is genuinely stale (consider derogation).
     - Orphan citations → fix the citation or document the missing rule.
     - Zombie rules → consider adding `@rule` comments, or note that the rule is policy/configuration without code.
     - Outstanding assumptions → resolve `[VERIFICAR]` / `[ASUNCIÓN]` and edit the rule in place.
     - Cross-BC pointers missing → add the apuntador in the indicated BC's file.
   - **Semantic**:
     - `contradiction` → derogate one of the rules and create a new one (Workflow C in `references/workflow.md`); or if it's a legitimate exception that was never declared, add a cross-reference in "Reglas relacionadas" of both rules.
     - `needs-review` → bring the pair to a domain stakeholder; the LLM is uncertain.
     - `extension` reported with low confidence → verify it really is an extension; if so, document the relationship.

4. **Commit fixes**

   Group related fixes into focused commits with `chore(business-rules):` or `fix(business-rules):` prefixes.

---

## Buckets de tamaño (estructural)

The size bucket from section A informs how to scope step 2:

- `OK` (< 150 active rules) — full semantic sweep is fine.
- `INFO` (150–249) — full sweep still feasible; consider scoping to a BC if the report is noisy.
- `WARN` (250–499) — start filtering by BC. Ask the user before running the full sweep.
- `SOFT_ERROR` (500–999) — filtering by BC is mandatory. Do not run the full sweep without explicit user opt-in.
- `REARCHITECT` (≥ 1000) — pairwise no longer scales; recommend RAG/sub-catalogs/embeddings before running.

---

## Guardrails

- The structural script is read-only. Step 2 is also read-only; Claude must NEVER modify the catalog from inside this command.
- The semantic verdicts are **best-effort guidance**, not enforcement. Treat the report as input for human review, not as ground truth.
- Pre-commit runs `br:validate` and `br:generate`, so structural errors should not reach this audit in normal flow.
- Don't suppress findings without explicit reasoning; they are signals about catalog health.
- The semantic sweep uses the tokens of the active Claude Code subscription. There is no API key, no SDK call, no remote routine — the analysis happens in this session.
