---
name: ba-audit-prd
description: >
  Audits the on-disk PRD of ONE module in a `.smartstack/ba/` project — checks
  across 7 dimensions: structure, completeness, clarity, consistency, traceability,
  feasibility, slices + per-page contract + custom-action contract + related-tabs
  contract (PRD-103..105 + PRD-108 route families, the 360 view) + the
  file-upload guard (PRD-107 — no `type:file` custom action; attachments
  pattern instead) + list elegance (PRD-109 column visibility budget,
  PRD-110 filter tiers) + form/detail sections (PRD-111 well-formed `sections[]`,
  PRD-112 grouping authored where warranted) + view-set completeness (PRD-114
  a mutable list declares its form/detail siblings) + cards representation
  folding (PRD-117 viewModes on the list pagespec, never a standalone SmartCard
  pagespec) + quick segments (PRD-116 cohort tabs: labelled, defaulted, wirable) + sort/density/empty-state coherence (PRD-118) + detail summary integrity (PRD-119) + form lifecycle (PRD-120 well-formed status-anchored `lifecycle` block — CLI `create-prd/cli/derive-lifecycle --mode check`; PRD-121 lifecycle authored where the entity lives one) + action-permission binding (PRD-128 — a kind:api action's permission roots at its OWN module.section, section grain; engine = derive-action-specs' blocking rejected[]) + business-rule links (PRD-129 every enforceable rule linked / PRD-130 cited codes resolve — CLI `create-prd/cli/derive-rule-links --mode check`) + use-case coverage (PRD-131 every user-goal UC reaches the pagespecs — CLI `create-screen/cli/derive-uc-coverage`) + coded-entity parity (PRD-132 entité.md `**Code pattern**` ⇔ pagespec `codedEntity` flag both ways — facets `label`/`supplied` included, unusable line = err, unparsable near-miss declaration (table cell / wrong casing) = err, supplied+{SEQ} = warn — CLI `ba-develop/cli/derive-code-specs --mode check`) + tab budget (PRD-133 — rendered strip ≤ 7 warn / ≤ 9 err, band cartouches excluded, unified fiche honoured; same derive-related-tabs run, RTV-108) + summary demanded (PRD-134 — ≥ 4 rendered strip triggers and no `summary` = warn, CLI `create-prd/cli/derive-detail-summary --mode check`) + kanban representation (PRD-135 — the `kanban` block folded on the LIST pagespec: columns ⊆ status enum verbatim, BR Flow ⇄ transitions parity both ways, viewModes coherence, no standalone kanban pagespec, labels seeded — CLI `create-prd/cli/derive-kanban-spec --mode check`). Reads `prd.md`,
  the three `prd.*.md` slices and the `pagespecs/*.md` blocks against the upstream
  BA docs, then writes a verdict to `_audit/prd.md` carrying the dev-readiness
  gate (`GO|NO-GO`). GO is the gate `/ba-develop` reads. User Story / Acceptance
  Criteria checks live in `/ba-audit-use-cases` (UC-012..018) — the PRD no longer
  carries US/AC sections; AC live under each UC in `use-case.md`. Run after
  `/ba-create-prd`.
allowed-tools: [Read, Write, Glob, Grep, Bash]
---

# ba-audit-prd — PRD quality audit (per module)

You audit the **PRD of ONE module** against the checks below and write a
verdict file. The checks keep their original intent and codes; only the I/O is
file-based.

> **No US/AC checks here.** User Stories and Acceptance Criteria are NOT in the
> PRD — they live under each UC in `<section>/use-case.md` as
> `**Acceptance Criteria**` fields, audited by `/ba-audit-use-cases` (UC-012..018).
> Legacy PRD rules that targeted `## User Stories` / `## Acceptance Criteria` /
> `AC-US{n}-{m}` ids were deleted (PRD-002/003/004/012/013/014/021/027/032/033/047/062/063/085)
> or migrated to `/ba-audit-use-cases` (PRD-022/023/024/031/034/048 → UC-014..018).

There is **no database, no Studio, no injected JSON envelope, no
`structured`/`markdown`/`slices` blocks** — the PRD lives on disk as `.md` files
and the `.md` verdict IS the record. The verdict header carries the dev-readiness
gate that `/ba-develop` reads.

## File model — how to audit

1. **Read the PRD subtree** `.smartstack/ba/<APP>/<MODULE>/`:
   - `prd.md` — `## Context`, `## Goals`, `## Non-goals`, `## MoSCoW`,
     `## Technical constraints`. (No `## User Stories` / `## Acceptance Criteria`
     — those live under each UC in `<section>/use-case.md`.)
   - `prd.entities.md`, `prd.api.md`, `prd.frontend.md` — the three `# Phase:`
     slices (self-contained + disjoint, one per dev sub-agent).
   - `pagespecs/<Entity>.<view>.md` — one per screen; each a fenced ```json
     pageSpec block + a human body. These are the contract feeding `scaffold-component`.
   - `claude.md` — the generated module CLAUDE.md (read for PRD-052).
2. **Read the upstream BA docs** in the same / parent folders, so traceability and
   coverage checks resolve (codes are Grepped on the tree — if a code is not found
   there, it does not exist; do not invent it):
   - `<MODULE>/entité.md` (entities `ENT-…` + PascalCase names, attributes, relationships, computed),
   - `<MODULE>/rbac.md` (permission matrix),
   - `<MODULE>/<section>/screen.md` (screens `SCR-…`, SmartComponent type, columns/filters/actions),
   - `<MODULE>/<section>/use-case.md` (use cases `UC-…`),
   - `<MODULE>/<section>/règles-métier.md` (business rules `BR-…`, valid/invalid examples),
   - `<APP>/acteur.md` (actor roles `BA-…-AC-…`),
   - the `index.md` **out-of-scope cascade** (project root → `<APP>` → `<MODULE>`,
     the `## Hors-périmètre` bullets).
3. **Apply** the checks below.
4. **Write** the verdict to `.smartstack/ba/<APP>/<MODULE>/_audit/prd.md` (skeleton
   in `_workflow/doc-templates.md`), with the dev-readiness gate header. Overwrite
   each run. Then print a concise GO / NO-GO chat summary in business terms.

There is **no `[ACTION]` envelope, no `[QUESTION]` block, no `persist:`, no
`--- CURRENT … ---` state, no i18n label codes, no fix-finding handler, no
targeted-regen endpoint, no `GET /prds`, no sidecar/frontend, no fan-out arrays**.
This audit is read-only — it never patches the PRD; each non-ok finding routes to
the owning phase skill to re-run.

## Scope

- **Module scope** (always): audit exactly one module's PRD. Resolve every cross
  reference against that module's upstream docs (+ the app `acteur.md` and the
  out-of-scope cascade). Do not re-audit a sibling module's PRD.
- If `prd.md` (or all three slices, or `pagespecs/`) is absent, the PRD has not
  been generated for this module — report a single blocking finding "PRD not
  generated → run `/ba-create-prd`", emit NO-GO, and stop.

---

## Dimension 1 — Structure & the contract gate (PRD-001, 005..010)

Schema and ID conformity. Failures here mean the PRD cannot be processed downstream.

- **PRD-001′** `err` — *(was: "`structured` parses against the Zod schema". Re-targeted —
  this is the new contract gate between the `.md` tree and `scaffold-component`.)*
  **Every** `pagespecs/*.md` file contains exactly one fenced ```json block, that
  block parses as valid JSON, and it carries every required field, each non-empty:
  `screenCode`, `appCode`, `module`, `section`, `entity`, `view`, `permission`,
  `filePath` (the OUTPUT path of the generated page — DEV-UI-011's primary
  page locator; scaffold-component requires it),
  `screenType`, plus `linkedBusinessRules` PRESENT (an array — `[]` is legal,
  PRD-129 then judges whether emptiness is right; an ABSENT field is how a rule
  used to vanish with DEV-API-008 green at count 0) and `linkedUseCases`
  PRESENT (an array — `[]` is legal, PRD-131 then judges module-wide
  coverage; same silent-loss shape for use cases). A pagespec whose JSON does
  not parse, or that drops any required field, breaks `scaffold-component`.
  → `/ba-create-prd` (`derive-rule-links --mode backfill` fills the BR links;
  the UC links transport the screen.md `Cas d'usage liés` / `UC:` channels).
- **PRD-005** `err` — `prd.md` is non-empty and contains all five `##` anchor
  sections, verbatim: `## Context`, `## Goals`, `## Non-goals`, `## MoSCoW`,
  `## Technical constraints`. *(structural-file check — US/AC sections were
  removed; the test contract lives in each UC's `**Acceptance Criteria**` field
  in `use-case.md`.)* → `/ba-create-prd`.
- **PRD-006** `err` — All three slice files exist and are non-empty:
  `prd.entities.md`, `prd.api.md`, `prd.frontend.md`. (3 slices since 2026-04 —
  `entities` is the combined domain+data view; there is no separate `domain`/`data`
  file.) *(structural-file check)* → `/ba-create-prd`.
- **PRD-007** `warn` — `prd.md` declares a `## Technical constraints` section (may
  be empty, but the heading must be present). → `/ba-create-prd`.
- **PRD-008** `warn` — Every entity referenced in `prd.entities.md` has a non-empty,
  unique name (no duplicate entity lines). → `/ba-create-prd`.
- **PRD-009** `warn` — Every `screenCode` across the `pagespecs/*.md` blocks is
  non-empty and unique (no two pagespecs share a `screenCode`). → `/ba-create-prd`.
- **PRD-010** `warn` — Every `permission` value across the pagespec blocks is
  non-empty (uniqueness not required — many views legitimately share `…read`). → `/ba-create-prd`.

---

## Dimension 2 — Completeness (PRD-011, 015..020)

Minimum content levels. An incomplete PRD leads Claude to invent filler.

- **PRD-011** `err` — `## Non-goals` lists ≥ 3 bullets. Non-goals prevent feature
  hallucination downstream. → `/ba-create-prd`.
- **PRD-015** `warn` — `## MoSCoW` lists ≥ 1 **Must** item. → `/ba-create-prd`.
- **PRD-016** `warn` — `## MoSCoW` populates at least one of **Should** / **Could**
  (a PRD with nothing beyond Must is probably under-scoped). → `/ba-create-prd`.
- **PRD-017** `warn` — `## Goals` lists ≥ 2 goals (a single goal usually hides scope). → `/ba-create-prd`.
- **PRD-018** `info` — `prd.entities.md` declares ≥ 1 entity (pure-UI modules may
  legitimately have 0 — informational only). → `/ba-create-prd`.
- **PRD-019** `info` — `pagespecs/` holds ≥ 1 pagespec (background-only modules may
  have 0). → `/ba-create-prd`.
- **PRD-020** `info` — `prd.api.md` lists ≥ 1 permission (same exception). → `/ba-create-prd`.

---

## Dimension 3 — Clarity (PRD-025, 026, 028..030)

Phrasing that can be acted on without reinterpretation. Logic UNCHANGED, new input.

- **PRD-025** `warn` — Each goal starts with an action verb (allow / enable /
  produce / guarantee / reduce / surface) rather than a noun phrase. → `/ba-create-prd`.
- **PRD-026** `warn` — Each non-goal is a **negated** sentence ("we will NOT",
  "out of scope:", "explicitly excludes"). Descriptive non-goals are ambiguous. → `/ba-create-prd`.
- **PRD-028** `info` — Sentences in `## Context` stay under ~40 words; longer ones
  get split. → `/ba-create-prd`.
- **PRD-029** `info` — Acronyms are expanded on first use in `prd.md` (e.g.
  "RBAC (role-based access control)"). → `/ba-create-prd`.
- **PRD-030** `info` — `## Context` names which other modules are touched — or
  states "standalone". → `/ba-create-prd`.

---

## Dimension 4 — Consistency (PRD-035..040, PRD-064)

Cross-field invariants — the document must not contradict itself.

- **PRD-035** `warn` — Every entity named in a `pagespecs/*.md` block (`entity`
  field) also appears in `prd.entities.md` (screens can't render an entity the PRD
  doesn't declare). → `/ba-create-prd`.
- **PRD-036** `warn` — Every pagespec `permission` is the
  `module.section[.resource].action` shape (3 or 4 segments, lowercase kebab, no
  app prefix), matching the `rbac.md` matrix shape. → `/ba-create-prd`.
- **PRD-037** `warn` — Every role named in `prd.api.md` / pagespec actions also
  appears as an actor upstream (`acteur.md`). No role materialises in the API
  slice without being defined upstream. → `/ba-create-rbac`.
- **PRD-038** `warn` — `## MoSCoW` **Must** items do not also appear under
  **Won't**. → `/ba-create-prd`.
- **PRD-039** `warn` — Every `## MoSCoW` **Won't** item is echoed in `## Non-goals`
  (a won't-have is a non-goal). → `/ba-create-prd`.
- **PRD-040** `info` — `prd.md` mentions every entity, screenCode and permission
  from the slices/pagespecs at least once (low-fidelity render flag). → `/ba-create-prd`.
- **PRD-064** `warn` — Every non-empty `## Hors-périmètre` line in the **out-of-scope
  cascade** (project root `index.md` + `<APP>/index.md` + `<MODULE>/index.md`) is
  reflected by at least one **semantically equivalent** non-goal in `## Non-goals`.
  Paraphrases are fine; the meaning MUST be preserved. Missing or contradicting an
  upstream out-of-scope warns (raises feature-hallucination risk downstream). → `/ba-create-menu` (fix the cascade) or `/ba-create-prd` (recopy it).

---

## Dimension 5 — Traceability (PRD-041..046, 049, 050)

Every piece of the PRD must connect to something upstream. Logic UNCHANGED, new input.

- **PRD-041** `err` — Every entity in `prd.entities.md` resolves to an `ENT-…`
  entity in the module `entité.md`, matched by either the PascalCase **name** or
  the BA stable **code**. No phantom entities. → `/ba-create-data-model`.
- **PRD-042** `err` — Every `screenCode` in a pagespec resolves to a `SCR-…`
  heading in some `screen.md` of the module. → `/ba-create-screen`.
- **PRD-043** `err` — Every pagespec `permission` resolves to a permission in
  `rbac.md`. The 4-seg vs 5-seg (resource-scoped) shapes are NOT interchangeable —
  a permission missing the `.{resource}.` segment must not resolve to one that has
  it (and vice-versa), since the resource segment changes the RBAC scope. → `/ba-create-rbac`.
- **PRD-044** `warn` — Every entity has at least one screen that displays it.
  **Skip** when the entity's `entité.md` classification is lookup / reference /
  junction / component (those surface inside parent screens, never as standalone
  pages). Orphan aggregate-root / full-module entities still warn. → `/ba-create-screen`.
- **PRD-045** `warn` — Every screen (`SCR-…` in `screen.md`) is covered by at least
  one permission (read / create / update / delete). → `/ba-create-rbac`.
- **PRD-046** `warn` — Every permission in `rbac.md` maps to at least one use case
  upstream (a `UC-…` whose flow uses that action verb). Disconnected permissions warn. → `/ba-create-use-case`.
- **PRD-049** `info` — Every `## Goals` statement is backed by at least one UC in
  the module's `use-case.md` files (a UC whose title or main flow speaks to that
  goal). → `/ba-create-use-case`.
- **PRD-050** `info` — Every `## Non-goals` statement is traced by an explicit
  exclusion (it is itself the exclusion list — flag a non-goal that contradicts a
  goal or a Must item). → `/ba-create-prd`.

---

## Dimension 6 — Feasibility (PRD-051..055)

Technical constraints must fit the generated-project stack.

- **PRD-051** `warn` — `## Technical constraints` only references the generated
  stack (`.NET 10`, `EF Core 10`, `React 18`, `Vite`, `Tailwind`, `Shoelace`,
  `SignalR`, `PostgreSQL / SQL Server / Azure SQL`). Anything outside belongs in a
  custom CLAUDE.md rule, not the PRD. **SQLite must never appear** (it is the
  Studio's dev DB, not a generated-app target). → `/ba-create-prd`.
- **PRD-052** `warn` — No `## Technical constraints` entry merely repeats a rule
  already in the module `claude.md` (the PRD adds module-specific constraints, not
  repeats). → `/ba-create-prd`.
- **PRD-053** `warn` / `err` — Entity attribute types in `prd.entities.md` are
  EF-Core-mappable primitives (`string`, `int`, `long`, `DateTime`, `decimal`,
  `bool`, `Guid`, `enum`) — unknown types are `warn`. **Denylist `err`
  (severity-mixed, like DEV-UI-033)**: `binary`, `varbinary`, `byte[]`, `blob`,
  `image`, `filestream` — file content is NEVER an attribute; model a metadata
  entity (`FileName`, `StoredFileName`, `ContentType`, `FileSizeBytes` + parent
  FK) and store the bytes via the platform `IFileStorageService`
  (`development/backend/data-layer/references/file-storage.md`;
  `scaffold-entity` throws on these types, so a PRD carrying one CANNOT build).
  → `/ba-create-data-model`.
- **PRD-054** `info` — Each pagespec `screenType` / `view` maps to one of the
  SmartComponent patterns (list, detail, form, dashboard + the home views).
  `SmartCard` and `SmartKanban` are REPRESENTATIONS of the list: they fold
  into the section's LIST pagespec (`viewModes` / the `kanban` block) and
  produce no view of their own — a standalone `view: kanban` pagespec is
  PRD-135(f), a standalone card pagespec PRD-117(b). → `/ba-create-screen`.
- **PRD-055** `info` — Permissions in `prd.api.md` respect the 12-action SmartStack
  vocabulary — mirror of the platform `PermissionAction` enum:
  <!-- permission-actions:v1 — drift-tested against lib/permission-actions.ts (edit ALL carriers or the suite fails) -->
  `access` `read` `create` `update` `delete` `export` `import` `approve`
  `reject` `assign` `execute` `lookup`
  <!-- /permission-actions:v1 -->
  → `/ba-create-rbac`.

---

## Dimension 7 — Slices, per-page contract & vibecoding readiness (PRD-056..088)

The three slices must let a sub-agent develop one phase without the rest;
`prd.entities.md` carries the combined domain + data view (entities, attributes,
relationships, business rules, migrations, indices, FKs). The pagespec blocks must
satisfy everything `scaffold-component` expects.

### Slice self-containment & disjointness (PRD-056..061, 094)

- **PRD-056** `err` — `prd.entities.md` covers every entity from the upstream
  `entité.md` AND, for every non-reference entity, an inline **domain invariants**
  section listing each scope-matched `BR-…` from `règles-métier.md` (with code +
  ≥ 1 valid + ≥ 1 invalid example). No UI references in this slice. → `/ba-create-prd`.
- **PRD-057** `err` — `prd.entities.md` describes migrations, indices and FK
  relationships for every declared entity — derivable from the entity list alone,
  no screen references. → `/ba-create-prd`.
- **PRD-058** `err` — `prd.api.md` lists every permission and maps each to an HTTP
  method + route — derivable from `rbac.md` alone. → `/ba-create-prd`.
- **PRD-059** `err` — `prd.frontend.md` lists every screenCode + route; it may
  reference entity names but never EF / repository implementation detail. → `/ba-create-prd`.
- **PRD-060** `warn` — Slices are **disjoint**: no slice duplicates another's
  content (`prd.entities.md` must not declare routes from `prd.api.md`;
  `prd.frontend.md` must not contain the SQL migrations from `prd.entities.md`). → `/ba-create-prd`.
- **PRD-061** `warn` — Each slice opens with a `# Phase: <name>` heading and lists
  its in-scope artefacts as `- [ ]` checkbox bullets. *(structural-file)* → `/ba-create-prd`.
- **PRD-094** `err` — **Self-containment test**: for each slice, every code it cites
  (entity, screen, permission, UC, BR, actor) is **defined inline** in that same
  slice (full body, not a bare ID reference). A sub-agent reading only one slice
  must be able to act. AC are intentionally NOT in this list — they live in
  `use-case.md` next to their UC and the test-scaffolder reads them directly. → `/ba-create-prd`.

### Per-page contract integrity (PRD-070..089)

Every `screen.md` screen produces exactly one pagespec (plus a synthesised
`detail` view per list+form pair). These catch the silent omissions that would
otherwise produce a non-functional PRD downstream.

- **PRD-070** `err` — Every screen in the module's `screen.md` files has a matching
  `pagespecs/*.md` whose `screenCode` equals the screen's `SCR-…` code (**coverage**).
  Synthesised detail entries are tolerated but should carry `needsRefinement: true`
  + a note. → `/ba-create-screen` if the screen is missing upstream, else `/ba-create-prd`.
- **PRD-071** `err` — Every pagespec `permission` matches
  `^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*){2,3}$` (3 segments, or 4 for the resource
  grain `module.section.resource.action`; lowercase, no appCode prefix) — the same
  shape `validate-page` enforces downstream. → `/ba-create-prd`.
- **PRD-072** `err` — Every pagespec `i18nKeys` carries **parallel key sets across
  the 4 locales `fr/en/it/de`** (the same key set in each). Missing keys per locale
  are the #1 cause of i18n-resolve failures downstream. *(structural-file: 4-locale parity)* → `/ba-create-prd`.
- **PRD-073** `warn` — Every computed column in a pagespec (`isComputed: true`, or a
  `columns[].formatHint`) carries a `formatHint` ∈ `{percent, currency, date,
  datetime, integer, decimal}`. Without it, numeric / date columns render raw. → `/ba-create-prd`.
- **PRD-074** `err` — Every pagespec `actions[].permission` is a valid
  `module.section[.resource].action` string (3 or 4 segments, same regex as PRD-071). Action permissions wrap mutating buttons in
  `<PermissionGuard>` — a wrong shape means an unguarded mutation. ⚠ For a
  `kind:"api"` CUSTOM action the 4-segment RESOURCE grain is additionally
  REFUSED by **PRD-128** (no generated code path enforces the resource
  segment — the shape is valid, the binding is not); the 4-seg form stays
  legal for the page-level `permission` and `kind:"navigate"`. → `/ba-create-rbac` if no matching permission, else `/ba-create-prd`.
- **PRD-076** `err` — Where a pagespec declares form defaults, they reference only
  field names the pagespec also exposes as editable — no orphan keys (catches
  rename drift between the BA capture and the form spec). → `/ba-create-prd`.
- **PRD-077** `err` — Every pagespec `entity` appears in `prd.entities.md` (a
  pagespec on an undeclared entity cannot be scaffolded — no DTO to import). → `/ba-create-data-model`.
- **PRD-079** `info`→`warn` — Pagespecs flagged `needsRefinement: true` are surfaced
  with their `refinementNotes`. `info` when the refined ratio < 0.7 (transparency,
  not a block); escalates to `warn` when ≥ 0.7 of pagespecs are flagged (manual
  review recommended before dev). → `/ba-create-prd`.
- **PRD-080** `err` — Every `actions[].labelKey` and `columns[].labelKey` in a
  pagespec exists in that pagespec's `i18nKeys.fr` (and so, by PRD-072, in the 3
  other locales). Pre-resolves the i18n catalogue so downstream `t('key')` lands. → `/ba-create-prd`.
- **PRD-082** `err` — For each pagespec whose `view ∈ {list, kanban, card}`, the
  pagespec `filters[]` **count equals** the matching screen's filter count in
  `screen.md` (no silent drop of filters). A `SmartKanban` / `SmartCard`
  screen's filters are counted against its section's LIST pagespec — the
  board/gallery is a representation of that list and shares its FilterBar
  (there is no kanban/card pagespec to count against on a folded PRD).
  *(structural-file: count preserved)* → `/ba-create-prd`.
- **PRD-083** `err` — Every screen in `screen.md` has at least one pagespec with the
  same `screenCode`, and its `view` follows the SmartXxx → view mapping
  (SmartListView → list, SmartForm → form, SmartDashboard → dashboard,
  SmartModuleHome → module-home, …). Synthesised `detail` views are tolerated.
  A `SmartKanban` (resp. `SmartCard`) screen is SATISFIED by its section's
  LIST pagespec carrying the `kanban` block (resp. `viewModes` with
  `"cards"`) — the folded representations never get a pagespec of their own. → `/ba-create-screen`.
- **PRD-084** `err` — Every entity in the module's `entité.md` is declared in
  `prd.entities.md` (by PascalCase name or BA code) — even entities not exposed by
  a pagespec, because the entities phase scaffolds the domain layer from this list.
  A missing entity amputates the backend. → `/ba-create-data-model`.
- **PRD-086** `err` — For each pagespec matched to a `screen.md` screen of type
  `SmartListView` / `SmartKanban` / `SmartCard`, the pagespec `actions[]` **count
  equals** the screen's action count (catches a silently dropped action). For
  the folded representations (SmartKanban/SmartCard) the count is read on the
  section's LIST pagespec; an auto-derived `move` action
  (derive-kanban-spec) is tolerated as +1 over the screen count.
  **Skip** when the screen type ∈ `{SmartForm, SmartDashboard, SmartModuleHome,
  SmartAppHome, SmartSectionHome}` (those capture actions implicitly). *(structural-file: count preserved)* → `/ba-create-prd`.
- **PRD-087** `err` — Every pagespec `appCode` equals the application code
  (lowercase, no `-web` / `-app` / `-api` suffix). Drift breaks the URL prefix in
  `scaffold-routes` (`componentKey = {appCode}.{module}.{section}`). → `/ba-create-prd`.
- **PRD-088** `err` — Every pagespec `screenCode` is **verbatim** a `SCR-…` code
  from `screen.md` — no abbreviated invented codes. **Tolerate** a synthesised
  `…-detail` code when it strips to a real upstream code by dropping `-detail`, that
  upstream section carries both a `SmartListView` and a `SmartForm`, and the pagespec
  carries `needsRefinement: true` with a note on the view. → `/ba-create-screen`.
- **PRD-089** `err` — **No untranslated i18n placeholder**. No `i18nKeys` value in
  any pagespec is an untranslated placeholder of the form `[fr] …` / `[en] …` /
  `[it] …` / `[de] …` (the abandoned "author FR, defer the rest" convention). There
  is NO downstream translation pass — `scaffold-component` copies each locale value
  verbatim, so a placeholder ships to the end user as a raw `[en] Opportunités`
  marker; every locale must carry a REAL translation. **Run this check
  DETERMINISTICALLY — do NOT eyeball the JSON** (this is exactly how an app shipped
  480 placeholders per locale under a GO PRD). Grep the module's pagespecs and treat
  every hit as a blocking `err`, one per file:
  ```bash
  grep -rnE '"\[(fr|en|it|de)\] ' <MODULE>/pagespecs/ || echo "PRD-089 OK: no placeholder"
  ```
  (or the equivalent Grep-tool / ripgrep pattern `"\[(fr|en|it|de)\]\s` over
  `pagespecs/*.md` — deterministic either way, no eyeballing).
  Any match is a blocking PRD-089 `err`, citing `file: "<key>": "<value>"`. Note
  this is orthogonal to PRD-079 (`needsRefinement`) — a pagespec can be fully
  refined structurally yet still carry i18n placeholders, and vice-versa. Fix by
  authoring the real translations: **`/ba-translate-prd`** backfills the pagespecs
  in place, or re-run `/ba-create-prd`. → `/ba-translate-prd` then re-audit.

### Custom-action contract (PRD-095..101)

Every entry under `pagespec.actions[]` is now subject to the full
`PageCustomActionSchema` declared in `templates/skills/lib/page-spec-actions.ts`.
These rules catch the silent drops that produce the class of bug (a UI button
that POSTs `/sync-from-pce` while the backend exposes `/sync-from-proconcept`).
Standard CRUD action codes (`create`, `read`, `edit`, `update`, `delete`,
`list`, `detail`) skip PRD-096 / PRD-097 / PRD-099 (they need only `code`,
`scope`, `permission`, `labelKey`, `variant`).

- **PRD-095** `err` — Every `pagespec.actions[]` entry parses against
  `PageCustomActionSchema`. **Run this check DETERMINISTICALLY — do NOT eyeball
  the JSON** (the schema rejects subtle shapes that look fine to a reader, which
  is exactly how a module shipped GO 100 with 16 malformed actions that then
  dropped to 0 at dev time and triggered a hand-written backend). Invoke the
  derivation CLI for the module and treat **every entry in `report.rejected[]`**
  as a PRD-095 `err`:
  ```bash
  npx --prefer-offline tsx skills/ba-develop/cli/derive-action-specs/index.ts \
    --spec '{"moduleRoot":"<absolute .smartstack/ba/{appCode}/{moduleCode}>"}'
  ```
  Read `report.rejected[]` — each entry is `{ file, code, path, message }` from
  the real `PageCustomActionSchema.safeParse`. A non-empty `rejected[]` (or
  `totals.rejectedActions > 0`) is a **blocking PRD-095 err**, one per rejected
  action, citing `file:"code" (path: message)`. The most common rejections (the
  ABSENCES post-mortem): `workflowTransition.fromStatus` must be an **array** of
  strings (not a bare string); `flowParameters` must be an **array** of names
  (not an object); a non-workflow `kind:"api"` action must **omit**
  `workflowTransition` entirely (`null` is rejected — the field is `.optional()`,
  not nullable). Beyond the workflow shape: `code` matches `^[a-z][a-zA-Z0-9]*$`
  (camelCase); `kind ∈ {api, navigate}`; `scope ∈ {row, bulk, header}`;
  `permission` is the `module.section[.resource].action` kebab regex (3 or 4
  segments); `labelKey` is non-empty. → `/ba-create-screen` (fix `screen.md`)
  then `/ba-create-prd`.
- **PRD-096** `err` — For every custom action with `kind: "api"`, `endpoint` is
  either present and kebab-case (`^[a-z][a-z0-9-]*$`) OR absent (the default
  `kebab(code)` will be applied at scaffold time); `httpMethod` is one of
  `GET / POST / PUT / PATCH / DELETE`; `endpoint`, `httpMethod`, `payloadDto`
  are absent when `kind: "navigate"`. → `/ba-create-prd`.
- **PRD-097** `err` — Every `pagespec.actions[].ucReference: UC-…` resolves to
  a use case present in the section's `use-case.md`. The audit Greps the
  `UC-…` code across the section's docs. → `/ba-create-use-case`.
- **PRD-098** `err` — Every `pagespec.actions[].permission` resolves to a
  permission constant in the module's `rbac.md` (same dynamic-segment shape as
  PRD-071 / PRD-074, no app prefix). → `/ba-create-rbac`.
- **PRD-099** `err` — **Endpoint uniqueness per entity**: across the union of
  pagespecs sharing the same `(appCode, module, entity)` triplet, no two
  custom actions of `kind: "api"` share the `(httpMethod, scope, endpoint)`
  triplet. A duplicate would emit a colliding `[HttpVerb("<endpoint>")]` on
  the controller (compile error) or shadow a TypeScript service method.
  Caught here because PRD spans multiple screens of the same entity (list +
  form + detail). → `/ba-create-screen`.
- **PRD-100** `err` — For every custom action with `kind: "navigate"`,
  `targetScreen: SCR-…` resolves to a `SCR-…` code present in some `screen.md`
  of the module (or app, for cross-module navigation). When `targetRoute` is
  also provided, it MUST follow the `routes.<section>.<view>(<arg>?)` shape
  expected by the React Router registry — broken targets crash the page on
  click. → `/ba-create-screen` (fix the target) or `/ba-create-prd`
  (re-resolve the route).
- **PRD-101** `err` — Every `pagespec.actions[].labelKey` exists in that
  pagespec's `i18nKeys.fr` (and so, by PRD-072, in `en/it/de`). Mirrors
  PRD-080 for custom actions specifically — a missing labelKey produces an
  empty button. → `/ba-create-prd`.
- **PRD-102** `err` — **Core-projected columns are fully backed**: every
  pagespec `columns[].source` block (a) names a `target` (default = `nav`)
  that is a **V1-whitelist** Core entity (User, Role, Tenant, TenantOrganisation,
  Department, JobTitle, Office, Language, Group); (b) has a dot-free
  `property` (whitelist→whitelist traversal is ignored by the runtime);
  (c) resolves to a `Proj:` line in `prd.entities.md` with the same
  nav/property/FK; and (d) that `Proj:` line is itself backed by an
  `entité.md` `**Personne**` line or a `Rel: … scope core` entry for the same
  FK. Reciprocally, every `Proj:` line of an entity with screens is carried by
  ≥ 1 pagespec column OR is a person-identity field (DTO-only is fine). An
  unbacked projection emits non-compiling LINQ in Phase 2; an unwhitelisted
  target is rejected by `scaffold-business`. → `/ba-create-prd` (re-derive the
  `source`/`Proj:` pair) or `/ba-create-data-model` (when the upstream
  `Personne`/`Relations` line is missing).

### Related-tabs contract (PRD-103..105 + PRD-133) — the 360 view survives the PRD

The `Onglet lié` bullets a detail/edit `SmartForm` declares in `screen.md` MUST
reach the detail pagespec as `relatedTabs[]` (canonical schema:
`templates/skills/lib/page-spec-related-tabs.ts`). Historically this was the
silent break point: the BA authored the 360 view, the PRD dropped it, no rule
noticed, and every fiche shipped flat. All three rules are backed by ONE
deterministic CLI run — **do NOT eyeball the JSON**:

```bash
npx --prefer-offline tsx skills/business-analyse/create-screen/cli/derive-related-tabs/index.ts \
  --spec '{"baRoot":".smartstack/ba","app":"<APP>","module":"<MODULE>","mode":"validate","pagespecs":true}'
```

With `"pagespecs": true` the CLI cross-checks `screen.md` ⟷
`pagespecs/{Entity}.detail.md` and schema-validates every pagespec entry;
violations tagged `source: "pagespec"` (rules RTV-101..104 + the RTV-108
budget) feed the four rules below.

- **PRD-103** `err` — **Coverage**: every `Onglet lié` entry of every
  detail/edit `SmartForm` in `screen.md` appears in the matching detail
  pagespec's `relatedTabs[]` (key-level match, count preserved — a missing tab
  is RTV-101, an extra tab RTV-102, a fk/target/displayMode mismatch RTV-103;
  one err each). Dropping an authored tab here is the historical 360-view loss
  this rule exists to block. "Count preserved" counts pagespec MEMBERSHIP, not
  strip triggers: a `summary` tab rendered as a band cartouche (`placement:
  'band'`, the renderer default for summary — `lib relatedTabPlacementOf`)
  still counts as covered; moving a tab to the band never reduces coverage.
  → `/ba-create-prd`.
- **PRD-104** `err` — **Schema**: every `relatedTabs[]` entry parses against
  `PageRelatedTabSchema` (RTV-104 — the CLI surfaces each rejection with its
  Zod path + message). An invalid `displayMode` (e.g. `report` — deliberately
  not in v1) fails here; so do a non-PascalCase `relatedEntity`, a kebab
  `relationFk` or a missing `relatedModule`/`relatedSection`. → `/ba-create-prd`.
- **PRD-105** `err` — **Referential integrity**: per entry, (a) `targetScreen`
  resolves to a list pagespec/screen of `relatedEntity`; (b) `relatedEntity`
  is in `prd.entities.md` OR the tab carries `"crossModule": true` (+
  `needsRefinement` on the pagespec); (c) `permission` (when authored)
  resolves in the owning module's `rbac.md` (same shape as PRD-098);
  (d) `labelKey` exists in the pagespec's `i18nKeys.fr` (mirrors PRD-101 — and
  PRD-072/089 then guarantee the 4 real locales). → `/ba-create-screen`,
  `/ba-create-rbac` or `/ba-create-prd` depending on the broken leg.
- **PRD-133** `warn`/`err` — **The rendered tab bar stays within budget**
  (the symmetric term the chain was missing: every rule above guards against
  LOSS, this one guards against ACCUMULATION). Same CLI run: map every
  **RTV-108** violation verbatim (warn→warn, err→err). For each `view: detail`
  pagespec the CLI counts the RENDERED strip — field `tabs[]` (0 on a unified
  fiche: detail+form view-set, read-first), plus the synthetic « info »
  trigger, plus every `relatedTabs[]` entry whose placement resolves `'tab'`
  (band cartouches excluded — `lib/page-spec-related-tabs.relatedTabPlacementOf`;
  thresholds = `lib/detail-tab-strip`). > 7 → warn (the bar overflows the
  reader), > 9 → err (the fiche is a binder, not a fiche). The remedy is
  NEVER dropping an authored tab (PRD-103 forbids it, rightly): switch inert
  satellites to `"displayMode": "summary"` (they render as band cartouches
  above the strip) and/or regroup own fields as `sections[]` (on the unified
  fiche they read above the bar). The BA-side twin is SCR-025 (RTV-009).
  → `/ba-create-prd` (placement/summary), `/ba-create-screen` (regrouping).

- **PRD-136** `err` — **A target outside this application says so**: same CLI
  run, map every **RTV-109** violation verbatim. A `relatedTabs[]` entry whose
  related entity lives in ANOTHER business application must carry
  `"relatedApp": "<kebab app code>"`, and that code must match where the entity
  actually lives. This is not cosmetic: the generator builds the tab's hook and
  routes imports as `@/features/{relatedApp}/{relatedModule}/…` and
  `@/extensions/{relatedApp}-{relatedModule}Routes`, defaulting to the PAGE's
  own application — so an unsaid (or wrong) application yields paths that do not
  exist and the page does not compile. It is also what lets the generated page
  gate the tab on the tenant catalogue (`useModuleAvailability().hasModule(app,
  module)` — DEV-UI-049 downstream), so a client that never had the billing
  application stops seeing a *Factures* tab on every customer record.
  The BA-side signal is already in the corpus: `entité.md` writes
  `scope cross-module (APP/MOD)`, and `derive-related-tabs` seeds `relatedApp`
  from it — a violation here means the PRD dropped it. Authoring escape hatch
  for a target that is genuinely in this application: nothing to write, the
  field is only ever emitted when it differs. → `/ba-create-prd`.

### Route-family contract (PRD-108) — sub-view tabs navigate to the right pages

The route identity of a satellite screen (`routeFamily` + `routeParent` on its
pagespecs) and its copy on the tabs that target it (`relatedRouteFamily`) is
what keeps a 360 tab's create button / row click on the SATELLITE's pages
instead of the porteur's (the AtlasHub mis-routing: « créer un lot » opened
« Créer Project »). The deterministic CLI half is `derive-related-tabs`
`pagespecs: true` (RTV-105/106/107) — run it and relay each violation as one
finding; then add the uniqueness leg the CLI does not cover:

- **PRD-108** `err` — **Route families are declared, unique and copied**:
  (a) when ≥2 list pagespecs share one `section` (the sub-view pattern), every
  non-primary one carries `routeFamily` (kebab) + `routeParent` (RTV-105
  surfaces the missing-`routeFamily` leg per targeting tab); (b) `routeFamily`
  values are UNIQUE within the module and distinct from every section slug —
  a collision merges two families in the emitted `*Routes.ts`; (c) every
  `relatedTabs[]` entry targeting such a satellite carries
  `"relatedRouteFamily"` equal to the target's `routeFamily` (RTV-105) plus an
  explicit `withCreate` (`false` when no `<RelatedEntity>.form.md` — RTV-106)
  and `withRowOpen` coherent with `<RelatedEntity>.detail.md` (RTV-107);
  (d) a tab with `withCreate: true` on a sub-view target carries
  `createPermission` copied verbatim from the target list pagespec's
  `actions[]` create entry (recomposition cannot guess resource-scoped shapes
  like `portfolio.list.work-package.create`). → `/ba-create-prd`.

### Form-field labels contract (PRD-106)

- **PRD-106** `err` — **Every form field has an authored label**. Every pagespec
  with `view: "form"` (a) carries a non-empty `fields[]` (mined 1:1 from the
  screen's `Champs`, mirror of `columns[]` — see the create-prd contract), and
  (b) every `fields[].labelKey` exists in that pagespec's `i18nKeys.fr` (and so,
  by PRD-072, in the 3 other locales). Exact mirror of PRD-080 for form fields.
  Why blocking: `scaffold-component`'s field-label floor is the humanised
  PROPERTY NAME, byte-identical in fr/en/it/de — an unauthored `form.fields.*`
  key ships an English "Name" on a French form, and NO downstream gate can see
  it (PRD-089 / DEV-UI-029 only catch `[xx]` markers; DEV-UI-037 downstream is
  a heuristic `warn`, not a gate). **Run the presence check DETERMINISTICALLY**
  (same discipline as PRD-089): extract `fields[].labelKey` and the
  `i18nKeys.fr` key set from each `pagespecs/*.form.md` machine block and diff
  them — do not eyeball. A form pagespec with NO `fields[]` at all is one
  blocking err (legacy pre-contract pagespec: re-run `/ba-create-prd`); each
  missing labelKey is one err citing `file: fields[].labelKey`. → `/ba-create-prd`.

### Custom-action file-upload guard (PRD-107)

- **PRD-107** `warn` — **No pagespec custom action carries
  `payloadParameters[].type: "file"`**. The generated pipeline is NOT wired for
  multipart: `scaffold-api-client` posts the payload as JSON (a `File`
  serializes to `{}`), the scaffolded controller binds `[FromBody]` JSON, and
  `run-smoke` skips the parameter — an authored `type:file` action ships a
  dead upload button. An upload is the ATTACHMENTS pattern instead: metadata
  entity + dedicated multipart endpoints + `FormData` via the package's `api`
  (`development/backend/data-layer/references/file-storage.md`; upstream
  screen guard: SCR-016). **Run the check DETERMINISTICALLY**: Grep
  `"type": "file"` (and `type: 'file'`) across `pagespecs/*.md` machine
  blocks — one finding per hit citing the pagespec + action code.
  → `/ba-create-screen` (redesign the action as an attachments tab) then
  `/ba-create-prd`.

### List elegance (PRD-109/110) — column budget + filter tiers

The list rendering shows at most ~7 default-visible columns (the rest behind
the column picker) and at most 3 primary filters (the rest behind « Plus de
filtres »). The pagespec carries the JUDGMENT through `columns[].priority` and
`filters[].tier`; without it the scaffolder falls back to declaration order —
a net, not a judgment. Both checks run DETERMINISTICALLY over each `view: list`
pagespec machine block:

- **PRD-109** `warn` — **Column visibility budget is authored and holds**:
  (a) `count(priority ∈ {always, high}) ≤ 7` — beyond that the default table
  is back to a horizontal-scroll wall (the scaffolder honours the BA verbatim,
  it never truncates always/high); (b) a list with ≥ 8 `columns[]` has a
  `priority` on EVERY column — none authored means the first-7 fallback ships
  arbitrary columns visible. One finding per pagespec citing the count.
  → `/ba-create-prd` (author the priorities per the Column priority &
  visibility budget block).
- **PRD-110** `warn` — **Filter tiers are authored and hold**:
  (a) `count(tier = "primary") ≤ 3`; (b) a list with ≥ 4 `filters[]` carries a
  `tier` on at least one filter — none authored means the heuristic decides
  which filters are promoted; (c) no filter has `field` matching
  `^(q|search|recherche|fulltext)$` **authored with a tier or a defaultValue**
  — the global-search filter is fused into the search box, tiering it is dead
  spec. One finding per pagespec. → `/ba-create-prd` (author the tiers per the
  Filter tiers block).
- **PRD-113** `err` — **Reference filters carry their target**. On every
  `view: list` pagespec, a filter is a REFERENCE when it declares
  `control: "lookup"`, carries the BA alias `entity`, or names a FK-shaped field
  (`…Id`, excluding `externalId`/`parentId`/`guidId`). Each such filter must:
  (a) carry a `fkTo` block (same shape as a form field's — `entity` + `module`,
  plus `apiEndpoint`); and (b) name the **FK property** (`departmentId`), not the
  relation (`department`) — i.e. `field` matches a `…Id` FK of the entity in
  `entité.md`. Either leg missing is one finding per filter.
  Why blocking: the filter's `field` IS the state key, the DTO property, the
  query param and the backend's `[FromQuery] Guid?`. A relation-named or
  target-less filter matches none of them — it renders as a free-text box over a
  Guid and its param is dropped on the wire, so the filter neither looks up nor
  filters, silently. → backfill deterministically with
  `npx tsx skills/ba-develop/cli/derive-filter-fks/index.ts --spec '{"moduleRoot":".smartstack/ba/<APP>/<MODULE>"}'`
  (idempotent, never renames `labelKey`), then re-scaffold the list page. A
  filter the CLI reports as `unresolved` is a BA gap — declare the relation in
  `entité.md`, never hand-author `fkTo`.

- **PRD-115** `err`/`warn` — **The KPI stat row is small, labelled and
  wirable**. On every `view: list` pagespec carrying `stats[]`:
  (a) `err` — every `stats[].labelKey` is authored in `i18nKeys` for ALL 4
  locales (fr/en/it/de) — an unlabelled tile renders a raw key;
  (b) `err` — a stat with `filter` names a `filter.field` that exists in the
  SAME pagespec's `filters[]` — that field is the server-bound wire param;
  anything else ships a visibly dead « — » tile;
  (c) `err` — a stat that declares an `entity` other than the pagespec's, or
  an `aggregation` other than `count` — not wirable on a list (belongs on a
  SmartDashboard);
  (d) `warn` — `count(stats) > 4` — the row is one grid line, beyond 4 it
  wraps into a wall. One finding per stat (a/b/c) or per pagespec (d).
  → `/ba-create-prd` (author per the KPI stat row block); the BA source is the
  `- **Indicateurs** :` bullet (SCR-017 caps it upstream).

- **PRD-119** `err` — **The detail summary names real fields**. On every
  `view: detail` pagespec carrying `summary` (or `uiDesign.detail.summary`):
  `titleField`, `statusField` and every `fields[]` entry name an entity field
  of `entité.md` (camelCase); `count(fields) ≤ 4`. An unknown key ships a
  dropped slot (generation warning) — the band silently thins. →
  `/ba-create-prd` (Detail summary block); BA source = the optional
  `- **Résumé** :` bullet of the detail screen.

- **PRD-134** `warn` — **A summary band is authored where the fiche warrants
  it** (twin of PRD-112(a) for the strip — PRD-119 only VALIDATES a band that
  exists; until this rule nothing ever demanded one, and whole projects
  shipped six fiches with zero bands). For every `view: detail` pagespec
  whose RENDERED strip carries ≥ 4 triggers (same counting as PRD-133 —
  synthetic « info » included, band cartouches excluded, unified fiche
  honoured; `lib/detail-tab-strip`) and that carries neither `summary` nor
  `uiDesign.detail.summary`: the record's identity and state vanish as soon
  as the reader leaves the first tab. The absence NEVER breaks a legacy PRD
  (warn, below the threshold silent). **Run the check DETERMINISTICALLY** —
  `derive-detail-summary --mode check` IS this rule:

  ```bash
  npx --prefer-offline tsx skills/business-analyse/create-prd/cli/derive-detail-summary/index.ts \
    --spec '{"mode":"check","pagespecDir":".smartstack/ba/<APP>/<MODULE>/pagespecs","moduleRoot":".smartstack/ba/<APP>/<MODULE>"}'
  ```

  Map every `findings[]` entry to one PRD-134 warn. → run `--mode derive`
  (deterministic backfill); a `needs-judgment` outcome routes to the
  `- **Résumé** :` bullet (`/ba-create-screen`) or `uiDesign.detail.summary`
  (`/ui-design`).

- **PRD-116** `err`/`warn` — **Segments are cohorts, defaulted and wirable**.
  On every `view: list` pagespec carrying `segments[]`:
  (a) `err` — every `segments[].labelKey` authored in `i18nKeys` for ALL 4
  locales; (b) `err` — a filtered segment's `filter.field` exists in the SAME
  pagespec's `filters[]` (the server-bound wire param — else the whole row is
  disabled at generation); (c) `warn` — the FIRST segment carries no `filter`
  (the unfiltered « Tous » default) ; (d) `warn` — `count(segments) > 4`
  (beyond 4 it is a filter, not a cohort row). → `/ba-create-prd` (Quick
  segments block); BA source = the `- **Segments** :` bullet.

- **PRD-118** `err`/`warn` — **Sort, density and empty state are coherent**.
  On every `view: list` pagespec: (a) `err` — `defaultSort.key` names a
  declared `columns[]` entry with `sortable: true`; (b) `err` —
  `emptyState.titleKey`/`descriptionKey`, when authored, exist in `i18nKeys`
  for ALL 4 locales; (c) `err` — `emptyState.withCreate` only when the
  entity's `*.form.md` pagespec exists (PRD-114's sibling contract);
  (d) `warn` — `density: "compact"` on a list with < 6 columns (compact is a
  volume judgment, not a default). → `/ba-create-prd`.

- **PRD-117** `err` — **The cards representation is well-formed and folded**.
  (a) `viewModes`, when authored, appears ONLY on a `view: list` pagespec with
  values from `{"table","cards"}` and `defaultViewMode ∈ viewModes`;
  (b) NO standalone SmartCard pagespec exists (`view: "card"`/`"cards"` or a
  second pagespec for the same entity mirroring the list) — a SmartCard screen
  in `screen.md` folds into the list pagespec as `viewModes` (the kanban-style
  representation rule);
  (c) a list with a SmartCard screen in its BA section but no `viewModes` on
  its pagespec = the reader is never OFFERED the gallery (one finding).
  → `/ba-create-prd` (Cards representation block).

  > **`viewModes` does not decide whether cards EXIST.** Every generated list
  > carries a cards branch and switches to it on its own once the container can
  > no longer give each column its minimum width — hiding columns to make a
  > table fit amputates the data silently, so the representation changes
  > instead. What `viewModes` declares is that cards are a FIRST-CLASS reading
  > of this section, offered through the manual Table ⇄ Cartes toggle on a wide
  > screen. Finding (c) is therefore about a missing affordance, never about a
  > missing narrow-screen fallback.

- **PRD-135** `err`/`warn` — **The kanban representation is well-formed,
  folded and governed** (the board twin of PRD-117 — with the extra duty that
  the BA's workflow rules actually reach the board). On every pagespec, the
  legs (severity per leg):
  (a) `err` — a `kanban` block appears ONLY on a `view: list` pagespec and
  parses against `lib/page-spec-kanban.PageKanbanSchema`;
  (b) `err`/`warn` — every `kanban.columns[].key` is a VERBATIM value of the
  entity's status enum in `entité.md` (err); an enum value with no column is
  a warn (its rows land in the unassigned bucket);
  (c) `err`/`warn` — every `transitions[].from/to` is a verbatim enum value
  (err); every workflow rule's Flow edge (mapped onto the enum) is projected
  in `kanban.transitions` (err — a missing edge means the BR graph silently
  does not govern the board); a block edge backed by NO rule's Flow is a warn
  (the board is more permissive than the BR graph);
  (d) `err`/`warn` — `statusField` is among the list's `columns[]` (err — the
  ListDto must carry the bucket field); `titleField`/`subtitleField`/
  `cardFields[]` outside the declared columns/fields are warns;
  (e) `err` — `viewModes` contains `"kanban"` **iff** the block is present
  (both directions), and `defaultViewMode ∈ viewModes`;
  (f) `err` — NO standalone `view: kanban` pagespec exists (the pre-fold
  legacy shape — fold via derive-kanban-spec, then delete the file);
  (g) `warn` — `transitions[]` authored but no `move` action on the pagespec
  (the board renders read-only, DnD stays off);
  (h) `err` — every `columns[].labelKey` exists in the pagespec's
  `i18nKeys.fr` (and so, by PRD-072, in the 3 other locales).
  **Run the check DETERMINISTICALLY** — `derive-kanban-spec --mode check` IS
  this rule:

  ```bash
  npx --prefer-offline tsx skills/business-analyse/create-prd/cli/derive-kanban-spec/index.ts \
    --spec '{"mode":"check","pagespecDir":".smartstack/ba/<APP>/<MODULE>/pagespecs","moduleRoot":".smartstack/ba/<APP>/<MODULE>"}'
  ```

  Map every `findings[]` entry to one PRD-135 finding of its `severity`.
  → run `--mode derive` (deterministic backfill); a `needs-judgment` outcome
  routes to the BA (align the Flow tokens / the `Colonnes` bullet with
  `entité.md`). BA source = the SmartKanban block of `screen.md`
  (`Champ statut`/`Colonnes`/`Carte` bullets) + the module's workflow rules.

- **PRD-114** `err` — **A mutable list declares its form/detail siblings**.
  For every entity whose `view: list` pagespec is NOT read-only — it declares a
  `create`/`edit`/`update` CRUD action, or the RBAC grants the section
  `create`/`update` — the module's `pagespecs/` must also carry the entity's
  `*.form.md` (and `*.detail.md` when rows are meant to open). One finding per
  entity, naming the missing pagespec(s).
  Why blocking: scaffold-routes emits route helpers ONLY for declared views and
  scaffold-component now gates its create/edit buttons and row-open on the
  sibling views actually existing — a list-only entity with mutation intent
  therefore ships a list with NO create/edit affordance at all: the BA's
  intent silently disappears instead of breaking the build (previously it was
  worse — TS2339 on `routes.{x}.edit`). Either author the form/detail
  pagespecs (re-run `/ba-create-prd` for the entity) or make the read-only
  choice explicit by dropping the mutation grants/actions from the list spec.

### Form/detail sections (PRD-111/112) — grouped fiches

The fiche rendering groups fields into titled cards through the pagespec's
first-order `sections[]` (form AND detail views — canonical schema
`lib/page-spec-sections.ts`; labels shared through `form.section.{key}`, the
edit render is read-first by default). Both checks run over each
`view: form|detail` pagespec machine block:

- **PRD-111** `err` — **Every authored section is well-formed and labelled**.
  For every pagespec carrying `sections[]`: (a) every entry has a `key` AND a
  `labelKey`; (b) every `labelKey` exists in that pagespec's `i18nKeys.fr`
  (and so, by PRD-072, in the 3 other locales); (c) every `sections[].fields[]`
  entry references an existing pagespec field (no orphan); (d) section keys
  are unique and no field belongs to 2 sections. Why blocking: the
  scaffolder's floor for a section title is the humanised key, byte-identical
  in all 4 locales — an untranslated section ships "Identity" on a French
  fiche and NO downstream gate can see it (same argument as PRD-106). **Run
  the check DETERMINISTICALLY**: extract the `sections[].labelKey` values and
  the `i18nKeys.fr` key set from each machine block and diff them — never
  eyeball. → `/ba-create-prd`.
- **PRD-112** `warn` — **Section grouping is authored where the fiche warrants
  it** (twin of PRD-109 for fiches). For every `view: form|detail` pagespec:
  (a) ≥ 8 `fields[]` with neither `sections[]` nor `tabs[]` → warn (the
  rendering falls back to the single default card — a wall); (b) when
  `sections[]` exists: 2 to 4 sections, each with ≥ 2 fields; (c) `sections[]`
  AND `tabs[]` on the same view → warn (pick one grouping form; nesting is
  not v1). The absence NEVER breaks a legacy PRD. One finding per pagespec.
  → `/ba-create-prd` (or `/ba-create-screen` when the source `screen.md` is
  not grouped — SCR-018).
- **PRD-120** `err` — **The lifecycle block is well-formed and anchored on real
  statuses**. For every `view: form` pagespec carrying `lifecycle` (canonical
  schema `lib/page-spec-lifecycle.ts`): (a) `statusField` names a
  state-semantics enum attribute of the entity in `entité.md`; (b) that field
  is listed in the pagespec `fields[]` — the compiled guards read
  `formData.<statusField>`, an absent status field silently degrades every
  phase gate to a bare edit-mode guard (`readonly`/`readonlyOn: "create"` is
  fine); (c) every `phases[].statuses[]` value exists **verbatim** among the
  enum's values; (d) every `phases[].fields[]`/`requiredFields[]` entry
  references an existing pagespec field — no orphan, no field owned by two
  phases, never the `statusField` itself, and the reserved key `creation` is
  never authored (un-phased fields ARE the creation phase); (e) no phase-owned
  field is `required: true` in the derived scaffold specs — the backend Create
  surface carries required fields, so a required later-phase field re-enters
  the create contract server-side (the invoice-asks-payment-date bug reborn);
  phase-scoped requiredness belongs to `phases[].requiredFields` + the
  capturing action's `payloadParameters[].required`; (f) `capturedBy`, when
  set, names a `kind: api` action of this pagespec whose
  `workflowTransition.toStatus` ∈ the phase's statuses (when both declared)
  and which declares one `payloadParameters` entry (`field` ?? `name`) per
  phase-owned field, `required: true` for the `requiredFields`. **Run the
  check DETERMINISTICALLY**: `npx --prefer-offline tsx
  skills/business-analyse/create-prd/cli/derive-lifecycle/index.ts --spec
  '{"mode":"check","pagespecDir":"<MODULE>/pagespecs","moduleRoot":"<MODULE>"}'`
  — its findings (legs a/b/c/d/f + schema) ARE this rule; leg (e) is enforced
  by the scaffold gate (scaffold-component validate.ts) and checked here in
  prose. → `/ba-create-prd`.
- **PRD-121** `warn` — **Lifecycle is authored where the entity lives one**
  (twin of PRD-112 for phased fields). For every `view: form` pagespec of an
  entity with state semantics and NO `lifecycle` block: (a) a pagespec action
  carries a `workflowTransition` whose parameters (`payloadParameters[].field`
  ?? `name`, else `flowParameters`) match form field keys → warn (the create
  form asks what the action captures at a transition); (b) `derive-lifecycle
  --mode derive` reports `needs-judgment` (later-phase lexicon candidates with
  a matching later status) → warn and route to the `/ui-design` rubric §6
  pass or the BA — the heuristic only FLAGS, it never writes. The absence
  NEVER breaks a legacy PRD. One finding per pagespec. → run
  `derive-lifecycle --mode derive` (deterministic anchors), then
  `/ba-create-prd` or `/ui-design` for the remainder.

### Vibecoding readiness (VIBE-001..009) — upstream coverage the dev sub-agent needs

These read the upstream BA docs (same content, file input). When the upstream doc
is absent, emit an `info` "upstream resolution unavailable" instead of failing.

- **VIBE-001** `err` — Every entity in `prd.entities.md` exists in `entité.md` with
  ≥ 1 attribute of an EF-mappable `dataType`. Otherwise the entities sub-agent must
  guess attributes. → `/ba-create-data-model`.
- **VIBE-002** `err` — Every entity in `entité.md` covered by the PRD has an
  unambiguous tenant mode (the module's multi-tenant convention is stated, not
  left implicit) — stated through `- **Portée** : strict|optional|none` on the
  entity, or once at document level before the first `### ENT-` heading
  (inherited). DM-028 is the BA-side engine; without the bullet the scaffolder's
  `strict` default silently decides the tenant-composite shape of every unique
  index. → `/ba-create-data-model`.
- **VIBE-003** `err` — For every N:M relationship in `entité.md`, `prd.entities.md`
  names the junction table explicitly (else `scaffold-entity` emits only a simple
  FK and breaks). → `/ba-create-data-model`.
- **VIBE-004** `err` — For every permission ending in `.create|.update|.delete`,
  the `prd.api.md` slice references ≥ 1 validating business rule (`BR-…`) — OR the
  upstream `règles-métier.md` truly has none for that entity (acknowledged). Else
  `scaffold-business` generates an empty validator and integration tests pass
  silently. → `/ba-create-business-rules`.
- **VIBE-006** `err` — `## Technical constraints` names the target DB provider
  explicitly (`PostgreSQL`, `SQL Server`, or `Azure SQL` — never `SQLite`). Else
  `scaffold-migration` emits a neutral migration that can break on the real
  provider. → `/ba-create-prd`.
- **VIBE-007** `err` — For the application, `rbac.md` defines ≥ 1 native role and
  the permission floor (`access` + `read`). Without it `scaffold-core-seed` emits an
  amputated seed (a dev role with no base permission). → `/ba-create-rbac`.
- **VIBE-008** `err` — Every entity in `prd.entities.md` is the target of ≥ 1
  permission in `rbac.md` (via the section, 4-seg, or the resource segment, 5-seg).
  Else the API phase has no controller to scaffold for that entity. → `/ba-create-rbac`.
- **VIBE-009** `err` — For every `view: form` pagespec, the editable field list is
  non-empty and every field belongs to that entity's attributes in `entité.md` (no
  orphan). Else `scaffold-component` emits an `<input>` for a non-existent attribute
  and the runtime crashes. → `/ba-create-screen`.

> The richer Studio-only fields (specHash idempotency, breadcrumb chains,
> errorScenarios / testScenarios / referenceData / endpointSpecs / domainEvents
> sidecars) were checked by the legacy PRD-075/078/081/089..097/VIBE-005/011 against
> the injected JSON envelope. On disk those structures are folded into the slices
> and pagespec bodies, so their intent is carried by PRD-056/057/072/082/086/094 and
> VIBE-004 above. There is **no** separate sidecar to validate and **no** partial-PRD
> gate (PRD-089) — a `.md` PRD is either present and audited or absent (handled in
> Scope). There is no `[ACTION]` fix handler; every fail routes to a phase skill.

---

- **PRD-125** `err` — **A dashboard pagespec binds its host entity.** Every
  `view: dashboard` pagespec carries `entity` — the endpoint's host:
  `scaffold-screen-controller` already emits the dashboard endpoint per HOST
  entity, so an unbound dashboard escapes the per-(section, entity) fan-out
  and ships a frontend page with NOTHING to call (`InspectionForecast`,
  `OdometerCoherence`: DEV-API-010/008's only errors on one client — 12 AC).
  Widgets may target OTHER entities (the widget schema carries `entity` +
  `permission`); the page-level `entity` names the host. A genuinely
  entity-less KPI surface is NOT a dashboard pagespec: model it as a home view
  (`section-home` widgets / the platform's INavigationStatsProvider seam) and
  mark the pagespec `needsRefinement`.
- **PRD-126** `warn` — **An entity has a birth path.** An entity whose views
  reduce to `form`/`detail` with NO create channel — no list `create` action,
  no POST-shaped custom action, no seed/`**Code pattern**` signal — cannot be
  born from the UI (the client's LifecycleSummary: GET/PUT/freeze, no POST).
  Decide: authorise the create, or declare the entity seeded/derived (created
  as the effect of another UC) in the PRD.
- **PRD-122** `err` — **Every form-pagespec field resolves on the entity.**
  Each `fields[].key` of a `view: form` pagespec matches an attribute of the
  bound entity in `entité.md` (camel-insensitive; the lifecycle statusField
  and the coded `code` are the sanctioned exceptions). A key living in a CHILD
  entity is the composite-creation trap: the Create DTO never carries it,
  model binding drops the value silently, and the UC's flow steps "never reach
  the API" (the vehicle's plate, the licence's categories — 6 amputated
  Create DTOs on one client). scaffold-component's validate refuses the same
  shape downstream, NAMING the child when Phase 3a passes `moduleEntities`.
  Fix: remove the child field from the form (create the child row from the
  fiche's 360 tab, or capture it through a post-creation workflow action) —
  composite creation is the named follow-up `creation-composite`.
- **PRD-123** `err` — **A derived member never enters a form.** Any
  `**Dérivé**` attribute of `entité.md` (or pagespec column flagged
  `derived: true`) present in a `view: form` pagespec's `fields[]` is an err —
  the member is read-only by construction (`lib/field-read-surface`), its C#
  write surfaces don't carry it, and an input on it would post a value the
  model binder silently drops. List/detail columns are its only surfaces;
  name it after the VALUE (`officeName`), never as a pseudo-FK (`officeId`).
- **PRD-124** `err` — **A GET custom action declares its response contract.**
  Every pagespec `actions[]` entry with `kind: "api"` and `httpMethod: "GET"`
  declares a `responseDto` that is neither absent nor `"NoContent"` (a
  screens-era `responseType` also satisfies it). The class it closes:
  `[HttpGet] → NoContent()` measures (`driver-at`, `mileage-forecast`,
  `history`…) — the service computed the answer and threw it away
  (`_ = await …`), ~20 acceptance criteria unreachable. The generation chain
  now REFUSES the shape (`lib/page-spec-actions` superRefine + the
  scaffold-controller / scaffold-business validates); this rule catches it at
  authoring time, `DEV-API-025` catches legacy controllers already on disk.
  Fix: declare the result DTO (e.g. `DriverAtResultDto`) or requalify the
  action as a POST state mutation.
- **PRD-128** `err` — **An action's permission binds to its OWN section, at
  the section grain.** Every pagespec `actions[]` entry with `kind: "api"`
  carries a 3-segment permission rooting at the pagespec's own
  `module`.`section`. Two refused shapes: (a) a permission rooting at another
  module/section — the generators compile the constant from the SPEC's
  module/section and keep only the action segment, so the authored permission
  would be SILENTLY REBOUND to a different one (cross-section intent must be
  modelled explicitly on the owning section); (b) a resource-grain (4-seg)
  action permission — no generated code path enforces the resource segment,
  the compiled constant silently WIDENS to the section (the row is seeded but
  never checked). Deterministic half: `ba-develop/cli/derive-action-specs`
  REJECTS both shapes via its BLOCKING `rejected[]` channel
  (`actionPermissionBindingIssue`, lib/page-spec-actions). `kind: "navigate"`
  actions are exempt — their permission legitimately roots at the TARGET
  screen. Fix: author `<module>.<section>.<action>` on the owning pagespec.
- **PRD-129** `err` — **Every enforceable business rule is linked to a
  pagespec.** Deterministic check — run the colocated create-prd CLI (Bash)
  and read its envelope; never re-derive by hand:

  ```bash
  npx --prefer-offline tsx skills/business-analyse/create-prd/cli/derive-rule-links/index.ts \
    --spec '{"baRoot":".smartstack/ba","app":"<APP>","module":"<MODULE>","mode":"check"}'
  ```

  A FAILED envelope maps too — never an undefined verdict: `règles-métier.md
  missing (module or section)` → one **err** finding « rules doc missing —
  run `/ba-create-business-rules` (phase 4) before the PRD »; `pagespecs/
  not found` → the PRD is not generated (the PRD-000 blocking case).
  Mapping from the envelope's `report`:
  - `missing-link` entries → **err** — an err/warn rule of `règles-métier.md`
    appears in NO pagespec's `linkedBusinessRules[]`: DEV-API-008 will pass
    green at count 0 and the rule ships unenforced (the audit's main BR
    silent-loss point). Name each rule + its mapped section(s).
  - `needs-judgment` entries → **warn** — module-level rule with no linked UC:
    no section is derivable mechanically; the author links it, links a UC, or
    exempts it (`- **Enforcement** : plateforme|manuel`). Never guessed.
  - exemptions (`severity-info`, `type-access` → RBAC matrix, `type-numbering`
    → codePattern/DEV-API-022, `enforcement-field`) are DATA, not findings —
    each names its real channel.
  - Fix: re-run the CLI in `"mode":"backfill"` (adds, never removes — authored
    links win), or author the link on the owning pagespec.
- **PRD-130** `err` — **Every cited BR code resolves, unambiguously.** Same
  CLI, same run — `report.citedCodeFindings`: `unresolved-code` (a
  `linkedBusinessRules` entry matching NO rule of the module — a dead
  reference satisfies no gate; the mirror of PRD-097 for UCs) and
  `ambiguous-code` (the code exists in SEVERAL docs of the module — BR codes
  are doc-scoped; renumber one doc). Both **err**.
- **PRD-131** `err` — **Every user-goal use case reaches the pagespecs.**
  Deterministic check — run the create-screen coverage CLI (Bash) and read
  its envelope; never recount by eye:

  ```bash
  npx --prefer-offline tsx skills/business-analyse/create-screen/cli/derive-uc-coverage/index.ts \
    --spec '{"baRoot":".smartstack/ba","app":"<APP>","module":"<MODULE>"}'
  ```

  Map every `report.ucs[]` entry with `prd: "uncovered"` to one **err**
  finding: a user-goal UC that no pagespec references — neither
  `linkedUseCases[]` nor any action's `ucReference` — is a UC the generators
  will never serve (its `[Fact]`s fail against nothing; the phantom-UC
  shape). This is what finally gives `linkedUseCases[]` a reader. Semantics:
  `scheduled` UCs are covered by the scheduled surface (derive-job-specs /
  DEV-API-028); `subfunction`/`summary` levels are exempt; an undeclared
  level counts as user-goal (fail-closed). The BA-side leg (`ba:
  "uncovered"`) belongs to `/ba-audit-screens` **SCR-024** — do not
  double-report it here. Fix: re-run `/ba-create-prd` (transports the screen
  links), or author `linkedUseCases[]`/`ucReference` on the owning pagespec.
- **PRD-132** `err` — **Coded-entity parity: entité.md ⇔ pagespec
  `codedEntity` flag, both directions.** Deterministic check — run the
  ba-develop derivation CLI (Bash) and read its envelope; never recount by
  eye:

  ```bash
  npx --prefer-offline tsx skills/ba-develop/cli/derive-code-specs/index.ts \
    --spec '{"moduleRoot":".smartstack/ba/<APP>/<MODULE>","mode":"check"}'
  ```

  Map every `report.drift[]` entry to one **err** finding: `missing` (an
  entity with a `**Code pattern**` line whose pagespec does NOT carry the
  `codedEntity` flag — the frontend guard never arms, scaffold-component
  happily emits an editable `code` input), `stale` (a pagespec flag with
  no upstream line — the guard blocks a legitimately typed code) and
  `facet-drift` (the flag is present but its `label`/`supplied` facets — the
  enriched object form — disagree with the entité.md line; the outcome's
  `facets[]` names what diverged). Map every `report.nearMisses[]` entry to
  one **err** finding too: a Code pattern DECLARED in an unparsable form
  (`table-cell` — the incident shape, `wrong-case`, `unbolded-bullet`,
  `prose-declaration`) derives NOTHING — the whole chain renders green over
  a real declaration (the green-by-vacuity class; the remedy wording is the
  CLI's `CODE_PATTERN_CANONICAL_FORM`). Also surface
  `report.totals.blocked > 0` as **err**: a `**Code pattern**` line
  without a valid backticked mask derives NOTHING — the seam stays
  unimplemented while looking authored (the exact hole the dev agent used to
  fill with a hand-rolled allocator, DEV-API-034's class). Surface each
  `sequentialSuppliedRisk` entity (supplied + `{SEQ}` mask) as **warn** —
  the CLI's warning text explains the deferred unique-index collision. Fix:
  re-run the CLI in `"mode":"derive"` (reconciles the flags both ways —
  entité.md is the single source of truth), or fix the entité.md line
  (DM-017 / DM-021).
- **PRD-127** `warn` — **No volatile business figure inside a frozen i18n
  label.** A pagespec `i18nKeys` title/subtitle/description that embeds a
  COUNT or business measure as literal digits (« 12 véhicules actifs », « 3
  contrôles en retard ») freezes a number the UI can never update — the page
  ships lying from the second day. Numbers belong to BOUND surfaces: `stats[]`
  KPIs, `detail.summary`, computed subtitles. Allowed digits: legal/norm
  references (« art. 55 LCR »), product names, years in static wording. Fix:
  reword the label (« Véhicules actifs ») and carry the live count in a
  `stats[]` KPI.

## Quality score & the dev-readiness gate

Count `err`, `warn`, `ok` across every check above (skipped checks don't count).
Keep the source's per-dimension saturating-monotonic formula:

```
score = round( 100 × 100 / (100 + 10·err + 3·warn) )
```

- `err` (×10) blocks the gate; `warn` (×3) is a quality hit; `info` (×0) is
  observation only. Examples: 0e/0w → 100, 0e/5w → 87, 1e/3w → 84, 3e/5w → 69.

**Dev-readiness gate** (what `/ba-develop` reads):

```
GO  ⟺  score ≥ 80  AND  err = 0
NO-GO otherwise
```

A GO is the gate for `/ba-develop`. Below GO, the PRD is not handed
to development — fix the findings (each routes to its owning phase skill) and re-run.

---

## Output — `.smartstack/ba/<APP>/<MODULE>/_audit/prd.md`

Write the verdict per the `_workflow/doc-templates.md` audit skeleton, but the
header MUST carry the dev-readiness gate so the orchestrator can read it:

```markdown
<!-- ba:audit dimension=prd scope=CRM/PIPELINE -->
# Audit PRD — CRM / PIPELINE
_2026-05-21 · Verdict : GO · score 92/100 · 0 err · 3 warn_

## ✅ Conforme
- **PRD-001′** — chaque spécification de page (`pagespecs/*.md`) est un bloc JSON
  valide et complet — contrat prêt pour la génération de composants.
- **PRD-005 / PRD-006** — le PRD et ses trois tranches de phase sont présents et complets.
- **PRD-070** — chaque écran défini a sa spécification de page (couverture complète).

## ⚠️ Avertissements
- **PRD-064** — l'exclusion « la facturation est gérée ailleurs » (hors-périmètre)
  n'est pas reprise dans les non-objectifs.
  - Pourquoi : risque que le développement réintroduise une fonction explicitement écartée.
  - → Recopier l'exclusion via `/ba-create-prd` (ou ajuster le périmètre via `/ba-create-menu`).

## ❌ Bloquants
- _(aucun)_
```

- The header line is `_<date> · Verdict : <GO|NO-GO> · score <N>/100 · <e> err · <w> warn_`.
  `GO` requires `score ≥ 80` AND `0 err`.
- Findings are grouped `✅ Conforme` / `⚠️ Avertissements` / `❌ Bloquants`. Rule
  codes stay **bold** (greppable) but are explained in business terms. Each non-ok
  finding gives **what's wrong** (offending codes/paths in bold), **why it matters**,
  and a `→` **fix** naming the owning phase skill (`/ba-create-prd`,
  `/ba-create-data-model`, `/ba-create-screen`, `/ba-create-rbac`,
  `/ba-create-business-rules`, `/ba-create-actors`, `/ba-create-use-case`,
  `/ba-create-menu`).
- Re-Write the whole file each run (overwrite — it is a fresh verdict).

## Chat summary

After writing the file, print a concise GO / NO-GO summary in the user's language,
in **business terms** (not rule codes): the verdict + score + counts, the top
blockers (max 5, one line each, naming the fix skill), and a plain statement that
**a GO is the gate for `/ba-develop`** — below GO, fix the blockers
and re-run before development.

## Used by the readiness orchestrator

`/ba-audit-pre-dev` aggregates the per-dimension verdicts. When invoked as part of
pre-dev readiness, still write `_audit/prd.md` as usual — the orchestrator reads
this file's `Verdict :` header.
