From a91436d002f15dc811ec075d07c608d2b2219d3e Mon Sep 17 00:00:00 2001 From: luisleo526 Date: Mon, 5 Oct 2026 11:42:34 +0800 Subject: [PATCH 1/2] docs: changelog and version scoping for 1.2.0 1.2.0 pairs with engine v1.2.0, whose pineforge.h defines PF_CAPABILITIES_API_VERSION and declares the two capability functions (engine #332) that the C++ of codegen 1.2.0 defines (#167). The changelog section takes in the Unreleased notes and covers #166, #167, #168 and #171: the capability receipt and what the live runner does with it, the diagnostic codes and catalog, the first error in source order, the linear-time classification as a security fix, the PineForge Source License 1.1 and the pairing and migration steps. The Python and JSON contract is additive; the engine's report harness is unchanged since v1.1.0, so no report key changes. The README, AGENTS.md / CLAUDE.md, CONTRIBUTING.md, docs/PUBLIC_CONTRACT.md and docs/pine-cap-activation.md name 1.2.0 where they named 1.1.0 as the current release or pair, the pairing table gets a 1.2.0 row, the license badge reads 1.1, and the npm README lists the catalog and LICENSE the package now carries. The release scoreboard sentence and the pf markers are left to the release lane. Measured for 1.2.0: the engine's 325 corpus sources and the 277 gate fixtures transpile, with the capability block removed, to 1.1.0's C++ byte for byte, each in a fresh process (13 refusals, same messages), and each in under 0.1 s on CPython 3.14.6 on an Apple M4 Max. The tutorial run of the quick-start C++ against engine main 44eab7b1 (Linux x86_64, GCC 13) prints 9 trades and +738.20, and 13 trades with the old sizing declared, as 1.1.0 with engine v1.1.0 does. Co-Authored-By: Claude Opus 5.5 (1M context) --- AGENTS.md | 20 +-- CHANGELOG.md | 276 ++++++++++++++++++++++++++++++------ CLAUDE.md | 20 +-- CONTRIBUTING.md | 11 +- README.md | 33 ++--- docs/PUBLIC_CONTRACT.md | 26 ++-- docs/pine-cap-activation.md | 8 +- npm/README.md | 4 + 8 files changed, 300 insertions(+), 98 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 04fb388..f9898d2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,16 +67,16 @@ This is the **source-available** half of the PineForge stack (PineForge Source License 1.1 — see `LICENSE`). The runtime half (`pineforge-engine`, Apache-2.0) lives in a sibling repo and is typically checked out at `../pineforge-engine`. From 1.0.0 on, a released codegen `X.Y.Z` pairs only -with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.1.0 pairs with -engine `v1.1.0` (the `pineforge-release` image `1.1.0`), codegen 1.0.1 with -engine `v1.0.1` (the image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` -(the image `1.0.0`). On the 0.x line the versions are independent: the last -0.x release, codegen 0.10.4, pairs with engine `v0.13.1` (the -`pineforge-release` image `0.1.25`). Use the paired release's generated -headers and static library, and regenerate C++ and relink on every pair -change. Equal `PF_ABI_VERSION` values are insufficient. Engines `v1.0.0`, -`v1.0.1` and `v1.1.0` use the `engine_script_run_v19` C++ namespace; see -`README.md` and `CONTRIBUTING.md`. +with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.2.0 pairs with +engine `v1.2.0` (the `pineforge-release` image `1.2.0`), codegen 1.1.0 with +engine `v1.1.0` (the image `1.1.0`), codegen 1.0.1 with engine `v1.0.1` (the +image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` (the image `1.0.0`). On +the 0.x line the versions are independent: the last 0.x release, codegen +0.10.4, pairs with engine `v0.13.1` (the `pineforge-release` image `0.1.25`). +Use the paired release's generated headers and static library, and regenerate +C++ and relink on every pair change. Equal `PF_ABI_VERSION` values are +insufficient. Engines `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` use the +`engine_script_run_v19` C++ namespace; see `README.md` and `CONTRIBUTING.md`. ## Pipeline diff --git a/CHANGELOG.md b/CHANGELOG.md index 811eaf3..a1ba9a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,51 +5,6 @@ Release notes for `pineforge-codegen`. From 1.0.0 on, versions of codegen and supported as exact pairs; on the 0.x line they are independent. See the [pairing rule](README.md#engine-pairing). -## Unreleased - -### Compiled execution capabilities - -- Emit the optional generated-strategy C ABI capability extension: - `strategy_capabilities_api_version()` and `strategy_capabilities_receipt()`, - versioned by the paired engine's `PF_CAPABILITIES_API_VERSION`. Its immutable - canonical JSON uses the checked-settings buffer protocol without changing the - base C ABI. Regenerate C++ and relink against the paired next-release engine. -- Record `strategy()` execution declarations, including positional arguments in - Pine signature order, and analyzed request/feed, FX and intrabar requirements. - Name nonliteral arguments and unpinned runtime-lowered request sites in - `unresolved`; retain every request kind, symbol, timeframe and lookahead. - Record endpoint/realtime builtin use even in plots, labels and tables. The - receipt proves declarations only, not arbitrary live-versus-batch equivalence. -- The paired close-only runner refuses intrabar/fill-policy declarations, - `process_orders_on_close`, every `request.*` site regardless of timeframe, - unsupported clock/feed/FX requirements, `varip`, unresolved declarations and - the six endpoint/realtime builtins before its ledger exists, naming the - requirement instead of silently changing the computation. Legacy libraries - without the extension warn and run, including their requests, without proving - eligibility. Default batch computation is unchanged. - -### Diagnostic codes - -An additive change to the public API; it leaves the emitted C++ unchanged. - -- **Diagnostic codes.** Every transpile diagnostic carries a stable `code` - (`PF-E1203` / `PF-W0412`) and named, raw `args`, in - `transpile_full(...)["diagnostics"]`, in `CompileError.diagnostics` and in - the `transpile_json` envelopes. `diagnostics_catalog()` and - `pineforge_codegen/diagnostics_catalog.json` (attached to each GitHub - release) give each code its severity, English ICU MessageFormat templates, - argument kinds and a one-line explanation; the templates render the - `message` and `hint` byte for byte, which keep their text. Codes are never - reused (`tests/fixtures/diagnostic_codes_pin.json`). See - [Diagnostic codes](docs/PUBLIC_CONTRACT.md#diagnostic-codes). A code is - read off its text in time linear in the text: a crafted script's text cannot - stall the classification, which a backtracking regex let it do. -- **First error in source order.** Since 1.1.0 the settings metadata visited - every input's `defval`, `options`, `minval`, `maxval` and `step` ahead of - the script body, so an error there (an unknown name in `minval`) was raised - before an error on an earlier line. The script's first error in source - order is raised again; no emitted C++ changes. - ## Release note policy - Keep a section for each released version, including prereleases. Use the exact @@ -65,6 +20,237 @@ An additive change to the public API; it leaves the emitted C++ unchanged. the release commit. A prerelease note describes changes since the preceding prerelease or stable tag; the final stable note consolidates the series. +## 1.2.0 — 2026-10-05 + +A minor release: generated strategy libraries gain the compiled execution +capability receipt that engine `v1.2.0` adds to the C ABI, every diagnostic +carries a stable code and named arguments, and the package is licensed under +the PineForge Source License 1.1. It covers the changes merged to `main` since +1.1.0: +[#167](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/167) +changes the emitted C++, +[#166](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/166) +adds diagnostic codes to the Python and JSON results and raises a script's +first error in source order again, +[#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171) +classifies diagnostic codes in linear time, moves to the PineForge Source +License 1.1 and renders the README's scoreboard, and +[#168](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/168) +replaces the license. Codegen `1.2.0` supports only engine `v1.2.0`. Engine +`v1.2.0` defines `PF_CAPABILITIES_API_VERSION` (1) and declares two functions +in `` +([pineforge-engine#332](https://github.com/pineforge-4pass/pineforge-engine/pull/332)) +that the C++ of codegen 1.2.0 defines; the pair keeps C ABI version 4 and the +script ABI epoch `engine_script_run_v19`. + +### Compatibility and migration + +- Regenerate C++ with 1.2.0 and relink it against engine `v1.2.0`'s headers + and `libpineforge.a`. The C++ defines the capability functions only when the + engine's `pineforge/pineforge.h` defines both `PF_SETTINGS_API_VERSION` and + `PF_CAPABILITIES_API_VERSION`, as engine `v1.2.0`'s does. Against headers + without `PF_CAPABILITIES_API_VERSION`, such as engine `v1.1.0`'s, that block + compiles to nothing and the library has no receipt; this does not make such + a pair supported. C++ generated by 1.1.0 has no receipt either. Engine + `v1.2.0`'s live runner warns that it cannot prove a library without a + receipt eligible, and runs it (see "Compiled execution capabilities"). +- Every generated C++ file changes: it gains the capability block. Beyond + that, the C++ does not change: for the engine's 325 public corpus sources + and this repository's 277 gate fixtures, each transpiled in a fresh process, + 1.2.0's C++ with the capability block removed is 1.1.0's C++ byte for byte, + and the 13 fixtures the gate expects to be refused are refused with the same + message. A script name spelled `strategy_capabilities_api_version` or + `strategy_capabilities_receipt` is renamed in the C++ (for example + `pf_safe_strategy_capabilities_receipt`), so a script cannot shadow the new + functions; input keys are unaffected. +- The Python and JSON contract is additive: each `Diagnostic` gains the + properties `code` and `args`, `pineforge_codegen` exports + `diagnostics_catalog()` and `render_diagnostic()`, and each JSON diagnostic + of `gate/glue.py`'s `transpile_json` success and error envelopes gains the + keys `code` and `args` (see "Diagnostic codes"). No argument, result key or + envelope is removed or renamed: `transpile()` and `transpile_full()` keep + their signatures and result keys, the envelopes keep every key they had, and + each diagnostic keeps its `message`, `hint`, severity and location. One + result changes: the error raised for a script with errors in more than one + place (see "First error in source order"). +- Report keys: the engine's Docker harness (`docker/run_json.py`, which the + `pineforge-release` image runs) is the same file in engine `v1.2.0` as in + `v1.1.0`, so no report key is added, removed or renamed; + `metrics.equity.sharpe_tv` and `sortino_tv` (`EQUITY_REPORT_KEYS`) are + unchanged, and the engine's ADR-0001 keeps serialized report keys as they + are. A report's fingerprint still differs between 1.1.0 and 1.2.0, since it + records the engine and codegen versions and the generated C++'s hash, and + the engine's Pine adapter changes since `v1.1.0` (such as + [pineforge-engine#330](https://github.com/pineforge-4pass/pineforge-engine/pull/330)) + can change a run's trades. +- 1.2.0 is the first release under the PineForge Source License 1.1. Releases + up to and including 1.1.0 keep the license they shipped with (see + "License"). + +### Compiled execution capabilities + +From [#167](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/167): + +- Built against engine `v1.2.0`, a generated strategy library defines + `strategy_capabilities_api_version()`, which returns + `PF_CAPABILITIES_API_VERSION` (1), and `strategy_capabilities_receipt(s, + json, capacity, required, error, error_capacity)`, which writes the + strategy's capability receipt. It uses the statuses and the buffer protocol + of 1.1.0's `strategy_get_effective_settings`: called with a NULL buffer and + 0, it returns `PF_SETTINGS_BUFFER_TOO_SMALL` and the size to allocate, the + NUL included; a short buffer gets an empty string, never partial JSON; a + NULL strategy returns `PF_SETTINGS_INVALID_ARGUMENT`; no exception gets + through. The base C ABI does not change. +- The receipt is canonical JSON (sorted keys, compact separators) written + into the C++ when it is generated, not read from a running strategy: every + handle returns the same bytes, before and after runs and setting changes. + Version 1 has the keys `version`, `declarations`, `requests`, + `requirements` and `unresolved`. `declarations` holds the `strategy()` + values of `calc_on_every_tick`, `calc_on_order_fills`, + `calc_on_every_history_tick`, `process_orders_on_close`, + `use_bar_magnifier`, `fill_orders_on_standard_ohlc`, + `backtest_fill_limits_assumption`, `currency`, `timeframe`, + `timeframe_gaps` and `dynamic_requests`, Pine's defaults where omitted; + positional arguments are read in Pine's parameter order. `requests` lists + each `request.security` and `request.security_lower_tf` site, recorded + request and request lowered to a run-time stop, with its function, symbol, + timeframe, lookahead, gaps, Heikin-Ashi flag and feed (`chart`, + `auxiliary`, `recorded` or `unpinned`). `requirements` says whether the + script needs other symbols' feeds, an FX curve (a `currency` other than + `currency.NONE`), recorded series or intrabar persistence (`varip`). + `unresolved` names what the receipt cannot state as a literal (a nonliteral + `strategy()` argument, a request's nonliteral timeframe or lookahead, a + request lowered to a run-time stop) and every use of `barstate.isrealtime`, + `timenow`, `barstate.islast`, `barstate.islastconfirmedhistory`, + `last_bar_index` and `last_bar_time`, in plots, labels and tables too. The + receipt proves declarations only, not that a stream computes what a batch + run computes. +- A host reads the receipt before it runs a strategy, to tell whether its + execution mode can honour what the strategy declares. Engine `v1.2.0`'s + live runner, `pineforge-live`, reads it before it opens its ledger + ([pineforge-engine#332](https://github.com/pineforge-4pass/pineforge-engine/pull/332)) + and refuses, naming the requirement, intrabar calculation + (`calc_on_every_tick`, `calc_on_order_fills`, `calc_on_every_history_tick`), + `process_orders_on_close`, the bar magnifier, standard-OHLC fills, nonzero + limit-fill verification, a `currency` or a `timeframe` declared in + `strategy()`, every true requirement, every request whatever its + timeframe, and every name in `unresolved`. A library without the + extension, such as one generated by 1.1.0, gets a warning that its + eligibility cannot be proved, and runs, its requests included. A batch run + does not read the receipt, and its computation is unchanged. The engine's + `docs/strategy-capabilities.md` gives the schema and the runner's policy, + and the + [public contract](docs/PUBLIC_CONTRACT.md#optional-compiled-execution-capabilities) + the codegen side. + +### Diagnostic codes + +From [#166](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/166): + +- Every diagnostic carries a stable `code` (`PF-E1203` for an error, + `PF-W0412` for a warning) and `args`, the named raw values (identifiers, + types, keywords, numbers) its English `message` and `hint` were built from: + in `transpile_full(...)["diagnostics"]`, in `CompileError.diagnostics` and + in the JSON diagnostics of the `transpile_json` envelopes. They are read off + the diagnostic's text when first asked for, after the transpile, so the + emitted C++ does not depend on them; `message` and `hint` keep their text. +- `diagnostics_catalog()` returns the catalog, and `render_diagnostic(code, + args)` the English `(message, hint)` a code renders, equal to the + diagnostic's byte for byte. The catalog (schema + `pineforge-diagnostics-catalog/v1`, 628 codes) gives each code its + severity, area, ICU MessageFormat message and hint templates, argument + kinds and a one-line explanation, so an application can translate a + diagnostic by its code. It ships in the package as + `pineforge_codegen/diagnostics_catalog.json`, in + `@pineforge/codegen-pyodide` as the `./diagnostics_catalog.json` export, + and with the GitHub release as `diagnostics_catalog-v1.2.0.json`. +- A code is never removed or reused, and a changed meaning gets a new code + (`tests/fixtures/diagnostic_codes_pin.json`). See + [Diagnostic codes](docs/PUBLIC_CONTRACT.md#diagnostic-codes). + +### First error in source order + +- 1.1.0's settings metadata read every input's `defval`, `options`, + `minval`, `maxval` and `step` ahead of the script body, so an error there, + such as an unknown name in a later input's `minval`, was raised before an + error on an earlier line. 1.2.0 raises the script's first error in source + order again, as 1.0.1 did + ([#166](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/166)). + The emitted C++ does not change. + +### Security + +- Classifying a diagnostic's code no longer stalls on crafted script text + ([#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171)). + As #166 merged it, the classifier matched each catalog template as a + backtracking regular expression over the message and hint, which carry text + the script spells: 1.8 KB of one template's text took 0.55 s to classify + and 3.4 KB took 23 s, a denial of service for `transpile_json`, which + classifies every diagnostic it returns, and for any host that reads + `code` or `args`. Classification now takes time linear in the text: the + same text grown to 6.6 MB classifies in milliseconds, with the same codes + and arguments. No release had the stall: it was on `main` from #166 to + #171, and 1.1.0 has no diagnostic codes. + +### License + +From [#168](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/168) +and [#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171): + +- 1.2.0 is the first release under the PineForge Source License 1.1, whose + licensor is pineforge, LLC. Releases up to and including 1.1.0 shipped + under "PineForge Codegen — License", the PolyForm Noncommercial License + 1.0.0 with PineForge's supplemental sections, and copies of those releases + keep that license. The PineForge Source License is not a PolyForm license. + `LICENSE` is the controlling text; `LEGAL.md` summarizes it and is not + legal advice. +- The permitted purposes, free of charge, are noncommercial purposes, + personal uses, use by the noncommercial organizations `LICENSE` lists for + their teaching, research and other operations, and Personal Trading: a + natural person's research, development and backtesting of strategies and + execution of trades for their own account with their own capital, as + `LICENSE` defines them. Investment Management (managing, advising on or + trading investment capital, researching, developing or backtesting + strategies for it, or operating the software for others who do, whoever + the capital belongs to and whether or not for a fee) is Commercial Use for + every individual and every organization, noncommercial organizations + included, unless it is Personal Trading. So is any other use that is not a + permitted purpose, such as use by, for or on behalf of a company, fund, + partnership or other organization. Commercial Use needs a commercial + license from pineforge, LLC (enterprise@pineforge.dev). +- Distributing copies is not Commercial Use, except that distributing the + software, changed or not, embedded in or bundled with a product or service + made available to others is Commercial Use unless it is a permitted + purpose. That exception is what 1.1 adds to the PineForge Source License + 1.0, which #168 put on `main` and no release carried. +- `LICENSE` defines Output: the code the software generates, such as the + C++ it generates from PineScript, and any program or library built from + it; backtest results, charts, reports and trade signals are not Output. +- Packaging: the PyPI classifier is `License :: Other/Proprietary License` + (it was `License :: Free for non-commercial use`), and + `@pineforge/codegen-pyodide`'s `package.json` says + `"license": "SEE LICENSE IN LICENSE"` (it said + `PolyForm-Noncommercial-1.0.0`) and the package contains `LICENSE`. + +### Documentation + +- The README's scoreboard of `main` renders from the facts tokens of + `pineforge-release` at 03b8dcc + ([#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171)): + baseline `pineforge-parity-baseline-20261004-engine-6b77f061` (engine + 6b77f061, this repository at 285ac035), 7,970 excellent and 19 strong of + 7,989 graded probes, none below strong. +- `docs/PUBLIC_CONTRACT.md` describes the capability functions + ([#167](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/167)) + and diagnostic codes + ([#166](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/166)). + The README's License section and `LEGAL.md` name the PineForge Source + License and pineforge, LLC and give enterprise@pineforge.dev for commercial + licenses, and `CONTRIBUTING.md` names pineforge, LLC as the party a + Contributor License Agreement grants rights to + ([#168](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/168), + [#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171)). + ## 1.1.0 — 2026-10-04 A minor release: generated strategy libraries gain the checked settings diff --git a/CLAUDE.md b/CLAUDE.md index 14602a3..3171656 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,16 +67,16 @@ This is the **source-available** half of the PineForge stack (PineForge Source License 1.1 — see `LICENSE`). The runtime half (`pineforge-engine`, Apache-2.0) lives in a sibling repo and is typically checked out at `../pineforge-engine`. From 1.0.0 on, a released codegen `X.Y.Z` pairs only -with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.1.0 pairs with -engine `v1.1.0` (the `pineforge-release` image `1.1.0`), codegen 1.0.1 with -engine `v1.0.1` (the image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` -(the image `1.0.0`). On the 0.x line the versions are independent: the last -0.x release, codegen 0.10.4, pairs with engine `v0.13.1` (the -`pineforge-release` image `0.1.25`). Use the paired release's generated -headers and static library, and regenerate C++ and relink on every pair -change. Equal `PF_ABI_VERSION` values are insufficient. Engines `v1.0.0`, -`v1.0.1` and `v1.1.0` use the `engine_script_run_v19` C++ namespace; see -`README.md` and `CONTRIBUTING.md`. +with engine `vX.Y.Z`; prereleases match exactly. Codegen 1.2.0 pairs with +engine `v1.2.0` (the `pineforge-release` image `1.2.0`), codegen 1.1.0 with +engine `v1.1.0` (the image `1.1.0`), codegen 1.0.1 with engine `v1.0.1` (the +image `1.0.1`), and codegen 1.0.0 with engine `v1.0.0` (the image `1.0.0`). On +the 0.x line the versions are independent: the last 0.x release, codegen +0.10.4, pairs with engine `v0.13.1` (the `pineforge-release` image `0.1.25`). +Use the paired release's generated headers and static library, and regenerate +C++ and relink on every pair change. Equal `PF_ABI_VERSION` values are +insufficient. Engines `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` use the +`engine_script_run_v19` C++ namespace; see `README.md` and `CONTRIBUTING.md`. ## Pipeline diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d2b696..c7ebeb2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,12 +47,13 @@ before treating a run as complete. ## Engine pairing -Codegen `main` is developed and tested against engine `main`. Codegen 1.1.0 -pairs with engine `v1.1.0`, the pair the +Codegen `main` is developed and tested against engine `main`. Codegen 1.2.0 +pairs with engine `v1.2.0`, the pair the [`pineforge-release`](https://github.com/pineforge-4pass/pineforge-release) -image `1.1.0` ships, codegen 1.0.1 with engine `v1.0.1`, the pair of the image -`1.0.1`, and codegen 1.0.0 with engine `v1.0.0`, the pair of the image -`1.0.0`. On the 0.x line the two version lineages are independent: +image `1.2.0` ships, codegen 1.1.0 with engine `v1.1.0`, the pair of the image +`1.1.0`, codegen 1.0.1 with engine `v1.0.1`, the pair of the image `1.0.1`, +and codegen 1.0.0 with engine `v1.0.0`, the pair of the image `1.0.0`. On the +0.x line the two version lineages are independent: the last 0.x release, codegen 0.10.4, pairs with engine `v0.13.1`, the pair the `pineforge-release` image `0.1.25` ships. diff --git a/README.md b/README.md index 72033c3..4d85717 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![PyPI](https://img.shields.io/pypi/v/pineforge-codegen.svg)](https://pypi.org/project/pineforge-codegen/) [![Python](https://img.shields.io/pypi/pyversions/pineforge-codegen.svg)](https://pypi.org/project/pineforge-codegen/) -[![License](https://img.shields.io/badge/license-PineForge%20Source%201.0-orange.svg)](https://github.com/pineforge-4pass/pineforge-codegen-oss/blob/main/LICENSE) +[![License](https://img.shields.io/badge/license-PineForge%20Source%201.1-orange.svg)](https://github.com/pineforge-4pass/pineforge-codegen-oss/blob/main/LICENSE) [![Personal use](https://img.shields.io/badge/personal%20trading-free-22c55e.svg)](#license) A pure-Python library that turns a PineScript v6 strategy into a complete C++ @@ -40,7 +40,7 @@ for the changes in each release from 1.0.0 on and the release-note policy. ## Releases and this README This README ships with each release as its package description on PyPI (`pineforge-codegen`); releases from 0.7.0 on are also on npm as -`@pineforge/codegen-pyodide`. It describes 1.1.0 (2026-10-04) and what changed +`@pineforge/codegen-pyodide`. It describes 1.2.0 (2026-10-05) and what changed since 0.10.4. The [PyPI release history](https://pypi.org/project/pineforge-codegen/#history) lists every release; the @@ -90,8 +90,8 @@ It does **not** own execution semantics. Order lifecycle, bracket legs, fill-price and slippage rules, `process_orders_on_close` / `calc_on_order_fills`, margin revival and trail/stop behaviour — everything TradingView parity depends on at run time — live in the engine's source-adapter runtime -([`src/source/`](https://github.com/pineforge-4pass/pineforge-engine/tree/v1.1.0/src/source) -in engine `v1.1.0`), which maps them onto the engine's Pine-agnostic kernel. See +([`src/source/`](https://github.com/pineforge-4pass/pineforge-engine/tree/v1.2.0/src/source) +in engine `v1.2.0`), which maps them onto the engine's Pine-agnostic kernel. See the engine's [architecture notes](https://github.com/pineforge-4pass/pineforge-engine#architecture-kernel-vs-parity). --- @@ -344,7 +344,7 @@ fields, such as `// @pf-trace gap=close - e` or `// @pf-trace body=math.abs(close - open)`. A `ta.*` call written in the pragma itself is not computed: `// @pf-trace rsi=ta.rsi(close, 14)` records `na` on every bar, and its C++ carries an `/* unsupported: ta.rsi */` marker. -0.10.4, 1.0.0, 1.0.1 and 1.1.0 all behave this way. +0.10.4, 1.0.0, 1.0.1, 1.1.0 and 1.2.0 all behave this way. ### Advanced: run the pipeline stages directly @@ -389,9 +389,9 @@ does not bypass them. The last column was measured on 2026-09-29 with 70c2b4a (the same code as 1.0.0) on CPython 3.14 on an Apple M4 Max, over the engine corpus that engine -35db01c8 pins (as `v1.0.0`, `v1.0.1` and `v1.1.0` do) and this repository's -`tests/gate-corpus`. On 2026-10-04, on CPython 3.14 on an Apple M4 Max, 1.1.0 -transpiled each of those sources in under 0.1 seconds. +35db01c8 pins (as `v1.0.0`, `v1.0.1`, `v1.1.0` and `v1.2.0` do) and this +repository's `tests/gate-corpus`. On 2026-10-05, on CPython 3.14 on an Apple +M4 Max, 1.2.0 transpiled each of those sources in under 0.1 seconds. Nesting counts brackets, indented blocks, prefix operators, `?:` and `else if` chains, and the depth of the parsed syntax tree, in which an @@ -441,6 +441,7 @@ Generated C++ compiles only against the engine it was generated for: | 1.0.0 (PyPI, 2026-09-30) | `v1.0.0` | The pair the `pineforge-release` image `1.0.0` ships. Its C++ needs `pineforge/source/pine_strategy_host.hpp`, which engine `v0.13.1` does not have. | | 1.0.1 (PyPI, 2026-10-02) | `v1.0.1` | The pair the `pineforge-release` image `1.0.1` ships. Engine `v1.0.1` changes only documentation since `v1.0.0`; regenerate and relink all the same. | | 1.1.0 (PyPI, 2026-10-04) | `v1.1.0` | The pair the `pineforge-release` image `1.1.0` ships. Its C++ defines the checked settings functions that engine `v1.1.0` adds to ``; regenerate and relink. | +| 1.2.0 (PyPI, 2026-10-05) | `v1.2.0` | The pair the `pineforge-release` image `1.2.0` ships. Its C++ defines the compiled execution capability functions that engine `v1.2.0` adds to ``; regenerate and relink. | | Later `X.Y.Z` releases | `vX.Y.Z` of the same version | See below. | On the 0.x line the engine and codegen versions are independent, and the @@ -466,8 +467,8 @@ Pine as `strategy.pine`, write `strategy.generated.cpp` with the [file example](#transpile-a-file-to-a-cpp) above, then from the same directory: ```bash -# 1.1.0 pairs with engine v1.1.0. For 0.10.4 use --branch v0.13.1. -git clone --branch v1.1.0 https://github.com/pineforge-4pass/pineforge-engine.git +# 1.2.0 pairs with engine v1.2.0. For 0.10.4 use --branch v0.13.1. +git clone --branch v1.2.0 https://github.com/pineforge-4pass/pineforge-engine.git cd pineforge-engine cp ../strategy.generated.cpp tutorial/macd/generated.cpp # the tutorial's strategy slot bash tutorial/run.sh # needs cmake, a C++17 compiler and python3 @@ -476,7 +477,7 @@ bash tutorial/run.sh # needs cmake, a C++17 compiler and python3 `run.sh` configures CMake once, builds `libpineforge.a` and `tutorial/macd/strategy.so`, and runs `tutorial/run.py`, which loads the `.so`, feeds it the bars and reads back the closed trades. For the quick-start SMA -cross, 1.1.0 with engine `v1.1.0` prints: +cross, 1.2.0 with engine `v1.2.0` prints: ``` MACD(12,26,9) on BTCUSDT 15m — 672 bars, 2026-04-29 18:15 → 2026-05-06 18:00 UTC @@ -494,7 +495,7 @@ order sizing: 1.0.0 gives an omitted `initial_capital`, `default_qty_type` and `default_qty_value` TradingView's Pine v6 defaults (100,000, `strategy.percent_of_equity`, 100), where 0.10.4 leaves the engine's own (1,000,000 and 1 contract). Declaring those in -`strategy()` books the same 13 trades on 1.1.0. +`strategy()` books the same 13 trades on 1.2.0. Since 1.0.0, generated strategies reset persistent Pine state before each new batch or stream warmup through the engine's script-run preparation hook. Input @@ -574,7 +575,7 @@ quote. The commercial-license store (coming soon) will take orders online. ## Explicit Pine execution attachment -This section describes 1.1.0 and engine `v1.1.0`. The Pine execution adapter is +This section describes 1.2.0 and engine `v1.2.0`. The Pine execution adapter is the engine's full Pine execution runtime (`PineExecutionAdapter` and `PineStrategyHost` in the engine's `src/source/`): order lifecycle, bracket legs, fill-price and slippage rules, POOC / `calc_on_order_fills`, margin @@ -597,9 +598,9 @@ Regenerate old generated C++ before using a new engine for Pine execution. C++ generated before the source-layer cut ([#129](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/129)), 0.10.4's included, derives from `BacktestEngine` and does not compile against -engine `v1.1.0`; old cap-only C++ does not attach the priority rule, and +engine `v1.2.0`; old cap-only C++ does not attach the priority rule, and metadata cannot silently restore it. Rebuild all modules against the -new matching C++ layout (`engine_script_run_v19` in engine `v1.1.0`); old +new matching C++ layout (`engine_script_run_v19` in engine `v1.2.0`); old fingerprint versions are not comparable. The extraction preserves Pine policy under explicit attachment; it does not implement the generic native child-activation scheduler or prove campaign neutrality. Compile-only corpus diff --git a/docs/PUBLIC_CONTRACT.md b/docs/PUBLIC_CONTRACT.md index d54b202..584bcda 100644 --- a/docs/PUBLIC_CONTRACT.md +++ b/docs/PUBLIC_CONTRACT.md @@ -2,8 +2,8 @@ ## Optional compiled execution capabilities -Availability: **since the next release**, with the paired engine's capability -extension and receipt-based runner admission policy. +Availability: **since 1.2.0**, with engine `v1.2.0`'s capability extension and +the receipt-based admission policy of its live runner. The receipt proves declarations only, not general live-versus-batch equivalence. Its `strategy()` positional arguments follow Pine signature order independently @@ -24,8 +24,9 @@ All six builtin uses are refused including display-only use (plots, labels, tables): the receipt records their use conservatively rather than certifying that display-only code cannot influence strategy execution. -Paired development headers defining `PF_CAPABILITIES_API_VERSION` add -`strategy_capabilities_api_version()` (version 1) and +From 1.2.0 on, C++ compiled against headers that define both +`PF_SETTINGS_API_VERSION` and `PF_CAPABILITIES_API_VERSION`, as engine +`v1.2.0`'s do, adds `strategy_capabilities_api_version()` (version 1) and `strategy_capabilities_receipt(handle, json, capacity, required, error, error_capacity)`. The receipt uses the checked-settings status and buffer protocol: NULL/0 queries return `PF_SETTINGS_BUFFER_TOO_SMALL`, `required` includes the NUL, and short @@ -41,7 +42,9 @@ feed source. Requirements name historical-only data and intrabar persistence; nonliteral contexts remain explicit rather than silently assuming defaults. See the paired engine's `docs/strategy-capabilities.md` for the exact schema and live-runner refusal policy. No batch dispatch, strategy calculation, matching, -margin or numeric behavior changes. Old paired headers emit no capability extension. +margin or numeric behavior changes. C++ compiled against headers without +`PF_CAPABILITIES_API_VERSION`, such as engine `v1.1.0`'s, has no capability +extension. ## Optional generated settings extension @@ -77,7 +80,8 @@ reports remain empty; checked batch returns `PF_SETTINGS_RUN_FAILED`. Free and recreate the handle to recover. Legacy setters that do not throw keep their existing permissive behaviour. -Engine `v1.1.0`, the pair of codegen 1.1.0, provides that header. Settings +Engines `v1.1.0` and `v1.2.0`, the pairs of codegen 1.1.0 and 1.2.0, provide +that header. Settings helper references are root-qualified and guarded by `PF_SETTINGS_API_VERSION`; old headers retain the standard-exception fallback and legacy batch precheck. Paired batch and stream refusals report NOT_COMPLETED through the shared native @@ -143,7 +147,12 @@ released 2026-10-02, implements unchanged. 1.1.0, released 2026-10-04, implements it with the generated settings extension and request discovery above added: `transpile_full()`'s result and the JSON success envelope gain `requests`, and `input.symbol` manifest entries gain `kind`. No argument, -result key or envelope is removed or renamed. +result key or envelope is removed or renamed. 1.2.0, released 2026-10-05, +implements it with the compiled execution capabilities and the diagnostic +codes described here added: each `Diagnostic` and each JSON diagnostic gain +`code` and `args`, and `pineforge_codegen` exports `diagnostics_catalog()` +and `render_diagnostic()`. No argument, result key or envelope is removed or +renamed. The last 0.x release, 0.10.4, has neither the `libraries` argument nor the `diagnostics` key described below. @@ -263,7 +272,8 @@ Since 1.2.0 every `Diagnostic` (in `transpile_full(...)["diagnostics"]`, in a `diagnostics_catalog()` returns the catalog, which ships as `pineforge_codegen/diagnostics_catalog.json` (schema -`pineforge-diagnostics-catalog/v1`) and is attached to each GitHub release. +`pineforge-diagnostics-catalog/v1`) and is attached to each GitHub release +(`diagnostics_catalog-v1.2.0.json` for 1.2.0). Per code it gives `severity`, `area`, the English ICU MessageFormat `message` template, the `hint` template or `null`, a one-line `explanation`, and `args`: per argument its `kind` — `identifier`, `type`, `keyword`, `number`, `vocab` diff --git a/docs/pine-cap-activation.md b/docs/pine-cap-activation.md index 9f01df3..e0c0583 100644 --- a/docs/pine-cap-activation.md +++ b/docs/pine-cap-activation.md @@ -4,7 +4,7 @@ This note came with the explicit cap attachment ([#127](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/127)). It now also covers the execution-adapter attachment that followed ([#128](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/128)) and -describes codegen 1.1.0 with engine `v1.1.0`. +describes codegen 1.2.0 with engine `v1.2.0`. Generated strategies explicitly select Pine intraday-cap compatibility in their constructor. When the engine defines @@ -20,7 +20,7 @@ The expression is evaluated only where the source executes it, and limit updates preserve the existing quota and pending obligations. Selection does not evaluate a limit or move a conditional statement into the constructor. -Engine `v1.1.0` defines both macros in `pineforge/source/pine_strategy_host.hpp`, +Engine `v1.2.0` defines both macros in `pineforge/source/pine_strategy_host.hpp`, the header the generated C++ includes; every engine commit with that header does, since the header and the macros arrived there together (engine #253). So the adapter branch is the one that compiles today. The cap-only branch and the @@ -30,9 +30,9 @@ capability, bare native construction leaves the Pine cap unselected. Matching runtime headers and library are required; this source bridge does not make stale compiled C++ objects compatible across internal ABI versions. -Engine `v1.1.0`, like `v1.0.0` and `v1.0.1`, no longer has the +Engine `v1.2.0`, like `v1.0.0`, `v1.0.1` and `v1.1.0`, no longer has the `script_has_strategy_close_` member that the C++ of codegen 0.10.4 and earlier -assigns, so that C++ does not compile there; regenerate it with codegen 1.1.0. +assigns, so that C++ does not compile there; regenerate it with codegen 1.2.0. The cap's three compatibility options retain their existing behavior and defaults. They belong to the selected Pine component, not universal native diff --git a/npm/README.md b/npm/README.md index 1303eff..b00d46f 100644 --- a/npm/README.md +++ b/npm/README.md @@ -16,6 +16,10 @@ Stable releases are on the `latest` dist-tag. A prerelease (for example - `transpile.worker.mjs` — an ES module worker that runs the glue in Pyodide. - `index.mjs` — exports `release`, `tables`, `archivePath`, `sourceRoot`, `codegenSourceDir`, `workerPath` and `glue`. +- `pineforge_codegen/diagnostics_catalog.json` — the diagnostics catalog (since 1.2.0), also + importable as `@pineforge/codegen-pyodide/diagnostics_catalog.json`; the repository's + `docs/PUBLIC_CONTRACT.md` describes it. +- `LICENSE` — the PineForge Source License 1.1 (since 1.2.0), which `package.json` names. ## Publishing (maintainers) A `v*` tag push, which the release workflow makes, publishes through npm OIDC Trusted From 95a5314bf0cff69bac3b140accccdbb6a7f1542d Mon Sep 17 00:00:00 2001 From: luisleo526 Date: Mon, 5 Oct 2026 11:56:08 +0800 Subject: [PATCH 2/2] docs: release 1.2.0's grades from the facts tokens README: the release sentence names 1.2.0 and renders releases[1.2.0] (baseline pineforge-parity-baseline-20261005-engine-52292db9, 7,970 excellent / 19 strong of 7,989), and the scoreboard of main renders the same baseline, from pineforge-release facts/facts.json as exported for the 1.2.0 release (sha256 c2f438f0). CHANGELOG: the 1.2.0 documentation entry states the release's grades, as 1.1.0's does. Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ba9a1..4615246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -240,6 +240,13 @@ and [#171](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/171): baseline `pineforge-parity-baseline-20261004-engine-6b77f061` (engine 6b77f061, this repository at 285ac035), 7,970 excellent and 19 strong of 7,989 graded probes, none below strong. + Release 1.2.0 is graded on registry baseline + `pineforge-parity-baseline-20261005-engine-52292db9`: 7,970 excellent and + 19 strong of 7,989 graded probes, none below strong, with engine 52292db9 + ([pineforge-engine#339](https://github.com/pineforge-4pass/pineforge-engine/pull/339)'s + merge), which v1.2.0 equals in behaviour, and this repository at 48e7a13b, + whose emitted C++ is codegen 1.2.0's: the release's remaining changes are + documentation. - `docs/PUBLIC_CONTRACT.md` describes the capability functions ([#167](https://github.com/pineforge-4pass/pineforge-codegen-oss/pull/167)) and diagnostic codes diff --git a/README.md b/README.md index 4d85717..a96d420 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ A pure-Python library that turns a PineScript v6 strategy into a complete C++ source file you can compile against the [`pineforge-engine`](https://github.com/pineforge-4pass/pineforge-engine) runtime. -**Measured 2026-10-04** on main engine `6b77f061` with codegen-oss `285ac035` (baseline `pineforge-parity-baseline-20261004-engine-6b77f061`, snapshot `21639bad`): 7,970 of 7,989 TradingView probes +**Measured 2026-10-05** on main engine `52292db9` with codegen-oss `48e7a13b` (baseline `pineforge-parity-baseline-20261005-engine-52292db9`, snapshot `7161ebdc`): 7,970 of 7,989 TradingView probes graded excellent and 19 strong, with 0 below strong; 17 more probes are held out as TradingView-side anomalies. A probe is a strategy exported from TradingView with its trade list and replayed trade for trade on the same bars. -Release **1.1.0 grades 7,951 excellent / 38 strong until the next release**, on 7,989 probes (baseline `pineforge-parity-baseline-20261004-engine-7b596622`, 2026-10-04). A main scoreboard advance does not change release results. +Release **1.2.0 grades 7,970 excellent / 19 strong until the next release**, on 7,989 probes (baseline `pineforge-parity-baseline-20261005-engine-52292db9`, 2026-10-05). A main scoreboard advance does not change release results. The quantities above render from the public [facts tokens](https://github.com/pineforge-4pass/pineforge-release/blob/main/facts/facts.json). Maintain them with `lab facts render --repo . --facts `; `lab facts check` with the same inputs reports drift. Grades are registry-derived; the authored-script and closed-trade inventory is explicitly sourced to a historical public README for the identical population, not to registry row or slug totals.