/** * lib/detail-cadence.ts — Canonical DETAIL CADENCE of the BA conversational * phases built in two passes: **Pas à pas / Par lot / Enchaîné**. * * SINGLE SOURCE OF TRUTH for how the SECOND pass iterates — how many items the * model drafts before it stops, and where the human gate sits. The full * methodology (the five invariants, when the cadence is pinned, the * non-interactive rule) lives in `business-analyse/_workflow/detail-cadence.md` * — repo-only, NOT deployed by the installer. * * The BA skills (deployed standalone, markdown-only) therefore carry the * cadence table inline between `` markers. * `lib/__tests__/detail-cadence-drift.test.ts` pins those tables to this * export — edit ALL carriers or the suite fails. Carriers: * * - business-analyse/_workflow/detail-cadence.md (canonical) * - business-analyse/create-use-case/levels/detail.md (UC detail pass) * - business-analyse/create-business-rules/levels/elaborate.md (rule elaboration) * * Why it exists: the second pass had FOUR undesigned behaviours — one UC at a * time with a gate per item (create-use-case), the whole scope in one batch * with a single gate (create-business-rules, already), a single named item with * no gate at all (modeling-detail, an orphan path), and fully unattended in a * subagent (/ba-loop). Nothing said why, and the user was never asked. * * Phases WITHOUT a cadence (deliberate, do not add carriers there): RBAC, * screens and the data model — they iterate per entity / per screen, not over * an inventory of items, so "how many before the gate" has no referent; and * `ba-modeling-inventory` / `ba-modeling-detail`, the orphan two-pass path * (nothing reads its `_inventory.md`). * * The WORKLIST the cadence iterates is derived, never remembered — see * `lib/ba-use-cases.undetailedUseCases`. */ /** One cadence of the detail pass. */ export interface DetailCadence { /** Client-facing French name (rendered bold in the carried table). */ readonly name: string /** What the model does under this cadence. */ readonly meaning: string /** Where the human gate sits — the whole point of the taxonomy. */ readonly gate: string } /** * The 3 cadences, in presentation order (fastest gate → no gate). `Par lot` is * the default: a gate per item becomes a reflex the user stops reading, and no * gate at all is what `/ba-loop` is for. */ export const DETAIL_CADENCES: readonly DetailCadence[] = [ { name: 'Pas à pas', meaning: 'One item at a time: full draft, validation, write, next', gate: 'One AskUserQuestion **per item**', }, { name: 'Par lot', meaning: 'Draft every remaining item of the pinned scope internally, then present a compact recap + the open arbitrations', gate: '**One** AskUserQuestion for the whole batch, **one** write', }, { name: 'Enchaîné', meaning: 'Draft and write the whole scope without stopping, then run the deterministic audit and publish its verdict + the arbitrations', gate: 'None mid-run — the gate is the audit verdict + the arbitration list, after the fact', }, ] as const /** Machine keys, in the same order as `DETAIL_CADENCES` (`--cadence `). */ export const DETAIL_CADENCE_KEYS = ['step', 'batch', 'chained'] as const export type DetailCadenceKey = (typeof DETAIL_CADENCE_KEYS)[number] /** Applied when the user picks nothing and the phrasing names no cadence. */ export const DEFAULT_DETAIL_CADENCE_KEY: DetailCadenceKey = 'batch' /** * The cadence a non-interactive caller runs at. A /ba-loop subagent is * forbidden from calling AskUserQuestion ("Make professional decisions — do not * use AskUserQuestion"), so a skill that asked would deadlock on a question it * may not put. */ export const NON_INTERACTIVE_DETAIL_CADENCE_KEY: DetailCadenceKey = 'chained' /** Marker name carried by every inline copy of the cadence table. */ export const DETAIL_CADENCE_MARKER = 'detail-cadence:v1' /** * Renders the canonical markdown block (markers included) that every carrier * must embed verbatim — the drift test compares parsed rows, so surrounding * prose stays free but the table itself must match. */ export function renderDetailCadenceBlock(): string { const rows = DETAIL_CADENCES.map( c => `| **${c.name}** | ${c.meaning} | ${c.gate} |`, ).join('\n') return [ ``, '| Cadence | What the model does | Where the human gate sits |', '|---|---|---|', rows, ``, ].join('\n') }