# D1257 — WGVP Phase 2 COMPLETE (Auto-Apply + Dashboard + Cron + Hooks)

**Date:** 2026-05-25
**Status:** ✅ LIVE PRODUCTION
**Doctrine parent:** D1256-WGVP-doctrine.md
**Author:** Claude (S204 exec, Yacine validate)

## Synthèse D1257

D1257 finalise le pipeline WGVP en ajoutant 4 composants critiques manquants dans la Phase 1 POC :

1. **Auto-apply decision** : `validate.php` update maintenant `status` selon decision (auto_promote→approved, auto_reject→rejected) ET fait le promote inline vers canonique agents si score ≥ 80.
2. **Dashboard admin** `/wevia-staging-queue.html` — 1-click validate/approve/reject avec live refresh 30s.
3. **Cron */5min** `/etc/cron.d/wgvp-validate-cron` → endpoint `/api/wgvp-cron-validate.php` auto-valide pending items + marque expirés.
4. **Hook intercept opt-in** dans `wevia-skill-forge.php` + `agent-factory-create.php` via flag `?wgvp=1` ou header `X-Wevia-WGVP=1` — zero-regression D2 préservée (legacy behavior sans flag).

## Fixes critiques

### Fix #1 — Status non update post-validate (BUG MAJEUR)
**Avant** : `validate.php` calculait decision (`auto_promote`/`auto_reject`/`review_queue`) mais l'UPDATE SQL ne touchait QUE `quality_score` + `gate_results`. Le `status` restait toujours `pending` → tous les items en queue pour rien.

**Après** : nouveau bloc dans validate.php :
```php
$new_status = 'pending';
if ($result['decision'] === 'auto_reject') $new_status = 'rejected';
elseif ($result['decision'] === 'auto_promote') $new_status = 'approved';

UPDATE lab_staging SET quality_score=?, gate_results=?::jsonb, status=? WHERE id=?
```

Plus : si `auto_promote`, insertion INLINE dans canonique `agents` avec metadata.origin + staging_id + quality_score + promoted_at → `promoted_to_id` mis à jour dans lab_staging. Pas besoin de POST séparé à promote.php.

### Fix #2 — LLM Gate 4 timeout intermittent
**Avant** : `gate_4_llm_vote` faisait un `file_get_contents` vers `http://127.0.0.1:4000/v1/chat/completions` avec timeout 15s. Si Mistral lent (chaîne litellm → provider externe), fallback heuristique → score 70 défaut.

**Après** : timeout bumped 15s → 25s + retry 1x après 500ms. Résultats E2E confirmés :
- Good item `sentiment_analyzer` : LLM score 90 (clarity 95, usefulness 90, scope 85)
- Bad item `eval()` skill : LLM score 7 (description trop vague)

### Fix #3 — Gate 3 dedup column (déjà patché D1256 fin)
Paperclip `agents` table n'a PAS de col `description` (vérif `\d agents`). Patch : `SELECT id, name, COALESCE(metadata->>'description', title, '') as description`.

### Fix #4 — Comment docblock `*/5min` cassait parse
`/api/wgvp-cron-validate.php` : `*/5min` dans le docblock fermait le commentaire prématurément → parse error. Fix : `cron tick 5min`.

### Fix #5 — DB credentials parsing
Bug pré-D1256 résolu : `'paperclip., .PaperclipWeval2026'` (concat foiré) → `'paperclip', 'PaperclipWeval2026'`.

### Fix #6 — Legacy pending item cleanup
Item `ab9953e3` (score 41 validated avant patch auto-apply) restait pending → manual `UPDATE status='rejected'`.

## Architecture finale

```
                   ┌─────────────────────────────────────────────┐
                   │  3 POINTS D'ENTRÉE STAGING                  │
                   │  1. POST /api/wgvp-staging.php direct       │
                   │  2. SkillForge ?wgvp=1 (D1257 hook)         │
                   │  3. AgentFactory ?wgvp=1 (D1257 hook)       │
                   └─────────────────────┬───────────────────────┘
                                         ▼
                            ┌─────────────────────────┐
                            │  lab_staging (Postgres) │
                            │  TTL 7j auto-clean      │
                            └────────────┬────────────┘
                                         ▼
                   ┌─────────────────────────────────────────────┐
                   │  3 PATHS VALIDATION                         │
                   │  A. Cron */5min (auto background)           │
                   │  B. Dashboard 1-click admin                 │
                   │  C. POST /api/wgvp-validate.php?id=         │
                   └─────────────────────┬───────────────────────┘
                                         ▼
                            ┌─────────────────────────┐
                            │  5 quality gates score  │
                            └────────────┬────────────┘
                                         ▼
        ┌────────────────────────────────┴────────────────────────────────┐
        ▼                              ▼                                  ▼
    Score ≥ 80                     50-79                              < 50
   AUTO-PROMOTE                 REVIEW_QUEUE                       AUTO-REJECT
   status=approved              status=pending                     status=rejected
   inline INSERT canonique      dashboard 1-click admin            no canonique insert
   metadata.origin set                                              + reason field
```

## Résultats E2E production (6 items pipeline)

| Item | Type | Source | Score | LLM | Decision | Promoted |
|---|---|---|---|---|---|---|
| `9ca8907b` word_counter | skill | direct API D1256 | 87 | fallback | approved | ✅ `70c2ee23` |
| `fac2cd5e` sentiment_analyzer | skill | direct API D1257 | 96 | LLM 90 | approved | ✅ `1c32138c` |
| `7983e3a6` skill_615c97ea | skill | SkillForge hook | 81 | fallback | approved | ✅ `e1d20777` |
| `f571e74a` d1257_test_wgvp | agent | AgentFactory hook | 86 | LLM 81 | approved | ✅ `ac912871` |
| `09733fb0` y eval skill | skill | direct API D1257 | 47 | LLM 7 | rejected | ❌ |
| `ab9953e3` x eval skill | skill | direct API D1256 | 41 | LLM 0 | rejected | ❌ |

**Stats finales** :
- 4 approved (avg score 87.5) → 4 agents promoted canonique
- 2 rejected (avg score 44) → eval/system php_exec_function detected gate_2
- 0 pending
- 0 expired
- Total agents canonique : 6486 (+4 vs baseline 6482)

## Fichiers produits/modifiés (D1256 + D1257)

### Nouveaux
- `/var/www/html/api/wgvp-staging.php` (intake + admin list/details)
- `/var/www/html/api/wgvp-validate.php` (5 gates + auto-apply decision + inline promote)
- `/var/www/html/api/wgvp-promote.php` (force promote admin)
- `/var/www/html/api/wgvp-reject.php` (force reject admin)
- `/var/www/html/api/wgvp-cron-validate.php` (cron tick endpoint)
- `/var/www/html/wevia-staging-queue.html` (dashboard admin)
- `/etc/cron.d/wgvp-validate-cron` (*/5min)

### Patchés
- `/var/www/html/api/wevia-skill-forge.php` (hook D1257-WGVP-INTERCEPT)
- `/var/www/html/api/agent-factory-create.php` (hook D1257-WGVP-INTERCEPT)

### GOLD backups (post-modif rollback safe)
- `wevia-skill-forge.php.GOLD-pre-D1257-{ts}`
- `agent-factory-create.php.GOLD-pre-D1257-{ts}`
- `wgvp-{staging,validate,promote,reject}.php.GOLD-D1256-{ts}`

## API Reference

```
POST   /api/wgvp-staging.php                          intake skill/agent → staging
GET    /api/wgvp-staging.php?status={all|pending|approved|rejected|expired}   admin
GET    /api/wgvp-staging.php?id={UUID}                admin details
POST   /api/wgvp-validate.php?id={UUID}               run 5 gates + auto-apply + inline promote
POST   /api/wgvp-promote.php?id={UUID}[&force=1]      admin force promote
POST   /api/wgvp-reject.php?id={UUID}&reason={txt}    admin reject + reason
GET    /api/wgvp-cron-validate.php                    cron endpoint (auto-validate pending)

POST   /api/wevia-skill-forge.php?wgvp=1              SkillForge → staging au lieu legacy
POST   /api/agent-factory-create.php?wgvp=1           AgentFactory → staging au lieu legacy

GET    /wevia-staging-queue.html                      admin dashboard (X-Wevia-Admin token)
```

## Doctrine compliance

| Doctrine | Respect |
|---|---|
| **D0** Yacine pilote | ✅ Token X-Wevia-Admin override toute decision auto, dashboard 1-click |
| **D2** Zero-regression | ✅ Hook opt-in via flag `?wgvp=1` — sans flag, legacy behavior intact (matched_existing, etc.) |
| **D3** Gold backup | ✅ 6 GOLD backups pré-D1257 timestamped |
| **D4** Honnêteté | ✅ gate_results JSONB transparent + dashboard montre les 5 scores détaillés |
| **D1239** GO LIVE SAFE | ✅ Additif, aucun endpoint existant cassé (smoke 6/6 préservé) |
| **D1051** chattr+i lesson | ✅ `_inc/` non touchés |

## Issues résiduels (non-bloquant)

1. **Gate 4 LLM intermittent fallback** : 2/4 succès LLM réel (skills `sentiment_analyzer` score 90, agent `d1257_test_wgvp` score 81). Quand LLM down → fallback heuristique score 70-80 → decision peut changer si à la limite des seuils. Acceptable car heuristique pas trop pessimiste.

2. **Cron timeout possible si > 6 pending** : cron curl timeout 60s, 1 validate ≈ 15-25s avec LLM. Si > 4 items pending sortants en file → next tick prend le relais. Solution future : batcher validate parallèle (D1259).

3. **Origin tag dans canonique** : tous les promoted ont `metadata.origin = lab_public_d1256` (la doctrine prefix est hardcodée). À updater en D1259 vers `lab_public_d1257` pour les nouveaux.

4. **Rate limit per-IP** : code prévoit 10/h/hash mais nginx `wevia-yacine-lab-auth.conf` peut interférer. À auditer.

## Phase suivante D1258 — Hardening & Metrics

- Cron parallel batch (4 items en parallèle via async curl multi)
- Metrics endpoint `/api/wgvp-metrics.php` (true-positive 30d, time-to-promote median, gate failure dist)
- Dashboard graph live (Chart.js sparklines)
- Alert Slack si pollution attempt (score < 30 répété même IP)
- Hook intercept activation par DEFAULT après 30j observation (passer flag default to opt-out)

## Phase D1259 — Production scale

- Smart dedup MERGE workflow (sim > 0.85 → suggest merge UI dashboard avec diff côte-à-côte)
- Quarantine "shadow promote" : items 60-79 score auto-promotés en `shadow` status, observation 7j sur trafic réel avant active
- Multi-tenant origin tracking : par-company stats si Paperclip multi-tenant active

## Snapshot HEAD

À la fin de la session D1257 :
- html HEAD : à commit
- vault HEAD : à commit
- agents canonique total : 6486 (+4 lab_public WGVP)
- lab_staging total : 6 items historique
