chore(plan): marca Phase G (Tasks 26-29) completada

Nota de desviación: Task 26 reescribe el escenario HSS para no colisionar con
'mos'; Task 27 colapsa EXAMPLES a una línea y reusa el __init__ del scaffolding;
Task 29 Step 2 (índice de ejecuciones persistido) ya estaba hecho en Task 24, así
que ese commit solo añade el test. Estilo del repo = ruff check (no ruff format).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Juan
2026-05-11 10:53:36 +02:00
co-authored by Claude Opus 4.7
parent 46d509beb1
commit e30f324794
+21 -14
View File
@@ -4431,6 +4431,13 @@ git commit -m "feat(api): implementa routers /policies y /violations"
## Phase G — Example Assets + Integration Tests (Tasks 2629)
> **Nota de implementación (desviación del plan):**
> - **Task 26:** `03_hss_capacity_active_active.txt` se reescribió ligeramente para evitar la subcadena `mos` (presente en "últimos") y que el `MockProvider._select` lo mapee a la respuesta canónica `hss` y no a la de `mos` (el dict se recorre `sip`→`mos`→`hss`). `index.yaml` y `versions/{v1,v2}.yaml` se committearon sin cambios respecto al plan.
> - **Task 27:** la constante `EXAMPLES` quedó en una sola línea (cabe en 100 cols); `tests/integration/__init__.py` ya existía desde el scaffolding inicial (Task 1). La fixture `integration_client` apunta a `agents/` y `policies/` **reales del repo**, no a fixtures de test.
> - **Task 29 Step 2** ("persistir índice de ejecuciones"): ya implementado en el **Task 24** — `api/executions.py` persiste `trace_id → {agent_name, version}` en `data_dir/execution_index.json` vía `_record_execution` / `_load_index` / `_resolve` (nombres distintos a los del plan, comportamiento equivalente; además sobrevive a reinicios). Por eso el commit del Task 29 solo añade el test (`test(integration): resume HITL tras recreación del app …`) y no toca `executions.py`.
> - El estilo del repo es `ruff check` (no `ruff format`); los bloques de código de los Tasks 27-29 son la versión del plan, la **versión autoritativa es la committeada**. `mypy` solo corre sobre `core/src`; los tests de integración llevan `# type: ignore[no-untyped-def]` donde usan la fixture sin tipar.
### Task 26: Incident Analyzer agent — YAMLs y escenarios
**Files:**
@@ -4441,7 +4448,7 @@ git commit -m "feat(api): implementa routers /policies y /violations"
- Create: `agents/incident_analyzer/examples/02_mos_degradation_pool_sbc.txt`
- Create: `agents/incident_analyzer/examples/03_hss_capacity_active_active.txt`
- [ ] **Step 1: `agents/incident_analyzer/versions/v1.yaml`**
- [x] **Step 1: `agents/incident_analyzer/versions/v1.yaml`**
```yaml
name: incident_analyzer
@@ -4486,7 +4493,7 @@ risk_threshold_for_hitl: 4
updated_at: 2026-04-12T10:00:00Z
```
- [ ] **Step 2: `agents/incident_analyzer/versions/v2.yaml`**
- [x] **Step 2: `agents/incident_analyzer/versions/v2.yaml`**
Idéntico a v1 pero con `temperature: 0.1` (más determinismo) y un `system_prompt` ampliado:
@@ -4531,7 +4538,7 @@ risk_threshold_for_hitl: 4
updated_at: 2026-05-01T12:00:00Z
```
- [ ] **Step 3: `agents/incident_analyzer/index.yaml`**
- [x] **Step 3: `agents/incident_analyzer/index.yaml`**
```yaml
name: incident_analyzer
@@ -4549,7 +4556,7 @@ versions:
active_version: v2
```
- [ ] **Step 4: Escenarios de ejemplo**
- [x] **Step 4: Escenarios de ejemplo**
`agents/incident_analyzer/examples/01_sip_registration_drop.txt`:
```
@@ -4601,7 +4608,7 @@ replicación es opción pero alto impacto: requerirá validar coherencia de la
DB de subscribers tras la operación.
```
- [ ] **Step 5: Commit**
- [x] **Step 5: Commit**
```bash
git add agents/
@@ -4616,7 +4623,7 @@ git commit -m "feat(agents): añade incident_analyzer v1+v2 con 3 escenarios de
- Create: `tests/integration/conftest.py`
- Create: `tests/integration/test_invoke_happy_path.py`
- [ ] **Step 1: Conftest común para integration tests**
- [x] **Step 1: Conftest común para integration tests**
```python
"""Fixtures compartidas para tests de integración."""
@@ -4651,7 +4658,7 @@ def integration_client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): # type
return TestClient(create_app())
```
- [ ] **Step 2: Test happy path completo**
- [x] **Step 2: Test happy path completo**
```python
"""Integration: invoca incident_analyzer real con escenario MOS (sin HITL)."""
@@ -4689,7 +4696,7 @@ def test_happy_path_completa_sin_hitl(integration_client) -> None: # type: igno
assert "finalize" in steps
```
- [ ] **Step 3: Verificar y commit**
- [x] **Step 3: Verificar y commit**
```bash
pytest tests/integration/test_invoke_happy_path.py -v
@@ -4705,7 +4712,7 @@ git commit -m "test(integration): happy path end-to-end con escenario MOS sin HI
- Create: `tests/integration/test_invoke_hitl.py`
- Create: `tests/integration/test_invoke_pii_block.py`
- [ ] **Step 1: HITL approve**
- [x] **Step 1: HITL approve**
```python
"""Integration: escenario SIP (risk=4) → awaiting_approval → approve → completed."""
@@ -4757,7 +4764,7 @@ def test_hitl_reject_marca_failed(integration_client) -> None: # type: ignore[n
assert "rejected_by_human" in r2.json()["error"]
```
- [ ] **Step 2: PII block**
- [x] **Step 2: PII block**
```python
"""Integration: input con PII (NIF) bloqueado por guardrails."""
@@ -4776,7 +4783,7 @@ def test_pii_es_nif_bloquea(integration_client) -> None: # type: ignore[no-unty
assert any(v["validator"] == "DetectPII" and v["blocked"] for v in body["violations"])
```
- [ ] **Step 3: Verificar y commit**
- [x] **Step 3: Verificar y commit**
```bash
pytest tests/integration/test_invoke_hitl.py tests/integration/test_invoke_pii_block.py -v
@@ -4793,7 +4800,7 @@ git commit -m "test(integration): HITL approve/reject + bloqueo por PII (NIF, em
Este test verifica que el `SqliteSaver` persiste el estado: tras una pausa HITL, "matar" el TestClient y crear uno nuevo apuntando al mismo `data_dir` debe permitir reanudar.
- [ ] **Step 1: Test**
- [x] **Step 1: Test**
```python
"""Integration: estado HITL sobrevive a reinicio del proceso (SQLite checkpointing)."""
@@ -4859,7 +4866,7 @@ def test_resume_tras_recreacion_del_app(tmp_path: Path, monkeypatch: pytest.Monk
> **Nota técnica:** La caché in-memory `_EXECUTION_INDEX` del router se pierde al recrear el app. Para que este test funcione, `_EXECUTION_INDEX` debe persistirse o reconstruirse desde `executions.jsonl` al arrancar. Añadir este step:
- [ ] **Step 2: Persistir índice de ejecuciones (await/HITL) en disco**
- [x] **Step 2: Persistir índice de ejecuciones (await/HITL) en disco**
Modificar `core/src/agentforge_core/api/executions.py` reemplazando el dict in-memory por persistencia simple:
@@ -4899,7 +4906,7 @@ def _get_execution_meta(data_dir: Path, trace_id: str) -> dict | None:
Y reemplazar las llamadas a `_EXECUTION_INDEX[...]` por `_record_execution_meta(...)` y a `_EXECUTION_INDEX.get(...)` por `_get_execution_meta(...)`. Eliminar el dict global.
- [ ] **Step 3: Verificar y commit**
- [x] **Step 3: Verificar y commit**
```bash
pytest tests/integration/test_invoke_resume_after_restart.py -v