@mostlyrightmd/core/qc
Classes
Section titled “Classes”QCEngine
Section titled “QCEngine”QCEngine — orchestrates per-rule evaluation and OR-aggregates each rule’s
bit into the per-row obsQcStatus bitfield column.
Defaults to ALPHA_RULES; custom rule sets can be injected via the constructor (used for testing, future rule additions, or downstream-defined custom rules).
The obsQcStatus column name is camelCase (the TS convention) — Python uses
snake_case obs_qc_status. The JSON serializer converts it for the wire
format (jsonDumps emits snake_case on export).
JS bitwise OR (|) operates on 32-bit signed integers, so this engine
accepts rules with bitPosition in [0, 31]. A defensive RangeError fires at
construction if any rule violates that ceiling.
Constructors
Section titled “Constructors”new QCEngine()
Section titled “new QCEngine()”new QCEngine(
rules):QCEngine
Parameters
Section titled “Parameters”readonly QCRule[] = ALPHA_RULES
Returns
Section titled “Returns”Properties
Section titled “Properties”
readonlyrules: readonlyQCRule[]
Methods
Section titled “Methods”apply()
Section titled “apply()”apply<
Row>(rows): readonlyRow&object[]
Apply all registered rules to rows; return new rows with an
obsQcStatus bitfield column appended.
obsQcStatus[i] has bit N set iff this.rules[N].evaluate(rows)[i] === true.
Source rows are not mutated; output rows are fresh objects.
Empty input → empty output (no throw).
Each rule’s evaluate(rows) is called exactly once: the rule sees the full
row array and returns a parallel boolean[].
Type Parameters
Section titled “Type Parameters”• Row extends Record<string, unknown>
Parameters
Section titled “Parameters”readonly Row[]
Returns
Section titled “Returns”readonly Row & object[]
Interfaces
Section titled “Interfaces”CrosscheckDisagreement
Section titled “CrosscheckDisagreement”Disagreement row emitted by crosscheckIemGhcnh. Keys are
camelCase; serialized snake_case equivalents are event_time,
temp_c_iem, temp_c_ghcnh, and delta_c.
Properties
Section titled “Properties”deltaC
Section titled “deltaC”
readonlydeltaC:number
eventTime
Section titled “eventTime”
readonlyeventTime:string
station
Section titled “station”
readonlystation:string
tempCGhcnh
Section titled “tempCGhcnh”
readonlytempCGhcnh:number
tempCIem
Section titled “tempCIem”
readonlytempCIem:number
CrosscheckOptions
Section titled “CrosscheckOptions”Options for crosscheckIemGhcnh.
Properties
Section titled “Properties”
optionaltolC:number
Maximum acceptable absolute delta in °C between paired IEM/GHCNh
temp_c values. Defaults to 2.0 °C. A delta strictly greater than
tolC produces a disagreement row; a delta equal to it does not.
QCRule
Section titled “QCRule”A QC rule: ruleId and bit position (both read from the codegen table) plus a
per-row evaluator. evaluate(rows) returns a boolean[] of length
=== rows.length where true means the rule fired for that row.
Properties
Section titled “Properties”bitPosition
Section titled “bitPosition”
readonlybitPosition:number
description
Section titled “description”
readonlydescription:string
readonlyfield:string
ruleId
Section titled “ruleId”
readonlyruleId:string
Methods
Section titled “Methods”evaluate()
Section titled “evaluate()”evaluate(
rows):boolean[]
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
Variables
Section titled “Variables”ALPHA_RULES
Section titled “ALPHA_RULES”
constALPHA_RULES:ReadonlyArray<QCRule>
The 5 alpha rules, indexed by bit position (0..4). Order matches the codegen QC_ALPHA_RULES, which is sorted by bit_position. A rule added to the codegen table needs a matching evaluator here, or the drift guard below throws at module load.
Functions
Section titled “Functions”crosscheckIemGhcnh()
Section titled “crosscheckIemGhcnh()”crosscheckIemGhcnh(
iemRows,ghcnhRows,opts): readonlyCrosscheckDisagreement[]
Cross-check IEM and GHCNh temperatures; return rows where the two
sources disagree above opts.tolC (default 2.0 °C).
Algorithm:
- If
iemRows.length === 0 || ghcnhRows.length === 0→ return[](matches Python qc.py:212-215). - Validate
station+eventTimepresent (string) on every input row; throwErroron first violation (parity with PythonValueErrorat qc.py:217-220). - Build
iemMap: Map<string, IemRow>keyed by${row.station}|${row.eventTime}. On duplicate keys the last IEM row wins — deterministic, and a documented deviation from Python’spd.merge(which would cartesian-product duplicates). - For each GHCNh row, look up the matching IEM row by composite key.
If missing → skip. If either
temp_cis null / non-finite → skip. - If
Math.abs(iem.temp_c - ghcnh.temp_c) > tolC→ emit a disagreement row. Strict>, not>=.
Output array order matches the iteration order of ghcnhRows
(deterministic, independent of iemRows order).
Pure: input arrays are not mutated.
Parameters
Section titled “Parameters”iemRows
Section titled “iemRows”readonly CrosscheckRowIn[]
IEM observation rows.
ghcnhRows
Section titled “ghcnhRows”readonly CrosscheckRowIn[]
GHCNh observation rows.
CrosscheckOptions = {}
Tolerance options. tolC default = 2.0.
Returns
Section titled “Returns”readonly CrosscheckDisagreement[]
Throws
Section titled “Throws”Error if any iem or ghcnh row is missing station or
eventTime (or they are not strings).
evalDewpointExceedsTemp()
Section titled “evalDewpointExceedsTemp()”evalDewpointExceedsTemp(
rows):boolean[]
Bit 1 — Dewpoint > temperature (physically impossible; strict >).
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
evalSlpOutOfRange()
Section titled “evalSlpOutOfRange()”evalSlpOutOfRange(
rows):boolean[]
Bit 4 — Sea-level pressure outside [870, 1085] mb.
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
evalTempOutOfRange()
Section titled “evalTempOutOfRange()”evalTempOutOfRange(
rows):boolean[]
Bit 0 — Temperature outside [-89C, 57C] (world-record bounds).
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
evalWindDirOutOfRange()
Section titled “evalWindDirOutOfRange()”evalWindDirOutOfRange(
rows):boolean[]
Bit 3 — Wind direction outside [0, 360] (inclusive).
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
evalWindSpeedNegative()
Section titled “evalWindSpeedNegative()”evalWindSpeedNegative(
rows):boolean[]
Bit 2 — Wind speed negative.
Parameters
Section titled “Parameters”readonly Record<string, unknown>[]
Returns
Section titled “Returns”boolean[]
References
Section titled “References”QC_ALPHA_RULES
Section titled “QC_ALPHA_RULES”Re-exports QC_ALPHA_RULES