Skip to content

Add selected-window backtests with retained pre-roll - #363

Merged
luisleo526 merged 1 commit into
mainfrom
win-rc1-landing
Oct 10, 2026
Merged

luisleo526 merged 1 commit into
mainfrom
win-rc1-landing

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Add an opt-in selected-window mode. A run evaluates retained bars from before the requested window to initialize strategy state, then reports only the activity inside the window. The last pre-roll evaluation may produce an order that fills at the first bar of the window, never earlier. The selected report starts flat at initial capital, carries a separate anchor, and reports the retained, pre-roll and window bar counts separately. With the mode off, every existing output is unchanged.

The development candidate supports the admitted intraday chart timeframes and compatible clock identities. Trusted admission refuses unsupported chart or request-feed timeframes, and incomplete or mismatched request inventories, before any feed is opened or any strategy is loaded. Execution completion is reported before result assembly, so a report failure after that point stays distinct from a strategy failure.

Report-only terminal-quote writers after the seal: once a selected run is sealed, these writers leave the stored quote and the captured report unchanged. The C++ setters raise the named exception selected_window_query_after_seal before storing anything. The C metadata setter keeps its existing void ABI, so its refusal is observable only through the status reader: hosts call strategy_state_query_status_v1, and PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1 now means that these report-only quote writes are refused as well as the state reads it already covered. This extends the documented scope of that status value, and hosts may rely on it. A refusal does not replace the run's first error or status, and no new run failure is latched after a completed execution. Setter behaviour in ordinary mode is unchanged. Because that refusal never reaches a run, its three throws in the source layer are admitted by a row of the run-failure throw allowlist rather than given a run-failure code; the run-failure catalog's release diff is regenerated from the unchanged catalog.

A selected Pine run on an aggregating chart counts the script bars it executes without re-checking the window end: the scheduler asks a new count_selected_executed_primary (the same request checks, clock admission, start alignment and row walk, with the end unbounded), because the end bounds none of the groups the consumer executes. count_selected_retained_primary keeps every end check. The new function is one additive declaration in the installed C++ header selected_window_plan.hpp; no C ABI symbol changes.

The native-counts test fixture now asks the kernel to record its curve. The product route runs KernelRecordedAtHostMarks; the native-counts fixture exercised a HostRecorded host that no product path in this release uses. The release image's backtest entry point is docker/run_json.py. Its selected run loads the transpiled strategy library, sets the window through strategy_set_selected_window_v1 and calls the generated run_backtest_full, whose strategy class derives from source::PineStrategyHost. PineStrategyHost::prepare_native_begin (src/source/pine_strategy_host.cpp:335) projects the run spec through PineExecutionAdapter::project, which sets spec.report_policy = NativeReportPolicy::KernelRecordedAtHostMarks (src/source/pine_adapter.cpp:2796), and nothing rewrites it before configure. That route passes on an aggregated chart: ROUTES-BATCH-TF (tests/test_selected_window_routes.cpp, check_pine_route) runs a PineStrategyHost 1 -> 15 with a selected window under its own projected policy and asserts a clean run that matches the ordinary run. The engine refuses a HostRecorded host that records nothing on purpose (test_selected_window_report_integration, wsr-mismatch). The fixture now asks the kernel to record (KernelRecorded); no CHECK, count or expected value changes. The release image's generated strategies take that route: the transpiler at 2e9aa21f emits "class GeneratedStrategy : public pineforge::source::PineStrategyHost {" (pineforge_codegen/codegen/base.py:4769), attaches the Pine execution adapter (emit_top.py:1157), and no non-test transpiler file names report_policy.

The pinned window of the two-entry same-open gate in tests/pine_input_domain_gates.json follows the split of apply_terminal_explicit_market_policy into a forwarding overload and a two-argument body: only the body's signature line gained ", bool execute_now"; the gate text, its old and new forms, line and evidence are unchanged.

New tests run a retained pre-roll on the product route (a Pine host under its own projected report policy on a 1 -> 15 chart with two pre-roll groups and an aligned window end), the planner-admitted window shape for the Pine timeframe route, the real planner and a real native run on the same rows, and count_selected_executed_primary directly. The verifier's test-count floors follow the fifteen new rows, set to the counts registered at this tree with a configure-only ctest -N on each profile's own definitions: RELEASE_MIN_TESTS 895, KERNEL_MIN_TESTS 325, EXCLUDED_REGISTERED_MIN debug 876, sanitizers 867, native 963, so a silent loss of any new row fails the check.

The documentation's source citations and stated ABI counts are brought up to date with the new code, and the verifier test's two ABI count constants follow the counts the ABI check derives. run-failure-codes.md said only window_mode_unsupported of the 24 selected-window and report-contract codes had a raise site. Twelve do, all in the Python wrappers under docker/ (the selected-window request refusals, the report-option refusals and report_post_execution_failed); the page now names them and the twelve with none. index.md and README.md counted 137 PF_API declarations across two headers. Every include/pineforge/*.h is installed, and five of them declare 145: pineforge.h 94, native_c_api.h 43, execution_observer.h 3, selected_window.h 3 and selected_window_plan.h 2. check_c_abi_runtime.py pins 80 runtime and 43 native symbols, not 81 and 43. abi-stability.md said enum values never change. This release renumbers RunFailureCode in the installed C++ header run_failure_codes.hpp: 36 of the 38 codes released in 1.4.0 get new numbers (none, chart_bars_rejected and chart_bars_unreadable keep their numbers). Codes cross the C boundary by name, so the page says who is affected. Two sentences of docs/pages/run-failure-codes.md are rewritten, not lost. From 65c69b0, "UTF-8, keys sorted, no whitespace; an integer argument is a JSON integer" is extended because the catalog gains the nullable_string and scalar argument kinds; it now lives in the same paragraph, which names both kinds. From 70ddaa3, "rows below are unreleased, targeted for 1.5.0, and not part of 1.4.0" is extended because the 24 selected-window and report-contract rows are unreleased as well; it now lives in the same sentence, which says so.

This is a development-only parity candidate. It advertises the selected-window contract revision 1.3-parity only, makes no claim of complete value-ownership coverage, declares no value sinks, reports lookback as explicitly unknown, and cannot be promoted to stable. Ordinary mode keeps its existing contract.

This change merges together with the paired transpiler change for 1.5.0-rc.1 (pineforge-codegen-oss #195).

🤖 Generated with Claude Code

Add an opt-in selected-window mode. A run evaluates retained bars from before the requested window to initialize strategy state, then reports only the activity inside the window. The last pre-roll evaluation may produce an order that fills at the first bar of the window, never earlier. The selected report starts flat at initial capital, carries a separate anchor, and reports the retained, pre-roll and window bar counts separately. With the mode off, every existing output is unchanged.

The development candidate supports the admitted intraday chart timeframes and compatible clock identities. Trusted admission refuses unsupported chart or request-feed timeframes, and incomplete or mismatched request inventories, before any feed is opened or any strategy is loaded. Execution completion is reported before result assembly, so a report failure after that point stays distinct from a strategy failure.

Report-only terminal-quote writers after the seal: once a selected run is sealed, these writers leave the stored quote and the captured report unchanged. The C++ setters raise the named exception `selected_window_query_after_seal` before storing anything. The C metadata setter keeps its existing void ABI, so its refusal is observable only through the status reader: hosts call `strategy_state_query_status_v1`, and `PF_STATE_QUERY_SELECTED_WINDOW_AFTER_SEAL_V1` now means that these report-only quote writes are refused as well as the state reads it already covered. This extends the documented scope of that status value, and hosts may rely on it. A refusal does not replace the run's first error or status, and no new run failure is latched after a completed execution. Setter behaviour in ordinary mode is unchanged. Because that refusal never reaches a run, its three throws in the source layer are admitted by a row of the run-failure throw allowlist rather than given a run-failure code; the run-failure catalog's release diff is regenerated from the unchanged catalog.

A selected Pine run on an aggregating chart counts the script bars it executes without re-checking the window end: the scheduler asks a new count_selected_executed_primary (the same request checks, clock admission, start alignment and row walk, with the end unbounded), because the end bounds none of the groups the consumer executes. count_selected_retained_primary keeps every end check. The new function is one additive declaration in the installed C++ header selected_window_plan.hpp; no C ABI symbol changes.

The native-counts test fixture now asks the kernel to record its curve. The product route runs KernelRecordedAtHostMarks; the native-counts fixture exercised a HostRecorded host that no product path in this release uses. The release image's backtest entry point is docker/run_json.py. Its selected run loads the transpiled strategy library, sets the window through strategy_set_selected_window_v1 and calls the generated run_backtest_full, whose strategy class derives from source::PineStrategyHost. PineStrategyHost::prepare_native_begin (src/source/pine_strategy_host.cpp:335) projects the run spec through PineExecutionAdapter::project, which sets spec.report_policy = NativeReportPolicy::KernelRecordedAtHostMarks (src/source/pine_adapter.cpp:2796), and nothing rewrites it before configure. That route passes on an aggregated chart: ROUTES-BATCH-TF (tests/test_selected_window_routes.cpp, check_pine_route) runs a PineStrategyHost 1 -> 15 with a selected window under its own projected policy and asserts a clean run that matches the ordinary run. The engine refuses a HostRecorded host that records nothing on purpose (test_selected_window_report_integration, wsr-mismatch). The fixture now asks the kernel to record (KernelRecorded); no CHECK, count or expected value changes. The release image's generated strategies take that route: the transpiler at 2e9aa21f emits "class GeneratedStrategy : public pineforge::source::PineStrategyHost {" (pineforge_codegen/codegen/base.py:4769), attaches the Pine execution adapter (emit_top.py:1157), and no non-test transpiler file names report_policy.

The pinned window of the two-entry same-open gate in tests/pine_input_domain_gates.json follows the split of apply_terminal_explicit_market_policy into a forwarding overload and a two-argument body: only the body's signature line gained ", bool execute_now"; the gate text, its old and new forms, line and evidence are unchanged.

New tests run a retained pre-roll on the product route (a Pine host under its own projected report policy on a 1 -> 15 chart with two pre-roll groups and an aligned window end), the planner-admitted window shape for the Pine timeframe route, the real planner and a real native run on the same rows, and count_selected_executed_primary directly. The verifier's test-count floors follow the fifteen new rows, set to the counts registered at this tree with a configure-only ctest -N on each profile's own definitions: RELEASE_MIN_TESTS 895, KERNEL_MIN_TESTS 325, EXCLUDED_REGISTERED_MIN debug 876, sanitizers 867, native 963, so a silent loss of any new row fails the check.

The documentation's source citations and stated ABI counts are brought up to date with the new code, and the verifier test's two ABI count constants follow the counts the ABI check derives. run-failure-codes.md said only window_mode_unsupported of the 24 selected-window and report-contract codes had a raise site. Twelve do, all in the Python wrappers under docker/ (the selected-window request refusals, the report-option refusals and report_post_execution_failed); the page now names them and the twelve with none. index.md and README.md counted 137 PF_API declarations across two headers. Every include/pineforge/*.h is installed, and five of them declare 145: pineforge.h 94, native_c_api.h 43, execution_observer.h 3, selected_window.h 3 and selected_window_plan.h 2. check_c_abi_runtime.py pins 80 runtime and 43 native symbols, not 81 and 43. abi-stability.md said enum values never change. This release renumbers RunFailureCode in the installed C++ header run_failure_codes.hpp: 36 of the 38 codes released in 1.4.0 get new numbers (`none`, `chart_bars_rejected` and `chart_bars_unreadable` keep their numbers). Codes cross the C boundary by name, so the page says who is affected. Two sentences of docs/pages/run-failure-codes.md are rewritten, not lost. From 65c69b0, "UTF-8, keys sorted, no whitespace; an `integer` argument is a JSON integer" is extended because the catalog gains the `nullable_string` and `scalar` argument kinds; it now lives in the same paragraph, which names both kinds. From 70ddaa3, "rows below are unreleased, targeted for 1.5.0, and not part of 1.4.0" is extended because the 24 selected-window and report-contract rows are unreleased as well; it now lives in the same sentence, which says so.

This is a development-only parity candidate. It advertises the selected-window contract revision `1.3-parity` only, makes no claim of complete value-ownership coverage, declares no value sinks, reports lookback as explicitly unknown, and cannot be promoted to stable. Ordinary mode keeps its existing contract.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread docker/run_json.py
try:
self.writer.advance(phase)
except self._error_type as error:
raise _typed_failure(error) from None

def test_non_sockets_are_rejected_and_left_open_and_untouched(self):
read_end, write_end = os.pipe()
null = os.open(os.devnull, os.O_RDWR)
]


_ABI_EXPORTS = ("pf_selected_window_version", "strategy_set_selected_window_v1",
import os
import subprocess
import tempfile
import unittest
import os
import socket
import sys
import unittest
import os
import socket
import time
import unittest
@luisleo526
luisleo526 marked this pull request as ready for review October 10, 2026 18:53
@luisleo526
luisleo526 merged commit 47184e5 into main Oct 10, 2026
11 of 20 checks passed
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