Pending hypotheses queue by priority and promote when a slot opens,
rather than pausing a running experiment mid-streak.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When ANTHROPIC_API_KEY is set, conclude_hypothesis now:
- Loads the scanner domain file for context
- Calls claude-haiku-4-5-20251001 for a 3–5 sentence interpretation
- Embeds the analysis in the concluded .md doc and PR comment
The LLM enriches the conclusion with sample-size caveats, market
context, and a follow-up hypothesis suggestion — without overriding
the programmatic accept/reject decision.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements compute_7d_return, compute_metrics, load_baseline_metrics,
and make_decision functions with full TDD coverage (11 tests passing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements compute_7d_return, compute_metrics, load_baseline_metrics,
and make_decision functions with full TDD coverage (11 tests passing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pending hypotheses queue by priority and promote when a slot opens,
rather than pausing a running experiment mid-streak.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers 5 tasks: knowledge base structure, /iterate command,
/research-strategy command, and two GitHub Actions workflows with
rolling PR logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
At most one open PR per skill at any time. Daily runs push onto the
existing branch and update the PR description. Merging resets the cycle.
Prevents PR accumulation from unreviewed automated runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Scanners and strategies are 1:1 in the current codebase — separate folder
was artificial. Each scanner file now captures both implementation and thesis.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds daily /iterate and weekly /research-strategy cron workflows to the
spec — full autonomous loop with PR-gated merges, no auto-merge to main.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defines /iterate and /research-strategy skills + docs/iterations/ folder
structure for a generic learn-improve-repeat cycle, demonstrated with the
trading agent discovery pipeline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous implementation redirected sys.stderr to /dev/null using a
context manager. This is not thread-safe: 8 concurrent scanner threads each
mutate sys.stderr, and when one thread's context manager closes the devnull
file, another thread that captured devnull as its saved stderr attempts to
write to the closed fd and raises "I/O operation on closed file".
This corrupted sys.stderr state caused _fetch_batch_prices to fail and
all per-ticker get_stock_price fallback calls to return None, resulting in
every candidate being dropped with "no data available".
Fix by suppressing at the Python logging level instead of redirecting
sys.stderr. Logger.setLevel() is protected by internal locks and is safe
to call from concurrent threads.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs causing zero recommendations:
1. risk_metrics.py was untracked — importing it raised ModuleNotFoundError which
was caught by the outer try/except in filter.py, silently dropping all 32
candidates that reached the fundamental risk check stage.
2. Minervini scanner at max_tickers=200 took >5 min to download 200 tickers x 1y
of OHLCV data. ThreadPoolExecutor.cancel() cannot kill a running thread, so the
download kept running as a zombie thread for 20 more minutes after the pipeline
completed, holding the Python process alive until the 30-min workflow timeout
killed the entire job.
Reducing to 50 tickers brings the download to ~75s, well under the 300s global
scanner timeout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The same-day mover filter used abs() to check intraday movement, which
filtered both gap-ups AND gap-downs. On volatile/crash days (e.g. 2026-04-07)
all stocks dropped >10% from open, causing every candidate to be filtered and
leaving zero recommendations.
The filter's purpose is to avoid chasing stocks that already ran up. A stock
down 20% intraday is not "stale" — it should be evaluated on its merits.
Changed threshold check from abs(pct) >= threshold to pct >= threshold so only
upside movers are filtered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>