144 lines
7.8 KiB
Markdown
144 lines
7.8 KiB
Markdown
# 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.
|