fix(vision-manager): LOW watermark must not idle-stop a running vision #9

Merged
fabi merged 1 commits from fix/vision-mem-yield-running-stop into main 2026-06-16 16:57:50 +00:00

View File

@@ -200,19 +200,27 @@ while true; do
analysis_off=0
fi
# Memory-yield gates (before the backlog logic). The active stop handles a
# running vision the idle path can't; the inhibit forces pending=0 so the
# existing idle-debounce path keeps it down (same shape as the crawl mutex).
# Memory-yield: two SEPARATE levers, never conflated.
# - active stop (HIGH watermark): mem_check_and_stop SIGTERMs a RUNNING
# vision when the host is critically short — the ONLY thing that stops a
# vision that is actively working.
# - start block (LOW watermark / cooldown): holds off STARTING a stopped
# vision when memory is already tight, via the mem_block_start flag.
# It must NOT zero `pending`: doing so made the idle-debounce path read
# "no work" and idle-stop a vision mid-analysis once the box floated past
# LOW (idle stack + LLM ≈ 80% here). LOW is a START gate, not a stop
# threshold.
mem_check_and_stop
running="$(vision_running)" # refresh: the active stop may have just flipped it
mem_block_start=0
if [ "$(mem_yield_active)" = "1" ]; then
mem_block_start=1
if [ "$mem_inhibited" != "1" ]; then
log "memory-yield: inhibiting vision start (used >= ${MEM_LOW_WATERMARK_PCT}% or cooldown active)"
log "memory-yield: blocking vision START (used >= ${MEM_LOW_WATERMARK_PCT}% or cooldown); a running vision keeps working until the ${MEM_HIGH_WATERMARK_PCT}% active stop"
mem_inhibited=1
fi
pending=0
elif [ "$mem_inhibited" = "1" ]; then
log "memory-yield: pressure cleared — start inhibit lifted"
log "memory-yield: pressure cleared — start block lifted"
mem_inhibited=0
fi
@@ -225,7 +233,12 @@ while true; do
if [ "$pending" -gt 0 ]; then
idle_for=0
if [ "$running" != "true" ]; then
if [ "$RESPECT_CRAWL_MUTEX" != "0" ] && [ "$(crawl_running)" != "0" ]; then
if [ "$mem_block_start" = "1" ]; then
# Memory pressure / cooldown — hold off STARTING (flip already logged).
# A RUNNING vision never reaches here; idle_for stayed 0 above because
# pending>0, so a working vision is never idle-stopped under pressure.
:
elif [ "$RESPECT_CRAWL_MUTEX" != "0" ] && [ "$(crawl_running)" != "0" ]; then
# Log once per deferral episode, not every poll, so a long crawl
# doesn't flood the log.
if [ "$crawl_deferred" != "1" ]; then