From e30f3247945205b6c1968532c301b029631f912f Mon Sep 17 00:00:00 2001 From: Juan Date: Mon, 11 May 2026 10:53:36 +0200 Subject: [PATCH] chore(plan): marca Phase G (Tasks 26-29) completada MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../plans/2026-05-09-agentforge.md | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/superpowers/plans/2026-05-09-agentforge.md b/docs/superpowers/plans/2026-05-09-agentforge.md index 5c5bb39..7099dd2 100644 --- a/docs/superpowers/plans/2026-05-09-agentforge.md +++ b/docs/superpowers/plans/2026-05-09-agentforge.md @@ -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