Δ Delta
Read Online · Appendix K

Language Quick-Start Guide (Python & TypeScript)

From the free book Delta: Closing the Specification Gap (Dhuri, 2026). The PDF is the canonical edition — figures, tables, and code formatting are simplified online.

K Language Quick-Start Guide Python 3.12, FastAPI, and Pydantic · TypeScript and Node.js This appendix translates the core patterns from the book into Python 3.12 / FastAPI and TypeScript / NestJS. Every Law, the Specification Frame, Evidence Brief, and Four-Stage Pipeline apply unchanged. What changes is only the concrete type name and import path in your <domain_types> section. Read this appendix alongside Chapter 3 (Specification Frame), Chapter 4 (Code Generation), and Chapter 5 (Code Review). For each recipe in those chapters, substituting the language-specific types below produces equivalent domain-correct output.

K

Language Quick-Start Guide

196

In This Chapter

  1. Python: the Decimal/Money equivalent and the Result pattern
  2. Python: system prompt template for FastAPI + Pydantic v2 + SQLAlchemy 2
  3. Python: HIPAA service recipe (Chapter 4 Recipe 1) translated
  4. TypeScript: the number/Decimal issue and type-safe Money representation
  5. TypeScript: NestJS system prompt template
  6. TypeScript: idempotent webhook handler recipe translated
  7. Cross-platform constraint mapping: .NET Java Python TypeScript

K.1 Law 5 in Every Language Law 5 — no float for money — applies identically in every language. The float type is IEEE 754 in C#, Java, Python, and JavaScript. The solution differs only in library name. Language

NEVER use

ALWAYS use

Why it works

C# / .NET 9

double, float

decimal, Money<TCurrency>
decimal is base-10. Money<T> enforces the pattern with compile-time double rejection.

Java 21

double, float

BigDecimal, Money record

BigDecimal stores exact decimal value. Money.of(String, Currency) factory prevents float construction.

Python 3.12

float, int (cents) decimal.Decimal, Pydantic Decimal field decimal.Decimal is base-10. Pydantic with Decimal type validates at API boundary.

TypeScript / Node.js

number

Decimal.js, string representation

JS number is float64. Decimal. js or string representation preserves precision through all operations.

Go float32, float64 github.com/shopspring/ decimal

Standard Go does not have a built-in decimal type. shopspring/decimal is the ecosystem standard.

Rust f32, f64 rust_decimal crate rust_decimal provides a 96-bit decimal type. Compile-time errors on float operations.

K

Language Quick-Start Guide

197

K.2 Python 3.12 — Core Types Money: Pydantic Decimal Field Python’s decimal.Decimal is already correct for monetary values. The pattern below makes it explicit at the Pydantic model boundary — equivalent to Money<TCurrency> in C# or Money in Java. Python 3.12 — MoneyAmount value type (Pydantic v2) # File: src/domain/value_objects.py from decimal import Decimal, ROUND_HALF_UP from pydantic import BaseModel, Field, field_validator from typing import Annotated # Money value: 4dp precision for storage, 2dp for output MoneyAmount = Annotated[ Decimal, Field(decimal_places=4, ge=0), ] class Money(BaseModel): amount: Decimal currency: str

# ISO 4217: "USD", "EUR", "GBP"

model_config = {'arbitrary_types_allowed': True} @field_validator('amount', mode='before') @classmethod def validate_amount(cls, v: object) -> Decimal: # Reject float construction — equivalent to [Obsolete(error: ,→ true)] in C# if isinstance(v, float): raise ValueError( "float not permitted for money. Use str or Decimal: " f"received {v!r}. Write Money(amount=Decimal('10.50'), ,→

...)" ) return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=

,→ ROUND_HALF_UP) def for_output(self) -> Decimal:

K

Language Quick-Start Guide

198

"""2dp for API responses, display, and persistence.""" return self.amount.quantize(Decimal("0.01"), rounding= ,→ ROUND_HALF_UP) def add(self, other: "Money") -> "Money": if self.currency != other.currency: raise ValueError(f"Currency mismatch: {self.currency} vs { ,→ other.currency}") return Money(amount=self.amount + other.amount, currency=self. ,→ currency)

Result Pattern in Python Python does not have a built-in Result<T> type. The cleanest enterprise approach is the returns library or a simple dataclass. The key constraint for your generation prompts: ‘Use Result[T, AppError] from the returns library. Never raise for business rule failures.’ Python 3.12 — Result pattern (dataclass approach) # File: src/common/result.py # Lightweight Result<T> without external dependencies from dataclasses import dataclass from typing import Generic, TypeVar, Optional T = TypeVar("T") @dataclass(frozen=True) class Result(Generic[T]): """Discriminated union: success value or structured failure. Use for all business rule outcomes. Never raise for business ,→ rules. """ _value: Optional[T] _error_code: Optional[str] _error_message: Optional[str] _is_success: bool @classmethod def success(cls, value: T) -> "Result[T]": return cls(_value=value, _error_code=None, _error_message=None, _is_success=True)

K

Language Quick-Start Guide

199

@classmethod def failure(cls, code: str, message: str) -> "Result[T]": return cls(_value=None, _error_code=code, _error_message=message, _is_success=False) @property def is_success(self) -> bool: return self._is_success @property def value(self) -> T: if not self._is_success: raise ValueError(f"[{self._error_code}] {self. ,→ _error_message}") return self._value

# type: ignore

@property def error_code(self) -> Optional[str]: return self._error_code @property def error_message(self) -> Optional[str]: return self. ,→ _error_message
K.3 Python — HIPAA Service Recipe (Chapter 4, Recipe 1 translated) Same Specification Frame as Chapter 4 Recipe 1. Only the <role> and <domain_types> sections change. Every constraint is identical.

K

Language Quick-Start Guide

200

Prompt — Python FastAPI HIPAA Patient Service <role> Senior Python engineer on a HIPAA EHR platform. Stack: Python 3.12, FastAPI 0.115, Pydantic v2, SQLAlchemy 2 async, structlog structured logging. </role> <existing_interface> class PatientDemographicsService(Protocol): async def update_contact_info( self, cmd: UpdateContactInfoCommand, ) -> Result[None]: ... </existing_interface> <domain_types> from src.common.result import Result from src.audit import audit_log

# @audit_log(action, resource)
,→ decorator </domain_types> <task> Implement update_contact_info that: - Validates patient exists, is not deceased, is not merged - Performs partial update of contact fields - Publishes ContactInfoUpdatedEvent after DB commit - Returns Result[None] success or Result.failure(code, message) for ,→

each guard

</task> <constraints> @audit_log(action="UPDATE_CONTACT", resource="Patient") REQUIRED on ,→ method. PHI (name, phone, email, address) NEVER in log messages. ALWAYS log patient_id (UUID string) only: log.info("contact_updated", ,→

patient_id=str(id))

Deceased patient: Result.failure("PATIENT_DECEASED", "Cannot update a ,→ deceased patient")

K

Language Quick-Start Guide

Merged patient: Result.failure("PATIENT_MERGED", "Cannot update a ,→ merged patient record") DB update and audit log: atomic in one transaction. ONE implementation. No alternatives. If ambiguous: ASSUMPTION: [what] because [why] BEFORE the code. </constraints> <output_specification> Generate: one complete compilable .py file. Include: all imports. Type-annotated throughout. </output_specification> Python Output — HIPAA PatientDemographicsServiceImpl # File: src/patients/patient_demographics_service.py import structlog from sqlalchemy.ext.asyncio import AsyncSession from uuid import UUID from src.common.result import Result from src.audit import audit_log from src.patients.commands import UpdateContactInfoCommand from src.patients.events import ContactInfoUpdatedEvent from src.patients.repository import PatientRepository log = structlog.get_logger()

class PatientDemographicsServiceImpl: def __init__( self, patient_repo: PatientRepository, session: AsyncSession, ) -> None: self._repo = patient_repo self._session = session @audit_log(action="UPDATE_CONTACT", resource="Patient") async def update_contact_info(

201 K

Language Quick-Start Guide

202 self, cmd: UpdateContactInfoCommand, ) -> Result[None]: patient = await self._repo.find_by_id(cmd.patient_id) if patient is None: return Result.failure("PATIENT_NOT_FOUND", "Patient not ,→ found") # Lifecycle guards if patient.is_deceased: return Result.failure("PATIENT_DECEASED", "Cannot update ,→ a deceased patient") if patient.is_merged: return Result.failure("PATIENT_MERGED", "Cannot update a ,→ merged patient record") patient.update_contact_info( phone=cmd.phone, email=cmd.email, address_line1=cmd.address_line1, city=cmd.city, postal_code=cmd.postal_code, ) await self._session.commit() # Publish AFTER commit — not inside the transaction await self._publish_event(ContactInfoUpdatedEvent(patient_id= ,→ patient.id)) # NO PHI in logs — patient_id (UUID) only log.info("contact_info_updated", patient_id=str(cmd. ,→ patient_id)) return Result.success(None) async def _publish_event(self, event: ContactInfoUpdatedEvent) -> ,→

None: # Implement with your event bus (Kafka, SNS, etc.) ...

K

Language Quick-Start Guide

203

K.4 TypeScript / Node.js — Core Types Money: Decimal.js (not number) ANTI-PATTERN — JavaScript number for monetary values

AVOID: const total = 0.1 + 0.2; // 0.30000000000000004 USE: import Decimal from ”decimal.js”; const total = new Decimal( ”0.1”).add(”0.2”); // Decimal(”0.3”) Why: JS number is IEEE 754 float64. 0.1 + 0.2 is 0. 30000000000000004 in every JavaScript runtime. Decimal.js wraps arbitrary-precision decimal arithmetic. TypeScript — Money type and Result<T> // File: src/common/money.ts import Decimal from "decimal.js"; Decimal.set({ precision: 20, rounding: Decimal.ROUND_HALF_UP }); export class Money { private constructor( private readonly _amount: Decimal, readonly currency: string, ) {} // Factory: use this. Never construct with number. static of(amount: string | Decimal, currency: string): Money { if (typeof amount === "number") { throw new Error( "number not permitted for Money. Use string or Decimal: " + `received ${amount}. Write Money.of("10.50", "USD")` ); } return new Money(new Decimal(amount).toDecimalPlaces(4), currency) ,→ ; } add(other: Money): Money { this.assertSameCurrency(other); return new Money(this._amount.add(other._amount), this.currency); K

Language Quick-Start Guide

204

} // Use forOutput() for API responses and persistence forOutput(): string { return this._amount.toDecimalPlaces(2). ,→ toString(); } toDecimal(): Decimal { return this._amount; } private assertSameCurrency(other: Money): void { if (this.currency !== other.currency) throw new Error(`Currency mismatch: ${this.currency} vs ${other. ,→ currency}`); } } // File: src/common/result.ts export class Result<T> { private constructor( private readonly _success: boolean, private readonly _value?: T, readonly errorCode?: string, readonly errorMessage?: string, ) {} static success<T>(value: T): Result<T> { return new Result(true, value); } static failure<T>(code: string, message: string): Result<T> { return new Result<T>(false, undefined, code, message); } get isSuccess(): boolean { return this._success; } get value(): T { if (!this._success) throw new Error(`[${this.errorCode}] ${this. ,→ errorMessage}`); return this._value!; } } K

Language Quick-Start Guide

205

K.5 TypeScript — Idempotent Webhook Handler Recipe Chapter 4 Recipe 2 (idempotent payment handler) translated to NestJS. Same constraints, same order-of-operations discipline. Only the framework syntax changes. TypeScript NestJS — Idempotent Stripe Webhook Handler // File: src/payments/stripe-webhook.controller.ts import { Controller, Post, Body, Headers, HttpCode, HttpStatus } from ,→
"@nestjs/common";

import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; import Stripe from "stripe"; import { Money } from "../common/money"; import { IdempotencyRecord } from "./entities/idempotency-record. ,→ entity"; import { PaymentService } from "./payment.service"; import pino from "pino"; const log = pino({ name: "stripe-webhook" }); @Controller("webhooks/stripe") export class StripeWebhookController { constructor( private readonly stripe: Stripe, private readonly paymentService: PaymentService, @InjectRepository(IdempotencyRecord) private readonly idempotencyRepo: Repository<IdempotencyRecord>, ) {} @Post() @HttpCode(HttpStatus.OK) async handleWebhook( @Body() rawBody: Buffer, @Headers("stripe-signature") sig: string, ): Promise<{ received: boolean }> { // STEP 1: Verify signature FIRST — before any processing let event: Stripe.Event; try { event = this.stripe.webhooks.constructEvent( K

Language Quick-Start Guide

206 rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET! ); } catch { log.warn("stripe_signature_invalid"); return { received: false }; } // STEP 2: Check idempotency BEFORE any business logic const existing = await this.idempotencyRepo.findOneBy({ eventId: ,→ event.id }); if (existing) { log.info("webhook_duplicate_skipped", { event_id: event.id }); return { received: true }; } // STEP 3: Execute business logic if (event.type === "payment_intent.succeeded") { const pi = event.data.object as Stripe.PaymentIntent; // Money.of(string) — never number for currency amounts const amount = Money.of( (pi.amount / 100).toFixed(2), pi.currency.toUpperCase() ); await this.paymentService.processSucceeded(pi.id, amount); } // STEP 4: Mark processed AFTER business logic succeeds await this.idempotencyRepo.save({ eventId: event.id }); // event.id is safe to log; no PCI data in log messages log.info("webhook_processed", { event_id: event.id, type: event. ,→ type }); return { received: true }; } } K

Language Quick-Start Guide

207

K.6 Cross-Platform Constraint Map When translating any recipe from Part II to a different language, use this table to find the equivalent constraint. Every NEVER/ALWAYS pair in the book has a cross-language equivalent below. Constraint

C# / .NET 9

Java 21

Python 3.12

TypeScript

Money type (Law 5)

Money<TCurrency> never decimal directly

Money record BigDecimal via factory

decimal. Decimal Pydantic Decimal field

Decimal.js never JS number

Result type

Result<T> (App B)
Result<T> (App B)

Result from App K or returns library

Result<T> from App K

Dependency injection

Constructor only @RequiredArgsConstructor = N/A
@RequiredArgsConstructor FastAPI Never @Autowired Depends() fields Never global instances

NestJS constructor Never manual new()

Logging (structured)

Serilog parameters Never $”string {var}”
SLF4J {} placeholders Never String.format in log

structlog bound context Never f-string in log calls

Pino structured fields Never string concatenation

Event publishing timing

After SaveChangesAsync()

After @Transactional commits (AFTER_ COMMIT listener)

After session. commit()

After TypeORM transaction commit()

No PHI in logs

Log correlation ID (UUID) only

Log patient_id UUID only

log.info() with patient_ id=str(id)

log.info({ patient_id }) only

Idempotency order

(1) check (2) business logic (3) mark processed

Same order

Same order

Same order — ALWAYS step 2 before step 3

Key takeaways

K

Language Quick-Start Guide

208

Everything else is universal. + Python: Pydantic v2 Decimal field with a @field_validator rejecting float construction is the Money<TCurrency> equivalent. Result is a simple dataclass or the returns library. + TypeScript: Decimal.js (string-based factory Money.of()) is the Money equivalent. JS number is float64 and will fail at scale. This is the most commonly missed constraint in TypeScript AI-generated financial code. + The HIPAA and idempotency recipes translate directly to Python/ TypeScript. The constraints are identical. Only the syntax for applying them (decorators, class structure) differs by platform.

Cite this appendix
Dhuri, Sandeep. (2026). Delta: Closing the Specification Gap. Acuity Press. Appendix K.
DOI