Files
fn_registry/python/functions/infra/drain_fleet_events.md
T
agent 118d5d36d3 feat(orquestador): feed reactivo FLEET-STATE + fix peek de drain_fleet_events
El orquestador no se enteraba de los cambios de estado de su flota: el drenado
era manual y el peek documentado `./fn run drain_fleet_events --advance false`
devolvia un falso `{total_new:0, cursor:0}` porque `fn run` mapea los argumentos
posicionalmente y no parsea flags `--nombre valor` (events_path acababa valiendo
"--advance", una ruta inexistente).

- drain_fleet_events: nuevo helper _normalize_fn_run_flags que renormaliza el
  patron `--advance <bool>` aplanado por `fn run`, de modo que el peek funciona
  directo desde la CLI sin tocar el runner de Go. Bump 1.1.0 + growth log + tests
  del normalizador (unit y end-to-end por HOME).
- summarize_fleet_transitions (nueva, pure, grupo claude-fleet): resume el dict
  by_classification de drain en un bloque de una linea con las tres categorias
  accionables (terminados / reclaman / estancados), dedup por session_id y
  truncado de objetivo.
- hook_fleet_state_inject.sh (UserPromptSubmit): si la sesion es role=orchestrator
  (leido de ~/.claude/goals/<session_id>.json), hace peek de la cola sin mover el
  cursor y emite el bloque FLEET-STATE cada turno. Degrada limpio si el watcher
  esta caido, la cola no existe o la sesion no es orquestador.

El registro del hook va en .claude/settings.local.json (gitignored, fuera de este
commit). Pendiente, lo integra otro agente: documentar el bloque FLEET-STATE en
.claude/commands/orquestador.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 00:06:01 +02:00

5.4 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
drain_fleet_events function py infra 1.1.0 impure def drain_fleet_events(events_path: str | None = None, cursor_path: str | None = None, advance: bool = True) -> dict 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.
fleet
claude-fleet
jsonl
cursor
queue
drain
watcher
orchestrator
false error_go_core
os
json
name desc
events_path ruta a la cola JSONL append-only de eventos. Default: ~/.claude/fleet/events.jsonl
name desc
cursor_path ruta al archivo de cursor (numero de lineas ya procesadas, entero en texto plano). Default: ~/.claude/fleet/cursor
name desc
advance si True avanza el cursor al total de lineas para no reprocesar; si False hace peek sin mover el cursor (inspeccion)
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 true
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
normaliza flag advance posicional de fn run
peek flag posicional no mueve cursor
python/functions/infra/drain_fleet_events_test.py python/functions/infra/drain_fleet_events.py

Ejemplo

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)

Tambien desde la CLI, sin escribir codigo. El drenado canonico consume y avanza el cursor; el peek inspecciona sin moverlo:

# Drenado canonico: consume los eventos nuevos y avanza el cursor.
./fn run drain_fleet_events

# Peek (no mueve el cursor): inspeccionar la cola sin consumirla.
./fn run 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).
  • Peek por fn run: fn run mapea los argumentos POSICIONALMENTE y no parsea flags --nombre valor. Para que el peek documentado ./fn run drain_fleet_events --advance false funcione, la funcion renormaliza ese patron internamente (_normalize_fn_run_flags): detecta --advance como primer posicional y lo interpreta como el booleano advance, devolviendo las rutas a su default. Una llamada normal por kwargs no se ve afectada. Acepta --advance false|true|0|1|no|yes; --advance sin valor equivale a true.

Capability growth log

  • v1.1.0 (2026-06-21) — el peek ./fn run drain_fleet_events --advance false ahora funciona directo desde la CLI. Antes fn run colaba el flag como events_path="--advance" (ruta inexistente) y devolvia un falso {total_new:0, cursor:0}. Se añade _normalize_fn_run_flags para renormalizar el patron sin tocar el runner de Go. Elimina el gotcha de invocacion que silenciaba la cola al orquestador (reports 0011/0012).