Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion changed_files.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[
"R/ARMA.R"
"DESCRIPTION",
"NNS_13.0.tar.gz",
"NNS_13.0.zip",
"R/Multivariate_Regression.R",
"src/NNS.dll",
"tests/testthat/Rplots.pdf"
]
17 changes: 11 additions & 6 deletions sync/last_live_r_parity_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
- Plan: `sync/last_r_api_plan.json`
- R checkout: `upstream/NNS`
- Fresh cache requested: `False`
- Skip install: `False`
- Live R recompute: `True`
- Skip install: `True`
- Live R recompute: `False`

## Result: live R parity diverged
## Result: manual review required

Mapped parity tests recomputed every R value from the freshly installed live R NNS and the Python implementation did not match. Public Python behavior differs from live R at the recorded commit.
The plan reports unmapped R files. A human must extend `sync/r_api_map.json` before automated parity can run:

Failing command: `/opt/hostedtoolcache/Python/3.11.15/x64/bin/python -m pytest -q -n 0 tests/parity/test_practical_examples.py tests/parity/test_r13_smoke.py`
Exit status: `1`
- `R/Multivariate_Regression.R`

## Workflow step outcome

- `run_live_r_parity_for_changed_api.py` step outcome: `failure`
- Fresh cache requested: `false`
- DESCRIPTION changed: `true`
26 changes: 17 additions & 9 deletions sync/last_r_api_inspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,33 @@

## Changed files

- `R/ARMA.R`
- `DESCRIPTION`
- `NNS_13.0.tar.gz`
- `NNS_13.0.zip`
- `R/Multivariate_Regression.R`
- `src/NNS.dll`
- `tests/testthat/Rplots.pdf`

## Affected Python modules

- `src/nns/arma.py`
- `pyproject.toml`
- `tests/_r_cache.json`
- `tools/NNS`

## Parity tests to run

- `tests/parity/test_practical_examples.py`
- `tests/parity/test_r13_smoke.py`
- `tests/parity`

## Cache scope

- `NNS.ARMA`
- `NNS.ARMA.optim`
- `NNS.VAR`
- None mapped

## Required actions

- Fresh cache required: `False`
- Fresh cache required: `True`
- Export review required: `False`
- Unmapped R files present: `False`
- Unmapped R files present: `True`

## Unmapped R files

- `R/Multivariate_Regression.R`
28 changes: 16 additions & 12 deletions sync/last_r_api_plan.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
{
"changed_files": [
"R/ARMA.R"
"DESCRIPTION",
"NNS_13.0.tar.gz",
"NNS_13.0.zip",
"R/Multivariate_Regression.R",
"src/NNS.dll",
"tests/testthat/Rplots.pdf"
],
"affected_python_modules": [
"src/nns/arma.py"
"pyproject.toml",
"tests/_r_cache.json",
"tools/NNS"
],
"parity_tests": [
"tests/parity/test_practical_examples.py",
"tests/parity/test_r13_smoke.py"
"tests/parity"
],
"cache_scope": [
"NNS.ARMA",
"NNS.ARMA.optim",
"NNS.VAR"
],
"requires_fresh_cache": false,
"cache_scope": [],
"requires_fresh_cache": true,
"requires_export_review": false,
"has_unmapped_r_files": false,
"unmapped_r_files": [],
"has_unmapped_r_files": true,
"unmapped_r_files": [
"R/Multivariate_Regression.R"
],
"warnings": []
}
4 changes: 2 additions & 2 deletions sync/nns_source.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"r_repo": "OVVO-Financial/NNS",
"r_commit": "905b8bbd42b3236bf88aba7f18df7a9a378dbd7b",
"r_commit": "8183e964c941d9981e19b23dfbc9fc8336903d89",
"r_version": "13.0",
"r_src_tree_hash": "654e411bd4e8caabfd57a1a4190eb1d97411e059",
"r_src_tree_hash": "e68bedaf44bce209a1f1a778d398adb5a84b57a6",
"core_repo": "OVVO-Financial/NNS-core",
"core_commit": "cfc25a3469df6460f9224fb976fcb58de9d58068",
"python_repo": "OVVO-Financial/NNS-python",
Expand Down
6 changes: 6 additions & 0 deletions tools/NNS/.Rbuildignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
^.*\.Rproj$
^\.Rproj\.user$
^\.travis\.yml$
^doc$
^Meta$
^\.github/
73 changes: 73 additions & 0 deletions tools/NNS/.github/downstream-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Downstream sync contract

`OVVO-Financial/NNS` is the source of truth for the NNS implementation. It is
the truth for **both** the native C++ layer under `src/**` and the R API
behavior under `R/**`, `NAMESPACE`, and `DESCRIPTION`.

Downstream flow (a diamond, not a single chain):

```text
OVVO-Financial/NNS (source of truth: R + C++ src/**)
/ \
src/** native truth R API behavior truth
v v
NNS-core (portable C++) (tested directly)
\ |
v v
NNS-python <-------------+
```

Two paths converge on `NNS-python`:

* **Native path:** `src/**` is the native C++ truth. It flows to `NNS-core`
(the portable C++ layer), which in turn feeds `NNS-python`.
* **API path:** `R/**`, `NAMESPACE`, and `DESCRIPTION` define the R API
behavior truth, which is tested directly and flows straight to `NNS-python`
for API and parity review.

`NNS-python` sits at the convergence of both paths and must satisfy both.

## Triggers

A push to `NNS-Beta-Version` dispatches downstream sync events based on changed files.

| Changed path | Downstream action |
| ------------- | ----------------------------------------------------------------------------- |
| `src/**` | Dispatch `nns-r-src-updated` to `OVVO-Financial/NNS-core` |
| `R/**` | Dispatch `nns-r-api-or-version-updated` to `OVVO-Financial/NNS-python` |
| `NAMESPACE` | Dispatch `nns-r-api-or-version-updated` to `OVVO-Financial/NNS-python` |
| `DESCRIPTION` | Dispatch `nns-r-api-or-version-updated` and require downstream version review |

A `DESCRIPTION` version change means downstream Python must perform fresh live-R parity-cache regeneration.

## Required secret

`OVVO_SYNC_TOKEN` must be a token or GitHub App installation token with permission to call `repository_dispatch` on:

* `OVVO-Financial/NNS-core`
* `OVVO-Financial/NNS-python`

The default `GITHUB_TOKEN` is intentionally not used for cross-repo dispatch, because it is scoped to this repository and cannot reliably trigger `repository_dispatch` on the downstream repositories.

## Payload

Dispatch payloads include:

* `r_repo`
* `r_commit`
* `r_ref`
* `r_version`
* `r_src_tree_hash`
* `src_changed`
* `r_api_changed`
* `description_changed`
* `changed_files`

## Expected downstream events

* `nns-r-src-updated` — received by `OVVO-Financial/NNS-core` when `src/**` changes.
* `nns-r-api-or-version-updated` — received by `OVVO-Financial/NNS-python` when `R/**`, `NAMESPACE`, or `DESCRIPTION` changes.

## Rule

No downstream sync is complete until each downstream repository records the exact upstream R commit and verifies its own build and parity gates.
119 changes: 119 additions & 0 deletions tools/NNS/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: R-CMD-check

on:
push:
branches: ["NNS-Beta-Version"]
pull_request:
branches: ["NNS-Beta-Version"]
workflow_dispatch:

jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
fail-fast: false
matrix:
config:
- {os: windows-latest, r: 'release'}
- {os: windows-latest, r: 'devel'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: macos-latest, r: 'release'}

env:
R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
_R_CHECK_FORCE_SUGGESTS_: false
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
RGL_USE_NULL: true
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v4

- name: Install system libraries (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libgsl-dev libjpeg-turbo8-dev libpng-dev libtiff5-dev libfreetype6-dev libharfbuzz-dev libfribidi-dev xorg-dev

- name: Install dependencies on macOS
if: runner.os == 'macOS'
run: |
brew update
brew install xquartz fribidi gsl
echo "PKG_CPPFLAGS=-I$(brew --prefix gsl)/include" >> "$GITHUB_ENV"
echo "PKG_LIBS=-L$(brew --prefix gsl)/lib -lgsl -lgslcblas -lm" >> "$GITHUB_ENV"

- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check

- name: Check
uses: r-lib/actions/check-r-package@v2
with:
args: 'c("--no-manual", "--ignore-vignettes", "--no-build-vignettes")'
error-on: '"error"'

ubsan-clang-docker:
name: UBSAN clang
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Run UBSAN check inside container
run: |
docker run --rm --platform linux/x86_64 \
--cap-add=SYS_PTRACE \
-e UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=0" \
-e RGL_USE_NULL=true \
-v "${GITHUB_WORKSPACE}:/data" -w /data \
rocker/r-devel-ubsan-clang bash -lc '
set -euo pipefail

echo "::group::Update and Align System"
apt-get update -y
# This forces the image to sync its internal versions to avoid the libgbm1 conflict
DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y
echo "::endgroup::"

echo "::group::Install system dependencies"
# Removed libgl1-mesa-dev and libglu1-mesa-dev to avoid the Sid conflict
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
cmake libgsl-dev libcurl4-openssl-dev libssl-dev libxml2-dev \
libjpeg-dev libpng-dev libtiff5-dev libfreetype6-dev \
libharfbuzz-dev libfribidi-dev
echo "::endgroup::"

echo "::group::Install R package dependencies"
RD -q -e "install.packages(c(\"remotes\", \"rcmdcheck\", \"Rfast\", \"rgl\", \"recipes\"), repos=\"https://cloud.r-project.org\", Ncpus=2)"
RD -q -e "remotes::install_deps(dependencies = TRUE, repos=\"https://cloud.r-project.org\")"
echo "::endgroup::"

echo "::group::Run R CMD check with UBSAN"
RD CMD check --no-manual --ignore-vignettes --no-build-vignettes . > ubsan_check.out 2> ubsan_check.err || true
cat ubsan_check.err
echo "::endgroup::"
'

- name: Check for UBSAN errors
run: |
if grep -iE "(runtime error|sanitizer)" ubsan_check.err; then
echo "::error::UBSAN detected runtime errors."
exit 1
fi

- name: Upload UBSAN logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ubsan-logs
path: |
ubsan_check.out
ubsan_check.err
*.Rcheck/
Loading
Loading