Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
612a814
runner: require reliable WebSocket message finality
luisleo526 Oct 3, 2026
26eee7d
Add live runner sanitizer verification
luisleo526 Oct 3, 2026
738d684
Keep existing documentation anchors stable
luisleo526 Oct 3, 2026
5ad7588
Make live sanitizer verification follow transport availability
luisleo526 Oct 3, 2026
1ddd1c7
Restore normalized live feed inputs and remove parser plugins
luisleo526 Oct 3, 2026
68e748e
Document the feed boundary and proposed webhook routing
luisleo526 Oct 3, 2026
df2df97
Reject malformed feed fields with adapter guidance
luisleo526 Oct 3, 2026
5ef0828
Refresh runner documentation anchors
luisleo526 Oct 3, 2026
8f56f2d
Correct feed documentation and kernel verification floor
luisleo526 Oct 3, 2026
52d17cb
Restore optional bar trade counts and clarify feed validation
luisleo526 Oct 3, 2026
ab90138
Add per-action webhook routing and append-only delivery audit
luisleo526 Oct 3, 2026
d4fff31
Verify concurrent runner delivery with ThreadSanitizer
luisleo526 Oct 3, 2026
0cc2784
Refresh rebased documentation anchors and verification fixtures
luisleo526 Oct 3, 2026
fd80053
Correct ThreadSanitizer fixture profile lookup
luisleo526 Oct 3, 2026
4851f13
Measure delivery isolation independently of sanitizer startup
luisleo526 Oct 3, 2026
f196921
Keep standalone corpus tooling outside runner test inventory
luisleo526 Oct 3, 2026
f32d6a0
Use durable attempt clocks in retry isolation assertions
luisleo526 Oct 3, 2026
0479ff9
Keep target attempt timestamps monotonic
luisleo526 Oct 3, 2026
aa53fca
Model ThreadSanitizer flags on runner example fixtures
luisleo526 Oct 3, 2026
d9898d1
Bound exit delivery and guard offline recovery
luisleo526 Oct 3, 2026
f85a961
Run live ThreadSanitizer with GCC and child ASLR disabled
luisleo526 Oct 3, 2026
d950812
Document routing delivery changes and recovery requirements
luisleo526 Oct 3, 2026
e053e6f
Refresh rebased documentation anchors and exit formatting
luisleo526 Oct 3, 2026
110c738
Keep recovery tests aligned with deployment checks
luisleo526 Oct 3, 2026
f3720ba
Recognize checked settings compatibility warnings in routing tests
luisleo526 Oct 3, 2026
a58308a
Compare action identity without relying on receiver thread order
luisleo526 Oct 3, 2026
227d8ac
ci: build the pinned libcurl for the kernel profile
luisleo526 Oct 3, 2026
7b0f153
tests: compare resolved temp paths in the live sanitizer checks
luisleo526 Oct 3, 2026
73a1ccf
docs: re-anchor runner startup after rebasing
luisleo526 Oct 3, 2026
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
37 changes: 37 additions & 0 deletions .github/actions/setup-live-curl/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Set up native runner libcurl
description: Cache and build the checksum-pinned WebSocket-enabled libcurl
outputs:
curl-dir:
description: CMake package directory for ci_verify.py --curl-dir
value: ${{ steps.dependencies.outputs.curl-dir }}
cache-hit:
description: Whether the pinned installation was restored from cache
value: ${{ steps.curl-cache.outputs.cache-hit }}
runs:
using: composite
steps:
- name: Identify pinned dependency environment
id: dependencies
shell: bash
run: |
bash scripts/build_live_curl.sh --metadata >> "$GITHUB_OUTPUT"
mkdir -p build-native-deps
{
printf '%s\n' "${ImageOS:-unknown}" "${ImageVersion:-unknown}" "${GITHUB_WORKSPACE}"
cc --version
cmake --version
dpkg-query -W libssl-dev zlib1g-dev
} > build-native-deps/environment.txt
echo "identity=$(sha256sum build-native-deps/environment.txt | cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT"
echo "curl-dir=${GITHUB_WORKSPACE}/build-native-deps/curl-install/lib/cmake/CURL" >> "$GITHUB_OUTPUT"
- name: Restore pinned WebSocket-enabled libcurl
id: curl-cache
uses: actions/cache@v4
with:
path: build-native-deps/curl-install
key: curl-${{ steps.dependencies.outputs.version }}-${{ steps.dependencies.outputs.sha256 }}-${{ steps.dependencies.outputs.identity }}-${{ hashFiles('.github/actions/setup-live-curl/action.yml', 'scripts/build_live_curl.sh') }}-${{ runner.os }}-${{ runner.arch }}
- name: Build pinned WebSocket-enabled libcurl
shell: bash
env:
CURL_CACHE_HIT: ${{ steps.curl-cache.outputs.cache-hit }}
run: bash scripts/build_live_curl.sh build-native-deps 4
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libeigen3-dev tzdata-legacy libsqlite3-dev libssl-dev libcurl4-openssl-dev ccache
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y cmake ninja-build libeigen3-dev tzdata-legacy libsqlite3-dev libssl-dev zlib1g-dev ccache

- name: Restore ccache
uses: actions/cache@v4
Expand All @@ -294,12 +294,16 @@ jobs:
restore-keys: |
ccache-${{ runner.os }}-${{ runner.arch }}-kernel-

- name: Set up pinned WebSocket-enabled libcurl
id: curl-deps
uses: ./.github/actions/setup-live-curl

- name: Verify (kernel)
run: python3 scripts/ci_verify.py kernel --build-dir build-kernel --jobs "$(getconf _NPROCESSORS_ONLN)" --ccache
run: python3 scripts/ci_verify.py kernel --build-dir build-kernel --jobs "$(getconf _NPROCESSORS_ONLN)" --ccache --curl-dir "${{ steps.curl-deps.outputs.curl-dir }}"

- name: Stage and summarize diagnostics
if: always()
run: python3 scripts/collect_ci_diagnostics.py --build-dir build-kernel --profile kernel
run: python3 scripts/collect_ci_diagnostics.py --build-dir build-kernel --profile kernel --dependency-dir build-native-deps

- name: Retain CI diagnostics
if: always()
Expand Down
70 changes: 21 additions & 49 deletions .github/workflows/native-live.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ env:
CCACHE_COMPILERCHECK: content
CCACHE_COMPRESS: "1"
CCACHE_MAXSIZE: 500M
CURL_VERSION: "8.14.1"
CURL_SHA256: "f4619a1e2474c4bbfedc88a7c2191209c8334b48fa1f4e53fd584cc12e9120dd"

# The organization's 16-core larger runner for a push, the schedule, a
# dispatch and a pull request from a branch of this repository; every other
Expand Down Expand Up @@ -65,61 +63,35 @@ jobs:
restore-keys: |
ccache-${{ runner.os }}-${{ runner.arch }}-native-

- name: Identify native dependency environment
id: native-deps
shell: bash
run: |
mkdir -p build-native-deps
{
printf '%s\n' "${ImageOS:-unknown}" "${ImageVersion:-unknown}" "${GITHUB_WORKSPACE}"
cc --version
cmake --version
dpkg-query -W libssl-dev zlib1g-dev
} > build-native-deps/environment.txt
echo "identity=$(sha256sum build-native-deps/environment.txt | cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT"

- name: Restore pinned WebSocket-enabled libcurl
id: curl-cache
uses: actions/cache@v4
with:
path: build-native-deps/curl-install
key: curl-${{ env.CURL_VERSION }}-${{ env.CURL_SHA256 }}-${{ steps.native-deps.outputs.identity }}-${{ hashFiles('.github/workflows/native-live.yml') }}-${{ runner.os }}-${{ runner.arch }}

- name: Build pinned WebSocket-enabled libcurl
env:
CURL_CACHE_HIT: ${{ steps.curl-cache.outputs.cache-hit }}
run: |
set -euo pipefail
cmake_file="build-native-deps/curl-install/lib/cmake/CURL/CURLConfig.cmake"
if [[ "${CURL_CACHE_HIT}" == "true" && -f "$cmake_file" ]]; then
echo "Using cached libcurl at ${cmake_file}"
exit 0
fi
mkdir -p build-native-deps
cd build-native-deps
curl --fail --location --proto '=https' --tlsv1.2 \
"https://curl.se/download/curl-${CURL_VERSION}.tar.xz" -o curl.tar.xz
echo "${CURL_SHA256} curl.tar.xz" | sha256sum -c -
tar -xf curl.tar.xz
cmake -S "curl-${CURL_VERSION}" -B curl-build -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PWD/curl-install" \
-DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON \
-DBUILD_TESTING=OFF -DCURL_USE_OPENSSL=ON -DENABLE_WEBSOCKETS=ON \
-DHTTP_ONLY=ON -DCURL_USE_LIBPSL=OFF -DUSE_LIBIDN2=OFF \
-DCURL_USE_LIBSSH2=OFF -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF \
2>&1 | tee curl-configure.log
cmake --build curl-build -j 4 2>&1 | tee curl-build.log
cmake --install curl-build 2>&1 | tee curl-install.log
- name: Set up pinned WebSocket-enabled libcurl
id: curl-deps
uses: ./.github/actions/setup-live-curl

- name: Verify native live
run: python3 scripts/ci_verify.py native --build-dir build-live --jobs "$(getconf _NPROCESSORS_ONLN)" --generator Ninja --curl-dir "${{ github.workspace }}/build-native-deps/curl-install/lib/cmake/CURL" --ccache --require-websocket ${{ inputs.exclude_slow && '--exclude-label slow' || '' }}
run: python3 scripts/ci_verify.py native --build-dir build-live --jobs "$(getconf _NPROCESSORS_ONLN)" --generator Ninja --curl-dir "${{ steps.curl-deps.outputs.curl-dir }}" --ccache --require-websocket ${{ inputs.exclude_slow && '--exclude-label slow' || '' }}

- name: Verify every live runner target with ASan and UBSan
if: ${{ !cancelled() }}
run: python3 scripts/ci_verify.py live-sanitizers --build-dir build-live-sanitizers --jobs "$(getconf _NPROCESSORS_ONLN)" --generator Ninja --curl-dir "${{ steps.curl-deps.outputs.curl-dir }}" --ccache

- name: Stage and summarize diagnostics
if: always()
env:
CURL_CACHE_HIT: ${{ steps.curl-cache.outputs.cache-hit }}
CURL_CACHE_HIT: ${{ steps.curl-deps.outputs.cache-hit }}
run: python3 scripts/collect_ci_diagnostics.py --build-dir build-live --profile native --dependency-dir build-native-deps

- name: Verify every live runner target with ThreadSanitizer
if: ${{ !cancelled() }}
run: python3 scripts/ci_verify.py live-tsan --build-dir build-live-tsan --jobs "$(getconf _NPROCESSORS_ONLN)" --generator Ninja --curl-dir "${{ steps.curl-deps.outputs.curl-dir }}" --ccache

- name: Stage thread sanitizer diagnostics
if: always()
run: python3 scripts/collect_ci_diagnostics.py --build-dir build-live-tsan --profile live-tsan --output ci-diagnostics/live-tsan --dependency-dir build-native-deps

- name: Stage live sanitizer diagnostics
if: always()
run: python3 scripts/collect_ci_diagnostics.py --build-dir build-live-sanitizers --profile live-sanitizers --output ci-diagnostics/live-sanitizers --dependency-dir build-native-deps

- name: Retain CI diagnostics
if: always()
uses: actions/upload-artifact@v4
Expand Down
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,41 @@ README's *Releases* section and on the GitHub releases page. From 1.0.0 the
version number follows semantic versioning over the surfaces the
[public contract](docs/pages/public-contract.md) lists.

## Unreleased

- **Native runner routing and delivery:** webhooks are optional; `--webhook-routes`
adds first-match per-action targets and payload `pineforge-native-order-action/v2`.
New `actions`, `status` and offline `redeliver` commands expose the journal and
delivery audit. `redeliver` requires the ledger's `--deployment` identity.
Existing `--webhook-url` deployments keep one default target, exact v1 payload
bytes and event-id idempotency keys, but delivery behavior changes: HTTP errors
are final, normal runs exit 0 even with failed deliveries, and `--max-attempts N`
caps transport retries at `min(2, N-1)` rather than stopping computation.
Default delivery timeouts are now 2 s connect / 5 s total (formerly 5 s / 15 s).
Fatal exits drain for at most one total timeout and report unsent actions;
SIGINT/SIGTERM exit 130. Redelivery exits 2 for failed or pending selections.
Schema-1 native ledgers migrate additively to an append-only delivery log without
rewriting actions. This migration is one-way: older runner binaries cannot open
the migrated ledger. Back up the ledger before upgrading. The engine is unchanged.

- **Runner tooling removal:** the native live runner accepts only normalized
PineForge feed events from stdin, files, or a user's own HTTP/WebSocket feed
service. The installed `pineforge/live_parser.h` header, its
`PF_LIVE_PARSER_*` types/constants and `pf_live_parser_abi_version` /
`pf_live_parse_message` plugin exports, the `--parser` / `--parser-config`
flags, and the example plugin are removed. This breaks callers that included
that header, authored native parser plugins, or passed raw provider messages
through the runner. Migrate translation to an **external feed adapter** that
emits [PineForge feed events](runner/README.md#feed-format); feed URLs address
that adapter, not an exchange. The outbound order-action webhook remains.
Strict native runner configurations now also require 1m input; higher script
timeframes still aggregate those minutes.
No versioned engine `PF_API` export, native C++ surface, script ABI epoch or
engine behavior changes. Frozen historical ABI header manifests and archives
remain intact. Plugin-free ledger identity bytes remain unchanged; ledgers
bound to removed plugins cannot be resumed by this runner and must not be
silently rewritten.

## 1.0.1 — 2026-10-02

A documentation-only release that pairs with pineforge-codegen 1.0.1, the pair
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ What each gate refuses:
### The floors

`ci_verify.py` counts the CTest rows that actually **ran** and fails below a
floor — `KERNEL_MIN_TESTS` ci_verify.py:320 and `RELEASE_MIN_TESTS`
ci_verify.py:594.
floor — `KERNEL_MIN_TESTS` ci_verify.py:321 and `RELEASE_MIN_TESTS`
ci_verify.py:595.
A deleted or silently skipped row is a failure, not a quieter run. If your
change adds rows, raise the floor in the same commit and say by how much; if it
legitimately removes one, lower it deliberately and say why. `--min-tests`
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,17 @@ reference underneath it.
## Native live runner

The optional C++17 `pineforge-live` executable uses this engine's native
warmup-to-stream lifecycle. It accepts normalized ticks or confirmed OHLCV bars,
supports user-defined C++ parsers for broker/provider messages, and commits
warmup-to-stream lifecycle. It accepts only normalized ticks or confirmed OHLCV
bars as PineForge feed events from stdin, a file or your own
feed service (exchange translation belongs in an external feed adapter), and commits
inputs plus order-action webhooks to a durable SQLite ledger. Hand-written
C++ strategies use the native contract; generated Pine strategies retain their
compatibility path. Both expose the versioned C ABI used by the runner.

Build with `-DPINEFORGE_BUILD_LIVE_RUNNER=ON`; the option is off by default,
so core-only users do not acquire SQLite/libcurl/OpenSSL dependencies. See
the [native runner guide](runner/README.md) for feed modes, symbol metadata,
parser ABI, recovery and execution limitations. The existing validation
feed format, recovery and execution limitations. The existing validation
scoreboard below describes batch backtests; it does not certify new native
live behavior or real broker fills.

Expand Down
30 changes: 28 additions & 2 deletions docs/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ even when the current benchmark files are correct.
| `release` | Release, tutorial enabled | Standard CI checks behind a row floor (`RELEASE_MIN_TESTS`; `--min-tests N` overrides it), installed package, and installed native include-independence proof |
| `debug` | Debug, tutorial enabled | The standard checks and installed package without Release optimization; no default row floor, examples, include-independence proof or twin-parity guard |
| `sanitizers` | Debug, ASan and UBSan | Instrumented library, tests and installed consumer; Linux CI also requires leak detection |
| `native` | Release, live runner enabled | Parser, journal, transport tests, installed runner help, and installed native include-independence proof |
| `native` | Release, live runner enabled | JSON, journal, transport tests, installed runner help, and installed native include-independence proof |
| `live-sanitizers` | Debug, live runner enabled, ASan and UBSan | Every runner target instrumented and audited from compile commands; all runner CTest rows, Python E2Es and installed runner help; WebSocket-enabled curl mandatory while `runner/transport.cpp` exists, no skips accepted |
| `live-tsan` | Debug, live runner enabled, ThreadSanitizer | Separate build instruments every runner target, audits compile commands and runs all runner rows and Python E2Es; WebSocket-enabled curl is mandatory and skips are refused |
| `kernel` | Release, live runner enabled, Pine source layer OFF | The source-free CTest set behind a row floor (`KERNEL_MIN_TESTS`; `--min-tests N` overrides it), installed package, and the `nm` half of the include-independence proof over `libpineforge_kernel.a` |

By default each profile uses `build-ci-<profile>`. Keep separate build directories
Expand All @@ -73,6 +75,10 @@ python3 scripts/ci_verify.py debug --jobs 4
python3 scripts/ci_verify.py sanitizers --jobs 4
python3 scripts/ci_verify.py native --curl-dir /path/to/curl/lib/cmake/CURL \
--require-websocket --jobs 4
python3 scripts/ci_verify.py live-sanitizers --curl-dir /path/to/curl/lib/cmake/CURL \
--jobs 4
python3 scripts/ci_verify.py live-tsan --curl-dir /path/to/curl/lib/cmake/CURL \
--jobs 4
```

The sanitizer profile uses the Linux CI ASan/UBSan environment, including
Expand All @@ -82,6 +88,26 @@ That flag turns a transport skip into failure. A local native run using system
curl may report the existing unsupported-WebSocket skip; that is not the required
Linux transport proof.

`live-sanitizers` performs a full all-target build, then runs the complete
`build-ci-live-sanitizers/runner` CTest inventory (at least twelve rows while
`runner/transport.cpp` exists, eleven after its removal), including
`native_live_e2e` and `native_live_startup_e2e`, and requires any additional
runner `tests/native_live*_e2e.py` on the tree to be registered too. The standalone
corpus equivalence driver is not a runner CTest row; its harness unit tests remain
in the engine-wide inventory. The profile does not rerun
the engine-wide CTest set or prepare historical ABI providers; those remain
covered by `sanitizers`. It refuses label exclusions, missing runner compile
commands, missing ASan/UBSan or frame-pointer flags, skipped/disabled tests,
and, while `runner/transport.cpp` exists, a missing WebSocket row or transport
skip even without `--require-websocket`. After transport removal those two
automatic gates no longer apply; an explicit `--require-websocket` still
requires the WebSocket test.
The runner's curl version floor still applies at configure time.
`live-tsan` runs the same inventory in a separate ThreadSanitizer build,
checks every runner compile unit for instrumentation, and stops on a race.
`native-live.yml` runs both profiles alongside `native`, reusing the same
checksum-pinned WebSocket-enabled curl, and retains all profiles' diagnostics.

The kernel profile also gates the CTest row count: `tests/CMakeLists.txt`
drops every test TU whose include closure reaches `pineforge/source/` or
`compat/pine/`, so a lane whose native witnesses shared a TU with an adapter
Expand Down Expand Up @@ -111,7 +137,7 @@ plus wave G's six rows, wave H's twenty-four, INT26's own tape row, INT27's
thirteen, XSYM-D's four, K-SESSION-WINDOWS' four, INT28's twenty-four,
INT28-FIX's four, INT29's seven, W15-KERNEL-CAL's two, INT30's twenty-four,
TAIL-I's one, XAU-CAL's four and FIX-E1E2's two). The full-run release and
kernel floors are 792 and 300 rows that ran; full runs do not exclude a label.
kernel floors are 792 and 299 rows that ran; full runs do not exclude a label.

Preflight also runs the detached-comment census of the kernel compile closure
(`detached-comments`: `scripts/measure_detached_comments.py --check-ceiling`)
Expand Down
Loading
Loading