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
334 changes: 287 additions & 47 deletions CHANGELOG.md

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/pages/contributing-llm.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ a **kernel** that matches triggers, prices fills, books lots and settles, and a
it. A separate project transpiles PineScript into C++ that attaches the
adapter. The engine's value is that its output is *byte-reproducible* and graded
*trade for trade against TradingView* on a fixed population (<!-- pf:scoreboard.population|int -->8,006<!-- /pf --> probes at
the current baseline; <!-- pf:scoreboard.excellent|int -->7,949<!-- /pf --> of the <!-- pf:scoreboard.graded|int -->7,989<!-- /pf --> graded are excellent, <!-- pf:scoreboard.strong|int -->40<!-- /pf --> strong), so
the current baseline; <!-- pf:scoreboard.excellent|int -->7,951<!-- /pf --> of the <!-- pf:scoreboard.graded|int -->7,989<!-- /pf --> graded are excellent, <!-- pf:scoreboard.strong|int -->38<!-- /pf --> strong), so
almost every rule below exists to keep a change from quietly moving a byte.

## Repo map
Expand Down
22 changes: 11 additions & 11 deletions docs/pages/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,24 @@ ${prefix}/
## Prebuilt tarballs

A release attaches the library prebuilt to its GitHub release. For
[v1.0.1](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.0.1)
they are `pineforge-v1.0.1-linux-x86_64.tar.gz`,
`pineforge-v1.0.1-linux-aarch64.tar.gz` and
`pineforge-v1.0.1-macos-universal.tar.gz` (one archive for arm64 and x86_64),
[v1.1.0](https://github.com/pineforge-4pass/pineforge-engine/releases/tag/v1.1.0)
they are `pineforge-v1.1.0-linux-x86_64.tar.gz`,
`pineforge-v1.1.0-linux-aarch64.tar.gz` and
`pineforge-v1.1.0-macos-universal.tar.gz` (one archive for arm64 and x86_64),
each with a `.sha256`. A tarball unpacks to one directory,
`pineforge-v1.0.1-<platform>/`, laid out as the install above (both archives,
`pineforge-v1.1.0-<platform>/`, laid out as the install above (both archives,
`include/pineforge/`, `lib/cmake/PineForge/`), with `LICENSE`, `NOTICE` and
`VERSION` beside them:

```bash
curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.0.1/pineforge-v1.0.1-linux-x86_64.tar.gz
curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.0.1/pineforge-v1.0.1-linux-x86_64.tar.gz.sha256
sha256sum -c pineforge-v1.0.1-linux-x86_64.tar.gz.sha256 # macOS: shasum -a 256 -c
tar -xzf pineforge-v1.0.1-linux-x86_64.tar.gz
curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.1.0/pineforge-v1.1.0-linux-x86_64.tar.gz
curl -LO https://github.com/pineforge-4pass/pineforge-engine/releases/download/v1.1.0/pineforge-v1.1.0-linux-x86_64.tar.gz.sha256
sha256sum -c pineforge-v1.1.0-linux-x86_64.tar.gz.sha256 # macOS: shasum -a 256 -c
tar -xzf pineforge-v1.1.0-linux-x86_64.tar.gz
```

A CMake consumer finds it with
`-DCMAKE_PREFIX_PATH=$PWD/pineforge-v1.0.1-linux-x86_64` (@ref integration_cmake).
`-DCMAKE_PREFIX_PATH=$PWD/pineforge-v1.1.0-linux-x86_64` (@ref integration_cmake).
The package config asks for Eigen 3.3 or later (`find_dependency(Eigen3 3.3)`):
install it on Linux (`libeigen3-dev` on Debian and Ubuntu); the macOS tarball
carries Eigen 3.4.0's headers and CMake package, which the same prefix finds.
Expand All @@ -89,7 +89,7 @@ with the hub's own version (`X.Y.Z`, `X.Y`, and `latest` for the newest stable
one), with `engine<E>-codegen<C>` naming the pair it carries, and with
`sha-<short>`; a release candidate gets no `latest`. Pin the
`engine<E>-codegen<C>` tag of the engine release you build against: for
v1.0.1, `engine1.0.1-codegen1.0.1`, the image the hub also tags `1.0.1`.
v1.1.0, `engine1.1.0-codegen1.1.0`, the image the hub also tags `1.1.0`.

```bash
docker pull ghcr.io/pineforge-4pass/pineforge-release:latest
Expand Down
63 changes: 36 additions & 27 deletions docs/pages/public-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

1.0.0 was released on 2026-09-30: engine v1.0.0 with pineforge-codegen 1.0.0.
1.0.1 followed on 2026-10-02: engine v1.0.1, which changes only documentation,
with pineforge-codegen 1.0.1. From 1.0.0 the engine's version number is a
with pineforge-codegen 1.0.1. 1.1.0 followed on 2026-10-04: engine v1.1.0, which
adds six functions to the C ABI (the checked settings calls of
`<pineforge/pineforge.h>`, which a strategy generated by codegen 1.1.0 exports),
with pineforge-codegen 1.1.0. From 1.0.0 the engine's version number is a
semantic version over the surfaces this page lists, and over nothing else: a PATCH release fixes behaviour, a
MINOR release adds to a surface, and only a MAJOR release removes or changes
one. Each rule below names the checker or the CTest row that holds it on this
Expand Down Expand Up @@ -126,24 +129,30 @@ and `<pineforge/native_module.hpp>` (@ref native_engine).
mismatched pairs to fail on the epoch-qualified
`BacktestEngine::broker_state_hash` symbol (`scripts/ci_verify.py` requires
their prepared receipts, so none of them skips there).
- **State-hash values are stable within the epoch.** The recipe of each state
hash — the broker-state hash (`strategy_broker_state_hash`, the per-bar
`pf_report_t::broker_state_hash` rows), the stream fingerprint
(`strategy_stream_state_hash`) and the native continuation hash — belongs to
the epoch, so from 1.0.0 every 1.x engine folds one state to one value, and
a new recipe is a new epoch and a major release. Values from builds before
1.0.0 are not comparable. `scripts/check_aggregate_cpp_versions.py` and
`scripts/check_broker_state_hash_coverage.py` pin the domain tags
`pineforge-broker-state/v19` and `pineforge-source-adapter/v4` and the
stream fingerprint's version 19; witness rows pin values —
- **State-hash recipes belong to the epoch.** The recipe of each state hash,
which fields it folds and how they are encoded, for the broker-state hash
(`strategy_broker_state_hash`, the per-bar `pf_report_t::broker_state_hash`
rows), the stream fingerprint (`strategy_stream_state_hash`) and the native
continuation hash, is the epoch's. A minor release may change a recipe only
by adding a hashed field, with the domain tags unchanged and only when the
added field changes no trade or report; its CHANGELOG discloses the addition
under *State hashes*, because state hashes from earlier releases of the epoch
will not match. A recipe change that removes, renames or re-encodes a hashed
field is a new epoch and a major release. Behaviour changes, fixes that
change values, trades or reports while the recipe stays the same, are not
recipe changes: they follow the normal release and parity rules. The first
uses of the addition rule are #315 and #316, in 1.1.0. Values from builds
before 1.0.0 are not comparable. `scripts/check_aggregate_cpp_versions.py`
and `scripts/check_broker_state_hash_coverage.py` pin the domain tags
`pineforge-broker-state/v19` and `pineforge-source-adapter/v4` and the stream
fingerprint's version 19; witness rows pin values —
`test_native_host_hash_extension`, `test_native_lean_path`,
`test_native_match_hash_witness`, `test_native_continuation_view`,
`test_adapter_quiet_bar`, `test_publication_witness` among them. Two
limits: the native continuation hash folds the resolved timezone's
resource digest, so a tzdata release that rewrites a zone moves the value of
a run in that zone (`test_native_report_truth` states why it pins no raw
continuation value), and no row pins a `strategy_stream_state_hash` value
directly.
`test_adapter_quiet_bar`, `test_publication_witness` among them. Two limits:
the native continuation hash folds the resolved timezone's resource digest,
so a tzdata release that rewrites a zone moves the value of a run in that
zone (`test_native_report_truth` states why it pins no raw continuation
value), and no row pins a `strategy_stream_state_hash` value directly.

## The 1.0 C-surface boundary

Expand All @@ -158,22 +167,22 @@ COVERAGE block, a named `ENUM_TWINS` exclusion, or a `C_V1_EXCLUSIONS` row of
neither twinned to its kernel enumeration nor declared C-only, when a
`C_V1_EXCLUSIONS` row's C++ declaration goes or its C spelling appears, and
when that table cites a `C_V1_EXCLUSIONS` row once too few or too many.
Four of its rows are planned for 1.1.0: a non-mutating execution preview, the
origin and label of an applied event, a closed-trade entry-comment accessor
and a replace-options word. Nothing in 1.0 promises C and C++ parity beyond
the fields and calls the C surface declares.
Four of its rows were planned for 1.1.0, which does not include them: a
non-mutating execution preview, the origin and label of an applied event, a
closed-trade entry-comment accessor and a replace-options word. Nothing in 1.0
promises C and C++ parity beyond the fields and calls the C surface declares.

## Pairing with codegen

- **From 1.0.0 the engine and the codegen share one version number, and the
only supported pair is the same `X.Y.Z`, prerelease included:** engine
`v1.0.0-rc.1` with codegen `1.0.0-rc.1` (PyPI spells it `1.0.0rc1`), engine
`v1.0.0` with codegen `1.0.0`, engine `v1.0.1` with codegen `1.0.1`. Any other
pair is unsupported: a release candidate with its final release, two minors,
or two builds that agree only on `PF_ABI_VERSION`. Generated strategy code
compiles against the engine's internal C++ headers, which the C ABI does not
cover and the script ABI checks above version (@ref abi_stability, "What's
*not* guaranteed").
`v1.0.0` with codegen `1.0.0`, engine `v1.0.1` with codegen `1.0.1`, engine
`v1.1.0` with codegen `1.1.0`. Any other pair is unsupported: a release
candidate with its final release, two minors, or two builds that agree only
on `PF_ABI_VERSION`. Generated strategy code compiles against the engine's
internal C++ headers, which the C ABI does not cover and the script ABI
checks above version (@ref abi_stability, "What's *not* guaranteed").
Regenerate the C++ and relink the strategy library on every pair change.
- **The release hub enforces it.** `release.yml` dispatches `engine-release`
to pineforge-release with `client_payload` `{version: "vX.Y.Z[-rc.N]",
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/streaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ separate surfaces and are not implied by using this lifecycle.
the first realtime bar, so its live results can differ from a backtest of
the same bars. Batch backtests are not affected. Workaround: run the stream
with a script timeframe larger than the input timeframe (for example input
`1`, script `5`), or use the batch backtest. **Fixed on main (#325); included in
the next release.** This change feeds each newly observed confirmed bar to the
`1`, script `5`), or use the batch backtest. **Fixed in 1.1.0 (#325).** This
change feeds each newly observed confirmed bar to the
requested-series evaluator, including equal-timeframe and Heikin-Ashi requests.

See [Lifecycle](@ref lifecycle) for handle ownership and
Expand Down
Loading