Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Exploratory paper runs

Owner direction, relayed by the CC on 2026-10-10 at 18:39 UTC:
They authorized paper and sim exploration without approval or qualification
prerequisites, covering all factors and leverage modes, including aggressive
presets. The direction is for exploratory paper and simulation runs to cover
every registered preset and the `leverage-schedule-v1-20260922` rungs: 1脳, 2脳
and 4脳 intraday, with overnight exposure capped at 2脳. That coverage is not in
place yet; [Remaining execution work](#remaining-execution-work) lists what
still blocks it. The frozen qualification trials and their retained records
under `trials/` stay frozen, and `scheduled_trial.sh` still supplies both
proofs. Heavy simulations run one at a time, paced to the host's capacity: none
starts while the host is low on available memory.

`runner.py paper` can start without `--gate-result` and `--snapshot`.
Supplying either argument requests qualification validation, so both must then
be supplied and the existing status, snapshot hash, row count and check
validation applies. The paper receipt's `preflight` block records
`promotion_gate`: `validated` when either argument requested validation and
`not_supplied` when neither was given. This follows the mover runner's existing
optional-proof behavior and marker. The `preflight` and `recover` commands
retain their existing behavior and add no marker.

Startup readiness remains separate from qualification. `validate_preflight`
still checks account readiness, cash/equity, broker margin entitlement,
session/window availability, flat startup, asset tradability and benchmark
freshness. Account locking, reconciliation, request budgets, deterministic risk
limits, fee/cash accounting and durable trial state continue through the same
code paths.

Measured broker-paper acceptance for this change is **NOT_RUN**. CLI tests use
fixture credentials and a synthetic broker observation and stop before native
execution. They establish optional qualification wiring and continued account
readiness checks.

## Remaining execution work

- No runner or configuration alias for the exploratory paper runs has been
verified. This change does not select an account or operate the frozen
qualification trials' state.
- The existing config-hash continuity check still raises
`next_trial_config_differs_from_frozen_limits` for a changed configuration on
the same account's next trial. Removing mandatory qualification does not
enable same-account preset/rung rotation. Retain the account's existing state
root and ledger, fee and cash continuity when resolving that limitation.
- The bounded source review of main at `03a986ed` and T22 at `a9e4eeb7` found
no production paper dispatch caller for T22's factor/cohort strategies. T22
documents that it supplies no paper command. Its native synthetic corpus
receipts measure engineering behavior; broker-paper execution, historical
performance and empirical preset refits remain unmeasured. Each future refit
must have appropriate results and a new preset version.

## Sources and regression evidence

Mechanism references are pinned to native-agent-stack main
`03a986ed637349403658f23da694c1833527819d`:

- [mover_runner.py:703](https://github.com/seathatflowsinourveins/native-agent-stack/blob/03a986ed637349403658f23da694c1833527819d/blueprints/us-equities/adaptive-paper/mover_runner.py#L703)
selects promotion validation only when either optional proof path is supplied;
[mover_runner.py:704](https://github.com/seathatflowsinourveins/native-agent-stack/blob/03a986ed637349403658f23da694c1833527819d/blueprints/us-equities/adaptive-paper/mover_runner.py#L704)
records that selection as the preflight summary's `promotion_gate` marker.
- [runner.py:2310](https://github.com/seathatflowsinourveins/native-agent-stack/blob/03a986ed637349403658f23da694c1833527819d/blueprints/us-equities/adaptive-paper/runner.py#L2310)
shows the prior unconditional paper selection corrected here;
[runner.py:661](https://github.com/seathatflowsinourveins/native-agent-stack/blob/03a986ed637349403658f23da694c1833527819d/blueprints/us-equities/adaptive-paper/runner.py#L661)
keeps qualification dispatch separate from ordinary readiness checks.
- [runner.py:2434](https://github.com/seathatflowsinourveins/native-agent-stack/blob/03a986ed637349403658f23da694c1833527819d/blueprints/us-equities/adaptive-paper/runner.py#L2434)
binds next-trial configuration and the following fee/cash continuity checks.
- [T22 README.md:54](https://github.com/seathatflowsinourveins/native-agent-stack/blob/a9e4eeb7f5ffc4cc1ce67b22746225684a8859ae/blueprints/us-equities/strategies/README.md#L54)
records the absent paper command at that strategy source pin.

`tests/test_adaptive_paper_runner.py::MainCommandGateWiring` drives the public
CLI. The no-proof test failed first with `promotion_gate_missing`. Its
`promotion_gate` assertions failed first against the previous runner.py, with
`None != 'not_supplied'` for both no-proof tests and `None != 'validated'` for
the valid complete proof. The suite also covers a blocked account without
proof, either proof argument alone, invalid complete proofs and unchanged
recovery and preflight behavior; recovery adds no marker. Run the touched module with the installed combined native
runtime: `python -B -m unittest tests.test_adaptive_paper_runner -v`.
21 changes: 15 additions & 6 deletions blueprints/us-equities/adaptive-paper/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,8 +645,9 @@ def validate_preflight(observation, config, *, require_open, allow_existing=Fals
allow_existing_positions=None, session_policy=None,
mode=None, gate_result_path=None, snapshot_path=None):
"""``mode="paper"`` additionally requires a passing, hash-matched promotion
gate (see ``_check_promotion_gate``); ``mode=None`` (the default) preserves
prior behavior exactly for existing preflight/recover call sites.
gate (see ``_check_promotion_gate``); ``mode=None`` (the default) skips it
for the preflight/recover call sites and for paper without either proof
argument.

``allow_existing`` (recovery mode, only set by ``--command recover``)
relaxes the cash/equity floor, the full-universe/benchmark-quote checks
Expand Down Expand Up @@ -2223,13 +2224,13 @@ def main():
parser.add_argument("--trial", default="adaptive-20260921")
parser.add_argument("--state-root", type=Path, default=DEFAULT_STOP.parent)
parser.add_argument("--gate-result", type=Path, default=None,
help="promotion-gate result JSON from "
help="optional qualification result JSON from "
"blueprints/us-equities/data/promotion_gate.py; "
"required (status pass, hash-matched) for `paper`")
"supply with --snapshot to validate a frozen qualification")
parser.add_argument("--snapshot", type=Path, default=None,
help="the exact bars/universe input file the promotion "
"gate validated (its hash must match --gate-result's "
"input_sha256); required for `paper`")
"input_sha256); required only with --gate-result")
parser.add_argument("--live-dir", type=Path, default=None,
help="optional directory for a live record of this run: events.jsonl "
"(decisions and intents as they happen) and NautilusTrader's own "
Expand Down Expand Up @@ -2307,7 +2308,15 @@ def observe_request(kind, **kwargs):
save(args.output, summary)
print(json.dumps({k: summary[k] for k in ("status", "orders_submitted")}, default=str))
return 0 if summary["status"] == "ready" else 2
gate_mode = "paper" if args.command == "paper" else None
gate_mode = "paper" if (
args.command == "paper"
and (args.gate_result is not None or args.snapshot is not None)
) else None
# The paper receipt's preflight block states whether qualification proofs
# were validated, as mover_runner.py's paper command records it. recover
# adds no marker: the paper receipt that admitted the trial carries it.
if args.command == "paper":
summary["promotion_gate"] = "validated" if gate_mode else "not_supplied"
# Rebase review D1: overnight_holds relaxes the flat-account/no-open-orders
# gate only to resume a trial this engine itself left "held_overnight".
# A first trial (or any other prior phase) still requires a flat account,
Expand Down
4 changes: 2 additions & 2 deletions blueprints/us-equities/adaptive-paper/source-hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"blueprints/us-equities/adaptive-paper/recovery.py": "76c1b6e21e39e1c87138ffa9e3dd4323e599d9f59af406807213f71eb3661259",
"blueprints/us-equities/adaptive-paper/registry.json": "60da73b985e718bd1dece7a3350f34636bda0fb38e766a44ae71c5a8c532282a",
"blueprints/us-equities/adaptive-paper/requirements.txt": "6859f3c7362730fb1e1f023777863dc70650607c90873836b99c4e7d63982216",
"blueprints/us-equities/adaptive-paper/runner.py": "19c079e32397532818a14d2919d7fa83c21e3eaf7f4c9c93be39c0d8a309030e",
"blueprints/us-equities/adaptive-paper/runner.py": "d7f83441269de29ea31d6eef328220aac40b463722a604ec68d3409da06b94d4",
"blueprints/us-equities/adaptive-paper/safety.py": "bfec57e021b65aee058c8d2e7c0cbafad46f6203edbe9396eec739c8546b0fd9",
"blueprints/us-equities/adaptive-paper/scheduled_trial.sh": "58a5b656875bda629443768cd0c69a4be28cbf90dfc9f5ae8782d7dcf3ac7d76",
"blueprints/us-equities/adaptive-paper/selector.py": "28de8ebf66b6e7135979554f73692ede772167682007d8c6ba41da6fb6fb39b3",
Expand All @@ -53,7 +53,7 @@
"tests/test_adaptive_paper_mover_native.py": "cc12a556b537cbe53f23c10e524dd6b3dfe9b3b09b09326aa4413ed7c19d83c1",
"tests/test_adaptive_paper_native.py": "728458624788243abcaf653f6a20a5a6201cfa9ec3328e8d7eb3fd58fdfa94b0",
"tests/test_adaptive_paper_recovery.py": "688e23f102249d170bf03d6a8d06196a42472cea049453228e4831a436c602ce",
"tests/test_adaptive_paper_runner.py": "5a1b81190e368c8891babb62f0c58b74eb5c898b4119f3bbfb8e146fd3c4d42f",
"tests/test_adaptive_paper_runner.py": "b3505e592b78beec416433c8d4b15991a34da2a84fb013712028715398d920d6",
"tests/test_adaptive_paper_safety.py": "dda093e5428a58ac667ae4d9a620acbf7ee78b8b26db83fccf08b530f1e58c7e",
"tests/test_adaptive_paper_selector.py": "27b431ac7911372d050f25d32ac24a3df9d2cf3c5e7dafdebfe51db6cab55936",
"tests/test_adaptive_paper_sessions.py": "dbb85e80b045c42dfed2ac90e0653a39b77718352d511b2e919f3311139abc70",
Expand Down
20 changes: 13 additions & 7 deletions blueprints/us-equities/data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,17 @@ are fetched fresh at preflight time, not read from a stored file), and
`config.json` itself cannot be the gated "snapshot": `promotion_gate.py`
only accepts `.parquet`/`.csv`/`duckdb://` input, so pointing it at a JSON
config always fails closed with `unsupported_input_format`. Instead,
`runner.py`'s `main()` registers `--gate-result <path>` and `--snapshot
<path>` CLI arguments; for the `paper` command (not `preflight`, not
`recover`, which resumes a trial admitted by an earlier `paper` invocation)
it calls `validate_preflight(..., mode="paper", gate_result_path=args.gate_result,
snapshot_path=args.snapshot)`. The gate result must satisfy the full
contract -- every required key present, every named check passing,
`runner.py`'s `main()` registers optional `--gate-result <path>` and
`--snapshot <path>` CLI arguments. For the `paper` command (not `preflight`,
not `recover`, which resumes a trial admitted by an earlier `paper`
invocation), supplying either argument requests validation: `main()` calls
`validate_preflight(..., mode="paper", gate_result_path=args.gate_result,
snapshot_path=args.snapshot)`. Without either argument, `paper` runs the same
readiness checks with `mode=None`, as the mover runner does
([README-paper-exploration.md](../adaptive-paper/README-paper-exploration.md)).
The paper receipt's `preflight` block records `promotion_gate` as `validated`
or `not_supplied`. When validation is requested, the gate result must satisfy
the full contract -- every required key present, every named check passing,
`row_count > 0`, a top-level `status: "pass"`, and an `input_sha256` matching
a `--snapshot` file the gate itself could accept (`.csv`/`.parquet`) -- or the
runtime raises `SafetyError` with kind `promotion_gate_missing` (no result
Expand All @@ -177,7 +182,8 @@ named check reports `status: "fail"` despite a "pass" top-level status),
`promotion_gate_empty` (`row_count <= 0` despite a "pass" top-level status),
`promotion_gate_failed` (top-level `status != "pass"`), or
`promotion_gate_mismatch` (hash does not match the current file). `mode=None`
(the `preflight` and `recover` call sites) is unaffected. `--snapshot` must
(the `preflight` and `recover` call sites, and `paper` without either
argument) skips this check. `--snapshot` must
name an actual bars/universe input file that
was run through `promotion_gate.py`. [`ingest_snapshot.py`](ingest_snapshot.py)
(added in #84) writes one: a bounded, read-only Alpaca daily-bar snapshot of
Expand Down
19 changes: 12 additions & 7 deletions manifests/evidence.json
Original file line number Diff line number Diff line change
Expand Up @@ -12855,6 +12855,11 @@
"sha256": "ae35cb8901695fecade818c8cb78ea0c738db2bbf5d6413d36893d5cca4713d4",
"bytes": 14691
},
{
"path": "blueprints/us-equities/adaptive-paper/README-paper-exploration.md",
"sha256": "b89575f2015573e0aea5480f419319370fb6b1baac767cc1ad4c9ae69978fc09",
"bytes": 5393
},
{
"path": "blueprints/us-equities/adaptive-paper/README-recovery.md",
"sha256": "aee5231130eb08d2f3008a1b62ef3d0f302e5527c7ea6843d1f9e8bd820199a2",
Expand Down Expand Up @@ -13217,8 +13222,8 @@
},
{
"path": "blueprints/us-equities/adaptive-paper/runner.py",
"sha256": "19c079e32397532818a14d2919d7fa83c21e3eaf7f4c9c93be39c0d8a309030e",
"bytes": 155497
"sha256": "d7f83441269de29ea31d6eef328220aac40b463722a604ec68d3409da06b94d4",
"bytes": 155977
},
{
"path": "blueprints/us-equities/adaptive-paper/safety.py",
Expand All @@ -13242,7 +13247,7 @@
},
{
"path": "blueprints/us-equities/adaptive-paper/source-hashes.json",
"sha256": "4a78486aec53ccbcce6cffeadae0a246c0b2c96e95a2a6a96da6e38ebfdf69f0",
"sha256": "be95543d4ff7a3b82f86b515947f7bd8c2d6b678789a1f7e43226b5314c19b4b",
"bytes": 7312
},
{
Expand Down Expand Up @@ -14602,8 +14607,8 @@
},
{
"path": "blueprints/us-equities/data/README.md",
"sha256": "8810322b8daa2459970f15432bea4c8476a683742327a81320f514ac50f544de",
"bytes": 12108
"sha256": "535a6945f5e6dd36740ca53a30840a1f81f3bc2d76397fde89ac72bc9d33412f",
"bytes": 12525
},
{
"path": "blueprints/us-equities/data/fixtures/bad-gate-result.json",
Expand Down Expand Up @@ -60087,8 +60092,8 @@
},
{
"path": "tests/test_adaptive_paper_runner.py",
"sha256": "5a1b81190e368c8891babb62f0c58b74eb5c898b4119f3bbfb8e146fd3c4d42f",
"bytes": 286409
"sha256": "b3505e592b78beec416433c8d4b15991a34da2a84fb013712028715398d920d6",
"bytes": 288091
},
{
"path": "tests/test_adaptive_paper_safety.py",
Expand Down
Loading
Loading