Premiere commit - Omika

This commit is contained in:
2026-10-23 18:46:50 +02:00
commit 8ea76c1b24
2155 changed files with 984301 additions and 0 deletions
@@ -0,0 +1,143 @@
# 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<DiagnosticEventRecord>?)`.
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.