Repository navigation
Pine adapter: per-bar and per-fill walks read only the cohorts that hold an opening or live units, and the roster pass only the rosters with members (#452) - #458
Open
letiep97 wants to merge 2 commits into
Conversation
…4pass#452) Adds the uniqueids row to test_adapter_live_state_scaling: an opening every 20 bars under an id of its own, closed 10 bars later, without recording, the way scripts that tag every trade with its bar or time spell strategy.entry. The adapter keeps a cohort for every id the run has used and the kernel a roster for each, and walks over all of them ran on every bar and at every fill and placement, so the run cost the square of its trades. Fails at this commit (base 0212cab, macOS 15.8 arm64, Apple clang 17, Release): FAIL tests/test_adapter_live_state_scaling.cpp:476 ratio < kShapeBound ... 32000 bars 0.3703s (1600 trades, ...), 128000 bars 8.4500s (6400 trades, ...), ratio 22.82 (bound 5.0) Signed-off-by: letiep97 <15042016+letiep97@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e units, and the roster pass only rosters with members (pineforge-4pass#452) cohorts_by_id_ / cohort_order_ keep a cohort for every entry id the run has used, and the core a CohortRoster for each handle; neither is pruned, since origin history and the state hash read them. The walks that only read `opened` and `live_units_by_origin` (source_entry_slot_count every bar, the two in erase_retired_rows, and some twenty at fills and placements) now go over held_cohort_ids_: the ids whose cohort holds an opening or live units, in cohort_order_ order, which is handle order. hold_cohort() adds an id when its cohort gains an opening; forget_emptied_cohorts() drops ids whose cohort lost its last opening and live units. Every non-Release read asserts the index equals what a full walk finds, in the same order. release_closed_cohort_origins keeps, in retired_row_scratch_, the handles of the rosters that hold members, fed by the core's append-only cohort_receipts() (only an applied add puts a member in a roster), and its four loops read those rosters only; non-Release builds assert the count against a walk over every roster. Both are derived: held_cohort_ids_ gets a waiver in broker_state_hash_waivers.txt, and the retired_row_scratch_ waiver names the roster memo. Not covered: a fill that reverses the position still calls cancel_exit_orders_for_full_close for every cohort id the run has used (on_applied, flipped_position branch). uniqueids row after: 128000 bars 0.1011 s, 512000 bars 0.4149 s, ratio 4.11 (bound 5.0). The pineforge-4pass#452 script on 702,505 BTCUSDT 5m bars: 232.09 s -> 1.72 s, trades and equity identical field by field. doc anchors: every pine_adapter.cpp / pine_adapter.hpp path:line anchor moved to the line its symbol now sits on (docs/adr/0001-kernel-adapter- boundary.md, docs/design/native-feature-parity.md, docs/native-refactor-progress.md, docs/pages/native-engine.md, two tests/ownership probe NOTES.md, six tests/*.cpp comments, and three comments in pine_adapter.cpp itself). corpus_parity_mutation_battery.tsv is left alone: its lines name an older tree already at base. Signed-off-by: letiep97 <15042016+letiep97@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #452.
What
PineExecutionAdapterkeeps a cohort incohorts_by_id_/cohort_order_for every entry id the run has used, and the core keeps aCohortRosterfor each of their handles; neither is ever pruned, and neither should be (origin history and the state hash read them). Several walks that only readopenedandlive_units_by_originwent over all of them: the open-entry count the scheduler publishes every bar (source_entry_slot_count), the two walks inerase_retired_rows, the bar-open roster pass inrelease_closed_cohort_origins, and some twenty more at fills and placements. A script that gives each position an id of its own therefore paid the square of its trade count. This change addsheld_cohort_ids_, the ids whose cohort holds an opening or live units, kept incohort_order_order (which is handle order) asopenedandlive_units_by_originchange, and points those walks at it.release_closed_cohort_originskeeps a memo of the rosters that hold members, fed by the core's append-onlycohort_receipts()(only an applied add puts a member in a roster), and its four loops read those rosters only. Both are derived, not state:held_cohort_ids_is waived inbroker_state_hash_waivers.txtlike the other indexes, and the roster memo lives inretired_row_scratch_, whose waiver now says so. In every non-Release read,held_cohort_ids()asserts the index equals the cohorts a full walk finds, in the same order, andsource_entry_slot_countand the roster pass assert their totals against the walks they replace. Trade lists and equity are unchanged.Not covered: a fill that reverses the position still collects every cohort id the run has used and calls
cancel_exit_orders_for_full_closefor each (on_applied, theflipped_positionbranch). For an id that matches nothing, that call still sweepsbracket_families_, so narrowing the set is not obviously equivalent; I left it for you to judge. On the synthetic below, the reversing variant goes from 219.6 s to 23.6 s, against about 1.4 s with fixed ids.The anchor moves are mechanical: every
pine_adapter.cpp/pine_adapter.hpppath:lineanchor in docs and test comments was remapped to the line its symbol moved to (check_doc_anchors.py: 1742/1742).scripts/corpus_parity_mutation_battery.tsvis left alone: its lines already name an older tree at base.Evidence
New row
uniqueidsintests/test_adapter_live_state_scaling.cpp: an opening every 20 bars under an id of its own, closed 10 bars later, no recording. Failing before, this TU against base0212cabe(macOS 15.8 arm64, Apple M1 Pro, Apple clang 17, Release):After:
python3 scripts/ci_verify.py release --build-dir build-ci-release --jobs 8(full population, no label excluded),build-ci-release/ci-summary.json:ci_verify.py kernel: not run. Its configure stops atCould NOT find CURL: Found unsuitable version "8.7.1", but required is at least "8.14.1"(the macOS SDK's libcurl, for the native runner). This change only compiles withPINEFORGE_BUILD_SOURCE_LAYER, which that profile turns off.ctest, Debug build with the new asserts on, every target,-j8 -E '^test_ci_verify$':That row expects a
RecursionErrorthat Homebrew Python 3.14.6'sjsonno longer raises; it fails the same way on base0212cabeand passes under Python 3.14.4, whichci_verifyused../scripts/check_corpus_parity.sh --subset:./scripts/check_corpus_parity.sh(full sweep):python3 scripts/ci_preflight.py: 48 passed, 4 failed, 1 skipped.actionlint-version,shellcheck-versionandworkflow-lintfail because neither tool is installed here;run-json-harness-testshas 9 failures from Python 3.14's argparseprog(usage: python3 -m pytest ...), identical on base.The script from #452 and three variants (fixed ids; reversing with
strategy.entryalone instead ofstrategy.close_all()first), Binance spot BTCUSDT 5m, 2020-01-01 to 2026-09-07, 702,505 bars, 13,500 trades each, onerun_backtest_fullper run, strategy built-O2against each tree's Releaselibpineforge.a. Trades and equity hashed field by field; every run on both trees printedtrades=13500 net=-286.760100 trades_sha=d6a9d963a7427d46 equity_sha=658408382d422c20 equity_len=702505.0212cabeclose_allfirst (#452)close_allfirst (median of 10)Out of scope: with recording on,
hash_statestill walks every cohort, and each id used keeps about 5 KB (about 271 MB RSS at 51k ids).🤖 Generated with Claude Code