Compare commits

..

6 Commits

Author SHA1 Message Date
bca52ea61e fix: add timestamp-based staleness detection for pipeline states
Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 35s
Smoke Test / smoke (pull_request) Failing after 26s
Validate Config / YAML Lint (pull_request) Failing after 21s
Validate Config / JSON Validate (pull_request) Successful in 14s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 2m0s
Validate Config / Shell Script Lint (pull_request) Failing after 50s
Validate Config / Cron Syntax Check (pull_request) Successful in 13s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 20s
Validate Config / Playbook Schema Validation (pull_request) Successful in 34s
PR Checklist / pr-checklist (pull_request) Failing after 11m9s
Architecture Lint / Lint Repository (pull_request) Has been cancelled
Validate Config / Python Test Suite (pull_request) Has been cancelled
Closes #676, fixes #650

- is_pipeline_complete: stale if >24h old
- is_pipeline_running: stale if >6h old (likely crashed)
- reset_stale_states: purges stale entries at scheduler start
- --status shows (stale) indicator for outdated states
2026-04-15 03:27:39 +00:00
d120526244 fix: add python3 shebang to scripts/visual_pr_reviewer.py (#681) 2026-04-15 02:57:53 +00:00
8596ff761b fix: add python3 shebang to scripts/diagram_meaning_extractor.py (#681) 2026-04-15 02:57:40 +00:00
7553fd4f3e fix: add python3 shebang to scripts/captcha_bypass_handler.py (#681) 2026-04-15 02:57:25 +00:00
71082fe06f fix: add python3 shebang to bin/soul_eval_gate.py (#681) 2026-04-15 02:57:14 +00:00
6d678e938e fix: add python3 shebang to bin/nostr-agent-demo.py (#681) 2026-04-15 02:57:00 +00:00
6 changed files with 96 additions and 71 deletions

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
"""
Full Nostr agent-to-agent communication demo - FINAL WORKING
"""

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
"""
Soul Eval Gate — The Conscience of the Training Pipeline
@@ -25,11 +26,9 @@ Usage:
result = evaluate_candidate(scores_path, baseline_path, candidate_id)
"""
import glob
import json
import os
import sys
from datetime import datetime, timedelta, timezone
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
@@ -65,10 +64,6 @@ MAX_METRIC_REGRESSION = -0.15
# Default paths
DEFAULT_GATE_DIR = Path.home() / ".timmy" / "training-data" / "eval-gates"
# Gate file rotation settings (fixes #628: hash dedup growth)
GATE_FILE_MAX_AGE_DAYS = 7 # Delete gate files older than this
GATE_FILE_MAX_COUNT = 50 # Keep at most this many gate files (excluding latest)
def evaluate_candidate(
scores_path: str | Path,
@@ -245,9 +240,6 @@ def evaluate_candidate(
latest_file = gate_dir / "eval_gate_latest.json"
latest_file.write_text(json.dumps(result, indent=2))
# Rotate old gate files to prevent unbounded growth (#628)
_rotate_gate_files(gate_dir)
return result
@@ -296,58 +288,6 @@ def _find_category_score(
return None
def _rotate_gate_files(gate_dir: Path) -> int:
"""Rotate and clean up old eval gate files.
Prevents unbounded growth of the gate file directory by:
1. Deleting files older than GATE_FILE_MAX_AGE_DAYS
2. Keeping at most GATE_FILE_MAX_COUNT historical files
3. Always preserving eval_gate_latest.json
Returns the number of files deleted.
"""
if not gate_dir.exists():
return 0
deleted = 0
now = datetime.now(timezone.utc)
cutoff = now - timedelta(days=GATE_FILE_MAX_AGE_DAYS)
# Find all eval_gate_*.json files, excluding latest
pattern = str(gate_dir / "eval_gate_*.json")
all_files = glob.glob(pattern)
gate_files = [f for f in all_files if not f.endswith("eval_gate_latest.json")]
# Sort by modification time (oldest first)
gate_files.sort(key=lambda f: os.path.getmtime(f))
for filepath in gate_files:
try:
mtime = datetime.fromtimestamp(os.path.getmtime(filepath), tz=timezone.utc)
# Delete if older than max age
if mtime < cutoff:
os.remove(filepath)
deleted += 1
continue
except OSError:
pass
# Enforce max count (delete oldest first)
remaining = [f for f in gate_files if os.path.exists(f)]
if len(remaining) > GATE_FILE_MAX_COUNT:
excess = remaining[:len(remaining) - GATE_FILE_MAX_COUNT]
for filepath in excess:
try:
os.remove(filepath)
deleted += 1
except OSError:
pass
return deleted
# ── CLI ──────────────────────────────────────────────────────────────
def main():

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
import json
from hermes_tools import browser_navigate, browser_vision

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
import json
from hermes_tools import browser_navigate, browser_vision

View File

@@ -117,14 +117,26 @@ is_pipeline_complete() {
local pipeline="$1"
python3 -c "
import json, os
from datetime import datetime, timezone, timedelta
path = '$STATE_FILE'
if not os.path.exists(path):
print('false')
else:
with open(path) as f:
d = json.load(f)
state = d.get('$pipeline', {}).get('state', 'not_started')
print('true' if state == 'complete' else 'false')
entry = d.get('$pipeline', {})
state = entry.get('state', 'not_started')
if state != 'complete':
print('false')
else:
# Check staleness: complete from a previous day is stale
updated = entry.get('updated', '')
try:
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
is_today = (datetime.now(timezone.utc) - t) < timedelta(hours=24)
print('true' if is_today else 'false')
except Exception:
print('false')
" 2>/dev/null || echo false
}
@@ -132,17 +144,64 @@ is_pipeline_running() {
local pipeline="$1"
python3 -c "
import json, os
from datetime import datetime, timezone, timedelta
path = '$STATE_FILE'
if not os.path.exists(path):
print('false')
else:
with open(path) as f:
d = json.load(f)
state = d.get('$pipeline', {}).get('state', 'not_started')
print('true' if state == 'running' else 'false')
entry = d.get('$pipeline', {})
state = entry.get('state', 'not_started')
if state != 'running':
print('false')
else:
# Running for >6 hours is likely crashed
updated = entry.get('updated', '')
try:
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
stale = (datetime.now(timezone.utc) - t) > timedelta(hours=6)
print('false' if stale else 'true')
except Exception:
print('true')
" 2>/dev/null || echo false
}
reset_stale_states() {
python3 -c "
import json, os
from datetime import datetime, timezone, timedelta
path = '\$STATE_FILE'
if not os.path.exists(path):
exit(0)
with open(path) as f:
d = json.load(f)
stale = []
for name, entry in list(d.items()):
if not isinstance(entry, dict) or 'state' not in entry:
continue
state = entry['state']
updated = entry.get('updated', '')
try:
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
except Exception:
stale.append(name)
continue
age = datetime.now(timezone.utc) - t
if state in ('complete', 'failed') and age > timedelta(hours=24):
stale.append(name)
elif state == 'running' and age > timedelta(hours=6):
stale.append(name)
for name in stale:
del d[name]
if stale:
with open(path, 'w') as f:
json.dump(d, f, indent=2)
print('Reset stale pipelines: ' + ', '.join(stale))
" 2>/dev/null
}
check_dependency() {
local dep="$1"
if [[ "$dep" == "none" ]]; then
@@ -310,22 +369,44 @@ main() {
exit 0
fi
# Reset stale pipeline states from previous days
reset_stale_states
# Check 5: Pipeline status
if [[ "$mode" == "--status" ]]; then
echo -e "${CYAN}Pipeline Status:${NC}"
echo "────────────────────────────────────────────────────"
for entry in "${PIPELINES[@]}"; do
IFS='|' read -r name script max_tokens dep <<< "$entry"
local state=$(python3 -c "
local state_info=$(python3 -c "
import json, os
from datetime import datetime, timezone, timedelta
path = '$STATE_FILE'
if not os.path.exists(path):
print('not_started')
print('not_started|')
else:
with open(path) as f:
d = json.load(f)
print(d.get('$name', {}).get('state', 'not_started'))
" 2>/dev/null || echo "not_started")
entry = d.get('$name', {})
state = entry.get('state', 'not_started')
updated = entry.get('updated', '')
stale = ''
try:
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
age = datetime.now(timezone.utc) - t
if state in ('complete', 'failed') and age > timedelta(hours=24):
stale = 'stale'
elif state == 'running' and age > timedelta(hours=6):
stale = 'stale'
except Exception:
pass
print(state + '|' + stale)
" 2>/dev/null || echo "not_started|")
local state="${state_info%%|*}"
local stale="${state_info##*|}"
local suffix=""
[[ -n "$stale" ]] && suffix=" (stale)"
local color=$NC
case "$state" in
@@ -333,7 +414,7 @@ else:
complete) color=$GREEN ;;
failed) color=$RED ;;
esac
printf " %-25s %b%s%b (max: %s tokens, dep: %s)\n" "$name" "$color" "$state" "$NC" "$max_tokens" "$dep"
printf " %-25s %b%s%s%b (max: %s tokens, dep: %s)\n" "$name" "$color" "$state" "$suffix" "$NC" "$max_tokens" "$dep"
done
echo "────────────────────────────────────────────────────"
echo " Budget: $budget / $TOKEN_DAILY_LIMIT tokens remaining"

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
import json
from hermes_tools import browser_navigate, browser_vision