diff --git a/validate_v1.3.sh b/validate_v1.3.sh new file mode 100755 index 0000000..c3d2ccd --- /dev/null +++ b/validate_v1.3.sh @@ -0,0 +1,247 @@ +#!/bin/bash +# Validation Script for openclaw-true-recall-base v1.3 +# Tests all fixes and changes from v1.2 → v1.3 + +set -e + +echo "╔══════════════════════════════════════════════════════════════════════════╗" +echo "║ TrueRecall Base v1.3 Validation Script ║" +echo "╚══════════════════════════════════════════════════════════════════════════╝" +echo "" + +PASS=0 +FAIL=0 +WARN=0 + +check_pass() { echo "✅ $1"; ((PASS++)); } +check_fail() { echo "❌ $1"; ((FAIL++)); } +check_warn() { echo "⚠️ $1"; ((WARN++)); } + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 1: File Structure +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 1: File Structure" +echo "═════════════════════════════════════════════════════════════════════════" + +PROJECT_DIR="$(dirname "$0")" + +if [ -f "$PROJECT_DIR/CHANGELOG.md" ]; then + check_pass "CHANGELOG.md exists" +else + check_fail "CHANGELOG.md missing" +fi + +if [ -f "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py" ]; then + check_pass "realtime_qdrant_watcher.py exists" +else + check_fail "realtime_qdrant_watcher.py missing" +fi + +# Check version in file +VERSION=$(grep -m1 "TrueRecall v" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py" | grep -oE "v[0-9]+\.[0-9]+") +if [ "$VERSION" = "v1.3" ]; then + check_pass "Version is v1.3" +else + check_fail "Version mismatch: expected v1.3, got $VERSION" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 2: Code Changes (v1.3 Fixes) +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 2: Code Changes (v1.3 Fixes)" +echo "═════════════════════════════════════════════════════════════════════════" + +# Fix 1: FileNotFoundError check +if grep -q "if not session_file.exists():" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py"; then + check_pass "FileNotFoundError fix: Pre-check exists before open()" +else + check_fail "FileNotFoundError fix MISSING: No session_file.exists() check" +fi + +if grep -q "except FileNotFoundError:" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py"; then + check_pass "FileNotFoundError fix: Exception handler present" +else + check_fail "FileNotFoundError fix MISSING: No FileNotFoundError exception handler" +fi + +# Fix 2: Chunking for long content +if grep -q "def chunk_text" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py"; then + check_pass "Chunking fix: chunk_text() function defined" +else + check_fail "Chunking fix MISSING: No chunk_text() function" +fi + +if grep -q "chunk_text_content" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py"; then + check_pass "Chunking fix: chunk_text_content used in store_to_qdrant()" +else + check_fail "Chunking fix MISSING: Not using chunked content" +fi + +if grep -q "chunk_index" "$PROJECT_DIR/watcher/realtime_qdrant_watcher.py"; then + check_pass "Chunking fix: chunk_index metadata added" +else + check_fail "Chunking fix MISSING: No chunk_index metadata" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 3: Service Status +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 3: Service Status" +echo "═════════════════════════════════════════════════════════════════════════" + +if systemctl is-active --quiet mem-qdrant-watcher 2>/dev/null; then + check_pass "mem-qdrant-watcher service is running" +else + check_warn "mem-qdrant-watcher service not running (may be running in daemon mode)" +fi + +# Check for running watcher process +if pgrep -f "realtime_qdrant_watcher" > /dev/null; then + check_pass "realtime_qdrant_watcher process is running" +else + check_fail "realtime_qdrant_watcher process NOT running" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 4: Connectivity +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 4: Connectivity" +echo "═════════════════════════════════════════════════════════════════════════" + +# Qdrant +QDRANT_URL="${QDRANT_URL:-http://10.0.0.40:6333}" +if curl -s -o /dev/null -w "%{http_code}" "$QDRANT_URL/collections/memories_tr" | grep -q "200"; then + check_pass "Qdrant memories_tr collection reachable" +else + check_fail "Qdrant memories_tr collection NOT reachable" +fi + +# Ollama (local) +if curl -s -o /dev/null -w "%{http_code}" "http://localhost:11434/api/tags" | grep -q "200"; then + check_pass "Ollama (localhost) reachable" +else + check_fail "Ollama (localhost) NOT reachable" +fi + +# Check embedding model +if curl -s "http://localhost:11434/api/tags" | grep -q "snowflake-arctic-embed2"; then + check_pass "Embedding model snowflake-arctic-embed2 available" +else + check_fail "Embedding model snowflake-arctic-embed2 NOT available" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 5: Crash Loop Test +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 5: Crash Loop Test (Last 1 Hour)" +echo "═════════════════════════════════════════════════════════════════════════" + +RESTARTS=$(journalctl -u mem-qdrant-watcher --since "1 hour ago" --no-pager 2>/dev/null | grep -c "Started mem-qdrant-watcher" || echo "0") +if [ "$RESTARTS" -le 2 ]; then + check_pass "Restarts in last hour: $RESTARTS (expected ≤2)" +else + check_fail "Restarts in last hour: $RESTARTS (too many, expected ≤2)" +fi + +# Check for FileNotFoundError in logs +ERRORS=$(journalctl -u mem-qdrant-watcher --since "1 hour ago" --no-pager 2>/dev/null | grep -c "FileNotFoundError" || echo "0") +if [ "$ERRORS" -eq 0 ]; then + check_pass "No FileNotFoundError in last hour" +else + check_fail "FileNotFoundError found $ERRORS times in last hour" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 6: Chunking Test +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 6: Chunking Test" +echo "═════════════════════════════════════════════════════════════════════════" + +# Test chunking with Python +python3 -c " +import sys +sys.path.insert(0, '$PROJECT_DIR/watcher') + +# Import chunk_text function +exec(open('$PROJECT_DIR/watcher/realtime_qdrant_watcher.py').read().split('def chunk_text')[1].split('def store_to_qdrant')[0]) + +# Test with long content +test_content = 'A' * 10000 +chunks = chunk_text(test_content, max_chars=6000, overlap=200) + +if len(chunks) > 1: + print(f'PASS: chunk_text splits 10000 chars into {len(chunks)} chunks') + sys.exit(0) +else: + print(f'FAIL: chunk_text returned {len(chunks)} chunks for 10000 chars') + sys.exit(1) +" 2>/dev/null && check_pass "chunk_text() splits long content correctly" || check_fail "chunk_text() test failed" + +# ════════════════════════════════════════════════════════════════════════════ +# SECTION 7: Git Status +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "SECTION 7: Git Status" +echo "═════════════════════════════════════════════════════════════════════════" + +cd "$PROJECT_DIR" + +# Check for v1.3 tag +if git tag -l | grep -q "v1.3"; then + check_pass "Git tag v1.3 exists" +else + check_fail "Git tag v1.3 missing" +fi + +# Check CHANGELOG.md committed +if git log --oneline -1 | grep -q "v1.3"; then + check_pass "v1.3 commit in git log" +else + check_fail "v1.3 commit not found in git log" +fi + +# Check for uncommitted changes +UNCOMMITTED=$(git status --short 2>/dev/null | wc -l) +if [ "$UNCOMMITTED" -eq 0 ]; then + check_pass "No uncommitted changes" +else + check_warn "$UNCOMMITTED uncommitted files" +fi + +# ════════════════════════════════════════════════════════════════════════════ +# SUMMARY +# ════════════════════════════════════════════════════════════════════════════ +echo "" +echo "═════════════════════════════════════════════════════════════════════════" +echo "VALIDATION SUMMARY" +echo "═════════════════════════════════════════════════════════════════════════" +echo "" +echo "✅ Passed: $PASS" +echo "❌ Failed: $FAIL" +echo "⚠️ Warnings: $WARN" +echo "" + +if [ $FAIL -eq 0 ]; then + echo "╔══════════════════════════════════════════════════════════════════════════╗" + echo "║ ✅ ALL VALIDATIONS PASSED - v1.3 READY FOR PRODUCTION ║" + echo "╚══════════════════════════════════════════════════════════════════════════╝" + exit 0 +else + echo "╔══════════════════════════════════════════════════════════════════════════╗" + echo "║ ❌ VALIDATION FAILED - $FAIL ISSUE(S) NEED ATTENTION ║" + echo "╚══════════════════════════════════════════════════════════════════════════╝" + exit 1 +fi \ No newline at end of file