feat: cerebro reactivo del meta-orquestador (flow 0012, fase 2)
Primitivas (python/functions/infra): - drain_fleet_events: consume la cola del watcher (~/.claude/fleet/ events.jsonl) desde un cursor, agrupa por clasificacion, marca urgentes. 7 tests. - set_dod_contract: escribe el DoD-contrato fijo (dod_contract/dod_status) en el goal.json de un agente sin pisar el resto (escritura atomica). 5 tests. Skill /orquestador evolucionado (sin romper lo existente): vigila la flota por su DoD (no por 'esta vivo'). Nueva seccion 'Consumo de la cola de la flota': DoD-contrato obligatorio al lanzar, drenar la cola, politicas por clasificacion (RECLAMA escala / DICE_TERMINADO verifica / ESTANCADO nudge / MAL_LANZADO re-DoD), verificador independiente del ejecutor (lee el report vs dod_contract), splitter con tope de fan-out, y cadencia (drain al actuar + heartbeat). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: drain_fleet_events
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def drain_fleet_events(events_path: str | None = None, cursor_path: str | None = None, advance: bool = True) -> dict"
|
||||
description: "Drena la cola JSONL de eventos de la flota desde un cursor persistente. Lee los eventos nuevos (desde la linea del cursor hasta el final), los parsea saltando lineas en blanco o JSON invalido, los agrupa por su campo `to` (RECLAMA, MAL_LANZADO, DICE_TERMINADO, ESTANCADO, TRABAJANDO, GONE), aisla los urgentes y avanza el cursor para no reprocesar. Pensado para que el orquestador-Claude de flota consuma eventos nuevos cada vez que despierta."
|
||||
tags: [fleet, claude-fleet, jsonl, cursor, queue, drain, watcher, orchestrator]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["os", "json"]
|
||||
params:
|
||||
- name: events_path
|
||||
desc: "ruta a la cola JSONL append-only de eventos. Default: ~/.claude/fleet/events.jsonl"
|
||||
- name: cursor_path
|
||||
desc: "ruta al archivo de cursor (numero de lineas ya procesadas, entero en texto plano). Default: ~/.claude/fleet/cursor"
|
||||
- name: advance
|
||||
desc: "si True avanza el cursor al total de lineas para no reprocesar; si False hace peek sin mover el cursor (inspeccion)"
|
||||
output: "dict con total_new (int), events (lista de eventos nuevos en orden), by_classification (dict agrupado por campo `to`), urgent (lista de eventos con urgent==True), cursor (nueva posicion) y opcionalmente reset==True si la cola estaba truncada/rotada y el cursor se reinicio a 0"
|
||||
tested: true
|
||||
tests:
|
||||
- "cola con eventos cursor cero devuelve todos y avanza"
|
||||
- "segunda llamada cero nuevos"
|
||||
- "advance false no mueve cursor"
|
||||
- "archivo ausente vacio sin crash"
|
||||
- "json invalido se salta"
|
||||
- "agrupacion por to y urgent"
|
||||
- "cursor mayor que lineas reinicia"
|
||||
test_file_path: "python/functions/infra/drain_fleet_events_test.py"
|
||||
file_path: "python/functions/infra/drain_fleet_events.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
from infra.drain_fleet_events import drain_fleet_events
|
||||
|
||||
# El orquestador despierta y consume los eventos nuevos de la flota.
|
||||
drained = drain_fleet_events() # usa ~/.claude/fleet/events.jsonl y ~/.claude/fleet/cursor
|
||||
|
||||
print(f"{drained['total_new']} eventos nuevos")
|
||||
for ev in drained["by_classification"].get("RECLAMA", []):
|
||||
print("RECLAMA:", ev["session_id"], ev["goal"])
|
||||
|
||||
# Eventos urgentes primero.
|
||||
for ev in drained["urgent"]:
|
||||
print("URGENTE:", ev["to"], ev["session_id"])
|
||||
|
||||
# Peek sin avanzar el cursor (no consume): util para inspeccionar antes de actuar.
|
||||
peek = drain_fleet_events(advance=False)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usala en el orquestador-Claude de flota cada vez que despierta y necesita ver
|
||||
las transiciones de estado producidas DESDE la ultima vez sin reprocesar las ya
|
||||
vistas. Tambien para diagnostico con `advance=False` cuando quieres mirar la
|
||||
cola sin consumirla.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Impura**: lee la cola JSONL del disco y, con `advance=True`, sobrescribe el
|
||||
archivo de cursor. Pasa `advance=False` para peek puro sin efectos en cursor.
|
||||
- **Cursor por lineas, no por bytes**: el cursor cuenta lineas procesadas. Las
|
||||
lineas en blanco e invalidas tambien avanzan el cursor (se cuentan en el
|
||||
total de lineas) aunque no produzcan eventos, de modo que nunca se re-leen.
|
||||
- **Cola rotada/truncada**: si el cursor guardado es mayor que el numero de
|
||||
lineas actual (la cola se trunco o rota), el drain reinicia desde 0 y marca
|
||||
`reset: True` en el dict de salida — devolvera de nuevo todos los eventos
|
||||
presentes. Diseñado asi para no perder eventos silenciosamente.
|
||||
- **JSON invalido o lineas en blanco**: se saltan sin romper el drain. Solo los
|
||||
objetos JSON validos entran en `events`.
|
||||
- **`by_classification`**: agrupa por el campo `to`. Un evento sin campo `to`
|
||||
(raro) entra en `events` pero no en ningun grupo.
|
||||
- **Fallo al persistir el cursor**: si `advance=True` pero no se puede escribir
|
||||
el cursor (permisos, FS), el drain sigue siendo valido pero la proxima llamada
|
||||
reprocesara estos eventos (at-least-once, no at-most-once).
|
||||
Reference in New Issue
Block a user