# Fondations communes

Implémentation JavaScript en modules ES, sans DOM, acteur, réseau, registre global ni chargement.
Entrée dédiée : `alloframe/common` (`src/common/index.js`). Réexports également à la racine.
Les fonctions et méthodes sont en camelCase dans toute l’API publique.

## Résultats

Les opérations de validation, normalisation, construction et résolution retournent :

- succès : `{ ok: true, value, diagnostics: [] }`, avec avertissements éventuels ;
- échec : `{ ok: false, diagnostics: [...] }`, sans propriété `value`.

Un diagnostic contenu dans `value` peut avoir une sévérité `error` alors que sa construction
réussit : `ok` décrit l'opération, pas la sévérité de la donnée construite.
Aucune propriété concurrente `status` ou `error` n'est ajoutée.
Les opérations de lecture du collecteur renvoient directement une liste, une Map ou un nombre.

Les entrées déclaratives sont des objets simples (prototype Object ou null), tableaux et
valeurs primitives. Les résultats copient les objets/tableaux récursivement et préservent
les champs inconnus. Les objets de classe, Date, Map et autres objets non déclaratifs ne
font pas partie de cette API ; leur copie lève TypeError. L'API ne remplace pas un parseur JSON.
Les accesseurs et proxies ne constituent pas des déclarations supportées.

## Identités et références

| Fonction | Valeur en cas de succès |
|---|---|
| `validateNamespace(value)` | Chaîne inchangée |
| `validateLocalId(value)` | Chaîne inchangée |
| `buildIdentity(namespace, id)` | `namespace:id` |
| `parseIdentity(value)` | `{ namespace, id }` |
| `resolveReference(reference, declaringNamespace)` | Identité qualifiée |
| `checkIdentityUniqueness(identities)` | Copie de la liste validée |

Namespace : segments non vides `[a-z0-9_]+`, séparés par un point.
Identifiant local : `[a-z0-9_]+`. Identité : exactement un deux-points.
Pas de trim, passage en minuscules, suppression d'accent ou autre correction.
Une référence locale exige le namespace du document déclarant. Une référence qualifiée
porte son propre namespace. La résolution ne vérifie pas l'existence dans un registre.

Le contrôle d'unicité porte sur l'ensemble de la liste fournie, sans exception par fichier
ou catégorie. Chaque doublon après la première occurrence produit `E_IDENTITY_COLLISION`,
avec l'identité, l'index courant et `first_index` dans `scope`.
Le registre/chargeur doit transmettre toutes les déclarations du périmètre concerné ;
ce module n'ajoute pas d'état global ni de registre persistant.

## Défauts et champs inconnus

| Fonction | Comportement |
|---|---|
| `applyDefaults(value, defaults)` | Ajoute les propriétés propres absentes au niveau courant |
| `checkUnknownFields(value, knownFields, scope = {})` | Conserve et copie tous les champs ; un avertissement par champ inconnu |

Seule l'absence de propriété propre déclenche un défaut. `undefined`, `null`, chaîne vide,
`false`, `0`, tableau vide et objet vide sont présents. Un champ invalide n'est jamais
remplacé silencieusement. Il n'y a pas de fusion récursive implicite : le schéma appelant
applique ses défauts à chaque niveau concerné. Les valeurs par défaut sont elles aussi copiées.
`E_UNKNOWN_FIELD` utilise `warning` et `none`.

## Ressources

| Fonction | Valeur en cas de succès |
|---|---|
| `validateResource(resource)` | Copie de la ressource valide |
| `buildResourceIdentity(resource, namespace)` | Identité qualifiée de la ressource |
| `resolveResourceUrl(resource, sourceUrl)` | URL absolue, ou `undefined` si `url` est absent |

Champs obligatoires : `id` (identifiant local), `role` (chaîne non vide).
Champs facultatifs : `type`, `url` ; s'ils sont présents, ils doivent être des chaînes non
vides. Aucun rôle ou type métier n'est imposé par le socle. Aucun champ facultatif fictif
n'est créé. Les champs supplémentaires sont conservés et avertis.
Le namespace est fourni par le contexte déclarant ; ni le rôle ni l'URL n'entrent dans l'identité.
L'unicité d'une ressource s'évalue par son identité qualifiée, au même titre que les autres
identités du namespace, en transmettant ces identités au contrôle commun.

La validation structurelle accepte une URL relative sans chercher à la résoudre.
La résolution utilise la classe URL standard : une URL relative requiert l'URL absolue du
document d'origine, jamais l'URL implicite de la page courante. Aucun téléchargement,
contrôle d'existence ou filtrage de protocole n'est effectué. La décision d'utiliser une
URL et les règles propres au consommateur appartiennent au consommateur de la ressource.
Une URL absente donne `{ ok: true, value: undefined, diagnostics: [] }` ; une URL présente
invalide donne un échec sans `value`.

## Diagnostics

`createDiagnostic(fields)` et `validateDiagnostic(value)` valident et copient les sept
champs obligatoires :

| Champ | Représentation acceptée |
|---|---|
| `code` | Chaîne `E_` suivie de lettres ASCII majuscules, chiffres ou `_` |
| `severity` | `info`, `warning`, `error` |
| `impact` | `none`, `degraded`, `blocked` |
| `phase` | Chaîne non vide |
| `message` | Chaîne non vide |
| `origin` | Chaîne non vide ou objet simple décrivant l'émetteur |
| `scope` | Chaîne non vide ou objet simple décrivant le périmètre affecté |

Les dimensions code, sévérité et impact restent indépendantes. Aucune table implicite ne
convertit un code en sévérité. Un diagnostic ne stoppe pas un traitement, ne journalise pas
sur la console, ne déclenche pas une récupération et ne crée pas un acte manqué.
Les champs supplémentaires sont conservés avec avertissement.

`DiagnosticCollector` :

- `add(diagnostic)` valide, copie et ajoute une occurrence ; échec sans ajout si invalide ;
- `list()` retourne une copie dans l'ordre d'ajout ;
- `group(field = 'code')` retourne une Map de listes copiées ; champs admis : `code`,
  `severity`, `impact`, `phase` ; champ de regroupement invalide : TypeError ;
- `size` donne le nombre d'occurrences ; `clear()` vide le collecteur.

Aucune déduplication implicite. Un avertissement de validation renvoyé par `add` reste
à la disposition de l'appelant ; il n'est pas ajouté automatiquement au collecteur.

## Codes fournis

Tous sont des exports nommés dont la valeur est leur nom : `E_INVALID_NAMESPACE`,
`E_INVALID_LOCAL_ID`, `E_INVALID_IDENTITY`, `E_INVALID_REFERENCE`, `E_IDENTITY_COLLISION`,
`E_INVALID_RESOURCE`, `E_INVALID_URL`, `E_INVALID_VALUE`, `E_UNKNOWN_FIELD`,
`E_INVALID_DIAGNOSTIC`.
Les erreurs produites par ces primitives utilisent `error` / `blocked`, phase `validation`,
origine `alloframe.common` ; l'avertissement de champ inconnu utilise `warning` / `none`.
Cela décrit l'opération locale, sans arrêt automatique de l'application.

## Vérification et portée

`npm run test:common` vérifie identités, références, défauts, ressources et diagnostics.
Le chargement est décrit dans [loading.md](loading.md), la validation des documents
 dans [declarations.md](declarations.md) et la vérification d’ensemble dans [verification.md](verification.md).
