Set-OPS-Public/docs/audit/schema-plan.json
Daniel Allaire 0eaceb1048 schema du plan : la forme des registres devient derivee, et gardee
Etape 2 du chantier « l UI reflete fidelement la structure ». Le GUI porte
CHAMPS_ECRITS_PAR_GUI, une liste tenue A LA MAIN de ce qu il sait ecrire, que
P19 confronte au reel. C est une copie — gardee, donc honnete, mais une copie :
quelqu un doit penser a l allonger.

`make schema` produit docs/audit/schema-plan.json : six registres, 42 champs,
leurs types, leurs enumerations et ce qui est requis.

CE QUE LE SCHEMA EST, ET CE QU IL N EST PAS

  schema       -> la FORME      -> generera les champs du formulaire
  validateurs  -> la COHERENCE  -> refusent une saisie incoherente

Un JSON Schema ne sait pas dire qu un `consommateur` designe une application
inexistante, ni qu une integration universelle recopiee au plan est un defaut.
Vouloir l y mettre creerait la seconde source de verite que tout ce depot
refuse. Les valider_* restent l autorite.

LES ENUMERATIONS SONT IMPORTEES, JAMAIS RECOPIEES

ETATS_SERVEUR, PORTEES_BD et AUTORITES_DNS viennent des constantes que les
validateurs appliquent. Une enumeration recopiee diverge — c est la lecon des
neuf resolutions d instance que P41 garde depuis.

CE QUE L ETAPE 1 AVAIT TROUVE, ET QUE P61 A CONFIRME

Le recensement montrait `categorie` et `service` presents dans TOUS les plans et
absents de CHAMPS_ECRITS_PAR_GUI, dont la ligne `nomenclature` est vide : le GUI
ne sait pas les editer, l operateur doit ouvrir le YAML. P61 a refuse le premier
schema pour cette raison exacte. Les trois tables imbriquees de la nomenclature
sont donc DECRITES et non resumees en « object ».

31 champs observes dans l instance courante, 42 decrits par le schema. La
difference n est pas du bavardage : observer une instance n est pas un schema.
`noeud`, `stockage` et `coeurs` sont legitimes et simplement inutilises ici — un
schema derive de l observation les INTERDIRAIT.

P61, EPROUVEE DANS LES DEUX SENS

  fichier genere perime                -> REFUSE
  champ du plan absent du schema       -> REFUSE
  champ decrit mais inutilise au plan  -> COMPTE, pas refuse

Le troisieme point est delibere : refuser obligerait a retirer du schema un
champ valide des que plus personne ne s en sert. Meme mesure que les lacunes
nommees de P29.

UN DEFAUT DE MON INSTRUMENT, PAYE EN ROUTE

P61 comparait des noms a plat quand couverture_gui aplatit les tables
imbriquees : elle criait sur un schema correct. L instrument mesurait autre
chose que la cible. On aplatit desormais des deux cotes.

make prouver : CONFORME, 60 OK, 0 echec, 1 saute.

Prochaine etape : generer les formulaires depuis ce schema, et retirer
CHAMPS_ECRITS_PAR_GUI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-08 15:19:20 -04:00

350 lines
10 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "GENERE par scripts/schema_plan.py (make schema). Ne pas editer a la main. Decrit la FORME des registres ; la COHERENCE reste aux validateurs de inventory_rules.py.",
"registres": {
"applications": {
"entite": {
"additionalProperties": false,
"properties": {
"expose": {
"description": "FQDN publies par l'edge. Derivent le vhost, les SAN et le plancher /etc/hosts.",
"items": {
"type": "string"
},
"title": "Exposition publique",
"type": "array"
},
"groupe": {
"description": "La capacite appliquee. Doit avoir un playbook homonyme.",
"title": "Groupe (role)",
"type": "string",
"x-source-valeurs": "groupes_operationnels"
},
"hote": {
"description": "Une VM declaree au plan. Un hote inconnu est un « hote fantome » (P06).",
"title": "Hote",
"type": "string",
"x-source-valeurs": "serveurs"
},
"liens": {
"description": "Roles acceptes par le role porteur (meta/liens.yml).",
"items": {
"type": "object"
},
"title": "Liens (bindings)",
"type": "array"
},
"port": {
"title": "Port",
"type": "integer"
},
"requiert": {
"description": "Dependance applicative. Indicative : l'ordre de deploiement vient des couches.",
"items": {
"type": "string"
},
"title": "Requiert",
"type": "array"
},
"websocket": {
"description": "L'edge doit relayer la mise a niveau de connexion.",
"title": "WebSocket",
"type": "boolean"
}
},
"required": [
"groupe",
"hote"
],
"type": "object"
},
"title": "Applications",
"x-fichier": "plan/applications.yml",
"x-racine": "applications"
},
"bases_donnees": {
"entite": {
"additionalProperties": false,
"properties": {
"base": {
"title": "Base",
"type": "string"
},
"consommateur": {
"title": "Consommateur",
"type": "string"
},
"portee": {
"description": "Comment le consommateur est designe : par application, par groupe ou par hote.",
"enum": [
"application",
"groupe",
"hote"
],
"title": "Portee",
"type": "string"
},
"proprietaire": {
"title": "Proprietaire",
"type": "string"
},
"secret": {
"description": "NOM d'une variable Vault, jamais une valeur. Le secret ne quitte pas le role.",
"title": "Secret (voute)",
"type": "string"
},
"serveur": {
"title": "Serveur de BD",
"type": "string",
"x-source-valeurs": "serveurs_bd"
},
"usage": {
"title": "Usage",
"type": "string"
}
},
"required": [
"base",
"consommateur",
"proprietaire",
"secret",
"serveur"
],
"type": "object"
},
"title": "Bases de donnees",
"x-fichier": "plan/bases-donnees.yml",
"x-racine": "bases_donnees"
},
"domaines_publics": {
"entite": {
"additionalProperties": false,
"properties": {
"autorite": {
"enum": [
"auto-heberge",
"delegue",
"primaire-cache"
],
"title": "Autorite DNS",
"type": "string"
},
"dnssec": {
"title": "DNSSEC",
"type": "boolean"
},
"edge": {
"title": "Edge",
"type": "string",
"x-source-valeurs": "serveurs"
},
"mail": {
"description": "La zone porte des enregistrements de messagerie.",
"title": "Courriel",
"type": "boolean"
},
"secondaires": {
"items": {
"type": "string"
},
"title": "Secondaires",
"type": "array"
}
},
"type": "object"
},
"title": "Domaines publics",
"x-fichier": "plan/domaines.yml",
"x-racine": "domaines_publics"
},
"nomenclature": {
"entite": {
"additionalProperties": false,
"properties": {
"categories": {
"additionalProperties": {
"additionalProperties": false,
"properties": {
"libelle": {
"description": "Nom lisible de la zone (Frontiere, Identite...).",
"title": "Libelle",
"type": "string"
}
},
"required": [
"libelle"
],
"type": "object"
},
"description": "Une zone de securite par cle. Le numero derive le 3e octet et le VLAN.",
"title": "Categories (zones)",
"type": "object"
},
"cidr_hote": {
"title": "CIDR d'hote",
"type": "integer"
},
"fonctions": {
"additionalProperties": {
"additionalProperties": false,
"properties": {
"categorie": {
"description": "La zone. Fixe le 3e octet (15 + categorie) et le VLAN.",
"title": "Categorie",
"type": "integer"
},
"service": {
"description": "Fixe le bloc d'adresses de l'hote dans la zone.",
"title": "Service",
"type": "integer"
}
},
"required": [
"categorie",
"service"
],
"type": "object"
},
"description": "categorie + service par fonction. VMID et IP en derivent.",
"title": "Fonctions",
"type": "object"
},
"index": {
"description": "LE seul champ d'adressage. Tout en derive ; P20 refuse d'en stocker un autre.",
"maximum": 255,
"minimum": 0,
"title": "Index (seed)",
"type": "integer"
},
"reservations": {
"additionalProperties": {
"additionalProperties": false,
"properties": {
"passerelle": {
"description": "Dernier octet de la passerelle. P23 refuse un SVI qui s'en ecarte.",
"title": "Passerelle",
"type": "integer"
},
"reserve_max": {
"title": "Reserve (max)",
"type": "integer"
},
"reserve_min": {
"title": "Reserve (min)",
"type": "integer"
}
},
"type": "object"
},
"description": "Adresses soustraites a la derivation dans chaque zone.",
"title": "Reservations",
"type": "object"
}
},
"required": [
"index"
],
"type": "object"
},
"title": "Nomenclature",
"x-fichier": "plan/nomenclature.yml",
"x-racine": null
},
"serveurs": {
"entite": {
"additionalProperties": false,
"properties": {
"coeurs": {
"description": "Vide = derive des empreintes des roles.",
"title": "Coeurs",
"type": "integer"
},
"disque": {
"description": "Ex. `32G`. Vide = derive des empreintes des roles.",
"title": "Disque",
"type": "string"
},
"etat": {
"description": "`planifie` = decrit mais pas deploye ; `actif` = joignable par Ansible.",
"enum": [
"actif",
"planifie"
],
"title": "Etat",
"type": "string"
},
"fonction": {
"description": "Determine VMID, IP, VLAN et passerelle. Doit exister dans la nomenclature.",
"title": "Fonction",
"type": "string",
"x-source-valeurs": "nomenclature.fonctions"
},
"integrations": {
"description": "Seulement les facultatives. Les universelles viennent du role et sont refusees ici.",
"items": {
"type": "string"
},
"title": "Integrations facultatives",
"type": "array"
},
"memoire": {
"description": "Vide = derive des empreintes des roles.",
"title": "Memoire (Mo)",
"type": "integer"
},
"noeud": {
"description": "Surcharge le defaut de `make config`.",
"title": "Noeud Proxmox",
"type": "string"
},
"stockage": {
"description": "Surcharge le defaut.",
"title": "Stockage",
"type": "string"
}
},
"required": [
"fonction"
],
"type": "object"
},
"title": "Serveurs (VM)",
"x-fichier": "plan/serveurs.yml",
"x-racine": "serveurs"
},
"serveurs_bd": {
"entite": {
"additionalProperties": false,
"properties": {
"groupe": {
"title": "Groupe",
"type": "string",
"x-source-valeurs": "groupes_operationnels"
},
"hote": {
"title": "Hote",
"type": "string",
"x-source-valeurs": "serveurs"
},
"port": {
"title": "Port",
"type": "integer"
},
"type": {
"title": "Moteur",
"type": "string"
}
},
"required": [
"hote",
"type"
],
"type": "object"
},
"title": "Serveurs de bases de donnees",
"x-fichier": "plan/bases-donnees.yml",
"x-racine": "serveurs_bd"
}
},
"title": "Registres du plan Set-OPS"
}