Problem Statement / Feature Objective
Resource consumption values in the utility dashboard span multiple decimal precisions: water in liters (integer), electricity in kWh (3 decimals), gas in therms (4 decimals), and financial costs in fiat (2 decimals with dynamic currency scaling). The current JavaScript Number-based arithmetic produces cumulative rounding errors that grow unboundedly over aggregation windows, leading to discrepancies of up to 0.05% in daily totals. A BigNumber fixed-point arithmetic safety wrapper must provide precise decimal arithmetic with explicit precision configuration, overflow detection, and seamless serialization for Redux state.
Technical Invariants & Bounds
- Supported precisions: 0 (integer), 2 (currency), 3 (electricity), 4 (gas), 6 (fine-grained sub-metering), 9 (nanoscale).
- Internal representation: BigNumber.js (or decimal.js) with default precision = 28 significant digits; rounding mode ROUND_HALF_UP.
- Overflow detection: an explicit max value of 10^21 per resource (1 trillion units at 9 decimals). Any operation resulting in a value exceeding this threshold throws a SafetyRangeError and surfaces a UI warning.
- Serialization: toRedux() outputs { value: string, precision: number, scale: number } to avoid floating-point corruption in Redux DevTools.
- Operator overloads: add, sub, mul, div, eq, gt, gte, lt, lte with type safety via a branded type Decimal.
Codebase Navigation Guide
- src/utils/decimal.ts - Core Decimal branded type and arithmetic functions.
- src/types/meter.ts - Type definitions for MeterReading, ResourceConsumption, TariffRate using the Decimal type.
- src/utils/aggregation.ts - Existing aggregation logic; must be refactored to use Decimal instead of number.
- src/store/slices/resourceSlice.ts - Redux slice storing consumption data; serialization/deserialization with Decimal.
- src/components/dashboard/ResourceChart.tsx - Chart component rendering time-series data; must accept Decimal values.
- src/hooks/useResourceData.ts - Data fetching hook; converts API responses (string-encoded decimals) to Decimal type.
Implementation Blueprint
- Create src/utils/decimal.ts: export a branded type Decimal
= { readonly __brand: unique symbol } & BigNumber. Provide factory functions: decimal(value: string | number, precision: P): Decimal
, and arithmetic functions: add, sub, mul, div, min, max, sum. Each function validates precision compatibility at runtime (throw if mismatched).
- Define a safety check in each arithmetic function: after computation, compare absolute value against MAX_SAFE = 10^21. If exceeded, throw SafetyRangeError with a descriptive message.
- Refactor aggregation.ts to replace all number arithmetic with Decimal calls. This includes sum, average, min, max, and cumulative totals. Ensure that intermediate results are not cast back to number.
- Update resourceSlice.ts: the Redux state stores consumption values as { value: string, precision: number }. Deserialize via decimal(payload.value, payload.precision) on read; serialize via { value: d.toFixed(p), precision: p } on write to the store.
- In ResourceChart.tsx, charting library (Chart.js or Recharts) typically expects numbers. Create a helper toDecimalNumber(d: Decimal
): number that converts at render time with explicit rounding, with a console.warn if precision loss > Number.EPSILON.
- Write unit tests in src/tests/decimal.test.ts covering: addition at mixed precision (upcast to higher precision), multiplication overflow, serialization round-trip, and 1,000-iteration accumulation to verify zero drift.
Problem Statement / Feature Objective
Resource consumption values in the utility dashboard span multiple decimal precisions: water in liters (integer), electricity in kWh (3 decimals), gas in therms (4 decimals), and financial costs in fiat (2 decimals with dynamic currency scaling). The current JavaScript Number-based arithmetic produces cumulative rounding errors that grow unboundedly over aggregation windows, leading to discrepancies of up to 0.05% in daily totals. A BigNumber fixed-point arithmetic safety wrapper must provide precise decimal arithmetic with explicit precision configuration, overflow detection, and seamless serialization for Redux state.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint
= { readonly __brand: unique symbol } & BigNumber. Provide factory functions: decimal(value: string | number, precision: P): Decimal
, and arithmetic functions: add, sub, mul, div, min, max, sum. Each function validates precision compatibility at runtime (throw if mismatched).
): number that converts at render time with explicit rounding, with a console.warn if precision loss > Number.EPSILON.