---
name: 'BUSINESS-RULES: Promote'
description: Crystallize business rules declared in an archived OpenSpec change into the catalog.
category: Business Rules
tags: [business-rules, catalog, openspec]
---

Promote rules declared in an archived OpenSpec change into the business-rules catalog.

This is the bridge between OpenSpec (where the change describes what rules are touched) and the catalog (where the rules live as reference material). Run it AFTER `/opsx:archive` for any change whose `proposal.md` includes a `## Business rules affected` section with declared actions.

---

**Input**: Optionally specify an archive name. If omitted, the most recently archived change is used.

**Steps**

1. **Preview before applying (recommended for non-trivial changes)**

   ```bash
   npx tsx scripts/business-rules/promote.ts <archive-name> --dry-run
   ```
   The script reports the actions it would take without modifying the catalog.

2. **Run the script**

   ```bash
   npx tsx scripts/business-rules/promote.ts <archive-name>
   ```
   Without arguments, the script picks the most recent directory under `openspec/changes/archive/`.

   The script (Node, no LLM):
   - Reads `openspec/changes/archive/<name>/proposal.md`.
   - Locates the `## Business rules affected` section.
   - For each declared action:
     - `mantiene BR-...` → no-op (the rule is referenced but unchanged).
     - `deroga BR-...` → flips `Estado` to `derogated`, appends a derogation note pointing to the archive.
     - `extiende BR-...` → leaves the rule active; reports a reminder to update "Reglas relacionadas" manually.
     - new rules declared as `- en \`<bc>/<aggregate>\` — <title>` → creates a scaffold inside the destination `cliter/<bc>/business-rules/<aggregate>.md` with: real sequential ID, `Estado: proposed`, body sections marked `[VERIFICAR]`.
   - Regenerates `cliter/business-rules-index.json` and `docs/business-rules/INDEX.md`.

3. **Fill the body of each new rule (in this same session)**

   For every rule the script reports under "Reglas nuevas creadas (state=proposed)", continue immediately:

   a. Read the source material that describes what the rule should say:
      - `openspec/changes/archive/<name>/proposal.md` (intent of the change).
      - `openspec/changes/archive/<name>/design.md` and `specs/` if present.
      - The implementing code under `backend/src/@app/<bc>/<aggregate>/`, `backend/src/@api/<bc>/<aggregate>/`, and `frontend/src/app/.../<aggregate>/`.
      - Tests for the aggregate (`*.spec.ts`).
      - The aggregate's `*.aurora.yaml` and `cliter/<bc>/CONTEXT.md`.

   b. For each new rule scaffold, replace each `[VERIFICAR]` section with real content:
      - **Enunciado**: one or two sentences in Spanish describing the rule.
      - **Casos exhaustivos**: a markdown table enumerating the relevant cases. Mark `[VERIFICAR caso N]` only on rows you genuinely cannot derive from the code.
      - **Implementa**: cite the actual paths and lines that implement the rule (e.g., `backend/src/@api/.../foo.handler.ts:42`).
      - **Tests**: cite real test files and test names. If none exist, leave the section with a brief note saying so.
      - If the rule describes effects propagating across aggregates, add a `### Diagrama de cascada` section.

   c. Adjust the metadata table:
      - Change `Estado` from `proposed` to `active` (the code is already implemented because we are post-archive).
      - Adjust `Severidad` to `informational` if appropriate (default scaffold is `blocking`).

   d. **Confirm with the user** before writing each rule body. Do not write to the file silently; show the user the proposed body and ask for confirmation or amendments.

   e. After all rules are completed, run `pnpm br:generate && pnpm br:validate` (the pre-commit hook will also do this on commit).

4. **Cross-aggregate / cross-BC pointers**

   If any of the new rules declares multiple bounded contexts or aggregates in its frontmatter (the `proposal.md` should hint at this), add the corresponding pointer entries in the non-owning files. See `references/format.md` for templates.

5. **Commit**

   The changes to the catalog and the regenerated index belong in the same commit, ideally with a `chore(business-rules):` or `feat(business-rules):` prefix referencing the archive name.

**Guardrails**

- Always run `--dry-run` first when the archive declares multiple rules or any derogation.
- The script never deletes a rule entry. Derogated rules remain visible with their identifier permanently taken; this is intentional for historical citation traceability.
- If the script reports `(no encontrada en el catálogo)` for an existing-rule action, double-check the identifier in `proposal.md` is correctly typed and matches an entry in `cliter/business-rules-index.json`.
- New rule entries should never reuse a derogated rule's identifier (the script handles this automatically by always picking the next sequential).
- Do NOT leave rules in `Estado: proposed` with `[VERIFICAR]` markers in the committed catalog unless there is a deliberate reason (e.g., documenting an intent that has not been implemented yet, like a known gap product wants closed). The whole point of step 3 is to bring each rule to `active` with real body in the same session.
- Before confirming step 3, the rule should not have any `[VERIFICAR]` markers in section headers (only inside specific table rows where you genuinely cannot derive the answer from code).
