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:
@@ -4431,6 +4431,13 @@ git commit -m "feat(api): implementa routers /policies y /violations"
|
||||
|
||||
## Phase G — Example Assets + Integration Tests (Tasks 26–29)
|
||||
|
||||
> **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
|
||||
|
||||
Reference in New Issue
Block a user