# `/ba-develop` — Output contract

> Loaded on demand when the orchestrator emits its final summary.

Emit one JSON object describing the entire run:

```json
{
  "moduleDir": ".smartstack/ba/<APP>/<MODULE>",
  "moduleCode": "…",
  "forceMode": false,
  "memoriesCleaned": [],
  "phase3": { "regeneratedFiles": [] },
  "uiDesign": { "formsSeen": 4, "overlaysWritten": 3, "skippedExisting": 1, "failures": [] },
  "migrationPlan": {
    "status": "deferred",
    "contextName": "ExtensionsDbContext",
    "tables": ["crm_TypeClients", "crm_CanalEchanges", "crm_CategorieClients", "crm_Clients", "crm_Contacts", "crm_Echanges", "crm_PieceJointes"],
    "command": "npx --prefer-offline tsx skills/efcore/cli/create/index.ts --spec '{\"cwd\":\"<projectPath>\",\"contextName\":\"ExtensionsDbContext\",\"description\":\"AddCrmEntities\"}' --json"
  },
  "phases": [
    { "name": "core",       "status": "passed",            "artifacts": [...], "gatesPassed": ["build", "core-foundation-seed"], "warnings": [], "commitHash": "a1b2c3d", "healIterations": 0 },
    { "name": "entities",   "status": "passed",            "artifacts": [...], "gatesPassed": ["build", "entities-present", "migration-valid", "configs-registered"], "warnings": [], "commitHash": "e4f5a6b", "healIterations": 0 },
    { "name": "api",        "status": "passed-after-heal", "artifacts": [...], "gatesPassed": ["build", "permissions-wired", "tests-pass", "business-tests-pass"], "warnings": [], "commitHash": "c7d8e9f", "healIterations": 3 },
    { "name": "frontend",   "status": "passed-after-heal", "artifacts": [...], "gatesPassed": ["build", "screens-present", "routes-registered", "tests-pass"], "warnings": [], "commitHash": "01a2b3c", "healIterations": 1 },
    { "name": "wire",       "status": "passed",            "artifacts": ["_audit/dev-wire-<module>.md"], "gatesPassed": ["audit-dev-wire", "run-smoke"], "warnings": [], "commitHash": null, "healIterations": 0, "wireReport": { "scope": "devWire", "findings": [], "counts": { "errors": 0, "warnings": 0, "oks": 1 } }, "smokeReport": { "passed": true, "totalProbes": 18, "passedProbes": 18, "failedProbes": 0, "backendBootMs": 4200, "frontendBootMs": 2800 } },
    { "name": "acceptance", "status": "passed",            "artifacts": ["Tests/<Module>/Acceptance/*.cs"], "gatesPassed": ["scaffold-emitted", "no-todo-marker", "dotnet-test-pass", "ac-coverage-complete"], "warnings": [], "commitHash": "12abf3d", "factsEmitted": 14, "acsParsed": 14, "healIterations": 0 }
  ],
  "healingSummary": [
    { "phase": "api",      "attempt": 1, "failureKind": "business.todo-br",              "fix": "Implemented BR-005 in BudgetService.Validate() from règles-métier.md L42" },
    { "phase": "api",      "attempt": 2, "failureKind": "audit-dev-api.applicable",      "fix": "Auto-applied DEV-API-008 (4 findings)" },
    { "phase": "api",      "attempt": 3, "failureKind": null,                             "outcome": "gate-passed" },
    { "phase": "frontend", "attempt": 1, "failureKind": "validate-page.i18n-keys-resolve","fix": "Re-scaffold-component for EmployeeListPage with priorErrors (i18n keys added)" }
  ],
  "blockers": [
    { "phase": "preflight", "kind": "prd.not-dev-ready", "severity": "high", "summary": "PRD score 72/100 (< 80)", "whatWasSkipped": "nothing — proceeded best-effort", "bestEffortTaken": "ran all phases on the current PRD", "userAction": "run /ba-audit-prd, fix findings, regenerate the PRD", "artifacts": ["_audit/prd.md"] },
    { "phase": "entities", "kind": "migration.deferred", "severity": "high", "summary": "EF migration NOT created — 7 extension tables pending: crm_TypeClients, crm_CanalEchanges, crm_CategorieClients, crm_Clients, crm_Contacts, crm_Echanges, crm_PieceJointes (with all FKs/indexes/enums).", "whatWasSkipped": "the Phase 1 migration AND the Phase 3e runtime smoke (it needs a migrated DB)", "bestEffortTaken": "entities + EF configurations generated and compiled; the migration is left for you to create on the branch/moment you choose", "userAction": "see migrationPlan.command — run the sanctioned /efcore create (no push, no remote DB), then boot the app (it auto-migrates) and re-run Phase 3e", "artifacts": ["Domain/Entities/<App>/<Module>/*.cs", "Persistence/Configurations/<App>/<Module>/*.cs"] }
  ],
  "acCoverage": { "total": 14, "covered": 14, "missing": [] },
  "nonGoalViolations": [],
  "overallStatus": "completed-with-blockers"
}
```

## Field reference

`commitHash` — short hash from `git rev-parse --short HEAD` after the phase
commit. Omit when no diff (do NOT fabricate).

`status` (per phase):
- `passed` — gate passed on first try, no heal.
- `passed-after-heal` — gate passed after N retries (see `healIterations`).
- `completed-with-blockers` — the phase ran to the end but ≥ 1 item was
  **deferred**; see `blockers[]` filtered to this phase. The phase is NOT a stop.
- `skipped` — re-run; pre-entry coverage confirmed all PRD items are
  implemented AND compile + test gate passed. No work needed.

There is no `halted` status — the run always completes.

`healIterations` — number of retries this phase consumed (0 when no auto-heal
needed).

`healingSummary[]` — cross-phase aggregation of every retry from the run's
`heal.log.json` (path defined ONCE in `auto-healing.md` § Heal log) so the user
sees what was auto-fixed without reading the log.

`forceMode` — `true` when the user passed `--force`. Affects Phase 3 only.

`memoriesCleaned[]` — list of memory file names rewritten during pre-flight
memory cleanup (e.g. `["ba-develop-phase3-cli-stack-mismatch.md"]`). Empty when
no stale memories found.

`phase3.regeneratedFiles[]` — files overwritten during `--force` mode
(pages, api-client services, i18n files). Empty in normal mode.

`uiDesign` — the sub-phase 3.1 judgment pre-pass tally: `formsSeen` (form
pagespecs in the module), `overlaysWritten` (judged this run via
`apply-form-directives`), `skippedExisting` (already carried a `uiDesign`
overlay — idempotence), `failures[]` (`{pagespec, reason}` — mirrored as
`ui-design.skipped` NOTES, never blockers; the form ships the plain
deterministic output).

`phases[].wireReport` (Phase 3e only) — JSON envelope from
`audit-dev-wire/cli/audit-dev-wire`. Includes `findings[]` (every
`DEV-WIRE-001 err`/`warn`/`ok`) + `counts.errors|warnings|oks`. A non-zero
`counts.errors` triggers the `wire.frontend-orphan` / `wire.strata-mismatch`
auto-healing kinds.

`phases[].smokeReport` (Phase 3e only) — JSON envelope from
`smoke-test/cli/run-smoke`. Includes `passed`, `backendBootMs`,
`frontendBootMs`, `totalProbes`, `passedProbes`, `failedProbes`, and
`probes[]` with status + `failureReason`. A non-zero `failedProbes`
triggers `smoke.4xx` / `smoke.5xx` / `smoke.boot` auto-healing.

`overallStatus`:
- `success` — no warnings, all ACs covered, no heal needed, no blockers.
- `success-after-heal` — gates passed but ≥ 1 phase needed heal iterations; no blockers.
- `success-with-warnings` — gates passed, coverage gaps or minor warnings; no blockers.
- `completed-with-blockers` — the run reached the end of the module but ≥ 1 item
  was **deferred** (see `blockers[]`). This is the terminal state for any run
  that hit a structural issue — it is NOT a failure to complete. `halted` is
  never emitted; the run always finishes.

`blockers[]` — every deferred item across every phase, aggregated from the
run's `blockers.json` (path defined ONCE in `auto-healing.md` § Heal log). Each entry: `{ phase, kind, severity (critical | high |
medium), summary, whatWasSkipped, bestEffortTaken, userAction, artifacts[] }`.
This is the ONLY channel for work the user must do — `/ba-develop` never asks
mid-run. After the JSON, print a short human recap, e.g.:
`⚠ 2 blockers — 1 critical (review migration M_xxx before applying), 1 high
(regenerate the frontend PRD slice for Demande).`

`migrationPlan` — present whenever the Phase 1 migration was NOT created by the
run (the orchestrator normally creates it via `scaffold-migration`, but it is
**deferred** when the project's standing rule reserves `dotnet ef migrations
add` to the user, or the migration step is otherwise skipped). Never run a
migration to populate this — emit the PLAN only:
- `status`: `applied` (migration written AND applied to the local DB this run
  through the sanctioned `skills/efcore/cli/apply` CLI — 🟢 verdict), `created`
  (written but not applied — destructive `Up()` or the apply CLI returned
  `blocked:true`; the matching `migration.destructive` / `migration.not-applied`
  blocker says why), or `deferred`.
- `contextName`: the extension DbContext to target (typically `ExtensionsDbContext`; `/efcore status` lists the contexts).
- `tables[]`: every extension table the pending migration must create, as
  `{domainPrefix}_{PluralName}` for each entity in `structured.entities[]`
  (e.g. `crm_Clients`) — with all FKs/indexes/enums.
- `command`: the exact, ready-to-paste **sanctioned** `/efcore create` invocation
  (runs `dotnet ef` inside tsx — bypasses `ef-guard` by design, does NOT push and
  does NOT touch a remote DB). The user runs it when they pick the branch/moment;
  the app then auto-migrates at boot, after which Phase 3e smoke can be re-run.
When `status` is `deferred`, ALSO emit the matching `migration.deferred` blocker
(severity `high`) so it surfaces in the recap — e.g.:
`⚠ 1 high (EF migration deferred — 7 crm_* tables pending; run migrationPlan.command, then re-run Phase 3e smoke).`
