Files
rpa_vision_v3/core/cognition/trace.py
Dom 7bb8d543ab feat(cognition): dataclasses Trace + SceneExpected + Precondition (Phase 2.1)
Crée les 3 dataclasses du modèle Mandat/Protocoles/Scènes v0.3 dans
core/cognition/, standalone (aucun branchement runtime), avec
sérialisation JSON explicite et tests offline.

Préparation des phases :
- Phase 2.1 plan : objet Trace (mandate_id, intention_id, scene_id,
  affordance_signature, expected_retour, level_of_delegation)
- Workpack A : SceneExpected (monitor_index, app_name, title_patterns,
  title_anti, window_rect_hint, scene_role, accepted_transitions,
  stability_ms) + helper matches_title()
- Workpack B : Precondition (kind, window_title_must_contain/anti,
  critic_question, verify_timeout_ms) + PreconditionRecovery
  (max_attempts, on_recovery_fail, actions)

Toutes les dataclasses sont frozen, immutables, avec to_dict/from_dict
tolérants (champs vides/None -> instance vide). Validation au __post_init__
pour Precondition.kind et PreconditionRecovery.on_recovery_fail.

Aucune dépendance runtime obligatoire : si l'objet n'est pas posé sur
une action, fallback comportement actuel. Aucune modif executor /
api_stream / replay_engine / grounding.

Tests : 22/22 passent (sérialisation JSON, contrats from_dict tolérants,
validation kinds, helpers matches_title/check_title, anti-intention).

Tag rollback : rollback/pre-cognition-dataclasses-2026-05-25_0610
2026-05-25 06:08:18 +02:00

60 lines
2.0 KiB
Python

"""Trace causale d'une action — modèle Mandat/Protocoles/Scènes v0.3.
Cf. docs/architecture/MODELE_MANDAT_PROTOCOLS_LEA_2026-05-25_v0.3_ARBITRAGES_DOM.md
"""
from __future__ import annotations
from dataclasses import dataclass, field, asdict
from typing import Any, Dict, Optional
@dataclass(frozen=True)
class Trace:
"""Contrat unificateur transporté du build au runtime à la preuve.
Tous les champs sont optionnels (str vide / None) pour permettre une
introduction progressive sans casser les actions existantes qui n'en
portent pas. Fallback : comportement actuel si trace absente.
Attributs
mandate_id : ID du mandat humain de niveau supérieur
intention_id : ID du sous-but courant servant le mandat
scene_id : ID de la scène d'intention pertinente
affordance_signature: signature stable de l'affordance ciblée
expected_retour : description courte du retour attendu
level_of_delegation : N0..N4 (cf v0.3 arbitrage 3)
"""
mandate_id: str = ""
intention_id: str = ""
scene_id: str = ""
affordance_signature: str = ""
expected_retour: str = ""
level_of_delegation: int = 0
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
@classmethod
def from_dict(cls, data: Optional[Dict[str, Any]]) -> "Trace":
if not data:
return cls()
return cls(
mandate_id=str(data.get("mandate_id", "") or ""),
intention_id=str(data.get("intention_id", "") or ""),
scene_id=str(data.get("scene_id", "") or ""),
affordance_signature=str(data.get("affordance_signature", "") or ""),
expected_retour=str(data.get("expected_retour", "") or ""),
level_of_delegation=int(data.get("level_of_delegation", 0) or 0),
)
def is_empty(self) -> bool:
return not (
self.mandate_id
or self.intention_id
or self.scene_id
or self.affordance_signature
or self.expected_retour
)