Decision kernel
Transport, thresholds, cache and ledger for JEV judgments, and where question templates belong.
The decision kernel is Rna’s only path to JEV. The code lives in four places:
| Location | Contents |
|---|---|
packages/sdk/src/decision-kernel.mjs | Transport, cache, ledger |
packages/sdk/src/decision-templates.mjs | Thresholds, question templates, functions that turn probabilities into verdicts |
packages/sdk/src/decision-state.mjs | State builders |
prototypes/control-center/decision-service.mjs | Host call sites |
Modes and backends
- Modes:
off,shadow(record only, no behavior change),active. - Backends:
typesafe(JEV) orllm(a language model acting as judge). - Each result names its
source:judgefor a judgment,fallbackfor the rule used when no judge is available, andrulefor a deterministic rule of the host. - In the Rna app all decision points are built in and
activeby default, with only a fewofforshadow; mode and backend can only be overridden for diagnosis with the environment variablesRNA_JEV_MODE,RNA_JEV_MODESandRNA_JEV_BACKEND. The backend is chosen automatically: the JEV key first, then the fast model, and with the fast model (llm) every threshold is raised by 0.1.
Thresholds
Thresholds are tiered by consequence; the constant is DECISION_THRESHOLDS in decision-templates.mjs. A yes/no question’s confidence is max(p, 1 - p):
| Tier | Threshold |
|---|---|
| low | 0.60 |
| medium | 0.75 |
| high | 0.85 |
The constants also hold a floor of 0.5, the fast-model offset llmOffset of 0.1, and numeric thresholds set per decision point (some points use two, {act, ask}). Look at the real distribution on a labelled set before choosing a tier for each question. Never copy one from another question or type.
Adding a decision point
- Write the question template and its combining function in
decision-templates.mjs. Phrase questions as literal, observable situations, one judgment each. - Register the template with every question ID in
TEMPLATE_SPECS. Missing entries make the kernel reject the whole plan asinvalid_assessment_plan;packages/sdk/test/decision-templates-valid.test.mjsguards this. - Register the point in the host's
decision-service.mjs(title, risk tier, effect) so it appears in the settings Judgment records. - Build the state in
decision-state.mjs: only the text the judgment needs, with lengths, counts and dates computed in code and bucketed. - Run a labelled set through the probe, record the distribution next to the study, then choose thresholds.
Probe
POST /api/v2/decision-kernel/probe
Content-Type: application/json
{ "state": "…", "questions": { "…": { "type": "noul", "instructions": "…", "criteria": "…" } } }The probe sends one raw call with the app’s configured key, bypassing thresholds, cache and ledger. The reusable harness is prototypes/control-center/benchmark/jev-capability-probe.mjs; set RNA_STATE to the main checkout’s .state/state.json to read real rule bodies.