Spaces:
Sleeping
Sleeping
| # core/validation_queue.py | |
| """ | |
| Validation Queue — Gestion des propositions en attente de validation humaine. | |
| Permet de soumettre, approuver, rejeter ou modifier des propositions avant intégration. | |
| """ | |
| import json | |
| import time | |
| import sqlite3 | |
| import uuid | |
| from typing import Dict, List, Optional | |
| from dataclasses import dataclass, asdict | |
| class Proposal: | |
| """Une proposition en attente de validation.""" | |
| id: str | |
| type: str # "fable_optimization", "hermes_refactor", "code_deploy" | |
| description: str | |
| code: str | |
| score: float | |
| status: str # "pending", "approved", "rejected", "modified" | |
| created_at: float | |
| approved_at: Optional[float] = None | |
| comment: Optional[str] = None | |
| def to_dict(self) -> Dict: | |
| return asdict(self) | |
| def from_dict(cls, data: Dict) -> "Proposal": | |
| return cls(**data) | |
| class ValidationQueue: | |
| """ | |
| File d'attente des propositions à valider humainement. | |
| Persistance SQLite pour survivre aux redémarrages. | |
| """ | |
| def __init__(self, db_path: str = "/data/validation.db"): | |
| self.db_path = db_path | |
| self.conn = sqlite3.connect(db_path, check_same_thread=False) | |
| self._init_db() | |
| def _init_db(self): | |
| self.conn.execute(""" | |
| CREATE TABLE IF NOT EXISTS proposals ( | |
| id TEXT PRIMARY KEY, | |
| type TEXT, | |
| description TEXT, | |
| code TEXT, | |
| score REAL, | |
| status TEXT, | |
| created_at REAL, | |
| approved_at REAL, | |
| comment TEXT | |
| ) | |
| """) | |
| self.conn.commit() | |
| def add_proposal(self, proposal: Proposal) -> str: | |
| """Ajoute une proposition en attente.""" | |
| self.conn.execute(""" | |
| INSERT INTO proposals (id, type, description, code, score, status, created_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?) | |
| """, ( | |
| proposal.id, | |
| proposal.type, | |
| proposal.description, | |
| proposal.code, | |
| proposal.score, | |
| "pending", | |
| proposal.created_at | |
| )) | |
| self.conn.commit() | |
| return proposal.id | |
| def get_pending(self) -> List[Proposal]: | |
| """Récupère toutes les propositions en attente.""" | |
| rows = self.conn.execute(""" | |
| SELECT id, type, description, code, score, status, created_at, approved_at, comment | |
| FROM proposals WHERE status = 'pending' | |
| """).fetchall() | |
| return [ | |
| Proposal( | |
| id=r[0], type=r[1], description=r[2], code=r[3], | |
| score=r[4], status=r[5], created_at=r[6], | |
| approved_at=r[7], comment=r[8] | |
| ) | |
| for r in rows | |
| ] | |
| def get_proposal(self, proposal_id: str) -> Optional[Proposal]: | |
| row = self.conn.execute( | |
| "SELECT * FROM proposals WHERE id = ?", (proposal_id,) | |
| ).fetchone() | |
| if not row: | |
| return None | |
| return Proposal( | |
| id=row[0], type=row[1], description=row[2], code=row[3], | |
| score=row[4], status=row[5], created_at=row[6], | |
| approved_at=row[7], comment=row[8] | |
| ) | |
| def approve(self, proposal_id: str, comment: str = ""): | |
| self.conn.execute(""" | |
| UPDATE proposals | |
| SET status = 'approved', approved_at = ?, comment = ? | |
| WHERE id = ? | |
| """, (time.time(), comment, proposal_id)) | |
| self.conn.commit() | |
| def reject(self, proposal_id: str, comment: str = ""): | |
| self.conn.execute(""" | |
| UPDATE proposals | |
| SET status = 'rejected', approved_at = ?, comment = ? | |
| WHERE id = ? | |
| """, (time.time(), comment, proposal_id)) | |
| self.conn.commit() | |
| def modify(self, proposal_id: str, new_code: str, comment: str = ""): | |
| self.conn.execute(""" | |
| UPDATE proposals | |
| SET code = ?, status = 'modified', approved_at = ?, comment = ? | |
| WHERE id = ? | |
| """, (new_code, time.time(), comment, proposal_id)) | |
| self.conn.commit() | |
| def delete_old(self, older_than_days: int = 30): | |
| """Supprime les propositions terminées de plus de N jours.""" | |
| cutoff = time.time() - older_than_days * 86400 | |
| self.conn.execute(""" | |
| DELETE FROM proposals | |
| WHERE status IN ('approved', 'rejected') AND approved_at < ? | |
| """, (cutoff,)) | |
| self.conn.commit() |