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..4615246 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,244 @@ 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. + 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 + ([#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..a96d420 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,19 @@ [![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++ 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. @@ -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