fix(goal-tracker): eliminar regeneracion LLM (haiku) del dod movil en cada prompt

El hook goal_refine.sh regeneraba el campo .dod del goal.json llamando a
ask_llm.py (haiku) en background en CADA UserPromptSubmit de CADA sesion.
Con muchas sesiones de la flota activas esto amplificaba el rate-limit
compartido de la organizacion (una request API por turno por agente).

El .dod movil no lo consume nadie: el parser de la flota
(functions/infra/list_claude_fleet.go, struct goalFile/readGoal) solo lee
goal/phase/emojis/rename/dod_contract/dod_status/role. El criterio que
clasifica la flota (RECLAMA/DICE_TERMINADO/ESTANCADO) es dod_contract +
dod_status, escrito por set_dod_contract.py sin LLM y consumido por
ClassifyFleetTermination. Ese sistema queda intacto.

Cambios:
- goal_refine.sh: convertido en no-op (exit 0) documentado.
- goal_tracker.sh: retirado el disparo de goal_refine + la acumulacion de
  .prompts que solo lo alimentaba; mensaje GOAL-TRACKER actualizado.

El objetivo+DoD inicial los sigue generando goal_autogen.sh una sola vez
por terminal (junto con goal/emojis, que si se usan). El usuario ajusta el
DoD a mano con 'dod: ...'. Resultado: cero llamadas LLM por prompt.
This commit is contained in:
agent
2026-06-21 12:56:14 +02:00
parent 86252b7d2c
commit e2b5ac56eb
2 changed files with 34 additions and 63 deletions
+19 -45
View File
@@ -1,48 +1,22 @@
#!/bin/bash
# Ajusta SOLO el DoD para mantenerlo coherente con los prompts del usuario hacia
# el objetivo. El OBJETIVO es fijo (identificativo de la terminal) y NUNCA se
# toca aqui. Lo lanza goal_tracker.sh en background (no bloquea). Usa ask_llm
# (haiku, API directa; nunca `claude -p`, ver regla llm_invocation.md).
# DESACTIVADO (2026-06-21): este hook regeneraba el campo `.dod` (movil) del
# goal.json llamando a un LLM (haiku via ask_llm.py) en CADA prompt de CADA
# sesion. Con muchas sesiones de la flota activas a la vez eso amplificaba el
# rate-limit compartido de la organizacion ("Server is temporarily limiting
# requests"). Una request API por turno por agente = coste innecesario.
#
# Args: <session_id> <goal_json_file>
SID="$1"
F="$2"
[ -f "$F" ] || exit 0
PY="$HOME/fn_registry/python/.venv/bin/python3"
ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
[ -x "$PY" ] || exit 0
[ -f "$ASK" ] || exit 0
GOAL=$(jq -r '.goal // ""' "$F" 2>/dev/null)
[ -z "$GOAL" ] && exit 0
DOD=$(jq -r '.dod // ""' "$F" 2>/dev/null)
PROMPTS=$(jq -r '(.prompts // []) | to_entries | map("\(.key+1). \(.value)") | join("\n")' "$F" 2>/dev/null)
[ -z "$PROMPTS" ] && exit 0
SYS="Dado un OBJETIVO fijo de una terminal de trabajo y los prompts del usuario, define o ajusta el DoD (definition of done): la condicion concreta de 'terminado' para ese objetivo, coherente con lo que el usuario va pidiendo. El OBJETIVO no se toca, solo el DoD. Responde SOLO JSON en una linea, sin markdown: {\"dod\":\"...\"}. dod en espanol, breve, maximo 9 palabras. Si el DoD actual ya es adecuado, devuelvelo igual."
PROMPT="OBJETIVO (fijo, no lo cambies): ${GOAL}
DoD ACTUAL: ${DOD}
PROMPTS DEL USUARIO (orden cronologico):
${PROMPTS}
Responde el JSON con el DoD:"
RAW=$("$PY" "$ASK" --system "$SYS" "$PROMPT" 2>/dev/null)
[ -z "$RAW" ] && exit 0
JSON=$(printf '%s' "$RAW" | tr '\n' ' ' | grep -o '{[^{}]*}' | head -1)
[ -z "$JSON" ] && exit 0
ND=$(printf '%s' "$JSON" | jq -r '.dod // ""' 2>/dev/null)
[ -z "$ND" ] && exit 0
TMP="${F}.tmp.$$"
if jq --arg d "$ND" '.dod=$d' "$F" > "$TMP" 2>/dev/null; then
mv "$TMP" "$F"
else
rm -f "$TMP"
fi
# El `.dod` movil NO lo consume nadie: el parser de la flota
# (functions/infra/list_claude_fleet.go, struct goalFile/readGoal) solo lee
# goal/phase/emojis/rename/dod_contract/dod_status/role; ignora `.dod` por
# completo. El criterio de aceptacion real que clasifica la flota es
# `dod_contract` + `dod_status`, escrito por set_dod_contract.py (sin LLM) y
# consumido por ClassifyFleetTermination. Ese sistema queda intacto.
#
# Por tanto la regeneracion del `.dod` movil con haiku se elimina por completo:
# cero llamadas LLM por prompt. El objetivo+DoD inicial los sigue generando
# goal_autogen.sh una sola vez por terminal (junto con goal/emojis, que si se
# usan); el usuario puede ajustar el DoD a mano con "dod: ...".
#
# Se conserva el archivo como no-op para no romper ningun disparador historico
# (defensa en profundidad). El disparo desde goal_tracker.sh tambien se retiro.
exit 0
+15 -18
View File
@@ -83,15 +83,22 @@ case "$PROMPT_TRIM" in
block "⏸️ Fase marcada en pausa." ;;
esac
# --- prompt NORMAL: pasa al agente + acumula para refinar el DoD + estado ---
# Distinguimos tres situaciones por el flag .provisional del goal file:
# --- prompt NORMAL: pasa al agente + estado ---
# Distinguimos dos situaciones por el flag .provisional del goal file:
# - no existe el archivo -> primer prompt: ponemos objetivo PROVISIONAL = tu
# texto + lanzamos autogen (haiku) que lo definira.
# texto + lanzamos autogen (haiku, UNA sola vez)
# que lo definira.
# - existe pero .provisional -> autogen aun no termino (o fallo): conservamos el
# provisional, acumulamos el prompt y relanzamos
# autogen (idempotente, self-healing).
# - existe y NO provisional -> objetivo definitivo: acumulamos prompt y solo
# refinamos el DoD; el objetivo no se toca.
# provisional y relanzamos autogen (idempotente,
# self-healing).
# - existe y NO provisional -> objetivo definitivo: solo mostramos estado.
#
# NOTA (2026-06-21): el campo `.dod` movil YA NO se regenera con LLM en cada
# prompt. goal_refine.sh esta desactivado (era una request haiku por turno por
# sesion -> amplificaba el rate-limit compartido de la organizacion). El `.dod`
# movil no lo consume nadie; el criterio que clasifica la flota es `dod_contract`
# + `dod_status` (set_dod_contract.py, sin LLM). El DoD inicial lo fija autogen
# una vez; el usuario lo ajusta a mano con "dod: ...".
PROV="false"
[ -f "$F" ] && PROV=$(jq -r '.provisional // false' "$F" 2>/dev/null)
@@ -99,17 +106,7 @@ if [ -f "$F" ] && [ "$PROV" != "true" ]; then
G=$(jq -r '.goal // ""' "$F" 2>/dev/null)
P=$(jq -r '.phase // ""' "$F" 2>/dev/null)
D=$(jq -r '.dod // ""' "$F" 2>/dev/null)
# Acumular el prompt y ajustar SOLO el DoD (background). El objetivo no cambia.
if [ "${#PROMPT_TRIM}" -ge 12 ]; then
TMP="${F}.tmp.$$"
if jq --arg p "$PROMPT_TRIM" '.prompts = ((.prompts // []) + [$p])[-12:]' "$F" > "$TMP" 2>/dev/null; then
mv "$TMP" "$F"
else
rm -f "$TMP"
fi
nohup bash "$HOME/.claude/hooks/goal_refine.sh" "$SID" "$F" >/dev/null 2>&1 &
fi
echo "GOAL-TRACKER: file=$F | goal=\"$G\" dod=\"$D\" phase=\"$P\". El objetivo es fijo (identificativo de la terminal, NO lo cambies). El DoD se ajusta solo con los prompts; la fase la mantienen los hooks (PostToolUse=activo, Stop=reposo) — NO la escribas. Comandos meta del usuario (no los uses tu): objetivo:/dod:/pausa."
echo "GOAL-TRACKER: file=$F | goal=\"$G\" dod=\"$D\" phase=\"$P\". El objetivo es fijo (identificativo de la terminal, NO lo cambies). El DoD inicial lo fija el autogen una vez (sin LLM por prompt); el usuario lo ajusta con \"dod: ...\" — NO lo regeneres tu. La fase la mantienen los hooks (PostToolUse=activo, Stop=reposo) — NO la escribas. Comandos meta del usuario (no los uses tu): objetivo:/dod:/pausa."
else
# Sin objetivo definitivo todavia. Mostramos de inmediato un objetivo PROVISIONAL
# igual a tu propio texto (truncado), para que el statusline no quede vacio