Skip to content

feat: add verified NeuroSleep qEEG research ingestion (ADR-051) - #7

Merged
ruvnet merged 4 commits into
mainfrom
feat/neurosleep-qeeg-v1
Aug 3, 2026
Merged

feat: add verified NeuroSleep qEEG research ingestion (ADR-051)#7
ruvnet merged 4 commits into
mainfrom
feat/neurosleep-qeeg-v1

Conversation

@ruvnet

@ruvnet ruvnet commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Implements the Helix side of ADR-051: verified ingestion of signed derived NeuroSleep bundles (H1), a physically separate research WASM artifact (H2), and a deterministic research panel (H3). Every capability is off by default.

Pairs with the upstream contract released as ruv-neural-core 0.2.0-alpha.1 (ruvnet/ruv-neural#5, #6, #7).

What this is — and is not

This ingests a sleep and qEEG phenotype. It does not produce an Alzheimer's estimate, a microglial claim, a health score, a treatment recommendation, or a participant alert, and there is no code path by which it could: the output model has no such field, and a static gate fails the build if one appears.

The underlying finding is a preclinical APP/PS1 mouse study. The UI says "change from personal baseline associated with emerging research" and carries an explicit preclinical caveat; it never implies a human clinical marker.

Trust boundary

Helix verifies signatures itself rather than delegating across the repository boundary, against a separately enrolled trust key — a self-supplied trust root is rejected. Ingestion binds signer, study, subject, and consent scope; rejects replay; and seals derived records atomically under participant-opaque identifiers. Raw EEG never crosses into this repository — only versioned, signed, derived bundles.

The dependency is pinned exactly (=0.2.0-alpha.1), not by range. Helix verifies what the upstream signer produced; a compatible-looking version carrying a changed schema or extractor would silently reinterpret already-stored records without a new fingerprint.

The research build is separated by construction

helix-neurosleep gates all verification, trust, and storage behind a default native-ingest feature. The separation is machine-checkable, not asserted:

$ cargo tree -p helix-neurosleep --no-default-features -e normal
helix-neurosleep v0.1.2
├── serde
└── serde_json

No ruv-neural-core, no helix-vault, no sha2/hmac. The research artifact links no attestation or key-custody code at all.

helix-neurosleep-wasm accepts only identity-free verified nights plus the four flags. It has no API to enroll a signer, set policy, or submit a bundle. Its view type uses deny_unknown_fields, so a payload carrying a study id, subject pseudonym, recording id, or nonce is rejected, not ignored. Every user-visible string is a &'static str constant. The UI renders via textContent/createElement only — no innerHTML anywhere.

A safety gate that was silently passing

Both static safety scripts were failing open. They invoked rg inside an if condition; rg was not installed, so every check exited 127, every condition evaluated false, and each script printed clean having tested nothing. This voided the AT-10 prohibited-claim evidence recorded earlier in the requirement trace.

They now use grep, treat a tool error as a failure, refuse to pass vacuously when an expected path is missing, and cover helix-neurosleep-wasm (which holds the user-facing copy). Both were re-verified by negative control — an injected microglial activation detected string produces exit 1. The requirement trace records the withdrawal explicitly rather than quietly amending the affected rows.

New CI jobs run both gates and cargo deny on every change so this cannot rot unnoticed again.

Verification

cargo fmt --all -- --check                                   # clean
cargo clippy --workspace --all-targets --all-features -D warnings   # exit 0
cargo test --workspace --all-features                        # 232 passed, 0 failed
cargo build -p helix-wasm            --target wasm32-unknown-unknown --release
cargo build -p helix-neurosleep-wasm --target wasm32-unknown-unknown --release
npm test --prefix ui                                         # 8/8
cargo audit                                                  # 234 deps, 0 vulnerabilities
cargo deny check                                             # advisories/bans/licenses/sources ok
./validation/neurosleep/check_safety_boundary.sh             # clean (negative control verified)
./validation/neurosleep/check_forbidden_claims.sh            # clean (negative control verified)

Not claimed

ADR-051 and AT-01 through AT-12 are not complete. Numeric parity against the frozen reference (AT-02/AT-03) is unproven — no pinned SciPy/FOOOF fixtures exist. Sealed storage is in-memory, so withdrawal, deletion, export ledger, and post-ingest revocation quarantine are absent. The WASM view lacks authenticated native provenance, so it is a trusted-host visualization adapter rather than independent verified ingestion. Sleep-EDF evidence, executed fuzz reports, and browser execution tests remain outstanding.

docs/validation/ADR-051-requirement-evidence.md tracks all of this per requirement and per acceptance test.

ruvnet added 4 commits August 3, 2026 13:37
Completes the H2 and H3 stages of ADR-051 on top of the H1 verified ingestion
commit: a physically separate research artifact and a deterministic research
panel, both disabled by default.

The research build is separated by Cargo feature rather than by convention.
`helix-neurosleep` now gates all bundle verification, signer trust, consent,
replay protection, and sealed storage behind a default `native-ingest`
feature. The `view`, `config`, and `longitudinal` modules compile without it.
The separation is machine-checkable rather than asserted: with
`--no-default-features` the crate's entire dependency tree is `serde` and
`serde_json`, so the research artifact links no attestation, HMAC, or vault
key-custody code at all.

`helix-neurosleep-wasm` is a new crate whose only entry point accepts an
identity-free `VerifiedNeuroSleepNight` list plus the four research flags. It
has no API to enroll a signer, set admission policy, or submit a signed
bundle, and every user-visible string it emits is a `&'static str` constant
rather than anything interpolated from imported data. The derived view type
uses `deny_unknown_fields`, so a payload carrying a study id, subject
pseudonym, recording id, or nonce is rejected rather than silently ignored.

The UI module renders through `textContent` and `createElement` only, requires
the dedicated research WASM artifact rather than falling back, reconstructs
all copy client-side from constants, and keeps its own prohibited-claim list.

Also in this commit:

- Both static safety scripts now fail closed. They previously invoked `rg`
  inside an `if` condition, so on a host without ripgrep every check exited
  127, every condition evaluated false, and each script printed "clean" while
  testing nothing — silently voiding the AT-10 prohibited-claim evidence. They
  now use grep, treat a tool error as a failure, refuse to pass when an
  expected path is missing, and cover `helix-neurosleep-wasm`, which holds the
  user-facing measurement label and caveat copy. A negative control confirms
  an injected forbidden claim now produces exit 1.
- `deny.toml` pins a permissive-only, crates.io-only dependency graph. The
  graph is free of copyleft licences.
- CI gains a `cargo deny` job and a job running both NeuroSleep safety gates,
  so neither can rot unnoticed again.
- The requirement-evidence trace records the withdrawn safety-script result
  explicitly instead of quietly amending the affected AT-10 and AT-12 rows.

The absolute band-power unit is corrected from `uV2_per_hz` to `uV2` to match
the upstream integrated-power contract; PSD-domain quantities such as the
theta peak power and aperiodic offset correctly remain `log10_uV2_per_hz`.

The upstream contract dependency is still a sibling path pin and is repointed
at the published alpha in a follow-up commit.
Replaces the `../../../ruv-neural/ruv-neural-core` path dependency with an
exact pin on the released `=0.2.0-alpha.1`.

The path dependency could not work outside this developer's machine. CI has no
sibling checkout, so the workspace did not build there at all; and because the
manifest also carried `version = "=0.1.0"`, any build without the path override
resolved to the *published* 0.1.0 crate, which predates the NeuroSleep contract
entirely. A release cut from that state would have linked a contract with no
NeuroSleep types rather than failing loudly.

The pin is exact rather than a range on purpose. Helix verifies bundles the
upstream signer produced; if a schema, extractor, or feature definition changed
under a compatible-looking version, already-stored records would be
reinterpreted by different rules without a new fingerprint.

Removing the path dependency also fixes `cargo fmt --all -- --check`, which
previously walked into the upstream checkout and reported that repository's
unrelated formatting debt as a Helix failure.

Verified against the published crate: 232 workspace tests, strict clippy, both
wasm32 release builds, 8 UI tests, cargo-audit over 234 dependencies,
cargo-deny, and both fail-closed safety gates all pass. The research build's
dependency tree resolves to serde and serde_json only.
…heckout

The NeuroSleep tests reached the golden bundle and trust profile through
`include_bytes!("../../../../ruv-neural/ruv-neural-core/tests/fixtures/...")`.
That path only resolves on a machine with the upstream repository checked out
next to this one, so the crate did not compile in CI at all. Pinning the
published upstream crate does not fix it either: `include_bytes!` cannot reach
into a registry dependency's sources.

Both fixtures are now vendored under
`crates/helix-neurosleep/tests/fixtures/upstream-neurosleep-v1/`, copied
verbatim from the exact pinned version with their SHA-256 digests and upstream
paths recorded alongside. Only the Ed25519 verifying key is stored; no private
key material enters this repository.

A vendored copy would normally risk drifting from its source. It cannot drift
silently here, because these fixtures are cryptographically verified by the
same pinned contract code rather than merely parsed: the signature covers every
analytic and method field under RFC 8785 canonicalization. Any upstream change
to a field name, unit, canonicalization, required key, or compatibility
fingerprint makes the fixture stop verifying and fails the suite, which is
precisely when a human should be refreshing it.

The safety boundary script gains a matching structural guard: no source file
may `include_bytes!`/`include_str!` a path that escapes the repository. Local
green was not evidence for this class of bug — the sibling checkout existed on
the development machine — so it needs to be enforced statically. Verified by
negative control: reintroducing such an include produces exit 1.
@ruvnet
ruvnet merged commit bf5277a into main Aug 3, 2026
4 checks passed
@ruvnet
ruvnet deleted the feat/neurosleep-qeeg-v1 branch August 3, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant