Anti-Corruption Layer & Zero Float Loss
🛡️ Anti-Corruption Layer & Zero Float Loss
Section titled “🛡️ Anti-Corruption Layer & Zero Float Loss”In enterprise software engineering, an Anti-Corruption Layer (ACL) acts as a defensive perimeter between external data providers (APIs, third-party CSV files, untrusted network inputs) and the internal pure Domain Model.
In financial software, this boundary has a second critical responsibility: guaranteeing mathematical precision and eliminating floating-point rounding errors.
🚫 The Danger of IEEE-754 Floating-Point Numbers
Section titled “🚫 The Danger of IEEE-754 Floating-Point Numbers”Standard JavaScript numbers are 64-bit binary floating-point numbers conforming to the IEEE-754 standard. In financial applications, this introduces catastrophic rounding anomalies:
// Classic floating point loss in JavaScript0.1 + 0.2 === 0.30000000000000004 // true
// In cryptocurrency micro-transactions:const satoshis = 0.00000001 * 3;console.log(satoshis); // 0.000000030000000000000004When calculating multi-year FIFO tax queues with thousands of lots and fractional token fees, floating-point rounding accumulates errors that:
- Prevent transactions from balancing (
amount_in - amount_out !== 0). - Fabricate fractional dust balances (
0.000000000000001 BTCremaining in closed lots). - Violate tax reporting standards (AEAT requires strict monetary balance).
💎 The PreciseAmount Branded Value Object
Section titled “💎 The PreciseAmount Branded Value Object”To eliminate floating-point drift while maintaining 100% decoupling from third-party libraries inside the core domain, Kryptofolio uses Branded Types:
export type PreciseAmount = string & { readonly __brand: 'PreciseAmount' };
export const toPreciseAmount = (val: string | number): PreciseAmount => { if (typeof val === 'number' && !Number.isFinite(val)) { throw new Error('Cannot construct PreciseAmount from non-finite number'); } return String(val) as PreciseAmount;};Architectural Constraints:
Section titled “Architectural Constraints:”- Domain Ports only speak
PreciseAmount: Interfaces likeILedgerPortandITaxPortnever accept rawnumberorDecimalobjects. - Encapsulated Math: High-precision arithmetic is confined strictly to Application use cases and Infrastructure adapters using
decimal.jsor DuckDB’sDECIMAL(38,18)columnar types.
🔍 The Anti-Corruption Layer (Zod Validation)
Section titled “🔍 The Anti-Corruption Layer (Zod Validation)”Before any external data touches the domain, it must pass through strict Zod schemas in the Infrastructure layer:
flowchart TD
External["External API / Raw CSV Input"] -->|Raw JSON / Strings| Adapter["Infrastructure Adapter"]
Adapter -->|safeParse| Schema{"Zod ACL Schema\n(preciseAmountSchema)"}
Schema -->|Valid| Domain["Domain Entity Mapping\n(PreciseAmount)"]
Domain -->|Safe| Store["Pinia Colada / Use Cases"]
Schema -->|Invalid| ErrorBus["Global Error Bus\n(Controlled Alert, No Crash)"]
Example: Strict Amount Validation Schema
Section titled “Example: Strict Amount Validation Schema”import { z } from 'zod';
// Strict regex: requires valid numeric format, non-empty, no exponent notationexport const preciseAmountSchema = z .string() .trim() .regex(/^-?\d+(\.\d+)?$/, 'Invalid precise numerical format') .transform((val) => val as PreciseAmount);
export const ExternalTransactionDtoSchema = z.object({ tx_id: z.string().min(1), timestamp: z.string().datetime(), amount_in: preciseAmountSchema.nullable(), amount_out: preciseAmountSchema.nullable(), total_fiat: preciseAmountSchema.refine((val) => Number(val) >= 0, { message: 'Fiat total must be non-negative', }),});🚨 Controlled Fault Tolerance: Global Error Bus
Section titled “🚨 Controlled Fault Tolerance: Global Error Bus”If an external exchange modifies their API contract or an invalid CSV row is ingested, the Anti-Corruption Layer prevents catastrophic application failure:
schema.safeParse()captures the malformed data.- Instead of throwing an unhandled runtime exception, the adapter dispatches a structured event to the
errorBus. - The UI gracefully surfaces a localized warning to the user, pinpointing the corrupted row or missing field while preserving the integrity of the active state.