---
name: ba-reconcile-menu
description: >
  Reconciles the `.smartstack/ba/` menu tree (sections/modules currently in
  `index.md`) against the codes embedded in downstream documents (`use-case.md`,
  `screen.md`, `règles-métier.md`, `rbac.md`). Detects RENAMES (heuristic) and
  DELETIONS, asks the user to validate the diff, then rewrites the downstream
  docs (drops stranded UC/SCR/BR/RBAC blocks, scrubs body references, renames
  codes in place). Idempotent. Run AUTOMATICALLY as Phase 0.5 of `/ba-loop`
  whenever the menu was modified after content was created — never skip a
  modified menu, always audit and correct.
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion]
argument-hint: '[--dry-run] [--app APPCODE]'
---

# ba-reconcile-menu — Menu reconciliation

You are the **menu reconciler**. Your job: when the user has modified the
menu tree (`/ba-create-menu`) after downstream content was generated,
detect what changed (rename or delete of a section/module) and either
**migrate** the existing UC/SCR/BR/RBAC codes to the new code or **clean
up** the stranded blocks.

You **never invent content** — you delete stale references and rename codes
that the heuristic (Levenshtein + UC overlap) confidently matches. When in
doubt, you **defer to the user** via `AskUserQuestion` before applying.

## Why this skill exists

`/ba-loop` (and the per-phase `/ba-create-*` skills) operate in "enrich" mode
— they **add** items but **never remove**. If a section disappears from the
menu, its UCs / screens / rules still exist in the downstream files and
become orphans. The audits don't detect this by default (the SEC-007 and
UC-019 rules were added to catch it, but those audits **report** the problem;
this skill **fixes** it).

The rule the orchestrator follows:

> **En cas de modification du menu lors d'un rerun, tu ne peux pas skipper :
> tu dois auditer si ce qui a été fait est correct et corriger si ce ne
> l'est pas.**

**Deterministic edits leave nothing to reconcile.** When the tree was changed
through `/ba-create-menu`'s `menu-node` CLI (add / rename / delete), the
downstream docs were rewritten at the same time, knowing `from → to` — long
codes (module renames and 4-segment resource codes included), rbac.md
permission paths, `depends=`, `cross-module` relation scopes, pagespec
references, `previousCodes=`. This skill then finds no ghost: that is the
expected outcome, not a skipped step. It remains the net for HAND-MADE edits
(a folder renamed in the explorer, a section removed by `rm`), where the
rename has to be guessed (Levenshtein + UC overlap below) — and a guess can
be wrong: a module rename is never recognised here (every section of the
module comes back as a DELETE), so prefer the CLI whenever the intent is
known. The two engines share their text rewriters (`lib/ba-menu-tree.ts`).

## Inputs

- The `.smartstack/ba/` tree must exist (otherwise the menu hasn't even been
  created — defer to `/ba-create-menu`).
- Optional `--app APPCODE`: scope to one application (default: all).
- Optional `--dry-run`: report the plan without writing.

## Workflow

### Step 1 — Dry-run scan

Invoke the CLI in dry-run mode to discover what changed:

```bash
npx --prefer-offline tsx skills/business-analyse/reconcile-menu/cli/reconcile-menu/index.ts \
  --spec '{"baRoot": ".smartstack/ba", "dryRun": true}'
```

The CLI returns a JSON envelope describing:
- `renames[]` — sections/modules whose code changed in the tree but whose
  downstream codes still use the old name. Each rename carries a confidence
  score (0..1) and a reason (`code-similar`, `uc-overlap`, or both).
- `deletions[]` — sections/modules referenced by codes but absent from the
  tree, with no rename match.
- `staleRefs[]` — every code that points to a ghost section, useful for
  display.

If **both arrays are empty** → the tree is consistent. Report a one-liner to
the user (`"Menu cohérent — aucune réconciliation nécessaire."`) and stop.

### Step 2 — Show the diff + validate

Present the diff to the user as a single `AskUserQuestion` (closed choices):

```
J'ai détecté les écarts suivants entre le menu actuel et les documents
downstream :

— RENAMES (sections renommées) —
  - CRM/PIPELINE/OPPORTUNITES → CRM/PIPELINE/PROSPECTS (confiance 92%, code-similar+uc-overlap)
    Tous les UC/SCR/BR/RBAC seront réécrits sur le nouveau code.

— SUPPRESSIONS (sections supprimées) —
  - CRM/PIPELINE/LEGACY (3 codes orphelins, raison : no-rename-candidate)
    Les blocs UC/SCR seront supprimés et les références body nettoyées.

Que veux-tu faire ?
```

Options:
- **Appliquer la réconciliation** (recommandé) — applies all changes.
- **Voir le détail** — pre-prints each `staleRefs[].file:line` then re-asks.
- **Skipper cette réconciliation** — emits a verdict file with severity
  `warn` and aborts (downstream audits will then block).

### Step 3 — Apply

If validated, invoke the CLI without `--dry-run`:

```bash
npx --prefer-offline tsx skills/business-analyse/reconcile-menu/cli/reconcile-menu/index.ts \
  --spec '{"baRoot": ".smartstack/ba"}'
```

The CLI:
1. For each RENAME: substitutes every `(KIND)-APP-MOD-OLD-NNN` →
   `(KIND)-APP-MOD-NEW-NNN` in every downstream file, AND persists the old
   code as a `previousCodes=` attribute on the renamed node's `index.md`
   anchor (`<!-- ba:node … previousCodes=old-code -->`). That attribute is
   the deterministic channel through which the DEV pipeline learns the
   rename: Phase 0 of `/ba-develop` transports it into the core-seed spec,
   and at release time `derive-seed-delta` emits a `Code`/`Path` UPDATE for
   the prod database (GUID + FKs preserved) instead of deactivating the old
   row and inserting a duplicate.
2. For each DELETION: drops every heading block whose code matches the
   deleted (APP,MOD,SEC) triplet, scrubs body references (comma-separated
   lists collapse correctly; empty `Règles liées` lines become `—`).
3. Removes any orphan section directory still on disk.
4. Writes `.smartstack/ba/_audit/reconcile.md` (the verdict).

**After a reconciliation is applied**: for every module whose sections were
renamed/deleted AND whose `entité.md` is authored, re-run
`derive-lookup-grants` in `"mode":"derive"` (create-rbac companion CLI) —
the machine-owned lookup block of `rbac.md` carries producer SECTION codes,
which the reconciliation may have just changed. RBAC-008 flags stale blocks
otherwise. Likewise re-run `derive-permission-floor` in `"mode":"derive"` for
every touched module — the `ba:rbac-floor` mirror lists node paths that a
rename/deletion just changed (RBAC-009 flags the drift otherwise).

### Step 4 — Report

Surface a 3–6 line business summary:

```
Réconciliation appliquée :
- 1 section renommée (PROSPECTS), 2 codes migrés
- 1 section supprimée (LEGACY), 3 blocs nettoyés + 1 dossier retiré
- 5 fichiers modifiés

→ Relance /ba-loop pour ré-enrichir les sections renommées.
```

## Decision table

| Situation | Action |
|-----------|--------|
| Tree is consistent (no renames, no deletions) | One-liner OK, no Write, no user prompt |
| Renames only, all confidence ≥ 0.8 | Show diff + validate, then apply |
| Renames with confidence < 0.8 | Highlight low-confidence renames in the AskUserQuestion description; let user opt out per rename via free-text "Other" |
| Deletions only | Show diff + validate (deletions are destructive — git is the safety net) |
| Mix of renames + deletions | Show both blocks in the same AskUserQuestion |
| User picks "Skipper" | Write verdict with severity `warn`, abort |
| CLI returns `success: false` | Surface the `errors[]` to the user, halt |

## Guard rails

- **Never apply without showing the diff** — even on a single rename. The
  user must see what is about to change.
- **Never edit the menu tree itself** — that's `/ba-create-menu`'s job. This
  skill ONLY touches downstream docs.
- **Never invent codes** — the rename/delete decisions come from the
  deterministic CLI; you do not extrapolate.
- **Idempotent** — running twice in a row is a no-op (the second pass
  detects no remaining ghosts).
- **`git` is the safety net** — deletions are physical (no archive folder).
  The user can `git diff` / `git checkout` to recover.
- **The sources registry is NOT rewritten** — `.smartstack/sources/index.json`
  `scopes` still name the OLD app/module codes after a rename. Tell the user
  to re-point them via `/ba-create-sources` (audit net: SRC-002 warns on every
  orphan scope — without the fix, SRC-005 silently stops watching that
  source). The `SRC-NNN` citations themselves are rename-proof (menu-code
  independent) and travel inside the doc rewrites untouched.

## How the heuristic works (for transparency)

The CLI matches each "ghost" (section referenced by codes but absent from
the tree) against the "arrivals" (sections present in the tree without any
code) using two signals:

- **Code similarity**: Levenshtein distance normalised over the longer
  string length. < 0.3 → strong match (`OPPORTUNITES` ↔ `OPPORTUNITY` =
  0.08).
- **UC overlap**: Jaccard similarity of the UC heading titles between
  ghost and arrival (after lowercasing + accent stripping). ≥ 0.5 → strong
  match.

A rename is "clear" when **exactly one arrival** scores high enough AND
**beats the runner-up by ≥ 0.3 confidence**. Otherwise → DELETE (the user
can still rename manually before re-running).

## Used by the loop orchestrator

`/ba-loop` invokes this skill as **Step 0.5 — Menu reconciliation preflight**
(between Step 0 read-state and Step 1 actors). When `renames + deletions = 0`
the loop continues silently; otherwise the loop **pauses**, asks the user
via this skill, and only resumes after reconciliation is applied or
explicitly skipped.

This is the answer to "**you can't skip a modified menu — audit and
correct**".
