Skip to content

Complete the bounded paper-learning loop - #7

Draft
Jerrycyborg wants to merge 2 commits into
mainfrom
codex/paper-learning-loop
Draft

Complete the bounded paper-learning loop#7
Jerrycyborg wants to merge 2 commits into
mainfrom
codex/paper-learning-loop

Conversation

@Jerrycyborg

Copy link
Copy Markdown
Owner

Outcome

Completes the bounded paper-learning milestone while preserving a hard separation from real-money authority.

What changed

  • establishes one configured trading-loop owner and drains the oldest pending entries before generating more;
  • runs champion and registered paper challengers on the same observed market snapshot;
  • persists deterministic signal traces, paper fills, round trips, learning cycles, proposals, and champion/challenger comparisons;
  • adds authenticated learning-curve/proposal APIs and an admin-only proposal-to-paper transition;
  • keeps challenger adoption, promotion, live-mode activation, and deployment as separate named-human actions;
  • hardens the paper broker with sleeve isolation, durable replay records, stale-position-generation protection, atomic persistence, strict corrupt-state refusal, and reserved exit capacity;
  • serializes the PostgreSQL challenger-cap decision across processes;
  • bounds learning inputs to recent executions while correctly handling carry-in positions and reversals through flat;
  • makes the handoff checksum manifest deterministic by excluding generated Python caches.

Safety boundary

This PR does not enable live mode, auto-promote a strategy, auto-adopt a challenger, deploy services, or grant the learner broker/lifecycle transition authority.

Verification

  • ruff check .
  • pytest -q with a disposable local-only internal key: 904 passed, 140 skipped
  • handoff manifest regenerated and validated: 120 source files
  • git diff --check
  • Codex Security diff scan: no reportable security vulnerabilities; four paper-integrity candidates found during review were reproduced, fixed, and regression-tested

The skipped tests require PostgreSQL and are intentionally exercised by repository CI.

Known blockers before real money

  • paper fills remain a simplified simulator (no partial fills, order-book queue, borrow, volume impact, or corporate-action model);
  • the paper broker is single-process file-backed state;
  • daily drawdown input is not yet wired to a measured source;
  • market-hours/EOD handling needs exchange-calendar and DST correctness;
  • arbitrary non-default champion strategy identity needs a persisted signal schema field;
  • native live-broker close idempotency must be separately verified;
  • the learning curve is exposed as an API but not yet rendered in the dashboard.

These are explicit follow-up gates, not hidden behind this PR.

Jerrycyborg pushed a commit that referenced this pull request Sep 3, 2026
The trading worker suppresses a BUY when ADX is below 20 or unmeasurable and
when volume does not exceed its 20-bar average. The backtest modelled neither,
so every result described a strictly more permissive strategy than the one
that trades — and whether those gates earn the entries they remove had never
been tested. They were applied on faith.

BacktestRequest gains regime_gate and volume_gate, both defaulting to off so
existing results stay comparable, applied at engine._compute_signals — the
single choke point where the rule's output becomes the traded series, which
mirrors live's "gates sit in front of the rule". run_edge_study now runs each
cost case twice and reports the difference, judging its verdict on the gated
stress case because that is the configuration that actually trades.

indicator_series gains adx_series: the live gate reads one scalar ADX from the
whole window it holds, so reproducing it per bar is an expanding window, and
recomputing the scalar at every bar is quadratic across trials and folds. This
runs the Wilder recursion forward once, including the branch where fewer DX
values than the period are averaged rather than smoothed.

entry_gates is a deliberate second copy of live's filters and says so. ADR-006
puts the one true definition in a shared library; that extraction is blocked
behind PR #7, which is itself refactoring the live gate, so touching worker.py
now would only create a conflict. test_entry_gates.py is what makes the
duplicate safe in the meantime: it pins adx_series to compute_adx at every
prefix length and asserts the gate decides bar-for-bar what live decides,
including the boundaries that are easy to get wrong — an unmeasurable regime
refused rather than passed on the 25.0 sentinel, and volume equality failing.

Verified by breaking: relaxing the volume comparison to >=, dropping the
measurability check, and corrupting the ADX seed branch each fail a test.
Suite: 1008 passed, 7 skipped offline; ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019shd9XwPXFFf1NqVMVoiAB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant