replay_state enrichi de safety_checks, checks_acknowledged, pause_reason,
pause_payload (audit trail).
Branche supervisée pause_for_human :
- appel build_pause_payload() avant bascule paused_need_help
- log [BUS] lea:safety_checks_generated (count, sources)
- fallback safe sur exception (pause sans checks plutôt que crash)
- déclenchement si safety_level/safety_checks déclarés OU execution_mode != autonomous
- sinon comportement legacy (skip silencieux)
POST /replay/resume :
- accepte body { acknowledged_check_ids: [...] }
- vérifie tous les checks required acquittés, sinon 400 required_checks_missing
- stocke checks_acknowledged comme audit trail
- nettoie safety_checks/pause_payload après reprise
Proxy VWB /api/v3/replay/resume → streaming /replay/{id}/resume (forward bearer
token + acknowledged_check_ids).
Backward 100% : workflows sans safety_checks → resume sans acquittement requis.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
2.1 KiB
Python
53 lines
2.1 KiB
Python
# tests/integration/test_replay_resume_acknowledgments.py
|
|
"""Tests intégration : /replay/resume valide les acquittements de safety_checks (QW4)."""
|
|
import pytest
|
|
|
|
|
|
def test_resume_accepts_when_all_required_acknowledged():
|
|
"""État pause + tous required acquittés → reprise OK."""
|
|
state = {
|
|
"status": "paused_need_help",
|
|
"safety_checks": [
|
|
{"id": "c1", "label": "X", "required": True, "source": "declarative", "evidence": None},
|
|
{"id": "c2", "label": "Y", "required": True, "source": "declarative", "evidence": None},
|
|
],
|
|
"checks_acknowledged": [],
|
|
}
|
|
# Simuler la validation côté serveur
|
|
acknowledged = ["c1", "c2"]
|
|
required_ids = {c["id"] for c in state["safety_checks"] if c["required"]}
|
|
missing = required_ids - set(acknowledged)
|
|
assert missing == set() # rien ne manque → reprise OK
|
|
|
|
|
|
def test_resume_rejects_when_required_missing():
|
|
"""État pause + un required non acquitté → 400 required_checks_missing."""
|
|
state = {
|
|
"status": "paused_need_help",
|
|
"safety_checks": [
|
|
{"id": "c1", "label": "X", "required": True, "source": "declarative", "evidence": None},
|
|
{"id": "c2", "label": "Y", "required": False, "source": "llm_contextual", "evidence": "..."},
|
|
],
|
|
"checks_acknowledged": [],
|
|
}
|
|
acknowledged = ["c2"] # only optional
|
|
required_ids = {c["id"] for c in state["safety_checks"] if c["required"]}
|
|
missing = required_ids - set(acknowledged)
|
|
assert missing == {"c1"} # c1 manquant → resume doit retourner 400
|
|
|
|
|
|
def test_resume_audit_trail_stored():
|
|
"""checks_acknowledged contient les ids reçus (audit)."""
|
|
state = {
|
|
"status": "paused_need_help",
|
|
"safety_checks": [
|
|
{"id": "c1", "required": True, "label": "X", "source": "declarative", "evidence": None},
|
|
],
|
|
"checks_acknowledged": [],
|
|
}
|
|
acknowledged = ["c1"]
|
|
state["checks_acknowledged"] = acknowledged
|
|
state["status"] = "running"
|
|
assert state["checks_acknowledged"] == ["c1"]
|
|
assert state["status"] == "running"
|