feat(core): signature de trajectoire stable pour identite workflow (Phase 0, F1)
Primitive partagee (SP-4/SP-2/competences) : hashe la sequence ordonnee (action_type, target) d'un parcours en ignorant les champs session-specifiques (node_id, timestamp, coordonnees) -> deux apprentissages du meme parcours = meme signature = base du create-or-update (decision F1). Le target stable peut etre compose avec screen_signature() existante. Test TDD: tests/unit/test_trajectory_signature.py (5 tests, RED->GREEN). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
34
core/execution/trajectory_signature.py
Normal file
34
core/execution/trajectory_signature.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Signature de trajectoire — identité stable d'un parcours appris (décision F1).
|
||||
|
||||
Une trajectoire = séquence ordonnée d'actions sur des cibles stables. La signature
|
||||
hashe uniquement `(action_type, target)` de chaque étape, dans l'ordre, en **ignorant
|
||||
les champs session-spécifiques** (IDs de nœuds, timestamps, coordonnées). Deux
|
||||
apprentissages du même parcours produisent donc la même signature → create-or-update.
|
||||
|
||||
Primitive partagée (Phase 0) : consommée par SP-4 (dédup/persist), SP-2 (rejeu) et le
|
||||
cycle compétences (dédup des skills). Pour composer avec un descripteur d'écran stable,
|
||||
passer `core.execution.screen_signature.screen_signature(...)` comme valeur de `target`.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
from typing import Any, Iterable, Mapping
|
||||
|
||||
_FIELD_SEP = "\x1f" # sépare action_type et target dans une étape
|
||||
_STEP_SEP = "\x1e" # sépare les étapes
|
||||
|
||||
|
||||
def _normalize_step(step: Mapping[str, Any]) -> str:
|
||||
action_type = str(step.get("action_type", "unknown")).strip().lower()
|
||||
target = str(step.get("target", "")).strip()
|
||||
return f"{action_type}{_FIELD_SEP}{target}"
|
||||
|
||||
|
||||
def trajectory_signature(steps: Iterable[Mapping[str, Any]]) -> str:
|
||||
"""Retourne la signature SHA-256 (hex, 64 car.) d'une séquence d'étapes.
|
||||
|
||||
Chaque étape est un mapping ; seuls `action_type` et `target` sont pris en compte.
|
||||
Tous les autres champs (node_id, timestamp, coordonnées…) sont ignorés afin de
|
||||
garantir la stabilité de la signature entre deux sessions du même parcours.
|
||||
"""
|
||||
canonical = _STEP_SEP.join(_normalize_step(step) for step in steps)
|
||||
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
||||
Reference in New Issue
Block a user