fix(session): clear exit signals on session reset (issue #91)
Root cause: Stale completion indicators in .exit_signals and .response_analysis files persisted across sessions, causing premature exit when combined with normal completion indicator increments. Changes: - Enhanced reset_session() to clear .exit_signals file (resets to empty structure) - Enhanced reset_session() to remove .response_analysis file - Session reset now comprehensively clears all exit-related state Added 2 new tests: - reset_session clears exit_signals file to prevent premature exit - reset_session prevents issue #91 scenario (stale completion indicators) Test count: 321 (up from 319) Fixes #91
This commit is contained in:
parent
761db2f67d
commit
d63f300c09
3 changed files with 151 additions and 2 deletions
14
CLAUDE.md
14
CLAUDE.md
|
|
@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
This is the Ralph for Claude Code repository - an autonomous AI development loop system that enables continuous development cycles with intelligent exit detection and rate limiting.
|
||||
|
||||
**Version**: v0.10.1 | **Tests**: 319 passing (100% pass rate) | **CI/CD**: GitHub Actions
|
||||
**Version**: v0.10.1 | **Tests**: 321 passing (100% pass rate) | **CI/CD**: GitHub Actions
|
||||
|
||||
## Core Architecture
|
||||
|
||||
|
|
@ -358,7 +358,7 @@ Ralph uses advanced error detection with two-stage filtering to eliminate false
|
|||
| `test_cli_parsing.bats` | 27 | CLI argument parsing for all 12 flags |
|
||||
| `test_cli_modern.bats` | 29 | Modern CLI commands (Phase 1.1) + build_claude_command fix |
|
||||
| `test_json_parsing.bats` | 45 | JSON output format parsing + Claude CLI format + session management + array format |
|
||||
| `test_session_continuity.bats` | 26 | Session lifecycle management + circuit breaker integration |
|
||||
| `test_session_continuity.bats` | 28 | Session lifecycle management + circuit breaker integration + issue #91 fix |
|
||||
| `test_exit_detection.bats` | 20 | Exit signal detection |
|
||||
| `test_rate_limiting.bats` | 15 | Rate limiting behavior |
|
||||
| `test_loop_execution.bats` | 20 | Integration tests |
|
||||
|
|
@ -381,6 +381,16 @@ bats tests/unit/test_cli_parsing.bats
|
|||
|
||||
## Recent Improvements
|
||||
|
||||
### Stale Completion Indicators Fix (v0.10.1) - Issue #91
|
||||
- Fixed premature exit caused by stale completion indicators persisting across sessions
|
||||
- Root cause: `.exit_signals` and `.response_analysis` files retained old completion counts
|
||||
- Enhanced `reset_session()` to clear exit-related state files:
|
||||
- Resets `.exit_signals` to empty structure (no completion indicators)
|
||||
- Removes `.response_analysis` to prevent stale EXIT_SIGNAL detection
|
||||
- Session reset now comprehensively clears: session ID, exit signals, and response analysis
|
||||
- Added 2 new tests validating exit signal clearing behavior
|
||||
- Test count: 321 (up from 319)
|
||||
|
||||
### JSON Array Format Support (v0.10.1)
|
||||
- Fixed `parse_json_response` to handle Claude CLI JSON array output format (issue #112)
|
||||
- Claude CLI outputs `[{type: "system", ...}, {type: "assistant", ...}, {type: "result", ...}]`
|
||||
|
|
|
|||
|
|
@ -638,6 +638,16 @@ reset_session() {
|
|||
# Also clear the Claude session file for consistency
|
||||
rm -f "$CLAUDE_SESSION_FILE" 2>/dev/null
|
||||
|
||||
# Clear exit signals to prevent stale completion indicators from causing premature exit (issue #91)
|
||||
# This ensures a fresh start without leftover state from previous sessions
|
||||
if [[ -f "$EXIT_SIGNALS_FILE" ]]; then
|
||||
echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}' > "$EXIT_SIGNALS_FILE"
|
||||
[[ "${VERBOSE_PROGRESS:-}" == "true" ]] && log_status "INFO" "Cleared exit signals file"
|
||||
fi
|
||||
|
||||
# Clear response analysis to prevent stale EXIT_SIGNAL from previous session
|
||||
rm -f "$RESPONSE_ANALYSIS_FILE" 2>/dev/null
|
||||
|
||||
# Log the session transition (non-fatal to prevent script exit under set -e)
|
||||
log_session_transition "active" "reset" "$reason" "${loop_count:-0}" || true
|
||||
|
||||
|
|
|
|||
|
|
@ -522,3 +522,132 @@ EOF
|
|||
run should_resume_session
|
||||
[[ "$output" == "false" ]]
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# SESSION RESET CLEARS EXIT SIGNALS (Issue #91 Fix)
|
||||
# =============================================================================
|
||||
|
||||
@test "reset_session clears exit_signals file to prevent premature exit" {
|
||||
# Setup: Create stale exit signals that would cause premature exit
|
||||
echo '{"test_only_loops": [1,2], "done_signals": [1], "completion_indicators": [1,2,3]}' > "$EXIT_SIGNALS_FILE"
|
||||
|
||||
# Verify stale signals exist
|
||||
local completion_count=$(jq '.completion_indicators | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$completion_count" == "3" ]]
|
||||
|
||||
# Source ralph_loop.sh to get reset_session function
|
||||
# We need to mock some things to prevent full initialization
|
||||
export RALPH_SESSION_HISTORY_FILE="$RALPH_DIR/.ralph_session_history"
|
||||
export RESPONSE_ANALYSIS_FILE="$RALPH_DIR/.response_analysis"
|
||||
|
||||
# Create a mock response analysis file
|
||||
echo '{"analysis": {"exit_signal": true}}' > "$RESPONSE_ANALYSIS_FILE"
|
||||
[[ -f "$RESPONSE_ANALYSIS_FILE" ]]
|
||||
|
||||
# Define reset_session inline for testing (extracted from ralph_loop.sh)
|
||||
reset_session() {
|
||||
local reason=${1:-"manual_reset"}
|
||||
local reset_timestamp
|
||||
reset_timestamp=$(get_iso_timestamp)
|
||||
|
||||
jq -n \
|
||||
--arg session_id "" \
|
||||
--arg created_at "" \
|
||||
--arg last_used "" \
|
||||
--arg reset_at "$reset_timestamp" \
|
||||
--arg reset_reason "$reason" \
|
||||
'{
|
||||
session_id: $session_id,
|
||||
created_at: $created_at,
|
||||
last_used: $last_used,
|
||||
reset_at: $reset_at,
|
||||
reset_reason: $reset_reason
|
||||
}' > "$RALPH_SESSION_FILE"
|
||||
|
||||
rm -f "$CLAUDE_SESSION_FILE" 2>/dev/null
|
||||
|
||||
# Issue #91 fix: Clear exit signals
|
||||
if [[ -f "$EXIT_SIGNALS_FILE" ]]; then
|
||||
echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}' > "$EXIT_SIGNALS_FILE"
|
||||
fi
|
||||
|
||||
# Clear response analysis
|
||||
rm -f "$RESPONSE_ANALYSIS_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# Call reset_session
|
||||
reset_session "test_reset"
|
||||
|
||||
# Verify exit signals were cleared
|
||||
local new_completion_count=$(jq '.completion_indicators | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$new_completion_count" == "0" ]]
|
||||
|
||||
local new_test_loops=$(jq '.test_only_loops | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$new_test_loops" == "0" ]]
|
||||
|
||||
local new_done_signals=$(jq '.done_signals | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$new_done_signals" == "0" ]]
|
||||
|
||||
# Verify response analysis was cleared
|
||||
[[ ! -f "$RESPONSE_ANALYSIS_FILE" ]]
|
||||
}
|
||||
|
||||
@test "reset_session prevents issue #91 scenario (stale completion indicators)" {
|
||||
# Issue #91: Ralph exits immediately when stale completion_indicators exist
|
||||
|
||||
# Simulate the issue scenario:
|
||||
# 1. Previous session ended with completion_indicators: [1,2]
|
||||
# 2. Previous session had EXIT_SIGNAL: true
|
||||
echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": [1,2]}' > "$EXIT_SIGNALS_FILE"
|
||||
echo '{"analysis": {"exit_signal": true, "has_completion_signal": true}}' > "$RESPONSE_ANALYSIS_FILE"
|
||||
|
||||
# Verify the problematic state exists
|
||||
local completion_count=$(jq '.completion_indicators | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$completion_count" == "2" ]]
|
||||
|
||||
local exit_signal=$(jq -r '.analysis.exit_signal' "$RESPONSE_ANALYSIS_FILE")
|
||||
[[ "$exit_signal" == "true" ]]
|
||||
|
||||
# Now simulate user running --reset-session (which should clear these files)
|
||||
export RALPH_SESSION_HISTORY_FILE="$RALPH_DIR/.ralph_session_history"
|
||||
export RESPONSE_ANALYSIS_FILE="$RALPH_DIR/.response_analysis"
|
||||
|
||||
# Define reset_session with the fix
|
||||
reset_session() {
|
||||
local reason=${1:-"manual_reset"}
|
||||
local reset_timestamp
|
||||
reset_timestamp=$(get_iso_timestamp)
|
||||
|
||||
jq -n \
|
||||
--arg session_id "" \
|
||||
--arg created_at "" \
|
||||
--arg last_used "" \
|
||||
--arg reset_at "$reset_timestamp" \
|
||||
--arg reset_reason "$reason" \
|
||||
'{
|
||||
session_id: $session_id,
|
||||
created_at: $created_at,
|
||||
last_used: $last_used,
|
||||
reset_at: $reset_at,
|
||||
reset_reason: $reset_reason
|
||||
}' > "$RALPH_SESSION_FILE"
|
||||
|
||||
rm -f "$CLAUDE_SESSION_FILE" 2>/dev/null
|
||||
|
||||
# Issue #91 fix
|
||||
if [[ -f "$EXIT_SIGNALS_FILE" ]]; then
|
||||
echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}' > "$EXIT_SIGNALS_FILE"
|
||||
fi
|
||||
rm -f "$RESPONSE_ANALYSIS_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# User runs --reset-session
|
||||
reset_session "manual_reset"
|
||||
|
||||
# Verify the fix: completion indicators should be cleared
|
||||
local new_completion_count=$(jq '.completion_indicators | length' "$EXIT_SIGNALS_FILE")
|
||||
[[ "$new_completion_count" == "0" ]]
|
||||
|
||||
# Verify response analysis is gone (no stale EXIT_SIGNAL)
|
||||
[[ ! -f "$RESPONSE_ANALYSIS_FILE" ]]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue