Tepna is a browser-native, 100%-local physiological analysis instrument — a fleet of single-signal analyzers over a shared kernel. These are the rules that keep it scalable: adopt them forward, migrate old code opportunistically, never in one risky sweep.
CLAUDE.md wins on any conflict — especially the Clock Contract and the two gates.A change that improves "code cleanliness" but weakens any of these is the wrong change. This is why the answer to "the system is getting serious — move to a backend, microservices, Python?" is no: that trades away advantages #1 and #2 to solve a problem we don't have. The real scaling limit is drift, and the fix for drift is tighter contracts inside the architecture we already have — not more infrastructure.
A bundled Foo.html is a frozen, hash-verifiable instrument. Open it in 2026 or 2036, online or on a plane — it computes the same numbers.
One file. No install, no server, no network. Runs straight from file://.
Provenance stamps + the test suite mean every number traces to a reproducible build and a known contract.
The single most important rule. Every file belongs to exactly one layer, and each layer has exactly one responsibility. The boundaries — not the folder names — are what matter.
The constitution every node obeys. Nothing device-specific ever lives here — no "oxygen" knowledge, no "glucose" knowledge. CORE is stable by default; new capability is added as new surface (new field, new method), never by mutating what exists.
metric-registry.jsDexKernel · kernel-constantscrossnight-envelope.jsClock ContractGanglior export schemaPure domain math: signal transforms, feature extraction, metric computation. Allowed to be complex — but only about its one signal. Runs headless in Node; the test suite essentially does.
localStorage. Takes parsed input, returns metrics. parseTimestamp is duplicated into each DSP by design (Clock Contract) — the one sanctioned duplication.oxydex-dsp.jshrvdex-dsp.jsecgdex-dsp.jscpapdex-dsp.jsVisualization, file input, calling DSP, wiring controls. A render file must never recompute a metric, re-threshold a value, or re-derive physiology — it asks DSP for the number and the registry for how to label and badge it.
*-render.js*-app.jsFoo.src.htmlWhy this matters concretely. Without the boundary, a desaturation rule could live in OxyDex's render code and get subtly re-implemented in CPAPDex's — two truths. With it, that rule can only live in DSP (or as a shared CORE definition), so there's exactly one place it can drift from — and the test suite watches that one place.
Dependencies point downhill only: UI → DSP → CORE. CORE never imports a node. DSP never imports UI. No cycles, ever. And nodes never import each other — a -Dex is standalone by design (a user may own only one device). Cross-node interaction happens exclusively through the Ganglior export contract, consumed by the Integrator.
The system's real product is three contracts. The test suite is the mechanism that makes them real — the shared assertions in tests/dex-tests.js are the public contract. When behavior and assertion disagree, the assertion is right until a human deliberately changes it.
Every metric has one definition — id, label, unit, goodDirection, depth, evidence, cite — in its node's registry. Render and export read it; never redefine it.
ganglior.node-export: schema.name, recording.startEpochMs = floating t0Ms, ganglior_events[] with wall-clock t + absolute tMs. Consumers tolerate legacy t-only exports.
Kernel scoring, envelope definitions, registry methods. These do not silently evolve — they are versioned, deliberate surface.
Keep back-compat. Add new params last and optional; expose new data via a new field or method. Do not edit a shared assertion to match changed behavior — either preserve the old shape, or update tests/dex-tests.js deliberately, knowing Node CI uses the same file.
Tepna's credibility rests on this, and it is encoded, not just cultural. The evidence ladder is attached to every metric — a raw sensor reading and a population projection must never look alike. Trust is encoded in disc shape, never hue.
Read straight off the device.
Checked against a standard.
Published, device-dependent.
Plausible, not confirmed.
Rule-of-thumb direction.
A missing value is null, never fabricated. A missing timestamp is null, never now() — absence must stay visible.
An event's conf (severity/likelihood) and sqi (signal quality) are separate axes. Fusion attenuates via effConf = conf × (sqi ?? 1) — never collapse them.
When sources disagree, you don't count devices. Filter to sensors that can observe the signal, check internal plausibility, then look for the obligate physiological consequence.
Authority is assigned per signal, and a gold-standard source yields to a clean backup when its own quality gate trips. Chest ECG owns HRV — but is useless when its battery dies; the wrist PPG is the fallback for heart rate, but never for HRV magnitude under motion. New nodes declare what they are authoritative for, not that they are authoritative.
100% local. No network, no CDN, ever. Fonts are system stacks; assets are inlined at bundle time, not fetched. Edit the inputs (*-dsp.js / *-render.js / *.src.html) and re-bundle to Foo.html — never edit the bundle. The bundle's manifestHash — a deterministic projection of its inlined JS/CSS — is the instrument's executed-code fingerprint, and the sole code identity the gates check. (buildHash is retired as a provenance signal — stamped into exports as inert legacy metadata, but no gate reads it.)
All-green after any DSP / app / bundle change. The guardian of physiological truth — the assertions are the contract.
No red mismatch after any re-bundle. A JS/CSS-only change doesn't shift buildHash; a .src.html change does — both fine as long as no fixture flips unexpectedly.
The one larger refactor implied by the three layers — done safely. Not during a rollout or a node build (moving code while other work edits it guarantees conflicts). Adopt forward first: new nodes are born layer-clean. Migrate old nodes opportunistically, one per pass, gating after each — never six at once.
Success test for a migrated node: you can run its DSP headless in Node with no DOM, and its render file contains no number that isn't sourced from DSP or the registry.
null not fabricated; conf ≠ quality; capability before consensus.