* test: golden-pin the four de-duplicated indicators across all C-ABI bindings
Extend gen_golden to emit reference fixtures for AdOscillator (ADOSC),
IntradayIntensity, AwesomeOscillatorHistogram and AverageDrawdown, and replay
them through the Go / C# / Java / R golden harnesses so their corrected
definitions stay bit-identical to the Rust core in every binding. Go suite
verified locally (gcc 13 + cgo): all 9 golden tests pass; C#/Java/R use the
same fixtures and harness pattern (CI-verified). First step of extending the
golden coverage beyond the seven archetype representatives.
* test: golden-pin the scalar-output tranche (308 indicators) against Rust
Extend gen_golden with a generated emit_scalar that writes reference fixtures
for every single-f64-output indicator (scalar / candle / pairwise input) using
valid constructor params, and add a manifest-driven generic Python golden
replay that reconstructs each by its native name and checks it bit-for-bit
against the Rust output. 308 indicators now value-tied to the Rust core in
Python (pytest: 308/308). Takes golden coverage from the 7 archetype
representatives to 308+ of the catalogue.
22 scalar indicators with non-default constructor constraints are skipped by
gen_golden for now (logged), as are non-f64-output ones; multi-output, exotic
inputs and the per-indicator arg arities of the C-ABI/Node replays follow.
Generated + verified locally with the full toolchain.
* test: golden-pin the multi-output tranche (70 indicators) in Python
Add a generated emit_multi to gen_golden (per-indicator Output-field access,
one CSV column per field) and a manifest-driven generic Python replay that
checks every field of each multi-output indicator against the Rust reference.
70 multi-output indicators now value-tied to Rust in Python; combined with the
scalar tranche, 378 indicators are golden-pinned. 8 multi with non-default
param constraints and 5 with non-f64 Output fields (Option/Vec/i64) are
deferred. pytest green.
* test(golden): add 30 constraint-tuned indicators to scalar/multi golden suite
Emit golden fixtures for 22 scalar-output and 8 multi-output indicators
whose constructors need non-default parameters (Alma, Jma, Psar, T3, Mama,
DoubleBollinger, ZigZag, ...). All 408 fixtures replay bit-for-bit through
the Python binding.
* test(golden): cover 36 missed scalar/multi indicators
Add 26 single-output (LinearRegression family, HT cycle, Candle
volatility estimators, DrawdownDuration) and 10 multi-output
(BollingerBands, MACD/MACDEXT/MACDFIX, Camarilla, VWAP bands, ...)
indicators to the golden suite. 444 fixtures replay bit-for-bit
through the Python binding.
* test(golden): cover 50 exotic-input indicators
Add deterministic synthetic feeders for the DerivativesTick (17),
CrossSection (15), Trade (8), TradeQuote (3) and OrderBook (7)
families, derived from the shared OHLCV input series in both
gen_golden and a new Python replay harness (test_golden_exotic).
All 494 fixtures replay bit-for-bit through the Python binding.
* test(golden): complete 514-indicator golden coverage
Add the final tranches: 3 mixed multi-output indicators (Ichimoku,
WilliamsFractals, LeadLagCrossCorrelation), 6 histogram profiles
(time/volume seasonality + TPO/volume price profiles), 10 alt-chart
bar builders and the footprint. Every one of the 514 distinct
indicators now has a Rust-generated g_<Canonical>.csv fixture and a
generic Python replay (scalar/multi/exotic/profile/bars), all passing
bit-for-bit.
* test(golden): add generic Node replay for all 514 indicators
A manifest-driven node:test harness reconstructs every indicator by its
native class, feeds the same synthetic stream derived from the shared
golden input, and checks output bit-for-bit against the Rust reference
fixtures (scalar/multi/exotic/profile/bars). node_manifest.json is
generated from index.d.ts plus the Python-side manifests. 514/514 pass.
* test(golden): add generated Go replay for all 514 indicators
golden_all_test.go (generated by gen_golden_test.py) reconstructs every
Go indicator, feeds the shared synthetic stream and checks output
bit-for-bit against the Rust reference fixtures. A reflection-based
comparator flattens multi-output structs, profiles and bar slices so one
path covers all archetypes. This is the first C-ABI binding verified
across the full catalogue. 514/514 pass.
* test(golden): add generated C# replay for all 514 indicators
GoldenAllTests.g.cs (generated by gen_golden_test.py) reconstructs every
C# indicator, feeds the shared synthetic stream and checks output
bit-for-bit against the Rust reference fixtures via a reflection-based
flatten covering scalar/multi/profile/bar archetypes. 514/514 pass.
Also add the '#nullable enable' directive the compiler requires to the
generated Indicators.g.cs, clearing the four CS8669 warnings on the
nullable double[] profile return types.
* fix(java): marshal C ABI bool params correctly; add 514 golden replay
The Java FFM binding marshalled the cross-section state flags (newHigh,
newLow, aboveMa, onBuySignal) as JAVA_DOUBLE arrays, but the C ABI takes
them as const bool* (one byte each), so the native side read the low byte
of each 8-byte double and saw every flag as false. Add WickraNative.
boolSegment and use it across the 15 cross-section indicators. Also pass
the MacdExt MaType arguments as byte to match the uint8_t downcall
descriptor (was int, throwing WrongMethodTypeException).
Add GoldenAllTest.java (generated by gen_golden_test.py): a reflection
runner replaying all 514 indicators against the Rust reference fixtures.
The bugs above were found by this test; 514/514 now pass.
* fix(r): marshal C ABI bool flags correctly; add 514 golden replay
The R wrapper passed the cross-section state flags as (bool *)REAL(x),
reinterpreting the 8-byte doubles as 1-byte bools so the native side read
every flag as false. Add wk_bool_vec to convert each flag vector into a
real C bool buffer and use it for all 15 cross-section update wrappers.
Add test-golden-all.R + generated golden_specs.R: a reflective runner
replaying all 514 indicators against the Rust reference fixtures. The bug
above was found by this test; verified 514/514 pass locally.
* test(golden): add WASM replay for all 514 indicators
A manifest-driven node:test harness loads the nodejs-target wasm-pack
build, reconstructs every indicator by its JS class, feeds the shared
synthetic stream and checks output bit-for-bit against the Rust
reference fixtures. wasm_manifest.json is generated from the wasm .d.ts
plus the shared manifests; a recursive flattener covers scalar, multi
(Reflect objects), profile and bar shapes. 514/514 pass locally
(wasm-pack build --target nodejs, then node --test).
* test(golden): add C and C++ replay for all 514 indicators
golden_test.c (generated by gen_golden_test.py) drives every indicator
through the C ABI (wickra.h) and checks output bit-for-bit against the
Rust reference fixtures. golden_test.cpp #includes the same source so the
identical runner is compiled and run under both gcc (C) and g++ (C++) via
the CMake targets golden_test / golden_test_cpp — proving the extern "C"
header is consumable from each language. Both 514/514 (verified via ctest).
* test(golden): gofmt the generated Go golden replay
* test(golden): make the Node fixture reader CRLF-safe and pin fixtures to LF
* feat(c-abi): expose warmup_period / is_ready across the C ABI bindings
The C ABI hub exposed new/update/batch/reset/free per indicator but not the
Indicator::warmup_period / is_ready queries that the native (Python/Node/WASM)
bindings already had, so C/C#/Go/Java/R callers could not ask an indicator
whether it was warmed up without feeding it and watching for NaN.
Regenerated from the ScriptHelpers capi + language generators:
- bindings/c: wickra_<ind>_warmup_period (size_t) and wickra_<ind>_is_ready
(bool) for every indicator (504; the 10 alt-chart bar builders are excluded
by design). wickra.h regenerated via cbindgen (additive only).
- bindings/csharp: int WarmupPeriod() / bool IsReady() on each wrapper.
- bindings/go: WarmupPeriod() int / IsReady() bool.
- bindings/java: int warmupPeriod() / boolean isReady().
- bindings/r: C glue + registration; hand-written warmup_period() / is_ready()
S3 generics in methods.R, plus NAMESPACE exports.
Tests: C-ABI Rust unit tests, the C examples/archetypes.c suite, and the C#,
Go, Java and R archetype suites all gain a warmup/is_ready transition check.
* build(go): sync vendored wickra.h with the C ABI header
The Go binding vendors bindings/c/include/wickra.h; refresh it with the new
warmup_period / is_ready declarations so the CI sync check passes.
* docs: standardise language naming and add binding security sections
Canonical binding list everywhere: Rust, Python, Node.js, WASM, C, C++, C#,
Go, Java, R. Use C# (not .NET) as the language label, WASM (not WebAssembly)
in prose, and frame the C ABI as a hub rather than a list item.
- Bump stale indicator counts (200+ -> 514) and family count (sixteen ->
twenty-four) in the Node/Python/WASM and docs READMEs.
- Add a short Security section to all eight binding READMEs.
- Relabel benchmark rows (C -> C / C++, C# / .NET -> C#).
- Fix the 'language stecker' wording in the C#/Go/R API intros.
- Documentation only; no code or public API changes.
* release.yml: extend install snippets and expose version output
Add the missing registry installs to the release body (dotnet, go, Gradle/
Maven Central, r-universe) alongside cargo/pip/npm, and expose a v-stripped
'version' output from the tag step for the Gradle coordinate. Also fix the
C-ABI language order in the assets note (C# before Go).
* release.yml: correct the release body (10 languages, all registries)
Reframe the tagline to '10 languages' (native Rust/Python/Node.js/WASM + a C
ABI hub for C, C++, C#, Go, Java, R) instead of '4 language registries', note
that C#/Java/Go/R publish to NuGet/Maven/Go/r-universe via their own jobs, and
tidy the Node.js label and the C-ABI hub list.
Follow-up to #272. The root `osv-scanner.toml` cleared the OpenSSF Scorecard
Vulnerabilities check from score 5 to 9 (the two pyo3 advisories, which live in
`Cargo.lock` at the root). One finding remained — `GHSA-72hv-8253-57qq`
(jackson-core 3.x async-parser DoS) — because OSV-Scanner resolves its config
relative to each manifest, and the repo-root config does not cover the Maven
sub-directory scans.
This adds the same not-affected suppression next to the two Maven manifests
(`bindings/java`, `examples/java`).
`tools.jackson.core:jackson-core` 3.x is not a dependency of this project: full
Maven resolution (publishing-plugin tree + project trees) resolves only jackson
`2.16.1` / `2.17.1`; tools.jackson 3.x appears nowhere. OSV-Scanner's own
resolver flags it as a false positive.
Maintenance release — supply-chain and CI housekeeping only. No library code or
public API changes.
### Security
- Triaged the pyo3 advisories RUSTSEC-2026-0176 / RUSTSEC-2026-0177 as not
affecting Wickra (vulnerable APIs unreachable from the binding; fix blocked
upstream by rust-numpy pinning pyo3 `^0.28`). Recorded in `deny.toml` and
`osv-scanner.toml`.
### Changed
- Java binding: `central-publishing-maven-plugin` 0.5.0 → 0.10.0.
- CI GitHub Actions bumped to latest (checkout, setup-go, setup-java,
codeql-action, taiki-e/install-action).
- Added a Maven ecosystem to Dependabot.
Version bumped across all manifests/lockfiles via `bump_version.py`; Cargo.lock
refreshed. CHANGELOG `[0.8.9]` filled. Tag/publish to follow on explicit GO.
Follow-up to the Dependabot action-bump merges and the cargo-deny ignore (#271).
Three low-risk supply-chain housekeeping changes — config/docs only, no library
code, no runtime change.
## 1. `osv-scanner.toml` (new)
The OpenSSF Scorecard *Vulnerabilities* check runs OSV-Scanner over the repo and
was flagging five advisory IDs (`score is 5`). These reduce to three findings,
all assessed as not affecting Wickra:
| Advisory | Assessment |
|----------|------------|
| RUSTSEC-2026-0176 / GHSA-36hh-v3qg-5jq4 (pyo3) | Vulnerable API unused; fix is pyo3 0.29 but rust-numpy 0.28 pins pyo3 `^0.28` → upstream-blocked. Already in `deny.toml`. |
| RUSTSEC-2026-0177 / GHSA-chgr-c6px-7xpp (pyo3) | Same — `PyCFunction::new_closure` not called. Already in `deny.toml`. |
| GHSA-72hv-8253-57qq (jackson-core 3.x) | **Not a dependency of this project.** No manifest, Maven plugin, or the GitHub dependency-graph SBOM references `tools.jackson` 3.x; the only jackson present is `com.fasterxml.jackson.core:jackson-databind` 2.17.1. |
`osv-scanner.toml` records these as ignored-with-reason at the OSV layer,
mirroring `deny.toml` and the SECURITY.md VEX section. The Scorecard finding
also flip-flopped (fixed → reappeared) across unrelated release-bump commits,
confirming it is not a stable real exposure.
## 2. Bump `central-publishing-maven-plugin` 0.5.0 → 0.10.0
The Java binding pinned a publishing plugin five versions behind. Validated
locally with the JDK 22 toolchain (`mvn -Prelease validate`): the extension
loads, the existing `publishingServerId`/`autoPublish` config is compatible, and
all 14 binding tests pass. The actual `mvn deploy` upload path is only exercised
at release time (needs the Central token + GPG key), so it will be confirmed at
the next release.
## 3. Add a Maven ecosystem to Dependabot
The Java binding had no Dependabot coverage, which is why the stale 0.5.0 plugin
went unnoticed. Adds `package-ecosystem: maven` over `/bindings/java`,
`/bindings/java/benchmarks`, and `/examples/java` so plugin and dependency
updates (incl. the examples' jackson) are tracked going forward.
Version bump `0.8.7` → `0.8.8`.
### Fixed
- R binding: declare `Depends: R (>= 2.10)`, clearing the `R CMD check` "package needs dependence on R (>= 2.10)" warning that the bundled, lazy-loaded `sample_ohlcv` dataset triggers on r-universe / CRAN. (#264)
Bump touches the manual release touchpoints only; docs/webpage version strings are left to `sync-about.yml` on the tag.
Version bump `0.8.6` → `0.8.7`.
### Added
- R binding: a *Getting started* vignette and a synthetic `sample_ohlcv` example dataset, giving new users a runnable, self-contained walkthrough and populating the R-universe Articles and Datasets tabs. The vignette's code is exercised in CI so a broken example is caught before the published build. (#262)
Bump touches the manual release touchpoints only; docs/webpage version strings are left to `sync-about.yml` on the tag.
Version bump `0.8.5` → `0.8.6`.
### Changed
- Package registry metadata for better discoverability (#259):
- R (R-universe): R-universe URL + `X-schema.org-keywords` in `DESCRIPTION`, package logo at `bindings/r/man/figures/logo.png`.
- Python (PyPI): `Documentation` project URL.
- C# (NuGet): package icon via `PackageIcon`.
Ships the metadata so the next PyPI/NuGet publish carries the new fields (R-universe rebuilds from main independently). Bump touches the manual release touchpoints only; docs/webpage version strings are left to `sync-about.yml` on the tag.
Version bump `0.8.4` → `0.8.5`.
### Fixed
- The R binding's golden-fixture parity test now skips gracefully when the shared `testdata/golden` fixtures are not bundled with the package — standalone r-universe / CRAN builds package only `bindings/r`, so the repo-root fixtures are unreachable there (this was failing the r-universe build of 0.8.4). The parity stays enforced by the repository CI, where the fixtures are present. (#257)
Bump touches the manual release touchpoints only (`Cargo.toml`/`Cargo.lock`, Python/Node/Java/C#/R manifests, lockfiles, `SECURITY.md`, `CHANGELOG.md`). docs/webpage version strings are left to `sync-about.yml` on the tag.
**Task 5 — golden-fixture parity for the C-ABI bindings.** Lifts the C#/Go/Java/R tests from *one indicator per archetype* toward reference-value parity, catching FFI wiring bugs (swapped params, wrong multi-output field) the math-only core tests cannot see.
## What's here
- **`examples/rust/src/bin/gen_golden.rs`** + **`testdata/golden/*.csv`** — a Rust generator computing a deterministic OHLCV series plus the core's reference outputs for a curated archetype-spanning set: scalar (`Sma`/`Ema`/`Rsi`), candle (`Atr`), scalar multi-output (`MACD`), candle multi-output (`ADX`), pairwise (`Beta`). `nan` marks warmup. Regenerate with `cargo run -p wickra-examples --bin gen_golden`.
- **Parity runners** replaying the identical fixtures through each FFI (rel-tol 1e-6), each a standard test in the binding's existing suite (no `ci.yml` change — rides `dotnet test` / `go test` / `mvn install` / `R CMD`+testthat). A walk-up search locates `testdata/golden` regardless of run dir.
- **C#** (`bindings/csharp/.../GoldenTests.cs`) — ✅ validated locally, 7/7 pass.
- **Go** (`bindings/go/golden_test.go`) — ✅ validated locally, pass.
- **Java** (`bindings/java/.../GoldenTests.java`) — modeled on the archetype API; validated by CI (no local mvn).
- **R** (`bindings/r/tests/testthat/test-golden.R`) — modeled on the archetype API; validated by CI (no local Rscript).
## Notes
- The curated set spans every marshalling archetype; extending the indicator list is mechanical (add to the generator + regenerate). Bars/profile archetypes can be added next.
- No new CI jobs.
Version bump `0.8.3` → `0.8.4`.
Ships the work merged via #254:
### Fixed
- A single non-finite (NaN/inf) tick no longer poisons indicator state — 38 more scalar/pairwise indicators (linear-regression family, rolling quantiles/IQR, `Variance`/`StdDev`-derived stats, `Kurtosis`/`Skewness`, trailing stops, `KalmanHedgeRatio`, `SpreadBollingerBands`, …) now reject non-finite input and return `None`, joining the 16 pairwise indicators fixed earlier.
### Added
- Catalogue-wide property-based invariant harness (`crates/wickra-core/tests/invariants.rs`) asserting `batch == streaming`, `reset == fresh`, and non-finite-input rejection for every indicator and bar-builder.
### Changed
- CI: every job now has a runtime cap and the flaky Node test step auto-retries.
- Documentation accuracy fixes in `SECURITY.md`, `ARCHITECTURE.md`, and `THREAT_MODEL.md`.
Bump touches the manual release touchpoints only (`Cargo.toml`/`Cargo.lock`, Python/Node/Java/C#/R manifests, lockfiles, `SECURITY.md`, `CHANGELOG.md`). docs/webpage version strings are left to `sync-about.yml` on the tag.
Version bump 0.8.2 → 0.8.3, releasing the per-binding throughput benchmark work
(merged in #246).
Bumped via `ScriptHelpers/bump_version.py` across all manual touchpoints —
`Cargo.toml`, `pyproject.toml`, the Node `package.json` + 6 platform packages +
both lockfiles, the Java `pom.xml`s + README, the C# `.csproj`, the R
`DESCRIPTION` — plus `Cargo.lock` (via `cargo build`) and the `CHANGELOG.md`
`[0.8.3]` section and compare URLs.
CHANGELOG `[0.8.3]`:
- Per-binding throughput benchmarks for all 9 targets (BENCHMARKS.md §3).
- C ABI archetype test (`examples/c/archetypes.c`).
`cargo fmt`, `cargo test --workspace --all-features` (all green) and
`cargo clippy --workspace --all-targets --all-features -D warnings` pass. The
docs/webpage version strings are bumped by `sync-about.yml` on the `v*` tag —
not touched here.
Adds a `throughput` benchmark to every target and closes two small
test-coverage documentation/QA gaps. One PR, no merge of binding code beyond
the additive benchmarks and one C test.
## 1. Per-binding throughput benchmarks (all 9 targets)
Each benchmark feeds a deterministic synthetic OHLCV series through three
indicators chosen by **FFI call-signature archetype** (not algorithm — the same
Rust core runs underneath all bindings):
- `SMA(20)` — 1-in → 1-out (baseline boundary cost)
- `ATR(14)` — multi-in → 1-out (input marshalling)
- `MACD(12,26,9)` — 1-in → multi-out (output marshalling)
Streaming is timed for all three; batch for the single-output SMA and ATR
(median of 3 runs, after a warmup pass).
New: Python (PyO3), WASM, C (CMake), C# (Stopwatch), Go, Java (FFM), R, and the
Rust core baseline (`examples/rust/.../throughput.rs`, **no FFI** — the ceiling
the bindings are measured against and the value their batch paths converge
towards). Node already had `throughput.js`.
**Not a speed claim:** there is no comparable streaming TA library for C, C#,
Go, Java, R or WASM to compare against, so these are raw per-binding throughput
numbers documenting each language's FFI overhead — see BENCHMARKS.md §3. The
"Wickra is fast" claim still lives in §1/§2 (Rust core + the Python/Rust
cross-library runs).
## 2. README `## Testing`: C# and C bullets
The section listed every layer except C# and C, even though both have suites.
Adds the two missing bullets.
## 3. C archetype ctest
`examples/c/archetypes.c` drives one indicator per FFI archetype through the
real C boundary (scalar + batch==streaming, multi-output, bars, profile, array
input) plus reset, invalid-parameter and NULL-safety — the C counterpart of the
Go/R/Java archetype suites. Runs on three OSes via the existing CMake/ctest.
## Notes
- Benchmarks are not CI-gated (manual-run scripts, like the existing
`throughput.js`); no `ci.yml`/`release.yml` changes.
- Docs: BENCHMARKS.md §3, a `## Benchmark` section in every binding README, a
CHANGELOG entry.
- Verified locally by running: Rust, Python, C, C#, Go, Java (real numbers); the
C archetype ctest with `-Wall -Wextra -Wpedantic -Werror`. WASM and R are
API-correct and syntax-checked but need their own toolchains to run.
Patch release shipping the R WebAssembly build fix (#244): `bindings/r/configure` builds the C ABI from source for `wasm32-unknown-emscripten`, so r-universe's webR build stops failing. Also carries the shared Go badge in `bindings/go/README.md`. Version bumped across all manual touchpoints via `bump_version.py` (incl. DESCRIPTION + csproj, which had drifted before).
Patch release shipping the wickra-go mirror license fix (#239). The release-time Go mirror now includes the dual MIT OR Apache-2.0 license files, so the next published Go module version resolves with a redistributable license on pkg.go.dev. No code changes; all other packages are republished unchanged at 0.8.1.
Bumps the workspace from 0.7.9 to 0.8.0 and adds the release-time mirror of the Go module to a standalone `wickra-go` repository.
## release.yml: `go-mirror` job
Adds a `go-mirror` job (independent of `github-release`, `needs: c-abi-build`) that on every `v*` tag:
- assembles the standalone Go module from `bindings/go` (single-package source + the vendored `include/wickra.h`),
- stages the six prebuilt C ABI libraries from the `c-abi-build` artifacts under `lib/<goos>_<goarch>/` (committed in the mirror, unlike the in-repo `lib/.gitignore`),
- rewrites `go.mod` to `module github.com/wickra-lib/wickra-go`,
- commits and tags the result in `wickra-lib/wickra-go` using the `WICKRA_GO_MIRROR_TOKEN` fine-grained PAT.
This makes `go get github.com/wickra-lib/wickra-go` build with no extra steps, closing the gap where the in-repo `bindings/go` module only built inside a full repository checkout. The mirror is a derived artifact, so its bot commit is intentionally unsigned.
## Version bump 0.7.9 -> 0.8.0
Patch never reaches double digits (`0.7.9` -> `0.8.0`). Touchpoints: `Cargo.toml` (+ `Cargo.lock` via build), `bindings/python/pyproject.toml`, `bindings/node/package.json` + 6 platform `npm/*/package.json` + both `package-lock.json` files, `bindings/java/pom.xml` + `examples/java/pom.xml` + Maven/Gradle snippets in `bindings/java/README.md`, and `CHANGELOG.md`. The C# `Wickra.csproj` (version set per tag) and `bindings/c` (inherits the workspace version) are intentionally untouched.
Tagging `v0.8.0` (which triggers the publish + the new mirror) stays gated on explicit confirmation.
Adds a Java binding (`bindings/java`) over the C ABI hub — the fourth language stecker after C#, Go and R, reaching the hub through the Java Foreign Function & Memory API (Panama, `java.lang.foreign`, final in Java 22) rather than JNI or jextract.
## What's here
- **`bindings/java`** — a Maven module (`org.wickra:wickra`) exposing all 514 indicators as idiomatic `AutoCloseable` classes. The downcall handles (`internal/NativeMethods.java`), the per-indicator wrappers and the output records are generated from `bindings/c/include/wickra.h` (same eight-archetype taxonomy as the C#/Go/R generators: scalar/batch, multi-output, bars, profile, values-profile, array-input). The opaque handle is a `MemorySegment` freed by a registered `java.lang.ref.Cleaner` action; multi-output returns a `record` (`null` at warmup), bars a `record[]`, profiles a record with a trailing `double[]`. The hand-written `WickraNative` resolves the native library (a bundled per-platform copy, or a `target/release` fallback for local development) and validates it against a sentinel symbol. repr(C) struct offsets are computed in the generator so the FFM reads land on the exact bytes.
- **`examples/java`** — the full example suite mirroring C/C#/Go/R: streaming, backtest, multi_timeframe, parallel_assets (parallel streams), three strategies, and `FetchBtcusdt`/`LiveBinance`.
- **CI** — a `java` job builds the C ABI library, sets up JDK 22 (Temurin, with a CDN-flake retry), runs the archetype test suite and the seven offline examples on Linux, macOS and Windows.
- **Release** — a gated `java-publish` job (skipped until the `JAVA_PUBLISH_ENABLED` repository variable is set) stages the native libraries from the `wickra-c-<triple>.tar.gz` assets into the binding's resources and deploys to Maven Central with GPG signing. Independent of the GitHub-release job, like the NuGet job.
- **Docs** — Java added to the README languages table, project layout, building/testing and comparison table, CONTRIBUTING, ARCHITECTURE, the examples index, the issue/PR templates, the About-description template, and the other binding READMEs.
## Requirements
Java 22+ (the FFM API is final since Java 22). The binding requires `--enable-native-access=ALL-UNNAMED` at runtime; the test and example runners pass it automatically.
No Rust crate or `Cargo.toml` change — the Java binding is standalone and additive. The generated `*.java` are committed (like the node `index.js`/`index.d.ts`); the generator stays private.