From cb216668ee51d37186f0721939a7b0d37b0a561e Mon Sep 17 00:00:00 2001 From: kingchenc Date: Thu, 11 Jun 2026 03:28:19 +0200 Subject: [PATCH] docs: fix accuracy drift in SECURITY, ARCHITECTURE, THREAT_MODEL (#253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation-only accuracy fixes from the codebase audit (no code changes). ## SECURITY.md - Supported-version policy was stale at `0.5.x` while `0.8.3` is published. Bump to the exact `0.8.3` (prose + table `0.8.3 (latest)` / `< 0.8.3`). The exact `x.y.z` form lets `bump_version.py` keep it current automatically (now wired as a touchpoint). ## ARCHITECTURE.md - `three` → **four** binding crates (the C ABI crate was added). - workspace diagram `214` → **514** indicators (matches the `mod`-count and `lib.rs` public-type count; now wired into the indicator-wiring automation so it self-heals). - WASM "does not have automated tests yet" → corrected: `bindings/wasm/src/lib.rs` carries **21** `wasm-bindgen-test` cases. - **Numerical-stability notes rewritten to match the code:** the sliding-window variance family (`StdDev`, `Variance`, `ZScore`, `Bollinger`) uses running `Σx²−mean²` with clamping (and periodic reseed for `Bollinger`), **not** Welford. True Welford is used only by `IntradayVolatilityProfile` and `SeasonalZScore` (it does not transfer cleanly to a sliding window). The **Kahan-summation** bullet is removed — no Kahan summation exists in the crate. ## THREAT_MODEL.md - The C ABI is built with `panic = "abort"` and has no `catch_unwind`. Replace the false "catches panics so none cross the boundary" claim with the honest abort strategy (terminates deterministically instead of unwinding across the FFI boundary, which would be UB). --- ARCHITECTURE.md | 29 ++++++++++++++++------------- SECURITY.md | 6 +++--- THREAT_MODEL.md | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index eb0bcb8f..e14f0de8 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -7,7 +7,7 @@ for the day-to-day workflow. ## Workspace layout -Wickra is a Cargo workspace of three Rust crates plus three binding crates. +Wickra is a Cargo workspace of three Rust crates plus four binding crates. The split is deliberate: every concern that one user might want to disable or replace lives behind a separate crate boundary. @@ -20,7 +20,7 @@ or replace lives behind a separate crate boundary. ┌───────────▼──────────┐ ┌──────────▼─────────┐ │ wickra-core │ │ wickra-data │ │ indicator engine │ │ i/o + aggregation │ - │ • 214 indicators │ │ • CSV reader │ + │ • 514 indicators │ │ • CSV reader │ │ • Indicator trait │ │ • Tick aggregator │ │ • BatchExt impl │ │ • Resampler │ │ • OHLCV / Candle │ │ • Live feeds │ @@ -203,14 +203,17 @@ typed object arrays for Node/WASM). A handful of indicators need care beyond naive accumulation: -- **Welford's online variance** is used in `StdDev`, `Variance`, `ZScore`, - `BollingerBands`, and several others. Standard sum-of-squares is - catastrophically lossy for low-variance inputs; Welford's recurrence - keeps O(eps) error. -- **Kahan summation** is used wherever rolling sums could span > 1e6 - elements without resetting — currently only Hurst-exponent's R/S - chunks. Most rolling sums are bounded by the window size and don't need - it. +- **Rolling variance is running-sum, not Welford.** The sliding-window + variance family — `StdDev`, `Variance`, `ZScore`, `Bollinger` — keeps + running `Σx` and `Σx²` over the window and reports `var = Σx²/n − mean²`, + clamping to zero the tiny negative values floating-point cancellation can + produce. `Bollinger` periodically reseeds its `Σx²` from the live window + so error cannot accumulate over a long stream. Welford's online algorithm + (an incremental `M2` accumulator) does **not** transfer cleanly to a + sliding window — removing the oldest point from `M2` is numerically + unstable — so it is used only where the statistic is *not* a fixed + window: `IntradayVolatilityProfile` and `SeasonalZScore` accumulate + per-bucket variance that way. - **Logarithm bases** matter for some indicators (Hurst, MFI). Wickra uses natural log everywhere unless the reference math explicitly requires `log10` or `log2` — and then it documents the choice in the @@ -327,9 +330,9 @@ re-discovering them. - **`FAMILIES` (from PR #60) is hand-maintained.** Adding a new indicator requires a separate entry in `FAMILIES`. The `total_count_matches_expected` test will fail if you forget. -- **WASM does not have automated tests yet.** Smoke-validated only - through the manual examples. Adding `wasm-bindgen-test` coverage is - on the roadmap. +- **WASM is covered by `wasm-bindgen-test`.** `bindings/wasm/src/lib.rs` + carries 21 in-crate tests (run under `wasm-pack test` in CI), in + addition to the manual browser examples. For the high-level project goals see [`ROADMAP.md`](ROADMAP.md); for day-to-day contribution mechanics see [`CONTRIBUTING.md`](CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md index fb66291b..30ce27d5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,13 +2,13 @@ ## Supported versions -Wickra is pre-1.0. Security fixes are applied to the latest released `0.5.x` +Wickra is pre-1.0. Security fixes are applied to the latest released `0.8.3` version only; please upgrade to the newest release before reporting an issue. | Version | Supported | | --- | --- | -| 0.5.x (latest) | :white_check_mark: | -| older 0.5.x | :x: | +| 0.8.3 (latest) | :white_check_mark: | +| < 0.8.3 | :x: | ## Reporting a vulnerability diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md index 29c93787..68a1ca38 100644 --- a/THREAT_MODEL.md +++ b/THREAT_MODEL.md @@ -33,7 +33,7 @@ small. | Threat | Mitigation | | --- | --- | | Memory-safety exploit (buffer overflow, UAF) via crafted input | Pure safe Rust; `unsafe` is forbidden/minimised, so the compiler precludes these classes. | -| Misuse of the C ABI FFI boundary (invalid/dangling handle, undersized batch buffer) | The C ABI (`bindings/c`) is the sole `unsafe` surface. Its shim adds no logic, NULL-checks every handle (returning `NaN`/no-op), writes only into caller-sized buffers, and catches panics so none cross the boundary. A caller passing a non-NULL but dangling pointer is undefined behaviour by C's own contract — out of scope, the same as any C library. | +| Misuse of the C ABI FFI boundary (invalid/dangling handle, undersized batch buffer) | The C ABI (`bindings/c`) is the sole `unsafe` surface. Its shim adds no logic, NULL-checks every handle (returning `NaN`/no-op), writes only into caller-sized buffers, and is built with `panic = "abort"` so a panic terminates the process deterministically instead of unwinding across the FFI boundary (which would be undefined behaviour). A caller passing a non-NULL but dangling pointer is undefined behaviour by C's own contract — out of scope, the same as any C library. | | Denial of service via malformed/degenerate input (NaN, infinities, extreme magnitudes) | Indicators reject non-finite inputs and validate parameters at construction; update paths are exercised by coverage-guided fuzzing and unit tests for edge cases. | | Silently incorrect results | 100% line coverage on the core crate; reference-value tests against known-good sources; streaming/batch parity tests. | | Integer overflow / panics | `clippy::pedantic` with `-D warnings`; debug assertions and overflow checks enabled in test/fuzz builds. |