# Vérificateur de conformité

Node >= 20. Entrée `alloframe/verification`,
également réexportée depuis `alloframe`. Sans dépendance npm pour les contrôles Node.

## Usage CLI

```sh
node tools/verify.mjs examples/verification/alloframe.manifest.json --mode strict
node tools/verify.mjs examples/verification/alloframe.manifest.json --format json
npm run verify -- examples/verification/alloframe.manifest.json --composition main
node tools/verify.mjs examples/verification/staging.json --kind staging \
  --context examples/verification/alloframe.manifest.json --composition main
node tools/verify.mjs chemin/library.json --kind library --framework-version 1.0.0
```

`alloframe-verify` est le nom du binaire déclaré dans `package.json`.
Avec `--format json`, appeler directement `node tools/verify.mjs` pour éviter
les bannières de npm sur stdout. Le processus lui-même n’écrit que le rapport
JSON sur stdout. Les erreurs d’appel et erreurs internes vont sur stderr.

| Option | Sens |
|---|---|
| SOURCE | Chemin local ou URL absolue |
| `--kind` | `project` par défaut ; `library`, `entities`, `composition`, `decor`, `staging`, `scenario`, `actor`, `director`, `choreography` |
| `--context MANIFEST` | Fichier contextualisé : vérifie son appartenance exacte à chaque composition sélectionnée du projet |
| `--composition NAME` | Répétable, dédoublonnée ; toutes les compositions déclarées par défaut |
| `--mode normal\|strict` | `normal` par défaut |
| `--format text\|json` | `text` par défaut |
| `--framework-version X.Y.Z` | Version explicite pour les contraintes de framework |
| `--help` | Aide |

Pour un fichier partagé avec certaines compositions seulement, sélectionner
ces compositions avec `--composition`. La fermeture documentaire des sélections
est contrôlée, pas uniquement le fichier isolé. Aucune recherche récursive du
répertoire, aucun fichier implicite, aucune installation, aucun chargement JS.

La CLI lit uniquement les déclarations locales. Les ressources locales sont
contrôlées par présence, type fichier et lisibilité ; ce n’est pas un décodage
ou une validation du contenu. Les ressources distantes, `data:` et `blob:` sont
explicitement non vérifiées. Une déclaration distante nécessaire à la CLI
produit une erreur de lecture. L’API permet des lecteurs explicites adaptés.
Les chemins `file:` servent à inspecter les fichiers avant publication ; ils ne
constituent pas une promesse de prise en charge `file:` par les acteurs navigateur.

| Code de sortie | Sens |
|---|---|
| 0 | Rapport accepté selon le mode |
| 1 | Rapport refusé : erreur établie, ou incomplétude en strict |
| 2 | Appel invalide |
| 3 | Erreur interne, notamment validateur injecté défectueux |

## API asynchrone

```js
import {verifyProject, formatVerificationReport} from 'alloframe/verification';
import {readFile} from 'node:fs/promises';

const report = await verifyProject({
  source: new URL('./alloframe.manifest.json', import.meta.url).href,
  readSource: url => readFile(new URL(url), 'utf8'),
  compositions: ['main'],
  mode: 'normal',
});
console.log(formatVerificationReport(report, 'text'));
```

`verifyProject(options)` retourne une promesse de rapport profondément gelé.
Les erreurs de configuration rejettent avec `TypeError`. Les déclarations
invalides et sources inaccessibles sont des diagnostics du rapport. Une exception
d’un contrat injecté reste une erreur interne, pas une faute imputée au document.

| Option | Valeur / contrat |
|---|---|
| `source` | URL absolue, obligatoire |
| `readSource(url)` | Lecteur obligatoire ; JSON texte ou objet JSON, synchrone ou asynchrone |
| `kind` | Mêmes catégories que la CLI ; `project` par défaut |
| `context` | URL absolue du manifeste de contexte ; interdit avec `kind: 'project'` |
| `compositions` | Tableau non vide de noms ; toutes si absent |
| `mode` | `normal` ou `strict` |
| `frameworkVersion` | Version stricte facultative ; nécessaire si une contrainte la demande |
| `checkResource(url, {origins})` | Retour `{status: 'available'\|'unavailable'\|'not_checked', reason?}` ; absence = non effectué |
| `resourcePolicy(url, {origins, required})` | Retour `required` ou `optional` ; peut renforcer, jamais supprimer une obligation native |
| `validators` | Validateurs statiques par identité canonique, sinon type |
| `contracts` | Contrats de rôles par `instance_id`, format décrit dans [composition.md](composition.md) |
| `reactions` | Réactions explicites, format décrit dans [composition.md](composition.md) |

Les lecteurs/contrats sont du code de confiance fourni par l’appelant. Jamais
importés depuis les déclarations. Les mêmes `contracts` et `reactions` s’appliquent
à chaque composition sélectionnée ; séparer les appels s’ils diffèrent.
Chaque appel possède un contexte neuf. Les lectures sont mutualisées par URL
au sein de cet appel ; les registres des compositions restent indépendants.

## Contrats statiques complémentaires

Un validateur reçoit `{definition, loaded}` (définitions gelées) et retourne :

```js
{
  status: 'passed', // failed, not_performed ou not_applicable
  diagnostics: [], // diagnostics communs, facultatifs
  reason: 'Explication facultative',
  capabilities: {commands: ['start'], events: ['ended']} // facultatif
}
```

Le validateur doit réellement examiner le payload de son contrat avant de
retourner `passed`. Une simple présence de type ne constitue pas une preuve.
Les capacités ne sont retenues qu’après réussite sans erreur. Le vérificateur
contrôle alors les exigences de rôles et les événements/commandes des réactions.
Les valeurs invalides du protocole des validateurs sont des erreurs internes.
Les validateurs ne doivent ni exécuter le métier ni modifier les entrées.

Les contrats natifs audio/vidéo/image/document contrôlent configurations, usages,
références de ressources et protocoles pertinents. Le moteur timeacte/lineacte
réutilise les modèles immuables de sources pour les scènes/actes et les règles de
bornes : pas de théâtre, cadre, acteur ni renderer créé. Une scène générique qui
n’est pas employée par cet acteur conserve son obligation de contrat métier.
Les bornes d’un acteur timeacte doivent être explicites pour une inspection
complète de sa définition ; les configurations d’usage sont aussi contrôlées.

Une ressource employée par un acteur natif est nécessaire : une absence établie
est une erreur. Une ressource déclarée sans obligation connue est facultative
par défaut ; une indisponibilité produit un avertissement et un contrôle non
effectué. `resourcePolicy` permet d’exprimer une obligation externe. Une ressource
non vérifiée rend le rapport incomplet quelle que soit son obligation.

## Règles et traçabilité

- Normalisation, champs inconnus, défauts, catégories et versions : normalisation déclarative.
- Identités, références exactes, collisions, dépendances transitives, cycles,
  contraintes cumulées, causes directes d’échec : même chargeur que le chargement.
- Assemblage, identifiants d’instances, bindings, cycles, cibles et contrats de
  rôles : `inspectComposition`, partagé avec le runtime de composition, sans fabrique appelée.
- Configurations/capacités natives : règles et constantes des acteurs.
- Ressources et synthèse : inspection statique de la disponibilité déclarée.

Les `rule` comme `2010-2030.load`, `2060.assembly`, `2050.actor-config` et
`2070.resource-access` sont des identifiants stables de règles de contrôle. Les diagnostics du chargeur gardent leur code `E_*`, gravité,
impact, source, chemin et chaînes causales. Les contrôles empêchés contiennent les
identifiants de leurs causes. Une résolution bloquée ne fabrique pas une liste
de références absentes à partir de définitions indisponibles.

## Rapport version 1.0.0

Les mêmes données alimentent le texte et le JSON, sans horodatage variable.
Ordre : sélections demandées/déclarées, découverte documentaire, contrôles locaux.
Pas de dépendance à l’ordre de fin des lectures. Les diagnostics sont conservés
par composition affectée : une source partagée peut donc être signalée plusieurs
fois dans le rapport, tout en n’étant lue qu’une fois.

| Champ | Contenu |
|---|---|
| `report_version` | `1.0.0` |
| `scope` | Source, catégorie, contexte, sélection demandée (`null` = toutes), frontière et exclusions |
| `mode` | `normal` / `strict` |
| `conformity` | `conformant`, `nonconformant`, `undetermined` |
| `complete` | Aucun contrôle applicable non effectué |
| `accepted` | Aucune erreur/échec et, en strict, complétude |
| `counts` | Erreurs, avertissements, informations et les quatre états de contrôle |
| `checks[]` | `id`, `family`, `rule`, `status`, `context`, `reason`, `causes`, IDs `diagnostics` |
| `diagnostics[]` | Diagnostic commun + `id`, `check`, `rule` |

| État du contrôle | Sens |
|---|---|
| `passed` | Contrôlé et conforme dans la portée indiquée |
| `failed` | Violation établie |
| `not_performed` | Applicable mais empêché ou contrat indisponible |
| `not_applicable` | Hors périmètre ou sans objet |

Une erreur ou un contrôle échoué donne `nonconformant`, même si d’autres
contrôles restent empêchés. Sans erreur mais avec incomplétude : `undetermined`.
`conformant` exige réussite sans incomplétude dans le périmètre déclaré.
Un avertissement seul ne bloque aucun mode. `E_UNKNOWN_FIELD` reste un avertissement.
Strict ne change ni les règles, ni le périmètre, ni la gravité : il refuse
uniquement l’incomplétude en plus des erreurs déjà refusées en normal.

## Limites et tests

Aucune instance d’usage, activation, commande, lecture multimédia, interprétation
HTML, exécution de scénario ou écriture dans les fichiers analysés. Rendu réel,
codecs et comportement du navigateur restent dans les essais d’exécution séparés.
OpenLayers n’est pas requis. Aucun résultat ne certifie une conformité globale 1.0.0.

```sh
npm run test:verification
npm test
npm run check
npm run test:browser
```

Les tests couvrent déclarations conformes et non conformes, champs inconnus,
identités, cycles, versions, contrôles empêchés, rapports, codes de sortie,
immutabilité, ressources et les deux modes timeacte.
