---
name: audit-dev-wire
description: Static parity gate between the generated frontend service URLs and the generated backend controller routes. Catches the "frontend calls a URL the backend never serves" class of bugs (the 404 the user sees in the browser) BEFORE runtime. Phase 3e gate of `/ba-develop`.
group: D
phase: devApi
kind: audit
audit_only: true
section_label: 'AUDIT-DEV-WIRE (frontend service URL ↔ backend controller route parity)'
allowed-tools: [Read, Glob, Grep, Bash]  # Bash: CLI invocation
---

# audit-dev-wire — Frontend ↔ Backend URL Parity Gate

## Context

You are running the static parity gate of `/ba-develop` Phase 3e. The CLI
enumerates every URL the generated frontend services call AND every route
the generated backend controllers expose, then diffs the two sets.

A `wire.frontend-orphan` finding means the frontend will receive a 404 at
runtime — exactly the failure the user reported with `GET /api/affaires/accueil/dashboard`.
A `wire.backend-orphan` finding is informational — a route nobody calls
(e.g. health probe, integration-stratum lookup) is not a defect.

The audit reads:

- `web/**/src/features/**/services/*Service.ts` — frontend service URLs
- `web/**/src/features/**/hooks/use*.ts` — additional URL call sites
- `src/<Ns>.Api/Controllers/**/*Controller.cs` — backend routes (both strata)

It writes a structured JSON envelope on stdout (`auditReport.findings[]`)
and a Markdown report under `_audit/dev-wire-<module>.md`.

## When to run

- **Automatically**: as Phase 3e of `/ba-develop`, after Phase 3 (Frontend)
  has scaffolded all the api-clients and controllers. The orchestrator
  calls the CLI; a single `err` finding blocks promotion to Phase 4.
- **Manually**: when a developer suspects a 404 in their generated app,
  run `audit-dev-wire --mode audit` to localise the drift in < 1 second.

## Rules

### DEV-WIRE-001 — Every frontend URL call has a backend route serving it

- **Severity**: `err` (BLOCKING) on frontend orphans, `warn` on backend
  orphans, `ok` when both sets align.
- **Check**: cross-reference the canonicalised URL paths of every
  `api.<verb>(<url>)` call in the frontend against every
  `[Route]+[Http<Verb>]` declaration on the backend.
- **fixSkill**: `backend-screen-controller` (when the orphan path matches
  `/api/screens/...`) or `backend-controller` (when the orphan path matches
  `/api/v1/integration/...`).
- **fixPhaseKey**: `api`
- **solution**: "Re-run the API phase. The orchestrator must re-invoke
  `scaffold-screen-controller` (or `scaffold-controller`) for the entity
  to emit the missing route. The frontend `*Service.ts` will then resolve
  at runtime."

### DEV-WIRE-002 — Verb mismatch on the same path

- **Severity**: `err` (BLOCKING)
- **Check**: when frontend and backend agree on the path but disagree on
  the HTTP verb (frontend `POST`, backend `[HttpPut]`), surface the
  discrepancy. The pagespec is the source of truth — the side that
  diverges must be re-scaffolded.
- **fixSkill**: `backend-screen-controller` if backend is wrong, otherwise
  `frontend-api-client`.
- **solution**: "Reconcile the pagespec.action.httpMethod with the controller
  route attribute. Re-run the appropriate scaffolder; do not edit the
  generated file by hand."

### DEV-WIRE-003 — Strata mismatch

- **Severity**: `err` (BLOCKING)
- **Check**: frontend calls `/api/v1/integration/{plural}/...` (legacy
  default) but only `{EntityPlural}ScreenController.cs` exists for that
  entity — the screen-driven backend has no integration counterpart.
- **fixSkill**: `frontend-api-client`
- **fixPhaseKey**: `frontend`
- **solution**: "Re-run `scaffold-api-client` for this entity with
  `useScreens: true`. The Phase 3a strata detection (stat the screen
  controller file) must have been out of order — verify the orchestrator's
  step ordering."

## Output contract

The CLI emits a JSON envelope identical to `audit-dev-api`:

```json
{
  "success": true,
  "command": "audit-dev-wire",
  "data": { "mode": "audit", "rulesRun": ["DEV-WIRE-001"], "valid": false },
  "report": { /* full AuditReport with findings, counts, byRule, markdown */ },
  "auditReport": {
    "scope": "devWire",
    "applicationCode": "gaf",
    "moduleCode": "affaires",
    "findings": [
      {
        "dimension": "devWire",
        "code": "DEV-WIRE-001",
        "severity": "err",
        "label": "DEV_WIRE_001_err",
        "params": { "calls": "GET /api/affaires/accueil/dashboard|src/features/affaires/demande/services/demandeService.ts" },
        "solution": "Re-run the API phase ...",
        "fixSkill": "backend-screen-controller",
        "fixPhaseKey": "api"
      }
    ]
  },
  "errors": [],
  "warnings": [],
  "nextSteps": ["1 ERROR finding(s) — blocking Phase 3e gate of /ba-develop."]
}
```

Exit code: `0` when no `err` findings, `1` otherwise.

## CLI invocation

```bash
npx --prefer-offline tsx skills/development/audit-dev-wire/cli/audit-dev-wire/index.ts \
  --project-path "<dotnet-root>"     \
  --web-path     "<web-root>"        \
  --module-code  "<MODULE>"          \
  --app-code     "<APP>"             \
  --mode audit
```

`<web-root>` defaults to `<project-path>/web/<appCode>-web` if omitted.

## Auto-healing mapping

This audit emits failure kinds the `/ba-develop` orchestrator's auto-healing
protocol picks up (see `ba-develop/references/auto-healing.md` rows 23-25):

| Finding | Failure kind | Auto-fix |
|---------|--------------|----------|
| `DEV-WIRE-001 err` (path starts with `/api/screens/`) | `wire.frontend-orphan` (screen) | Re-invoke `scaffold-screen-controller` for the entity |
| `DEV-WIRE-001 err` (path starts with `/api/v1/integration/`) | `wire.frontend-orphan` (integration) | Re-invoke `scaffold-controller` for the entity |
| `DEV-WIRE-002 err` | `wire.verb-mismatch` | HALT for now — pagespec adjudication needed |
| `DEV-WIRE-003 err` | `wire.strata-mismatch` | Re-invoke `scaffold-api-client` with `useScreens=true` |
