Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8807885
test(entries): lock in /entries type-filter parity vs Nightscout
ryceg Jun 20, 2026
b0d3935
feat(alerts): freeze engine semantics + golden parity corpus
ryceg Jun 12, 2026
2be40a3
feat(alerts): nocturne-alerts-core Rust crate
ryceg Jun 12, 2026
6c710cb
feat(alerts): C ABI for the Rust engine + .NET bindings + three-way p…
ryceg Jun 12, 2026
f374dc1
feat(alerts): IAlertEvaluationEngine seam with managed/shadow/rust en…
ryceg Jun 12, 2026
fdf4543
feat(alerts-ffi): add UniFFI Kotlin bindings behind `uniffi` feature
ryceg Jun 12, 2026
4f35b2f
feat(alerts): dnd_windows table + rule scope_class (ADR 0004 D2)
ryceg Jun 21, 2026
b1699cd
feat(alerts): DndWindowSnapshot resolver — live + replay (ADR 0004 D3)
ryceg Jun 21, 2026
ad9b5d3
feat(alerts-core): scope-class classify (ADR 0004 D4)
ryceg Jun 21, 2026
5fff198
feat(alerts): scope-class classify FFI + host wiring (ADR 0004 D4b)
ryceg Jun 21, 2026
b7923a6
feat(alerts): shared DND suppression gate + scope plumbing (ADR 0004 …
ryceg Jun 21, 2026
43294ef
feat(alerts): resolve active DND scopes in the enricher (ADR 0004 D5.2)
ryceg Jun 21, 2026
3f5b03c
feat(alerts): route orchestrator + replay through the scoped DND gate…
ryceg Jun 21, 2026
b2502a4
feat(alerts): DND window endpoints (ADR 0004 D5.4)
ryceg Jun 21, 2026
b9b2b00
feat(alerts): manual DND becomes a scope=all window (ADR 0004 D5.5)
ryceg Jun 21, 2026
00bdf93
test(alerts): Aspire integration tests for scoped DND (ADR 0004 D5.6)
ryceg Jun 21, 2026
c784297
feat(alerts): describe FFI for condition readouts (ADR 0007 slice 1)
ryceg Jun 30, 2026
e597bf0
feat(alerts): emit canonical node paths in describe
ryceg Jun 30, 2026
82188d1
fix(ci): clippy + rustfmt + classify dnd_windows in the share guard
ryceg Jul 1, 2026
9af4f99
ci(docker-publish): build the nocturne_alerts cdylib into the nocturn…
ryceg Jul 1, 2026
b380b26
fix(alerts): skip the scope-class backfill when the native engine is …
ryceg Jul 1, 2026
8a4ea8f
fix(alerts): manual all-window takes precedence over scheduled for th…
ryceg Jul 1, 2026
cc0407e
fix(alerts-ffi): reject structurally malformed root condition_params …
ryceg Jul 1, 2026
562224a
fix(alerts): DND window writes cannot silently kill or fabricate a mute
ryceg Jul 1, 2026
741675b
fix(alerts): migrated legacy DND windows keep their original receipt …
ryceg Jul 1, 2026
628ca28
chore: repair UTF-8 em-dashes mangled to Windows-1252 mojibake in Noc…
ryceg Jul 1, 2026
a22020b
test(alerts): completeness guard for shadow comparator over AlertEngi…
ryceg Jul 1, 2026
8c9b89e
test(alerts): completeness guard for the three hand-synced FFI contex…
ryceg Jul 1, 2026
708bb08
refactor(alerts-tests): dedupe native gate, corpus locator, JSON diff…
ryceg Jul 1, 2026
80cfa13
perf(alerts): scope-class backfill no longer gates startup or tracks …
ryceg Jul 1, 2026
7ad9bcf
perf(alerts): memoise the FFI context wire element per SensorContext …
ryceg Jul 1, 2026
0d52f56
fix(alerts): DND window create returns 409 on a cross-tenant id colli…
ryceg Jul 1, 2026
5e1919b
fix(alerts): settings DND toggle-off also clears future-started all-w…
ryceg Jul 1, 2026
d555175
fix(alerts): replay reconstructs the do_not_disturb leaf from all-win…
ryceg Jul 1, 2026
902943c
Merge remote-tracking branch 'origin/main' into rust-alerts
ryceg Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
22 changes: 22 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ jobs:
exit 1
fi

# The scoped-DND rule classifier (and the optional rust/shadow alert engines)
# load the nocturne_alerts cdylib at runtime. The API csproj packs it only when
# crates/target/release contains it at publish time, so build it here or the
# image ships without it and every rule classifies as undirected.
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
crates/target
key: cargo-${{ runner.os }}-${{ hashFiles('crates/Cargo.lock') }}

- name: Build nocturne_alerts native library
working-directory: crates
run: |
cargo build --release -p nocturne-alerts-ffi
test -f target/release/libnocturne_alerts.so

- name: Build and push Nocturne.API container
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false)
working-directory: src/API/Nocturne.API
Expand Down
67 changes: 67 additions & 0 deletions .github/workflows/native-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Native release (alerts)

# Builds the nocturne_alerts cdylib (crates/nocturne-alerts-ffi) for linux-x64
# and win-x64 on a tag push like `alerts-v0.1.0` and attaches the artifacts to
# the GitHub release for that tag (creating the release if it doesn't exist).

on:
push:
tags: ["alerts-v*"]

permissions:
contents: write

jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
rid: linux-x64
artifact: libnocturne_alerts.so
asset: libnocturne_alerts-linux-x64.so
- os: windows-latest
rid: win-x64
artifact: nocturne_alerts.dll
asset: nocturne_alerts-win-x64.dll
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
crates/target
key: cargo-release-${{ runner.os }}-${{ hashFiles('crates/Cargo.lock') }}
- name: Build cdylib
working-directory: crates
run: cargo build --release -p nocturne-alerts-ffi
- name: Stage artifact under its release asset name
shell: bash
run: |
mkdir -p dist
cp "crates/target/release/${{ matrix.artifact }}" "dist/${{ matrix.asset }}"
- uses: actions/upload-artifact@v4
with:
name: nocturne-alerts-${{ matrix.rid }}
path: dist/${{ matrix.asset }}
if-no-files-found: error

release:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Attach artifacts to the GitHub release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
91 changes: 91 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,97 @@ jobs:
name: unit-trx
path: "**/*.trx"

# The alert-engine golden corpus (tests/Parity/AlertEngineCorpus) is the normative
# spec for the Rust port of the leaf/node evaluation engine. While the C# engine is
# authoritative, any behavioural change to the evaluators/tracker must regenerate the
# corpus deliberately — this job fails if the committed corpus no longer matches what
# the engine produces.
alert-corpus-check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0"
- name: Cache NuGet
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }}
- name: Verify alert engine corpus is current
run: |
dotnet run --project tests/Parity/Nocturne.Alerts.ParityCorpus.Generator \
-p:GenerateNSwagClient=false -- --check

# Rust alert engine FFI: lints + tests the crates workspace, builds the
# nocturne_alerts cdylib, then runs the three-way parity suite (C# engine vs
# committed corpus vs Rust engine over the C ABI). NOCTURNE_ALERTS_REQUIRE_NATIVE
# turns silent skips (native lib not found) into a hard failure so the parity
# theories can never quietly stop running here.
alerts-ffi-parity:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0"
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
crates/target
key: cargo-${{ runner.os }}-${{ hashFiles('crates/Cargo.lock') }}
- name: Cache NuGet
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }}
- name: Rust tests, clippy, fmt
working-directory: crates
run: |
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --check
- name: Build nocturne_alerts cdylib
working-directory: crates
run: cargo build --release -p nocturne-alerts-ffi
- name: Three-way parity tests (C# engine vs corpus vs Rust FFI)
env:
NOCTURNE_ALERTS_NATIVE_DIR: ${{ github.workspace }}/crates/target/release
NOCTURNE_ALERTS_REQUIRE_NATIVE: "1"
run: |
dotnet test tests/Unit/Nocturne.Alerts.Native.Tests/Nocturne.Alerts.Native.Tests.csproj \
--logger "trx;LogFileName=alerts-ffi-parity.trx" \
-p:GenerateNSwagClient=false \
|| exit 1
# Engine-seam tests (IAlertEvaluationEngine): corpus parity for both the managed and
# rust-backed seam adapters, cross-engine timer continuity, shadow-mode divergence
# logging, and Alerts:Engine flag selection. The rust-backed theories require the
# cdylib built above; NOCTURNE_ALERTS_REQUIRE_NATIVE turns silent skips into failures.
- name: Engine seam tests (managed + rust adapters, shadow, flag)
env:
NOCTURNE_ALERTS_NATIVE_DIR: ${{ github.workspace }}/crates/target/release
NOCTURNE_ALERTS_REQUIRE_NATIVE: "1"
Alerts__Engine: rust
run: |
dotnet test tests/Unit/Nocturne.API.Tests/Nocturne.API.Tests.csproj \
--filter "FullyQualifiedName~Services.Alerts.Engines" \
--logger "trx;LogFileName=alerts-engine-seam.trx" \
-p:GenerateNSwagClient=false \
|| exit 1
- uses: actions/upload-artifact@v4
if: failure()
with:
name: alerts-ffi-parity-trx
path: "**/*.trx"

# Database integration tests: bare-Postgres Testcontainers (no Aspire), so they
# run reliably on GitHub-hosted runners where Docker is available. Other
# integration projects stay deferred until their fixtures/references are fixed.
Expand Down
1 change: 1 addition & 0 deletions crates/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
Loading
Loading