1. Five-step Pre-Change Protocol
- Read TAS —
docs/TAS.md constitutional anchors
- Validate Invariants — BigInt cents, physical-unit gates, verbatim UI labels
- Cite Impact — blast-radius doc + affected Prisma models
- Confirm Zero-Bleed — tenant cookie scope, RLS, integration tests TENANT-*
- Formulate Proposal — amendment metadata in Audit Trail before merge
2. Monetary data dictionary (BIGINT cents only)
| Model.field | SQL column | Type |
| Tenant.ale_baseline | ale_baseline | BigInt NOT NULL |
| ThreatEvent.financialRisk_cents | financialRisk_cents | BigInt |
| ThreatEvent.mitigatedValueCents | mitigated_value_cents | BigInt? |
| RiskEvent.governedImpact | governed_impact | BigInt (generated) |
| SustainabilityMetric.mitigatedValueCents | mitigated_value_cents | BigInt NOT NULL |
| ActiveRisk.score_cents | score_cents | BigInt |
| Company.industry_avg_loss_cents | industry_avg_loss_cents | BigInt? |
3. API routes (tenant-scoped excerpt)
| Method | Path | Notes |
| GET | /api/dashboard | totalValueMitigatedYtdCents as digit string |
| POST | /api/sustainability/ironbloom | 400 PHYSICAL_UNIT_REQUIRED if monetary-only |
| GET | /api/insurance/actuarial-report | PDF export; premiumCents query param (string) |
| GET | /api/docs/download-protocol | Feature test protocol docx + ?manifest=1 JSON |
| GET | /api/docs/download-matrix | Ironframe-UI-UX-Feature-Test-Matrix.csv |
4. Java — BigIntContractValidator
package com.ironframe.grc.contract;
import java.math.BigInteger;
import java.util.regex.Pattern;
/** Mirrors app/utils/financialIntegrityLedgerCsv.parseCentsInput */
public final class BigIntContractValidator {
private static final Pattern DIGIT_CENTS = Pattern.compile("^-?\\d+$");
public static BigInteger parseCentsString(String raw) {
if (raw == null || raw.isBlank()) return BigInteger.ZERO;
String trimmed = raw.trim().replace(",", "");
if (!DIGIT_CENTS.matcher(trimmed).matches()) {
throw new IllegalArgumentException("FIN_LEDGER_CSV_FLOAT_BLOCKED: cents must be whole digits");
}
return new BigInteger(trimmed);
}
public static String formatUsdFromCents(BigInteger cents) {
boolean neg = cents.signum() < 0;
BigInteger abs = cents.abs();
BigInteger dollars = abs.divide(BigInteger.valueOf(100));
int frac = abs.mod(BigInteger.valueOf(100)).intValue();
return String.format("%s%s.%02d", neg ? "-" : "", dollars, frac);
}
public static void rejectPhysicalUnitPayload(boolean hasKwh, boolean hasLiters, boolean hasKm, boolean monetaryOnly) {
if (monetaryOnly && !(hasKwh || hasLiters || hasKm)) {
throw new PhysicalUnitRequiredException("PHYSICAL_UNIT_REQUIRED");
}
}
public static class PhysicalUnitRequiredException extends RuntimeException {
public PhysicalUnitRequiredException(String code) { super(code); }
}
}
5. Security & compliance matrix
| Control | Implementation | Evidence |
| DMZ air-gap | Irongate (Agent 14) mandatory ingress | docs/TAS.md § DMZ |
| Row isolation | Supabase RLS + tenantCompanyId filters | tests/integration/dashboard.test.ts |
| WORM evidence | Epic 12 sealed bucket policy | docs/pr/EPIC12_WORM_OPS.md |
| Export integrity | Export Tabular Ledger Data (CSV) — data-testid export-tabular-ledger-csv | tests/unit/financialIntegrityLedgerCsv.test.ts |
6. CSV ledger matrix columns
metric_key, unit, amount_cents, amount_usd, bps_value, text_value, carrier_key, framework
amount_usd derived via integer division: dollars = cents / 100n; frac = cents % 100n (no JavaScript Number division on export path).