# T24-A — Prompt IA local + référentiel administrable ScreenCode/FeatureCode > Statut : PRÉPROD LOCAL / recette manuelle. Aucun Git, aucune Production. ## 1. Générer le prompt IA (Partie A) ### Principe Le centre Diagnostics génère un **prompt d'analyse local** depuis un diagnostic/erreur. **Aucun appel IA externe** (OpenAI, ChatGPT ou autre) : le système se contente de : ``` diagnostic → construire un texte local → afficher le prompt → permettre « Copier » ``` Le prompt n'est **jamais enregistré en PostgreSQL** (génération à la demande uniquement, V1). ### Boutons - **Détail diagnostic** (`/Diagnostics/{id}`) : bouton « Générer le prompt IA » à proximité du contexte technique. - **Détail erreur** (`/Erreurs/{id}`) : bouton « Générer le prompt IA » (depuis l'occurrence la plus récente du groupe). Un clic déclenche la génération **côté serveur** (handler Razor Pages `OnGetPromptAsync`), puis affiche le prompt dans une modale dédiée avec un bouton **« Copier le prompt »** (réutilise `OmikaCopy()`, aucune nouvelle librairie JS). ### Service partagé La construction du prompt est centralisée dans `Omika.Diagnostics.Core` : `DiagnosticPromptBuilder.Build(DiagnosticEventRecord, IReadOnlyList?)`. Le chargement des événements corrélés est partagé par `DiagnosticsDetailModel.GetCorrelatedEventsAsync(...)` (utilisé par le détail diagnostic ET le détail erreur). Aucune logique dupliquée. ### Informations incluses (si disponibles) - **CONTEXTE** : ClientCode, Environment, ServerInstance, Source, Component, Platform, OperatingSystem, OperatingSystemVersion, Manufacturer, Model, AppVersion, AppBuild, ScreenCode, FeatureCode. - **ERREUR** : EventCode, Level, Priority, ErrorCode, Timestamp, DurationMs. - **MESSAGE** : Message (tronqué à 2000 caractères). - **EXCEPTION** : ExceptionType, StackTrace (tronquée à 4000 caractères). - **HTTP / MÉTADONNÉES** : uniquement les clés whitelistées (`method`, `statusCode`, `routeTemplate`, `retryCount`, …) et valeurs simples non interdites. - **CORRÉLATION** : TraceId, OperationId, SessionId. - **IDENTITÉ TECHNIQUE AUTORISÉE** : LicenseNumber (numéro fonctionnel), DeviceKey et ActorKey **tronqués** (pseudonymes HMAC-SHA256, jamais réversibles). - **ÉVÉNEMENTS CORRÉLÉS** (si TraceId/OperationId) : chronologie compacte, **bornée à 25 événements**, sans stack trace (timestamp, level, eventCode, component, message court, screen/feature). ### Informations exclues (jamais) password, password_hash, ApiKey, api_key_hash, Bearer token, SigningKey, HmacKey, ConnectionString, DeviceId brut, UserId brut, CollaborateurId brut, ClientId brut, email, téléphone, IMEI, serial, MAC, secret de licence. La politique **réutilise** les filtres existants : `DiagnosticForbiddenData` (jetons interdits) et `DiagnosticMetadataPolicy` (whitelist des clés). Aucune seconde logique de filtrage. Défense en profondeur : chaque valeur relue est re-vérifiée avant inclusion. ### Format Le prompt commence par : > « Analyse cette erreur Omika et aide-moi à déterminer sa cause probable. » puis demande explicitement : cause probable, niveau de confiance, fichier/méthode à vérifier en priorité, éléments de preuve, hypothèses alternatives, correctif recommandé, tests de confirmation, dire si l'erreur semble volontaire/de test, distinguer faits confirmés et hypothèses. ### Exemple /dev/throw L'événement de recette `API_HTTP_ERROR` / `InvalidOperationException` / `/dev/throw` / `TELEMETRY_TEST_ERROR` / `Development` produit un prompt contenant naturellement ces données — **aucune règle codée en dur** « /dev/throw ». ## 2. Référentiel administrable (Partie B) ### Règle absolue `diagnostic_event` **reste la vérité** sur ce qui a réellement été observé. Le référentiel (`diagnostics_reference`) est un **enrichissement** (libellé / description / ordre / état) et ne détermine **jamais** quels événements sont acceptés. Un code observé non référencé reste visible dans les filtres. ### Table `diagnostics_reference` (migration 011) `id`, `reference_type` (`SCREEN_CODE` / `FEATURE_CODE`), `code` (normalisé TRIM+UPPER), `label`, `description`, `enabled`, `sort_order`, `created_at_utc`, `updated_at_utc`. - Unicité : `(reference_type, UPPER(code))` — index unique. - **Code immuable** après création. Pour corriger un code : créer une nouvelle entrée + archiver l'ancienne. - **Archivage = `enabled=false`**, jamais de DELETE physique (V1). ### Ownership / GRANT (011) - Propriétaire : `omika_diagnostics_owner`. - `omika_diagnostics_web` : `SELECT`, `INSERT`, `UPDATE (label, description, enabled, sort_order, updated_at_utc)` + `USAGE` séquence. **Aucun DELETE.** - `omika_diagnostics_api` et `omika_diagnostics_worker` : **aucun droit** (testé négativement). ### Initialisation (idempotente) Les **29 ScreenCode** et **3 FeatureCode** du catalogue applicatif sont seedés par la migration avec leurs libellés (`ON CONFLICT DO NOTHING`). Un libellé modifié par un Admin n'est **jamais écrasé** au redémarrage. ### Pages - `/Referentiel` : consultation (Support + Admin) — sections Codes écran / Codes fonctionnalité alimentées par le référentiel DB (libellé + description + état), repli catalogue statique si DB indisponible. - `/Referentiel/Admin` : **Admin uniquement** — liste (Type, Code, Libellé, Description, État, Dernière modification, Actions), création, modification (libellé/description/état/tri), archivage/réactivation, et section **« Codes observés non référencés »** avec **ajout rapide**. ### Procédure : ajout d'un nouveau code 1. Un événement arrive avec un `screen_code`/`feature_code` inconnu (ex. `FACTURE_DETAIL`). 2. Le code **apparaît automatiquement** dans les filtres Diagnostics (alimentés par `diagnostic_event`), affiché `FACTURE_DETAIL (non référencé)`. 3. Dans `/Referentiel/Admin` → « Codes observés non référencés » → « Ajouter » (type + code préremplis) → Admin renseigne le libellé/la description. 4. Le filtre affiche alors `Détail de facture (FACTURE_DETAIL)` — **sans modifier les données historiques**. La recherche SQL utilise toujours le **code**, jamais le libellé. ### Dropdowns / filtrage Les listes déroulantes continuent d'être alimentées par les codes **réellement observés** (jamais `SELECT` sur `diagnostics_reference` uniquement). Si une référence existe : `Libellé (CODE)` ; sinon : `CODE (non référencé)`. La valeur du filtre reste toujours le CODE. ## 3. Corrections UX (Partie C) - Filtre « Acteur » → **« Acteur pseudonymisé »** + aide : « Identifiant pseudonymisé permettant de retrouver les événements d'un même utilisateur. » - Page/menu « Versions » → **« Versions Omika »**. - « Version la plus représentée » → **« Version Omika la plus observée »** + note : « Les valeurs correspondent aux événements observés, pas au nombre d'installations. » ## 4. Sécurité - Prompt généré : 0 fuite de données interdites (testé — `DiagnosticPromptBuilderTests`). - HTML : le prompt est affiché via `textContent` (aucune injection HTML). - Aucun enregistrement du prompt (ni PostgreSQL, ni log). - Migration 011 : aucune colonne secret, aucun mot de passe. ## 5. Tests - `Omika.Diagnostics.Tests` : 574/574 (baseline 536 + 38 tests T24-A). - `Omika.Tests` : 3366/3370 — 4 échecs environnementaux/préexistants (construction de vues Avalonia ×2, course temporelle ShellViewModel, accès HFSQL), **aucune régression** liée à T24-A (T24-A est isolé dans le sous-système Diagnostics, non référencé par Omika.Tests). ## 6. Migration 011 `infra/postgresql/011_diagnostics_reference.sql` — ordre final : `001 → … → 010 → 011`. Idempotente, non destructive (aucun DROP/DELETE), aucun mot de passe.