Install other symbols' bars for request.security in the Docker harness (--symbol-feeds) - #327
Merged
Merged
Conversation
docker/run_json.py --symbol-feeds (PINEFORGE_SYMBOL_FEEDS in the entrypoint)
reads a JSON index of other symbols' bars, keyed by the exact symbol string a
script passes to request.security and by timeframe, and installs each symbol's
catalog syminfo (tickerid as canonical, type, timezone, session, currency,
mintick) and feeds through strategy_set_symbol_facts and
strategy_set_symbol_feed, which engine and codegen have shipped since 1.0.0
but no release harness called. A feed is an OHLCV CSV like --ohlcv; each
bar's close is its open plus the timeframe unless a time_close column gives it.
Everything is checked before the first strategy state: timeframe spelling
(bare D/W/M/S folded, "4h" refused), one feed per timeframe, CSV columns and
numbers, increasing opens, closes at or before the next open, mintick, the
256-feed cap. A refusal, a library without the setters or a feed the engine
refuses is the structured {"engine","error"} line (harness exit 1, entrypoint
exit 4), like a rejected --syminfo. What was installed is recorded as
applied_runtime.symbol_feeds (facts, bar counts, first/last open, a value
hash), so such a run has its own fingerprint; without --symbol-feeds the
report is unchanged.
Stacked on harness/syminfo-mincontract (#322): it reuses that change's
structured-failure path in main().
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Every refusal is the structured line, never a traceback: a feed that is not UTF-8 (or a CSV error), a time outside +-(2^53-1) ms or a monthly close outside the calendar, a mintick integer beyond binary64, a symbol or fact string with a lone surrogate, an index nested past the recursion limit. - A header-only feed is installed without bars, as the engine documents it (its requests read na), instead of refused. - An empty time_close cell falls back to open plus timeframe; a UTF-8 BOM is read; error line numbers are the CSV's own (blank lines counted). - Install-time refusals carry the same "--symbol-feeds:" prefix. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The harness README gains a limits bullet (256 symbols and 256 feeds, the chart as its own input with the engine's exact error, historical runs only, the cost of a feed, request.security_lower_tf) and states that a feed must be at the timeframe it serves: the engine aggregates only the chart's own input and the C ABI has no call that aggregates bars, so a 1m feed serves neither a 240 nor a D request. The CHANGELOG entry says the same. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review fixes. Inside the request syminfo.tickerid is always the key and
syminfo.ticker the key after its last ":"; the catalog tickerid is set as the
canonical fact, which no syminfo.* reads. The no-aggregation bullet now says
why (the engine looks a feed up by exact symbol and timeframe and installs its
bars as given) instead of claiming no C call aggregates. The missing-feed
sentence covers an index that lacks the requested symbol or timeframe, and the
refusal list is marked as examples ("timestamps that do not strictly
increase").
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
luisleo526
force-pushed
the
symfeeds/run-json-symbol-feeds
branch
from
October 4, 2026 04:52
6cc8247 to
673e95b
Compare
luisleo526
added a commit
that referenced
this pull request
Oct 4, 2026
Brings the branch up to date with main 4f2a475 (#325 7b59662, #327 4f2a475) so the release notes merge last, as the merge order now asks. Conflicts resolved neutrally; the next commit does the editing: - CHANGELOG.md: this branch's 1.1.0 section, with main's two new Unreleased bullets ("Confirmed-bar streams compute what the batch computes:" from #325, "Harness symbol feeds:" from #327) kept verbatim inside it; main's "## Unreleased" heading and its older copies of the bullets this branch already rewrote are not taken. - README.md: #325's known-issue lines replace this branch's "Known issue (v1.0.0, v1.0.1, v1.1.0)" line from a80485c. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
luisleo526
added a commit
that referenced
this pull request
Oct 4, 2026
… rule #325 (confirmed-bar streams compute what the batch computes) and #327 (docker/run_json.py --symbol-feeds) merged before the release notes, so their Unreleased bullets join the 1.1.0 section, rewritten and linked; no Unreleased heading stays. - CHANGELOG.md: the lead names the stream fix and, in the pairing sentence, codegen 1.1.0's request discovery (transpile_full()["requests"], codegen #164). #325's bullet says what a stream user sees; #327's bullet and its Report keys entry (applied_runtime.symbol_feeds, the --symbol-feeds: failure messages). A new State hashes section lists the four recipe additions since v1.0.1 (#315, #316, #319, #325; none removed, renamed or re-encoded; domain tags unchanged). #315's range-end equity-extreme change moves to the Pine adapter parity bullet as a behaviour fix. The #319 bullet named the broker-state hash; the change is in the native continuation hash, which the broker-state hash folds. The known-issue bullet now says it is fixed in 1.1.0 (#325). Migration gains a line on stream results and hashes. - README.md: the known issue is fixed in 1.1.0 (#325); the v1.1.0 Releases line gains the stream fix, request discovery and the harness's multi-symbol request.security feeds. Fact markers rendered from the facts export that maps releases[1.1.0] to pineforge-parity-baseline-20261004-engine-7b596622 (7,951 excellent / 38 strong of 7,989); the active scoreboard moves to the same baseline, here and in docs/pages/contributing-llm.md. - docs/pages/streaming.md: the known issue affected v1.0.0 and v1.0.1 and is fixed in 1.1.0. - docs/pages/public-contract.md: the state-hash rule, amended by the owner's ruling for 1.1.0. It covers the recipe only: a minor release may add a hashed field (domain tags unchanged, the added field changing no trade or report, disclosed under State hashes); removing, renaming or re-encoding a hashed field is a new epoch and a major release; behaviour changes follow the normal release and parity rules. The first uses are #315 and #316. The semver rule is unchanged. Replaces text introduced by 7b59662 (#325): CHANGELOG.md's "Confirmed-bar streams compute what the batch computes:" bullet, and the "Fixed on main (#325); included in the next release." lines of README.md and streaming.md; by 4f2a475 (#327): CHANGELOG.md's "Harness symbol feeds:" bullet; by d093560 (#290): public-contract.md's "State-hash values are stable within the epoch." and "a new recipe is a new epoch and a major release"; by a80485c (this branch's first commit): the "Known issue, as in v1.0.0 and v1.0.1" bullet, streaming.md's "(v1.0.0, v1.0.1, v1.1.0)", the #319 bullet's "A tick stream's broker-state hash folds the new accumulator state only where it adds information, so the existing tick, bar and batch hash pins hold.", the Report keys failure-output bullet and the v1.1.0 Releases line; by 66be240 and 83d64dc: the lead's state-hash sentences ("Three changes also change what the hashes fold"); and, as git attributes them through this branch's merge of main, by e59c09f: README.md's v1.1.0 Releases line and streaming.md's "(v1.0.0, v1.0.1, v1.1.0)". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
luisleo526
added a commit
that referenced
this pull request
Oct 4, 2026
* docs: release notes and version scoping for v1.1.0 v1.1.0 is a minor release: <pineforge/pineforge.h> declares six more functions, the checked settings calls that a strategy generated by pineforge-codegen 1.1.0 exports (#317). It pairs with pineforge-codegen 1.1.0. PF_ABI_VERSION stays 4 (pineforge.h only gains declarations; native_c_api.h and the native C++ host headers are unchanged) and the script ABI epoch stays engine_script_run_v19. - CHANGELOG.md: "## Unreleased" becomes "## 1.1.0 — 2026-10-04": a lead paragraph, one bullet per change a user can observe since v1.0.1 (#312-#324), each linking its PR, a Report keys subsection (docker/run_json.py v1.0.1 -> v1.1.0) and a Migration subsection. The three Unreleased bullets stay; the lot-grid bullet now gives both failure messages. - README.md: pineforge-codegen==1.1.0, the v1.1.0 tarballs, the pairing sentence, the stream known issue's scope, the benchmark refresh line, the release scoreboard sentence (releases[1.1.0] markers) and a v1.1.0 line in Releases. The public corpus sweep's "311 excellent + 1 declared anomaly" is scoped to the v1.0.1 library it was measured on. Facts rendered from the facts file that adds releases[1.1.0]; the active scoreboard markers move to baseline pineforge-parity-baseline-20261003-engine-dbd17b38. - docs/pages/install.md: the v1.1.0 tarballs and the hub tag engine1.1.0-codegen1.1.0. - docs/pages/public-contract.md: 1.1.0's release line, engine v1.1.0 with codegen 1.1.0 among the supported pairs, and the four C-boundary rows that were planned for 1.1.0 are not in it. - docs/pages/streaming.md: the known issue's scope includes v1.1.0. Lines that state what an earlier version shipped or did stay. Replaces text introduced by dc74e63 (#318): README.md's "Release 1.0.1 still grades ... until the next release" sentence, now 1.1.0's; by d093560 (#290): public-contract.md's "Four of its rows are planned for 1.1.0"; by 783bb39 (#322): CHANGELOG.md's "The engine library is unchanged."; by dbd17b3 (#320): CHANGELOG.md's "The engine is unchanged."; by b2a578c (#300): README.md's "this repository's sweep: 311 excellent + 1 declared anomaly"; by 271d687 (#311): README.md's "its releases 1.0.0 and 1.0.1 do". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: state the 1.1.0 hash folds and scope two runner sentences The 1.1.0 lead now says how state-hash values change while the epoch and the domain tags stay: a run whose fills an adapter change alters hashes to new values, and three changes fold more state, so a run can hash differently from 1.0.1 with byte-identical trades: #315 (an unbatched same-bar entry request and placement; the stream report's terminal re-mark leaves the hashed extremes; witness row Stream/0/1 re-pinned), #316 (an opening stop's next waypoint; Random44/0/0 and /1 re-pinned) and #319 (tick-volume state, every existing pin kept). In the runner tooling bullet, "No versioned engine PF_API export ... changes" and "Plugin-free ledger identity bytes remain unchanged" read as release-wide; they now speak for #320 itself and for a strategy without the checked settings calls. The Report keys intro points at the report schema page. The terminal-quote bullet names the chart feed that PINEFORGE_RUN_REPORT_CHART_QUOTE points at, and two runner bullet headings are re-wrapped. Replaces text introduced by a80485c (this branch's first commit): the lead's "A run whose fills one of the Pine adapter changes below alters hashes to new values, and [#316] adds one placement field to the adapter's hashed state, for which two witnesses with byte-identical trades were re-pinned.", the Report keys intro and the terminal-quote harness clause; and text introduced by dbd17b3 (#320): "No versioned engine PF_API export, native C++ surface, script ABI epoch or engine behavior changes." and "Plugin-free ledger identity bytes remain unchanged". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: #315's range-end change folds less, not more The 1.1.0 lead said three changes "fold more state"; #315's range-end change instead stops folding a stream report's terminal re-mark into the hashed extremes. The sentence now says the three changes change what the hashes fold, and names Stream/0/1 as a re-pinned witness row without claiming it is #315's only one. Replaces text introduced by 66be240 (this branch's second commit): "Three changes also fold more state" and "re-pinning one witness row (`Stream/0/1`, whose recorded-row digest alone moves)". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: fold #325 and #327 into 1.1.0, add State hashes, amend the hash rule #325 (confirmed-bar streams compute what the batch computes) and #327 (docker/run_json.py --symbol-feeds) merged before the release notes, so their Unreleased bullets join the 1.1.0 section, rewritten and linked; no Unreleased heading stays. - CHANGELOG.md: the lead names the stream fix and, in the pairing sentence, codegen 1.1.0's request discovery (transpile_full()["requests"], codegen #164). #325's bullet says what a stream user sees; #327's bullet and its Report keys entry (applied_runtime.symbol_feeds, the --symbol-feeds: failure messages). A new State hashes section lists the four recipe additions since v1.0.1 (#315, #316, #319, #325; none removed, renamed or re-encoded; domain tags unchanged). #315's range-end equity-extreme change moves to the Pine adapter parity bullet as a behaviour fix. The #319 bullet named the broker-state hash; the change is in the native continuation hash, which the broker-state hash folds. The known-issue bullet now says it is fixed in 1.1.0 (#325). Migration gains a line on stream results and hashes. - README.md: the known issue is fixed in 1.1.0 (#325); the v1.1.0 Releases line gains the stream fix, request discovery and the harness's multi-symbol request.security feeds. Fact markers rendered from the facts export that maps releases[1.1.0] to pineforge-parity-baseline-20261004-engine-7b596622 (7,951 excellent / 38 strong of 7,989); the active scoreboard moves to the same baseline, here and in docs/pages/contributing-llm.md. - docs/pages/streaming.md: the known issue affected v1.0.0 and v1.0.1 and is fixed in 1.1.0. - docs/pages/public-contract.md: the state-hash rule, amended by the owner's ruling for 1.1.0. It covers the recipe only: a minor release may add a hashed field (domain tags unchanged, the added field changing no trade or report, disclosed under State hashes); removing, renaming or re-encoding a hashed field is a new epoch and a major release; behaviour changes follow the normal release and parity rules. The first uses are #315 and #316. The semver rule is unchanged. Replaces text introduced by 7b59662 (#325): CHANGELOG.md's "Confirmed-bar streams compute what the batch computes:" bullet, and the "Fixed on main (#325); included in the next release." lines of README.md and streaming.md; by 4f2a475 (#327): CHANGELOG.md's "Harness symbol feeds:" bullet; by d093560 (#290): public-contract.md's "State-hash values are stable within the epoch." and "a new recipe is a new epoch and a major release"; by a80485c (this branch's first commit): the "Known issue, as in v1.0.0 and v1.0.1" bullet, streaming.md's "(v1.0.0, v1.0.1, v1.1.0)", the #319 bullet's "A tick stream's broker-state hash folds the new accumulator state only where it adds information, so the existing tick, bar and batch hash pins hold.", the Report keys failure-output bullet and the v1.1.0 Releases line; by 66be240 and 83d64dc: the lead's state-hash sentences ("Three changes also change what the hashes fold"); and, as git attributes them through this branch's merge of main, by e59c09f: README.md's v1.1.0 Releases line and streaming.md's "(v1.0.0, v1.0.1, v1.1.0)". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <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.
What
docker/run_json.pygains--symbol-feeds <index.json>, anddocker/entrypoint.shmapsPINEFORGE_SYMBOL_FEEDSto it. The flag installs other symbols' bars forrequest.securityon another symbol. Engine and codegen have supported such requests since 1.0.0 (engine #292, codegen #146/#148). Until now the release harness had no way to hand them the bars, so every such run whose request value reaches an order stopped with exit 4 (request.security(...) at line N: no data is pinned for this request, and its value was read).{"symbols": {"BINANCE:ETHUSDT": {"syminfo": {...the symbol's catalog object...}, "feeds": {"240": "ethusdt-240.csv", "1D": "ethusdt-1D.csv"}}}}pine_security_eval.cpp:1031).BINANCE:ETHUSDT,ETHUSDTandBINANCE:ETHUSDT.Pare three symbols. Forinput.symbol, the key is the input's value."240", never"4h"), else<n>D|W|M|S, and bareD/W/M/Sfold to1D/1W/1M/1S.time_closecolumn.syminfo:type,timezone,session,currencyandmintickare whatsyminfo.*reads inside the request.tickeridis set as thecanonicalfact, which nosyminfo.*reads: inside the requestsyminfo.tickeridis always the key, andsyminfo.tickeris the key after its last:(pine_security_eval.cpp:1089-1109).mintick, at most 256 symbols and 256 feeds. Then a library without the setters, or a feed the engine refuses. Every refusal is one{"engine":"pineforge","error":"--symbol-feeds: ..."}line (harness exit 1, entrypoint exit 4).applied_runtime.symbol_feeds: the facts, and per feed the bar count, first and last open, and a value hash underpf-symbol-feed-barc-close-le-v1. It is fingerprinted, so such a run has its own digest.{"symbols": {}}: the report is byte-identical, apart fromelapsed_seconds.The engine library and the C ABI are unchanged; the harness calls the existing
strategy_set_symbol_factsandstrategy_set_symbol_feed. Docs:docker/README.md("Other symbols' bars": field, keys, spelling, the missing-feed error, refusals, limits, record), the entrypoint header andCHANGELOG.md(Unreleased, the 1.1.0 entry). The release repo's own entrypoint line is pineforge-4pass/pineforge-release#23.One feed per requested timeframe (the 1m question)
The app asked whether a feed may be 1m bars for a request at
240orD, with the harness or engine aggregating it. Answer: no, not in 1.1.0. Each requested timeframe needs its own feed.PF_APIdeclarations inpineforge.h(62 implemented in the static runtime, the rest emitted per strategy), nor anything innative_c_api.h, takes raw bars and hands back aggregated ones.strategy_set_symbol_feedcopies the bars verbatim, keyed by (key, tf); the only change is foldingDto1D(pine_security_eval.cpp:1251-1294). The lookup is exact (:1031).native_run_spec.hpp:481-484,native_execution_consumer.cpp:8574-8600).strategy_set_native_security_feed, works on the chart symbol's own daily feed (a W/M request reads it folded per week or month).NativeExecutionConsumer::contribute_input(native_execution_consumer.cpp:8340-8400), aligned to session and timezone bynative_calendar::interval_containing. It is hidden C++. The only C-reachable route to it is a whole native-kernel run per feed through the native-host API (strategy_native_host_create_v1/strategy_configure_native_ext_v1/strategy_native_run_v1with anon_barcallback). That means mirroring four structs in ctypes and running a broker kernel just to bucket bars, so it is not taken. Per the brief, there is no second aggregator in Python either.input '1' aggregated to chart '240' is not supported(pine_security_eval.cpp:1045-1051). So an app that runs such a script already fetches the chart at the script timeframe, and can fetch the other symbols the same way.PF_API int pf_aggregate_bars_v1(bars, n, input_tf, target_tf, timezone, session, out_bars, out_close_ms, capacity). It runs the chart's own fold through a privateNativeStrategyHost, so its output matches the chart path by construction. The harness would then accept a"1"feed and aggregate it with that call. The acceptance test is ready: the case below fed 1m bars must give the same 12 rows. On this window Binance's 4h and 1d klines equal the UTC aggregation of its 1m klines (E2E data check), so the test is well posed.E2E (AWS spot box, c6a.2xlarge, ap-southeast-1): PASSED on 6cc8247 with release #23 head 3475b0c
The rebase onto main 7b59662 (#325) gives head 673e95b and leaves
docker/byte-identical:git diff 6cc82475 673e95b8 -- docker/is empty, and both heads have the samedocker/tree9c6ccaa1. Only the CHANGELOG bullet moved, to follow #325's. So these results hold for this head.Two images from pineforge-release's
docker/Dockerfile(engine 1.0.1 static library + codegen 1.0.1, the latest releases).run_json.pyis synced from the engine commit, asscripts/sync-harness.shdoes from a tag:sf-pr: release PR head (its entrypoint) + this PR'srun_json.py(sha256afaa6952…, the same file as the prototype's final pass);sf-main: release main + engine main'srun_json.py.The shared XSYM case (BTCUSDT 4h chart;
input.symbol("BINANCE:ETHUSDT")requested attimeframe.periodand atD), withcheck_case.py:feeds(ETHUSDT at 240 and 1D)applied_runtime.symbol_feedshashes recomputed from the CSVs: CASE PASSEDno_feedsrequest.security(other, timeframe.period, ...) at line 7: no data is pinned for this request, and its value was read: PASSEDbare_key(keyedETHUSDT)no_daily(240 only)"D"error: PASSEDsol_input(inputBINANCE:SOLUSDT)"4h"timeframe in the index--symbol-feeds: a timeframe is whole minutes ...line: PASSEDsf-mainwithPINEFORGE_SYMBOL_FEEDSsetThe qty-step case (#322) is unchanged on
sf-pr: 22 rows withmincontract, 27 without, withnulland with no syminfo (itscheck_case.pyPASSED ×4).Scripts that request no other symbol give reports byte-identical to
sf-main(elapsed_secondszeroed): the four qty-step runs (digestssha256:b9e00cb9…with the grid,sha256:e4315ec2…without), theno_feedserror line, and a qty-step run with{"symbols": {}}set.applied_runtimehas nosymbol_feedskey without the variable. The 101 harness tests pass on the box (Linux).The 1m question on the same case (same
sf-primage; Binance ETHUSDT and BTCUSDT 1m klines over the case window, 573,120 and 525,600 bars):1feedrequest.security(other, timeframe.period, ...) at line 7: no data is pinned .... A 1m feed serves neither the 240 nor the D request1plus240and1DPINEFORGE_INPUT_TF=1,PINEFORGE_SCRIPT_TF=240) with the tf feedsrequest.security of another symbol needs the chart's own bars as input; input '1' aggregated to chart '240' is not supportedpf_aggregate_bars_v1fed 1m must therefore reproduce the 12 rowsTests
docker/run_json_symbol_feeds_test.py(new, pytest): index and entry shapes, duplicate keys, timeframe spelling and folding, CSV columns, numbers, BOM, empty volume,time_close, monotonic opens and closes, caps, facts andmintick, setter order and arguments, refusal by the engine with its last error, a library without the setters, the record and its hash,main()with the report and fingerprint, the structured failure in the body run and in both bench loops, and no change without the flag. All 101 tests indocker/pass on this head, on macOS and on Linux (the box). As with the olderdocker/*_test.py, nothing registers them with ctest or CI; they run withpython3 -m pytest docker/.docker/run_json.py,docker/run_json_symbol_feeds_test.py,docker/entrypoint.sh,docker/README.mdandCHANGELOG.md, therelease-harnesscategory of ruleno-behaviour-diff/v3. The six-step lab jobrj-20261004t045310-66dd70(preflight, release, debug, sanitizers, kernel, docs) runs on this exact head (tree48100d11, 5 files since 7b59662: docs 2, release harness 3);pineforge/verifyandpineforge/parityare posted from it via the diff rule. The pre-rebase head 6cc8247 passed the same gate (jobrj-20261004t034744-44c80c).🤖 Generated with Claude Code