Skip to content

bug: signal counter race condition in observe.sh throttle logic #2296

@JartanFTW

Description

@JartanFTW

Summary

In skills/continuous-learning-v2/hooks/observe.sh around lines 485-495, the SIGUSR1 throttle counter uses a plain file read-modify-write pattern with no locking. When multiple hook invocations fire concurrently (which is common since tool calls can fire every second), they can read the same counter value, both increment it, and write back — losing increments and potentially signaling the observer more or less frequently than intended.

Relevant code

if [ -f "$SIGNAL_COUNTER_FILE" ]; then
  counter=$(cat "$SIGNAL_COUNTER_FILE" 2>/dev/null || echo 0)
  counter=$((counter + 1))
  if [ "$counter" -ge "$SIGNAL_EVERY_N" ]; then
    should_signal=1
    counter=0
  fi
  echo "$counter" > "$SIGNAL_COUNTER_FILE"
else
  echo "1" > "$SIGNAL_COUNTER_FILE"
fi

Impact

  • Counter increments can be lost, causing signals to fire at unpredictable intervals
  • Two concurrent hooks could both read the same value (e.g., 19), both see >= 20, and both signal — defeating the throttle
  • This was the exact class of problem the throttle was designed to prevent (Memory Explosion in Continuous Learning v2 Observer #521)

Suggested fix

Use an atomic approach such as flock around the read-modify-write, or use mkdir as a lockfile primitive, or use an append-based counter (count lines in the file rather than read/modify/write a single value).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions