28a53ee357
Fase 1, piezas 1+2: - ClaudeFleet + list_claude_fleet ganan DodContract/DodStatus/Role, leidos de goals/<sessionId>.json (.dod_contract/.dod_status/.role). Aditivo: fleetview sigue compilando. - classify_fleet_termination (pura): clasifica el estado de terminacion de un agente (RECLAMA/MAL_LANZADO/DICE_TERMINADO/ESTANCADO/TRABAJANDO) con precedencia fija, para que un watcher sin LLM decida. 34 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
4.6 KiB
Go
75 lines
4.6 KiB
Go
package infra
|
|
|
|
import "testing"
|
|
|
|
func TestClassifyFleetTermination(t *testing.T) {
|
|
const stall = 600
|
|
|
|
cases := []struct {
|
|
name string
|
|
status string
|
|
phase string
|
|
dodC string
|
|
dodS string
|
|
idle int
|
|
thresh int
|
|
want string
|
|
}{
|
|
// --- RECLAMA (precedencia 1) ---
|
|
{"waiting reclama input", "waiting", "haciendo", "criterio", "pending", 10, stall, TerminationReclama},
|
|
{"phase preguntando reclama", "busy", "preguntando", "criterio", "pending", 10, stall, TerminationReclama},
|
|
{"phase bloqueado reclama", "idle", "bloqueado", "criterio", "pending", 9999, stall, TerminationReclama},
|
|
{"waiting manda aunque sin dodContract", "waiting", "haciendo", "", "", 10, stall, TerminationReclama},
|
|
{"preguntando manda aunque sin dodContract", "idle", "preguntando", "", "", 10, stall, TerminationReclama},
|
|
{"bloqueado manda aunque idle estancado", "idle", "bloqueado", "criterio", "pending", 10000, stall, TerminationReclama},
|
|
|
|
// --- MAL_LANZADO (precedencia 2) ---
|
|
{"sin dodContract busy", "busy", "haciendo", "", "pending", 10, stall, TerminationMalLanzado},
|
|
{"sin dodContract idle reciente", "idle", "haciendo", "", "", 5, stall, TerminationMalLanzado},
|
|
{"sin dodContract idle estancado", "idle", "haciendo", "", "pending", 10000, stall, TerminationMalLanzado},
|
|
{"sin dodContract phase hecho", "idle", "hecho", "", "met", 10, stall, TerminationMalLanzado},
|
|
{"sin dodContract dodStatus met", "idle", "testeando", "", "met", 10, stall, TerminationMalLanzado},
|
|
|
|
// --- DICE_TERMINADO (precedencia 3) ---
|
|
{"idle phase hecho", "idle", "hecho", "criterio", "pending", 10, stall, TerminationDiceTerminado},
|
|
{"idle dodStatus met", "idle", "testeando", "criterio", "met", 10, stall, TerminationDiceTerminado},
|
|
{"idle hecho y met", "idle", "hecho", "criterio", "met", 10, stall, TerminationDiceTerminado},
|
|
{"idle met aunque estancado por tiempo", "idle", "puliendo", "criterio", "met", 10000, stall, TerminationDiceTerminado},
|
|
{"idle hecho aunque estancado por tiempo", "idle", "hecho", "criterio", "pending", 10000, stall, TerminationDiceTerminado},
|
|
|
|
// --- ESTANCADO (precedencia 4) ---
|
|
{"idle no hecho en umbral exacto", "idle", "haciendo", "criterio", "pending", stall, stall, TerminationEstancado},
|
|
{"idle no hecho por encima del umbral", "idle", "investigando", "criterio", "pending", stall + 1, stall, TerminationEstancado},
|
|
{"idle iterando estancado", "idle", "iterando", "criterio", "failed", 5000, stall, TerminationEstancado},
|
|
{"idle dodStatus failed estancado", "idle", "testeando", "criterio", "failed", 700, stall, TerminationEstancado},
|
|
{"idle en_pausa estancado", "idle", "en_pausa", "criterio", "pending", 601, stall, TerminationEstancado},
|
|
|
|
// --- TRABAJANDO (precedencia 5, todo lo demas) ---
|
|
{"busy trabajando", "busy", "haciendo", "criterio", "pending", 0, stall, TerminationTrabajando},
|
|
{"busy aunque idleSeconds alto", "busy", "investigando", "criterio", "pending", 99999, stall, TerminationTrabajando},
|
|
{"idle reciente bajo umbral", "idle", "haciendo", "criterio", "pending", stall - 1, stall, TerminationTrabajando},
|
|
{"idle reciente cero segundos", "idle", "planificando", "criterio", "pending", 0, stall, TerminationTrabajando},
|
|
{"idle no hecho justo bajo umbral", "idle", "testeando", "criterio", "failed", 599, stall, TerminationTrabajando},
|
|
{"busy phase vacia con dodContract", "busy", "", "criterio", "", 10, stall, TerminationTrabajando},
|
|
|
|
// --- Bordes y combinaciones ---
|
|
{"umbral cero idle no hecho => estancado", "idle", "haciendo", "criterio", "pending", 0, 0, TerminationEstancado},
|
|
{"idle hecho con umbral cero => dice terminado", "idle", "hecho", "criterio", "pending", 0, 0, TerminationDiceTerminado},
|
|
{"dodStatus met con status busy NO termina", "busy", "haciendo", "criterio", "met", 10, stall, TerminationTrabajando},
|
|
{"phase hecho con status busy NO termina", "busy", "hecho", "criterio", "pending", 10, stall, TerminationTrabajando},
|
|
{"idle pendiente_revision bajo umbral trabajando", "idle", "pendiente_revision", "criterio", "pending", 100, stall, TerminationTrabajando},
|
|
{"idle pendiente_revision sobre umbral estancado", "idle", "pendiente_revision", "criterio", "pending", 1000, stall, TerminationEstancado},
|
|
{"waiting con dodStatus met sigue reclamando", "waiting", "hecho", "criterio", "met", 10, stall, TerminationReclama},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
got := ClassifyFleetTermination(c.status, c.phase, c.dodC, c.dodS, c.idle, c.thresh)
|
|
if got != c.want {
|
|
t.Errorf("ClassifyFleetTermination(%q,%q,%q,%q,%d,%d) = %q, want %q",
|
|
c.status, c.phase, c.dodC, c.dodS, c.idle, c.thresh, got, c.want)
|
|
}
|
|
})
|
|
}
|
|
}
|