[codex] Finish Kronos cleanup and hardening#335
Conversation
592de63 to
b5e93e9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 592de6315e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| x_timestamp = features.index | ||
| y_timestamp = compute_future_timestamps(x_timestamp[-1], PRED_DAYS) |
There was a problem hiding this comment.
Pass Series timestamps into Kronos
When any scan candidate reaches this Kronos gate, features.index is a DatetimeIndex, and compute_future_timestamps returns another DatetimeIndex; KronosPredictor.predict() immediately calls calc_time_stamps(), which uses x_timestamp.dt.* in model/kronos.py, so this path raises 'DatetimeIndex' object has no attribute 'dt' and the adapter returns a failed KronosResult for every otherwise-valid setup. Convert both timestamp indexes to pd.Series here, as the web UI path already does, before calling the predictor.
Useful? React with 👍 / 👎.
| base_idx = synthetic.index.get_indexer([created], method="nearest") | ||
| if len(base_idx) == 0 or base_idx[0] < 0: | ||
| continue | ||
| start_pos = int(base_idx[0]) |
There was a problem hiding this comment.
Avoid resolving stale decisions to unrelated bars
For pending decisions older than the 60-day intraday lookback, the fetched synthetic series no longer contains the decision timestamp, but get_indexer(..., method="nearest") still chooses the nearest available bar, often the first bar in the current window. That causes old journal entries to be marked win/loss from an unrelated date, corrupting the outcome history that drives diagnostics and autotuning; add a tolerance/window check or leave the record pending when the created timestamp is outside the fetched data range.
Useful? React with 👍 / 👎.
Baseline checkpoint of in-progress work from the prior Codex session: - scanner/learning/adaptive_policy.py + tests - scanner/strategy/potter_doctrine.py + tests - after-hours outcome-review anchoring fix + regression test - zero-result diagnostic test, daily notes, doctrine v2 plan doc Verified before commit: 101 tests passed, doctor status=ok. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GSD codebase map from 4 parallel mapper agents: stack, integrations, architecture, structure, conventions, testing, concerns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ures Analog retrieval quality overhaul, all evidence-backed defects: - Distance now uses a curated ANALOG_FEATURE_KEYS allowlist (scale-free setup shape, volume/volatility, empty space, doctrine v2, research score). Price levels (latest_close, box_top/bottom, atr_value) made analogs cluster by share price; options/kronos/data-quality fields are populated live but zero/absent in history, distorting every live-vs-historical match. - Optional direction matching (EDGE_ANALOG_DIRECTION_MATCH, on): a bullish query no longer borrows expectancy from bearish history. - Optional cross-ticker embargo (EDGE_CROSS_TICKER_EMBARGO_DAYS=1) used in validation so same-day market-wide moves cannot inflate skill. - Kronos features are None (not 0.0) when Kronos was never consulted. 0.0 read as maximum disagreement and silently docked ~10 points from every candidate scored without a Kronos forecast - which was all of them, in both the edge lab and live edge scans. - Validation now samples the most recent EDGE_VALIDATION_MAX_RECORDS (raised 600 -> 1500) by timestamp across all tickers. The old tail slice of a ticker-grouped list validated only the last ~3 watchlist names. - Validation top-k decoupled from analog K (EDGE_VALIDATION_TOP_K=25). FEATURE_VERSION bumped to 3; the index is rebuilt on every edge-lab run. Verified: 108 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bie pendings Outcome truth upgrade: - Historical edge records are now labeled by the trade plan, not the 5-bar close sign: stop at -risk, target at +target (default 2R), time exit at horizon, evaluated bar-by-bar against the High/Low path. Same-bar stop+target resolves conservatively to the stop. A trade that stopped out and drifted back green is now a loss. - Risk gets a defined fallback (one ATR, else 2%, clamped 0.25-15) so near-zero empty-space risk can no longer manufacture huge R multiples. R capped to +/-10. - EdgeRecord gains exit_reason / risk_pct_used / outcome_method with defaults, so older index files still load; validation candidates carry the fields through. - Outcome reviewer records directional MAE/MFE over the resolved path (outcome_mae_pct / outcome_mfe_pct) so the journal can later support stop-aware analysis of live and counterfactual decisions. - Pending decisions that fell out of the sliding 60d intraday window are expired (not_applicable, expired_before_resolution_window) after OUTCOME_EXPIRY_DAYS=45 instead of being re-checked forever. Verified: 116 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The audit demanded 20+ signals above score 55 while the scorer caps gate-failed candidates (nearly the whole cohort) at 44 - an unsatisfiable gate that measured threshold attainment instead of skill. Statistical grounding: a rank IC of ~0.07 is detectable at n=600 samples, while a 55%-win-rate threshold cohort needs 600+ independent trades to distinguish from coin flip. - validation: Spearman rank IC (score vs r_multiple and vs return) over ALL samples with one-sided p-values, top-5/10/20% percentile blocks, decile spread, Wilson 95% lower-bound precision, per-block t-stat on R, stop/target exit rates, and day-concentration stats. - audit: new ranking_evidence check (rank IC >= 0.07 with p <= 0.05, top decile >= 20 signals, avg R > 0, t >= 2, Wilson-LB precision >= 0.45). Either evidence route (legacy absolute threshold OR ranking) now satisfies the evidence gate; both must fail to block. - audit: direction guardrails - any direction with >= 15 validation samples and negative avg R is flagged (bearish currently: 55% precision but negative expectancy) and promoted candidates in a blocked direction cannot grant paper_trade_only readiness. - new scanner/edge/stats.py shared by validation and adaptive policy (Wilson bound moved out of adaptive_policy; one source of truth). Verified: 124 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ial registry The tighten-only ratchet dead-locked the learning loop: a noise-driven tightening to 72 left ~5 signals per quarter (20% WR, -1.37% avg) while threshold 65 held 17 signals at 47% WR / +1.06%, and the policy could neither gather enough samples at 72 to act nor ever step back down. - Loosening path for RESEARCH_CANDIDATE_MIN_SCORE (a data-collection throttle for paper counterfactuals, not a live gate): only when a lower-threshold cohort DOMINATES the current one - n >= 12, positive avg return, Wilson LB >= 0.30, LB >= current+0.05, avg return >= current+0.25pp - capped at 10 points, never below bounds. - Asymmetric application per small-sample best practice: tightening applies immediately; loosening requires a 7-day cooldown since the last automatic change plus a second confirmation on a later calendar day (pending state stored in overrides _meta). - Trial registry (scanner/reports/trial_registry.jsonl): every adaptive/autotune application attempt is logged so the true multiple-testing trial count is a recorded fact. - autotuner.apply_overrides now merges with the existing overrides file instead of overwriting it, which silently dropped adaptive-policy keys and change history. Verified: 129 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lift Kronos was structurally dormant: the strict pipeline only reaches the Kronos stage after the options gate, and the Potter gate has never fully passed, so the foundation model has never been consulted on a single journaled decision - its value was unmeasurable. - research_scan and dry-run counterfactual paths now run kronos.evaluate() on every research-passed candidate (a few per day, best-effort, KRONOS_RESEARCH_ENABLED toggle) and journal agreement, median forecast return, worst sampled return, and pass state. - adaptive policy report gains a kronos_lift section: win rate and average return split by agreement >= MIN_KRONOS_AGREEMENT among resolved research candidates. This is the case-control evidence that decides whether the Kronos confirmation stage earns its gate. Verified: 133 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Evidence velocity: - EDGE_INDEX_EXTRA_UNIVERSE adds 25 liquid optionable names to the retrieval-index build (deduped against the watchlist), nearly doubling the honest walk-forward sample per lab run. The live scan watchlist is untouched; the extras exist only as history. Operator UX: - New --mode brief renders scanner/reports/daily_brief.md and prints it: verdict first, progress toward each evidence gate (rank IC, top-decile counts, per-direction R with BLOCKED tags), today's scan, learning-loop state incl. Kronos lift, every blocker translated to plain English with its concrete fix, and the single next action. - research_ops now ends with the brief, so the daily loop always leaves a current human-readable summary. Verified against today's real reports. Verified: 137 tests passed; --mode brief smoke-tested on live report artifacts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…loosening, data upgrade paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the frontier Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Red-team verdict on the session's changes was BROKEN with three confirmed findings; all fixed fail-closed: 1. Direction guardrail failed OPEN for under-sampled or absent directions: a promoted candidate in a direction with n=14 and average R of -3.0 (or no validation history at all) could still reach paper_trade_only. Promotion eligibility now requires a direction PROVEN positive (>= min samples AND avg R > 0); negative, under-sampled, and absent cohorts are all non-promotable. Tests at n=14 and missing-direction added. 2. Gap-through-stop losses were floored at -1R, inflating the average_r_multiple that hard-gates promotion (a true -2.75R cohort scored +0.5R). Stops now fill at the bar's open when it gaps past the stop; favorable gaps through the target stay conservatively capped at the target. 3. The journal/adaptive-policy path still labeled outcomes by the sign of the close at horizon - the exact optimism the lab upgrade removed. Extracted the barrier walk into scanner/edge/outcomes.py (one source of truth) and the outcome reviewer now applies the same triple-barrier definition (ATR-proxy risk, 2R target) with a close_horizon fallback when sessions lack OHLC; outcome_method is recorded per row. Also from the review: brief.py now guards present-but-null report values (_int/_num helpers), and the loosening cooldown normalizes tz-naive timestamps instead of silently skipping the check. Verified: 142 tests passed, compileall OK. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t sets the label Closes the adversary's remaining LOW: a stopped-out-then-recovered trade recorded a loss label but a positive close-at-horizon return. The reviewer now stores outcome_return_pct from the barrier exit (close-horizon fallback keeps parity) and adaptive-policy metrics prefer it, with outcome_ret_5bar_pct preserved as the legacy close metric. 143 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…RA NBBO) Wires the researched $0 data upgrade: with TRADIER_API_TOKEN set (a PRODUCTION brokerage token; sandbox is 15-min delayed), option selection uses Tradier's OPRA-consolidated chains first - real NBBO bid/ask with sizes, native volume and open interest, ORATS greeks, and a true quote timestamp. - Tradier-first with honest semantics: liquidity-gate failures are authoritative (no fallback to lower-grade data to force a pass); only infrastructure failures (auth/transport) fall back to the legacy indicative pipeline, with a warning. - options_data_quality: 0.9 for fresh OPRA-consolidated quotes (execution-grade, clears the audit's 0.75 bar during market hours), degrading past 30 minutes so after-hours scans stay research-grade. - Handles Tradier's single-item payload collapse, ms-epoch quote timestamps, and both directions; bid/ask sizes recorded on OptionsContractResult. - Options gates now read config via module attributes so tuning overrides apply without a process restart (first slice of the hot-reload fix). Verified: 7 new tests (ATM selection, authoritative gate fail, infra fallback, no-token path, stale-quote degradation, payload collapse, puts) + live production smoke: SOFI 2026-08-21 18C bid 1.93 ask 1.95 spread 1.0% OI 9561 sizes 6x9 greeks present; after-hours quality 0.7 as designed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
reload_overrides() updated module globals, but most consumers imported the tunable constants by name and froze them at import time - so overrides applied mid-process (research_ops applies adaptive policy, then runs research_scan in the SAME process) silently did not affect the Potter gates, empty-space gates, Kronos agreement gate, or options gates until the next process start. Worse, autotune proposals stepped from the import-time defaults instead of the effective values. - potter_box: ATR/range/no-trend compression gates read scanner_config attributes. - empty_space: MIN_EMPTY_SPACE_SCORE / MIN_RR via attributes. - kronos_adapter: MIN_KRONOS_AGREEMENT via attributes. - autotuner: proposal bases read effective values, not defaults. - main.py: removed dead MIN_RR / MIN_EMPTY_SPACE_SCORE imports. - options_data was converted in the Tradier commit. Regression tests: reload updates all 10 tunables; the empty-space gate flips with live config; autotune steps from the effective MIN_RR. Also: scanner/README.md documents the wired Tradier provider and the remaining equity-feed upgrade paths. Verified: 153 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…piration Unquotable rows (zero bid, crossed, zero strike) are filtered before the ATM pick so a quote-less nearest strike falls through to the nearest LIVE strike; spread/OI gates still apply to the pick. 8 Tradier tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The adapter passed bars.index (DatetimeIndex) to KronosPredictor, which uses the .dt accessor and expects Series - so every inference crashed with "'DatetimeIndex' object has no attribute 'dt'". Latent forever: the strict pipeline never reached the Kronos stage, and the first real invocations (research candidates, wired earlier today) surfaced it. Verified live after the fix: model loads, samples 10 paths, returns multi_path_agreement with a real agreement figure. - kronos_adapter: x/y timestamps wrapped in pd.Series; regression test drives evaluate() through a fake predictor asserting Series types. - research journaling honesty: an adapter error (agreement None) is no longer journaled as kronos_passed=False - that would have poisoned the kronos_lift measurement with infra failures dressed as disagreements. Warning logged, fields omitted, test added. - brief: options guidance updated for the wired-Tradier reality (stale-after-hours explanation and intraday-run next action instead of "open an account"). Verified: 156 tests passed; live probe returns agreement 0.30 on random-walk bars (correctly no edge in noise). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…review Future-dated quote timestamps (clock skew / corrupt feed epoch) now read as unknown age instead of fresh, so they cannot claim execution-grade quality. reload_overrides() resets tunables whose override keys were removed to their module defaults instead of keeping stale values until restart; malformed override values also fall back to defaults instead of raising. Tests for both. 157 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… nits) Kronos eval failures journal a kronos_eval_error field so a persistently broken model surfaces in the brief and adaptive report (rows_with_eval_errors) instead of looking like normal early accumulation. Int tunables accept float-looking override strings. 157 tests passed. Adversary closing verdict: HOLDS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- add REPO_MAP.md naming the three products (upstream model, desktop app, scanner evidence lab); link it from README.md and README_JAKE.md; scanner/README.md stays the live docs - fix stale CUDA/RTX claims (README_JAKE.md, launch_kronos.bat banner, kronos_app.py sub-header) — venv torch is 2.7.0+cpu, CPU-only - reconcile pins with the installed venv: flask-cors 6.0.2, plotly 6.7.0, numpy 2.4.6, yfinance 1.2.1, pytest 9.0.3 across requirements.txt, pyproject.toml, scanner/requirements-scanner.txt, webui/requirements.txt; pip --dry-run confirms pins == installed - install_deps.bat: drop dead ccxt and the unpinned CUDA torch install; now bootstraps venv/ if missing and delegates to setup_dependencies.bat - delete stale LLM_PROJECT_MEMORY.md (superseded by REPO_MAP.md) and the empty .venv/ stub — venv/ is the only environment verified: pytest 162 passed, doctor status ok Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zero-memory operation: - Windows scheduled task "Kronos Daily Research Ops" runs scanner\run_research_ops_scheduled.bat every weekday at 13:30 Central (14:30 ET, mid-session so Tradier quotes are execution-grade), wakes the PC, catches up after missed starts, and propagates the python exit code. Registered and verified (next run confirmed). - Every ops run (and --mode brief) delivers a condensed phone-sized brief to Telegram when TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID are set: verdict, gate progress, scan, journal/policy state, Kronos health, next action. Best-effort and fail-safe; status report only - live alerting stays evidence-gated. (Creds are currently EMPTY in .env; path verified to no_credentials gracefully.) Kronos research fix shiyu-coder#2 (stacked behind the Series fix): - The research path builds ~42-46 synthetic sessions from the 60-day intraday window, but the adapter demanded 60 bars - Kronos could never run on research candidates. New KRONOS_MIN_BARS=30 floor; the adapter uses available history up to the 60-bar lookback. - End-to-end verified on real data: F, 46 sessions, model sampled 10 paths, 50% directional agreement journal-ready. Also: scanner/reports/daily_brief.md untracked + gitignored (runtime artifact), exit-geometry config knobs land with this commit (their consumer wiring follows from the exit-geometry work stream). Verified: 162 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First lab run (20260702T190537Z-c0d68cd8) showed the edge score ranks raw 5-bar returns (IC .075, p .002) while the encoded plan bleeds (bearish avg R -.152, t -7.5; ~66% target-hit rate yet negative avg R): the nearest empty-space target sits too close to the stop. - resolve_plan_target_pct in edge/outcomes.py: nearest_empty_space / next_empty_space / atr_multiple target modes plus an R-floor, measured against the resolved stop; every branch keeps the 2x-risk degenerate fallback so the baseline mode reproduces the original geometry exactly. - empty_space diagnostics now report the next-further level. - Index records carry target_pct_used/target_mode provenance; the validation report stamps exit_geometry_config. - Consumes the KRONOS_EXIT_TARGET_* env knobs from 37917f4 so lab sweeps flip variants per process without code edits. - Live gates, live plan encoding, and the journal reviewer untouched. Verified: 174 tests passed; single-ticker smoke shows the 1.5R floor engaging on 141/179 SOFI candidates (confirms targets sit inside 1.5R). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
webui/prediction_results/ is gitignored (.gitignore:90), but these 29 prediction_20250826_*.json outputs were committed before the ignore rule existed and stayed tracked — contradicting the doctor hygiene check's intent that web prediction outputs stay out of git (CONCERNS.md "Dead code and upstream dead weight"). git rm --cached only; files remain on disk and are now properly ignored. verified: check-ignore passes (example probe + real file), doctor status ok, pytest 174 passed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e edge Six-variant walk-forward sweep on identical data (11,033 index records, 1,500 validation samples, all logged as exit_geometry_trial in the trial registry): bullish avg R by target geometry - nearest empty-space level (old): -0.014 (t -0.82) next-further level: -0.016 (t -0.97) 1.5R floor: +0.135 (t +4.46) 2.0R floor: +0.153 (t +4.77) 2x ATR: +0.158 (t +4.92) no target (stop/horizon only): +0.195 (t +5.16) <- shipped Monotone dose-response: the further the target, the better, saturating at none. The bullish edge is a right-tail drift edge; the old nearest-level exits cashed 68% of trades at +0.11R while stops cost -1.04R. Decomposition: no-target horizon exits average +0.53R. Bearish stayed negative under all six geometries (-0.14 to -0.25, |t| >= 6.4) - structurally bad post-2015, remains direction-blocked. With honest geometry the audit now shows promotable=[bullish], blocked=[bearish]; overall readiness stays "blocked" (within-direction ranking skill still unproven - score calibration is the next stream; no gate was touched). "none" is a first-class mode: resolve_plan_target_pct returns a None target and walk_triple_barrier skips the target barrier (the 2x-risk fallback stays for degenerate numeric targets). Confirmation run 20260702T235540Z-d09ea09b reproduces the swept v5 bit-for-bit. Verified: 177 tests passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…contract Ground-truth accuracy fixes for every R-multiple the evidence engine computes: - Edge-index daily bars now fetch adjustment='split' (config EDGE_BARS_ADJUSTMENT, env KRONOS_BARS_ADJUSTMENT for sweeps, not an adaptive tunable). Raw bars let splits/dividends read as real price moves inside the 5-bar outcome window; the top ticker by record count (AGNC) distributes ~1%/month. - yfinance daily fallback stamps its true basis (Yahoo is always split-adjusted) and logs provider fallbacks instead of failing silent. - _to_ny_index no longer shifts naive midnight DATE indexes to the prior NY evening via the UTC assumption. - New fail-closed OHLCV bar contract (scanner/data/bar_contract.py): hard invariants fail the ticker at index build; split-sized one-bar moves surface as warnings in the index report. - _alpaca_get retries transport exceptions with the same budget as retryable HTTP statuses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'purged_walk_forward' label was only partially true: allow_future blocked future ENTRIES, but analogs entered 1-8 days before the query had 5-trading-bar outcome windows extending past the query bar - their realized R (not knowable at query time) fed analog_expectancy, leaking concurrent-week market moves into apparent ranking skill. - EDGE_EMBARGO_DAYS 5 -> 9 and EDGE_CROSS_TICKER_EMBARGO_DAYS 1 -> 9 calendar days: covers the 5-bar horizon worst case incl. a holiday. - Validation report stamps purge_config provenance. - Regression tests pin horizon coverage and the unresolved-outcome exclusion. Honest numbers may drop; that is the point. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The declared frontier is 'does anything rank R inside bullish' - but no per-direction rank IC existed anywhere, and every inferential stat treated 910 overlapping trades as independent. - by_direction validation blocks now carry: within-direction rank IC (score vs R and vs return) with a day-clustered p-value, day-clustered t on R, tercile lift with a day-block bootstrap CI (deciles at n~900 are noise: ~0.12-0.15R SE per bucket), and a tail-retention diagnostic (share of >=2R trades captured by the top tercile - the veto that stops mean-R calibration silently repeating what profit targets did). - Mass score ties (51% of bullish walk-forward rows score exactly 0) previously handed decile membership to input recency via stable sort; tercile machinery breaks ties by deterministic hash instead. - Audit ranking gate now ALSO requires within-direction IC >= 0.07 with day-clustered p <= 0.05 in at least one direction: pooled IC could pass on bullish-vs-bearish separation while ranking nothing inside either direction. Fail-closed when per-direction blocks are absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
outcome_reviewer hardcoded a 2R profit target while the lab ships no-target (stop + 5-bar horizon) - so every journal label the adaptive policy and autotuner learn from described trades under a geometry that is no longer traded. The reviewer now routes through resolve_plan_target_pct (single source of truth with the lab) and stamps outcome_target_mode for provenance. Level-based sweep modes resolve to their documented 2R fallback at review time, identical to the old behaviour, so only mode 'none' changes labels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The frontier work. The composite score is a fail-closed evidence accumulator whose gate caps collapse walk-forward scores into ties (51% of bullish rows score exactly 0) - it cannot rank R within a direction, and monotone calibration of it never will. The literature's answer is meta-labeling (Lopez de Prado; Joubert et al. JFDS 2022-23): a secondary model predicting P(win) for setups the primary already surfaced, used only to rank/size within a direction, strictly downstream of every gate. scanner/edge/calibration.py (numpy-only; venv has no sklearn/scipy): - L2 logistic (IRLS) on 10 PRE-REGISTERED scale-free features led by relative volume/participation (the strongest published conditioner of short-horizon breakout outcomes); winsorize 1/99 + standardize, parameters frozen into a JSON-safe model dict. - Expanding-window walk-forward OOF evaluation: refit every 21 days, 9-day purge (outcome must be resolved before prediction time). - PRE-REGISTERED acceptance: OOF within-bullish rank IC >= 0.07 at day-clustered p <= 0.05, n >= 300, tercile spread CI low > 0, tail retention >= pro-rata (the right-tail veto - mean-R filters can silently repeat what profit targets did), and OOF Brier beating the base-rate Brier. Anything less ships the constant predictor. Wiring: run_validate_edge evaluates over the FULL index history, joins OOF p_win_meta onto validation candidates, reports report['meta_model'], persists the final model to reports/meta_model.json, and registers every evaluation as kind=calibration_trial. run_edge_scan attaches advisory p_win_meta/expected_r_meta to live bullish candidates without touching ranking or recommendations. conftest now isolates the trial registry and meta-model paths from tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reliability layer for the daily hands-off loop: - New scanner/utils/atomic_io.py (temp + fsync + os.replace, temp file in the target's own directory). Wired into: the 31MB edge index, the scan-decisions journal, tuning/overrides.json (both writers - a torn write there silently reverted every tuned gate AND lost the cooldown state), every edge report (the audit authorizes live mode), and the meta-model artifact. - load_decisions now recovers exactly one torn FINAL line by quarantining it (scan_decisions.quarantine.jsonl) and fails CLOSED on mid-file corruption - it previously deleted every unparseable row silently, shrinking the evidence base without a trace. - load_edge_index gives a clear rebuild instruction on corrupt JSON and ignores unknown record fields (a newer schema no longer TypeErrors the whole lab). - Live preflight rejects an edge audit older than 24h: a stale paper_trade_only verdict must not authorize live mode days later. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The first full-history evaluation FAILED acceptance and proved P(win) anti-informative for this right-tail edge (top tercile +0.06R vs bottom +0.20R, tail retention 0.25 < 0.33): high-p_win annotations on live candidates would invite exactly the trade selection the evidence rejects. run_validate_edge now persists meta_model.json only when the pre-registered acceptance passes and removes any stale artifact otherwise, so run_edge_scan's advisory join goes silent instead of misleading. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial review verdict on the changeset: HOLDS (brute-forced 5y of NYSE holiday calendars: 0 strict outcome-window leaks at purge=9; no self-training; 0 join-key collisions on the real index; 0/20 pure-noise datasets accepted). One confirmed-latent defect fixed here: - An all-NaN feature column (feature outage / un-backfilled new key) poisoned winsorize bounds -> NaN standardization -> NaN IRLS weights, and predict returned NaN (which 'is None' checks miss), silently annotating live candidates. Fit now neutralizes dead columns, refuses to return non-finite parameters, predict fails closed on non-finite z, and the live join double-checks isfinite. - tercile/tail bucket size guard (ordered[-0:] returns the whole list). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Jake's directive: the system must improve itself - no human remembering to 'rerun with a different objective'. The calibration frontier now runs as a pre-registered THREE-OBJECTIVE suite on every lab run: p_win L2 logistic on R>0 (control arm - proven anti-informative) expected_r L2 ridge on R (hunts magnitude) tail_prob L2 logistic on R>=2 (hunts the right tail directly) Autonomy contract, enforced in code: - every objective's out-of-fold evaluation registers in the trial registry every run (the multiple-testing ledger keeps counting); - a model ships as the live advisory ONLY on the two-touch rule: pass the pre-registered acceptance on THIS run AND the previous registered run (read back from the registry, not a mutable state file); - if several qualify, highest current OOF rank IC ships - deterministic, pre-registered, no human pick; - otherwise nothing ships and take-all-bullish stays the policy. Advisory annotations are objective-aware (meta_objective, meta_score, expected_r_meta where defensible). trial_registry gains load_trials (torn-tail tolerant). 237 tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hion Options DTE used the machine (Central) date instead of the exchange date; Yahoo ex-dividend epochs were rendered in local time, shifting the date back a day. Yahoo forward earnings dates are estimates with documented off-by-one failure modes, so the block window gains a +1 day cushion and a stale past date now blocks as unknown-next-earnings instead of passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ompleteness Deterministic stale-feed rules (5+ identical closes / 4+ identical OHLCV bars fail daily evidence; warn-only intraday since quiet 30m bars can legitimately repeat), zero-volume-with-range and forward-filled flat bars as hard violations, and a split-ratio snap test on overnight gaps that catches the 3:2 splits the 45% move rule misses. New session-completeness check diffs daily bars against the NYSE calendar (pandas_market_calendars, new pinned dep) so halted/partially-delivered histories fail out of evidence. Also bumps yfinance 1.2.1 -> 1.5.1 (1.5.0 is retracted upstream). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…finance repair Alpaca adjustment=split adjusts price AND volume on every timeframe, so all intraday fetches now request it - a split inside the 60d window no longer reads as a giant gap in the synthetic sessions. drop_in_progress_daily_bar removes the current session still-forming daily bar (the 13:30 CT scheduled run was ingesting ~60%-of-a-day bars as the newest evidence every day). The yfinance daily fallback runs repair=True (fixes Yahoo unapplied splits and 100x glitches) and stamps repaired-bar provenance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The evidence index build now runs session-completeness and, when a Tradier production token is configured, cross-checks each ticker daily RETURNS against Tradier /markets/history - returns, not levels, so the vendors different adjustment bases cancel while a missed split shows as one 33%+ single-day divergence. One >20pp session or a >5% flagged-day rate fails the ticker for the run (Alpaca has documented missing-split-factor lapses); no token or transport failure is skipped, never a block. The index report records per-ticker cross-check results and dropped partial bars. conftest scrubs provider credentials from the test environment so pytest can never reach live APIs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…antine Outcome resolution - the ground truth behind autotune and the adaptive policy - was walking triple-barrier paths on live IEX bars: ~3% of the tape with structurally clipped High/Low (stop AND target touches under-detected) and raw adjustment. Resolution happens days after the decision, so the free 16-minute-delayed SIP feed applies; bars are now consolidated and split-adjusted. Corrupt bars (contract violations) block resolution for retry instead of becoming labels, and a split between decision and review is quarantined via an entry-vs-decision-session-close scale check ([0.75,1.33]) rather than resolving to a fabricated stop-out. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Validation
Rebased onto current upstream
masterat67b630eand re-ran:venv\Scripts\python.exe -m pytest -q-> 78 passedvenv\Scripts\python.exe -m compileall scanner tests webui kronos_app.py model-> passedvenv\Scripts\python.exe -m pip check-> no broken requirementsvenv\Scripts\python.exe -m scanner.main --mode doctor-> status okgit diff --check origin/master...HEAD-> passedGitHub State
jakehiggins89/Kronos:codex/finish-kronos-cleanupshiyu-coder/Kronos:masterMERGEABLE/CLEAN.jakehiggins89does not haveMergePullRequestpermission onshiyu-coder/Kronos.