@actuarial-ts/compliance 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +85 -0
- package/dist/ave.d.ts +74 -0
- package/dist/ave.d.ts.map +1 -0
- package/dist/ave.js +87 -0
- package/dist/ave.js.map +1 -0
- package/dist/bundle.d.ts +112 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +214 -0
- package/dist/bundle.js.map +1 -0
- package/dist/disclosure.d.ts +76 -0
- package/dist/disclosure.d.ts.map +1 -0
- package/dist/disclosure.js +204 -0
- package/dist/disclosure.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger.d.ts +84 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +85 -0
- package/dist/ledger.js.map +1 -0
- package/dist/metadata.d.ts +63 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +138 -0
- package/dist/metadata.js.map +1 -0
- package/dist/modelCards.d.ts +30 -0
- package/dist/modelCards.d.ts.map +1 -0
- package/dist/modelCards.js +445 -0
- package/dist/modelCards.js.map +1 -0
- package/package.json +57 -0
package/dist/bundle.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reproducibility bundle: canonical JSON serialization + a tiny integrity
|
|
3
|
+
* hash, so an analysis can state "these results came from exactly these
|
|
4
|
+
* inputs, parameters, and SDK versions" and a re-run can be byte-verified.
|
|
5
|
+
*
|
|
6
|
+
* Ground truth:
|
|
7
|
+
* - `canonicalJson` is the package's single equality oracle: object keys are
|
|
8
|
+
* sorted recursively, arrays keep their order, numbers render via
|
|
9
|
+
* `String(n)` except -0 which normalizes to "0" (so 0 and -0 never differ),
|
|
10
|
+
* and anything JSON cannot faithfully represent (undefined, functions,
|
|
11
|
+
* NaN/Infinity, bigint, symbol, non-plain objects such as Date/Map/Set,
|
|
12
|
+
* circular references) THROWS with the offending path instead of being
|
|
13
|
+
* silently dropped or coerced the way JSON.stringify would.
|
|
14
|
+
* - `fnv1a64` is an integrity aid, NOT a security control (see its doc block).
|
|
15
|
+
* - Timestamps are caller-supplied ISO strings; this module never reads a
|
|
16
|
+
* clock, so identical inputs yield byte-identical bundles.
|
|
17
|
+
* - Browser-safe: no node builtins (TextEncoder is a web-standard global).
|
|
18
|
+
*
|
|
19
|
+
* Error style for the whole package: `ComplianceError` with a registered
|
|
20
|
+
* machine code, mirroring core's `ReservingError` idiom. It lives here (not
|
|
21
|
+
* in its own module) because bundle.ts is the package's dependency-root
|
|
22
|
+
* module — ledger.ts already imports `canonicalJson` from it. Core's
|
|
23
|
+
* `RESERVING_ERROR_CODES` registry is a closed contract enforced against
|
|
24
|
+
* core's own source, and compliance failures (missing rationale, unsupported
|
|
25
|
+
* bundle values) are not reserving-input errors, so this package does not
|
|
26
|
+
* reuse `ReservingError`.
|
|
27
|
+
*
|
|
28
|
+
* These utilities are designed to support the actuary's compliance with
|
|
29
|
+
* ASOP No. 41 (documentation and reproducibility of the analysis);
|
|
30
|
+
* responsibility for compliance remains with the credentialed actuary.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Every machine-readable code a ComplianceError can carry, across all modules
|
|
34
|
+
* of this package. Add the code here when introducing a new throw.
|
|
35
|
+
*/
|
|
36
|
+
export const COMPLIANCE_ERROR_CODES = [
|
|
37
|
+
"BAD_BUNDLE",
|
|
38
|
+
"BAD_CDF",
|
|
39
|
+
"MISSING_RATIONALE",
|
|
40
|
+
"UNSUPPORTED_VALUE",
|
|
41
|
+
];
|
|
42
|
+
/** Thrown for invalid compliance input (unrepresentable bundle payloads, judgment without rationale, non-positive CDFs). */
|
|
43
|
+
export class ComplianceError extends Error {
|
|
44
|
+
code;
|
|
45
|
+
constructor(code, message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "ComplianceError";
|
|
48
|
+
this.code = code;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isPlainObject(value) {
|
|
52
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
53
|
+
return false;
|
|
54
|
+
const proto = Object.getPrototypeOf(value);
|
|
55
|
+
return proto === Object.prototype || proto === null;
|
|
56
|
+
}
|
|
57
|
+
function canonicalize(value, path, seen) {
|
|
58
|
+
if (value === null)
|
|
59
|
+
return "null";
|
|
60
|
+
switch (typeof value) {
|
|
61
|
+
case "string":
|
|
62
|
+
return JSON.stringify(value);
|
|
63
|
+
case "boolean":
|
|
64
|
+
return value ? "true" : "false";
|
|
65
|
+
case "number": {
|
|
66
|
+
if (!Number.isFinite(value)) {
|
|
67
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `non-finite number (${String(value)}) at ${path}`);
|
|
68
|
+
}
|
|
69
|
+
return Object.is(value, -0) ? "0" : String(value);
|
|
70
|
+
}
|
|
71
|
+
case "undefined":
|
|
72
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `undefined at ${path}`);
|
|
73
|
+
case "function":
|
|
74
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `function at ${path}`);
|
|
75
|
+
case "bigint":
|
|
76
|
+
case "symbol":
|
|
77
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `${typeof value} at ${path}`);
|
|
78
|
+
case "object":
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
const obj = value;
|
|
82
|
+
if (seen.has(obj)) {
|
|
83
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `circular reference at ${path}`);
|
|
84
|
+
}
|
|
85
|
+
seen.add(obj);
|
|
86
|
+
let out;
|
|
87
|
+
if (Array.isArray(obj)) {
|
|
88
|
+
const parts = [];
|
|
89
|
+
for (let i = 0; i < obj.length; i++) {
|
|
90
|
+
parts.push(canonicalize(obj[i], `${path}[${i}]`, seen));
|
|
91
|
+
}
|
|
92
|
+
out = `[${parts.join(",")}]`;
|
|
93
|
+
}
|
|
94
|
+
else if (isPlainObject(obj)) {
|
|
95
|
+
const keys = Object.keys(obj).sort();
|
|
96
|
+
const parts = [];
|
|
97
|
+
for (const key of keys) {
|
|
98
|
+
parts.push(`${JSON.stringify(key)}:${canonicalize(obj[key], `${path}.${key}`, seen)}`);
|
|
99
|
+
}
|
|
100
|
+
out = `{${parts.join(",")}}`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const name = obj.constructor?.name ?? "unknown";
|
|
104
|
+
throw new ComplianceError("UNSUPPORTED_VALUE", `non-plain object (${name}) at ${path}; only plain objects, arrays, and JSON primitives are canonicalizable`);
|
|
105
|
+
}
|
|
106
|
+
seen.delete(obj);
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Deterministic JSON serialization: sorted object keys (recursively), arrays
|
|
111
|
+
* in order, no whitespace, -0 normalized to "0". Two structurally equal
|
|
112
|
+
* values always produce the same string regardless of key insertion order.
|
|
113
|
+
* Throws ComplianceError("UNSUPPORTED_VALUE") — with the offending path, e.g.
|
|
114
|
+
* "$.rows[2].ultimate" — for any value JSON cannot faithfully represent.
|
|
115
|
+
*/
|
|
116
|
+
export function canonicalJson(value) {
|
|
117
|
+
return canonicalize(value, "$", new Set());
|
|
118
|
+
}
|
|
119
|
+
const FNV_OFFSET_BASIS = 0xcbf29ce484222325n;
|
|
120
|
+
const FNV_PRIME = 0x100000001b3n;
|
|
121
|
+
const MASK_64 = 0xffffffffffffffffn;
|
|
122
|
+
/**
|
|
123
|
+
* FNV-1a 64-bit hash over the UTF-8 bytes of `text`, returned as a 16-hex-char
|
|
124
|
+
* string.
|
|
125
|
+
*
|
|
126
|
+
* This is an INTEGRITY AID for detecting accidental divergence between a
|
|
127
|
+
* bundle and a re-run. It is NOT a security control: FNV-1a is not collision
|
|
128
|
+
* resistant and offers no protection against deliberate tampering. Anyone
|
|
129
|
+
* needing tamper evidence must sign or cryptographically hash the payload
|
|
130
|
+
* (which is exactly why the full canonical payload — not just the hash — is
|
|
131
|
+
* stored on the bundle).
|
|
132
|
+
*/
|
|
133
|
+
export function fnv1a64(text) {
|
|
134
|
+
const bytes = new TextEncoder().encode(text);
|
|
135
|
+
let hash = FNV_OFFSET_BASIS;
|
|
136
|
+
for (const byte of bytes) {
|
|
137
|
+
hash ^= BigInt(byte);
|
|
138
|
+
hash = (hash * FNV_PRIME) & MASK_64;
|
|
139
|
+
}
|
|
140
|
+
return hash.toString(16).padStart(16, "0");
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Packages an analysis run into a reproducibility bundle. The payload is
|
|
144
|
+
* canonical, so two runs with structurally equal inputs produce byte-identical
|
|
145
|
+
* payloads (and therefore identical hashes) regardless of key insertion order.
|
|
146
|
+
* `seeds` is included only when provided (undefined would be unrepresentable).
|
|
147
|
+
*/
|
|
148
|
+
export function createBundle(input) {
|
|
149
|
+
const body = {
|
|
150
|
+
createdAt: input.createdAt,
|
|
151
|
+
inputs: input.inputs,
|
|
152
|
+
parameters: input.parameters,
|
|
153
|
+
results: input.results,
|
|
154
|
+
sdkVersions: input.sdkVersions,
|
|
155
|
+
};
|
|
156
|
+
if (input.seeds !== undefined)
|
|
157
|
+
body["seeds"] = input.seeds;
|
|
158
|
+
const payload = canonicalJson(body);
|
|
159
|
+
return { payload, hash: fnv1a64(payload) };
|
|
160
|
+
}
|
|
161
|
+
/** First differing path between two canonicalizable structures, or null when equal. */
|
|
162
|
+
function firstDifference(stored, rerun, path) {
|
|
163
|
+
if (isPlainObject(stored) && isPlainObject(rerun)) {
|
|
164
|
+
const keys = [...new Set([...Object.keys(stored), ...Object.keys(rerun)])].sort();
|
|
165
|
+
for (const key of keys) {
|
|
166
|
+
const keyPath = `${path}.${key}`;
|
|
167
|
+
if (!(key in stored) || !(key in rerun))
|
|
168
|
+
return keyPath;
|
|
169
|
+
const diff = firstDifference(stored[key], rerun[key], keyPath);
|
|
170
|
+
if (diff !== null)
|
|
171
|
+
return diff;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(stored) && Array.isArray(rerun)) {
|
|
176
|
+
const shared = Math.min(stored.length, rerun.length);
|
|
177
|
+
for (let i = 0; i < shared; i++) {
|
|
178
|
+
const diff = firstDifference(stored[i], rerun[i], `${path}[${i}]`);
|
|
179
|
+
if (diff !== null)
|
|
180
|
+
return diff;
|
|
181
|
+
}
|
|
182
|
+
return stored.length === rerun.length ? null : `${path}[${shared}]`;
|
|
183
|
+
}
|
|
184
|
+
return canonicalJson(stored) === canonicalJson(rerun) ? null : path;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Verifies a re-run against a bundle: canonicalizes `rerunResults` and
|
|
188
|
+
* byte-compares it with the bundle's stored `results` segment. On mismatch,
|
|
189
|
+
* reports the FIRST differing path (see VerifyBundleResult.mismatchPath).
|
|
190
|
+
*
|
|
191
|
+
* Throws ComplianceError("BAD_BUNDLE") when the payload is not a valid bundle
|
|
192
|
+
* body, and propagates ComplianceError("UNSUPPORTED_VALUE") when
|
|
193
|
+
* `rerunResults` itself is not canonicalizable — a result that cannot be
|
|
194
|
+
* serialized cannot be verified.
|
|
195
|
+
*/
|
|
196
|
+
export function verifyBundle(bundle, rerunResults) {
|
|
197
|
+
let stored;
|
|
198
|
+
try {
|
|
199
|
+
stored = JSON.parse(bundle.payload);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
throw new ComplianceError("BAD_BUNDLE", "bundle payload is not valid JSON");
|
|
203
|
+
}
|
|
204
|
+
if (!isPlainObject(stored) || !("results" in stored)) {
|
|
205
|
+
throw new ComplianceError("BAD_BUNDLE", 'bundle payload has no "results" segment');
|
|
206
|
+
}
|
|
207
|
+
const storedResults = stored["results"];
|
|
208
|
+
const rerunCanonical = canonicalJson(rerunResults);
|
|
209
|
+
const storedCanonical = canonicalJson(storedResults);
|
|
210
|
+
if (rerunCanonical === storedCanonical)
|
|
211
|
+
return { reproduced: true };
|
|
212
|
+
return { reproduced: false, mismatchPath: firstDifference(storedResults, rerunResults, "$") ?? "$" };
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { EstimateMetadata } from "./metadata.js";
|
|
2
|
+
import type { AssumptionLedger, ChangedAssumptions } from "./ledger.js";
|
|
3
|
+
import { type MethodId } from "./modelCards.js";
|
|
4
|
+
/**
|
|
5
|
+
* ASOP No. 41 (Actuarial Communications) disclosure generator.
|
|
6
|
+
*
|
|
7
|
+
* ASOP 41 requires disclosure of the methods, procedures, assumptions, and
|
|
8
|
+
* data underlying the findings with enough clarity that another qualified
|
|
9
|
+
* actuary could objectively appraise the reasonableness of the work. The
|
|
10
|
+
* SDK already knows every method invoked, every parameter, and (through the
|
|
11
|
+
* assumption ledger) which values were machine defaults versus human or
|
|
12
|
+
* agent judgment — so it can render that appendix instead of the actuary
|
|
13
|
+
* reconstructing it by hand.
|
|
14
|
+
*
|
|
15
|
+
* DETERMINISM CONTRACT: identical DisclosureInput yields byte-identical
|
|
16
|
+
* markdown. No clock reads, no randomness — `generatedAt` is an input.
|
|
17
|
+
*
|
|
18
|
+
* The generated document is a DRAFT SUPPORT DOCUMENT for the responsible
|
|
19
|
+
* actuary to review, edit, and adopt; generating it is not compliance.
|
|
20
|
+
*/
|
|
21
|
+
export interface MethodResultSummary {
|
|
22
|
+
ultimate?: number;
|
|
23
|
+
ibnr?: number;
|
|
24
|
+
unpaid?: number;
|
|
25
|
+
standardError?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface MethodUse {
|
|
28
|
+
methodId: MethodId;
|
|
29
|
+
/** e.g. "paid", "incurred", "capped layer". */
|
|
30
|
+
basisLabel?: string;
|
|
31
|
+
/** The parameters the method actually ran with (JSON-serializable). */
|
|
32
|
+
parameters?: unknown;
|
|
33
|
+
resultSummary?: MethodResultSummary;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Structural stand-in for @actuarial-ts/data's DataReviewReport (no package
|
|
37
|
+
* dependency; anything with this shape renders).
|
|
38
|
+
*/
|
|
39
|
+
export interface DataReviewLike {
|
|
40
|
+
checks: {
|
|
41
|
+
id: string;
|
|
42
|
+
description: string;
|
|
43
|
+
status: string;
|
|
44
|
+
details: string[];
|
|
45
|
+
}[];
|
|
46
|
+
summary: {
|
|
47
|
+
pass: number;
|
|
48
|
+
warning: number;
|
|
49
|
+
fail: number;
|
|
50
|
+
notEvaluated?: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export interface PriorComparison {
|
|
54
|
+
priorLabel?: string;
|
|
55
|
+
changes: ChangedAssumptions;
|
|
56
|
+
priorReserve?: number;
|
|
57
|
+
currentReserve?: number;
|
|
58
|
+
}
|
|
59
|
+
export interface DisclosureInput {
|
|
60
|
+
title?: string;
|
|
61
|
+
/** Identification of the responsible actuary (ASOP 41 section 3.1.4). */
|
|
62
|
+
preparedBy?: string;
|
|
63
|
+
metadata: EstimateMetadata;
|
|
64
|
+
methods: MethodUse[];
|
|
65
|
+
ledger?: AssumptionLedger;
|
|
66
|
+
dataReview?: DataReviewLike;
|
|
67
|
+
priorComparison?: PriorComparison;
|
|
68
|
+
reliances?: string[];
|
|
69
|
+
limitations?: string[];
|
|
70
|
+
sdkVersion: string;
|
|
71
|
+
/** Caller-supplied ISO timestamp (determinism: the generator never reads a clock). */
|
|
72
|
+
generatedAt: string;
|
|
73
|
+
}
|
|
74
|
+
/** Renders the ASOP 41-oriented methods-assumptions-and-data appendix. */
|
|
75
|
+
export declare function generateDisclosure(input: DisclosureInput): string;
|
|
76
|
+
//# sourceMappingURL=disclosure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../src/disclosure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG7D;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACjF,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;CACrB;AAkDD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+KjE"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { MODEL_CARDS } from "./modelCards.js";
|
|
2
|
+
import { canonicalJson, fnv1a64 } from "./bundle.js";
|
|
3
|
+
const fmtNumber = (v) => Number.isInteger(v) ? v.toLocaleString("en-US") : v.toLocaleString("en-US", { maximumFractionDigits: 2 });
|
|
4
|
+
function describeMeasure(m) {
|
|
5
|
+
switch (m.kind) {
|
|
6
|
+
case "central-estimate":
|
|
7
|
+
return "central estimate (actuarial central estimate / expected value)";
|
|
8
|
+
case "high-estimate":
|
|
9
|
+
return "high estimate";
|
|
10
|
+
case "low-estimate":
|
|
11
|
+
return "low estimate";
|
|
12
|
+
case "specified-percentile":
|
|
13
|
+
return `specified percentile (${m.percentile ?? "unstated"})`;
|
|
14
|
+
case "range":
|
|
15
|
+
return "range of reasonable estimates";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function describeBasis(b) {
|
|
19
|
+
const gross = {
|
|
20
|
+
gross: "gross of reinsurance",
|
|
21
|
+
"net-of-reinsurance": "net of reinsurance",
|
|
22
|
+
"net-of-salvage-subro": "net of salvage and subrogation",
|
|
23
|
+
"net-all": "net of reinsurance, salvage, and subrogation",
|
|
24
|
+
}[b.grossNet];
|
|
25
|
+
const lae = {
|
|
26
|
+
"excluding-lae": "excluding loss adjustment expenses",
|
|
27
|
+
"including-all-lae": "including all loss adjustment expenses",
|
|
28
|
+
"dcc-only": "including defense and cost containment (DCC) expenses only",
|
|
29
|
+
"aao-only": "including adjusting and other (A&O) expenses only",
|
|
30
|
+
}[b.laeTreatment];
|
|
31
|
+
return `${gross}, ${lae}`;
|
|
32
|
+
}
|
|
33
|
+
function mdTable(header, rows) {
|
|
34
|
+
const out = [];
|
|
35
|
+
out.push(`| ${header.join(" | ")} |`);
|
|
36
|
+
out.push(`|${header.map(() => "---").join("|")}|`);
|
|
37
|
+
for (const r of rows)
|
|
38
|
+
out.push(`| ${r.join(" | ")} |`);
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
function parameterLines(parameters) {
|
|
42
|
+
if (parameters === undefined || parameters === null)
|
|
43
|
+
return "(engine defaults)";
|
|
44
|
+
const json = canonicalJson(parameters);
|
|
45
|
+
return json.length > 400 ? `${json.slice(0, 400)}… (truncated; full value in the reproducibility bundle)` : json;
|
|
46
|
+
}
|
|
47
|
+
/** Renders the ASOP 41-oriented methods-assumptions-and-data appendix. */
|
|
48
|
+
export function generateDisclosure(input) {
|
|
49
|
+
const L = [];
|
|
50
|
+
const m = input.metadata;
|
|
51
|
+
L.push(`# ${input.title ?? "Actuarial analysis: methods, assumptions, and data disclosure"}`);
|
|
52
|
+
L.push("");
|
|
53
|
+
L.push("> Draft support document generated by the actuarial-ts SDK for the responsible actuary's review and adoption. It is designed to support disclosures under ASOP Nos. 41, 43, 23, and 56; responsibility for the actuarial communication and for compliance with the ASOPs remains with the credentialed actuary.");
|
|
54
|
+
L.push("");
|
|
55
|
+
// 1. Identification, purpose, users, measure.
|
|
56
|
+
L.push("## 1. Identification and intended purpose");
|
|
57
|
+
L.push("");
|
|
58
|
+
if (input.preparedBy)
|
|
59
|
+
L.push(`- **Responsible actuary / preparer:** ${input.preparedBy}`);
|
|
60
|
+
L.push(`- **Intended purpose:** ${m.intendedPurpose}`);
|
|
61
|
+
if (m.intendedUsers && m.intendedUsers.length > 0) {
|
|
62
|
+
L.push(`- **Intended users:** ${m.intendedUsers.join("; ")}`);
|
|
63
|
+
}
|
|
64
|
+
L.push(`- **Intended measure:** ${describeMeasure(m.intendedMeasure)}`);
|
|
65
|
+
L.push(`- **Generated:** ${input.generatedAt} — actuarial-ts SDK v${input.sdkVersion}`);
|
|
66
|
+
L.push("");
|
|
67
|
+
// 2. Scope, dates, basis.
|
|
68
|
+
L.push("## 2. Scope, dates, and basis");
|
|
69
|
+
L.push("");
|
|
70
|
+
L.push(`- **Accounting date:** ${m.accountingDate}`);
|
|
71
|
+
L.push(`- **Valuation date:** ${m.valuationDate}`);
|
|
72
|
+
if (m.reviewDate)
|
|
73
|
+
L.push(`- **Review date:** ${m.reviewDate}`);
|
|
74
|
+
L.push(`- **Basis:** ${describeBasis(m.basis)}`);
|
|
75
|
+
if (m.currency)
|
|
76
|
+
L.push(`- **Currency:** ${m.currency}`);
|
|
77
|
+
if (m.scopeNotes)
|
|
78
|
+
L.push(`- **Scope notes:** ${m.scopeNotes}`);
|
|
79
|
+
L.push("");
|
|
80
|
+
// 3. Data review (ASOP 23).
|
|
81
|
+
L.push("## 3. Data and data review (ASOP No. 23)");
|
|
82
|
+
L.push("");
|
|
83
|
+
if (input.dataReview) {
|
|
84
|
+
const r = input.dataReview;
|
|
85
|
+
const notEvaluated = r.summary.notEvaluated ?? 0;
|
|
86
|
+
L.push(`A data review was performed: ${r.checks.length} checks (${r.summary.pass} pass, ${r.summary.warning} warning, ${r.summary.fail} fail${notEvaluated > 0 ? `, ${notEvaluated} not evaluated` : ""}). The checks performed, and their findings, were:`);
|
|
87
|
+
L.push("");
|
|
88
|
+
L.push(...mdTable(["Check", "Description", "Status", "Findings"], r.checks.map((c) => [
|
|
89
|
+
c.id,
|
|
90
|
+
c.description,
|
|
91
|
+
c.status.toUpperCase(),
|
|
92
|
+
c.details.length === 0 ? "none" : c.details.join("<br>"),
|
|
93
|
+
])));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
L.push("No automated data review report was attached. ASOP No. 23 requires the actuary to review data for reasonableness, consistency, and completeness, or to disclose that no such review was performed and the limitations that imposes.");
|
|
97
|
+
}
|
|
98
|
+
L.push("");
|
|
99
|
+
// 4. Methods and models (ASOP 56).
|
|
100
|
+
L.push("## 4. Methods and models (ASOP No. 56)");
|
|
101
|
+
L.push("");
|
|
102
|
+
for (const use of input.methods) {
|
|
103
|
+
const card = MODEL_CARDS[use.methodId];
|
|
104
|
+
L.push(`### ${card.title}${use.basisLabel ? ` — ${use.basisLabel}` : ""}`);
|
|
105
|
+
L.push("");
|
|
106
|
+
L.push(`- **Intended use:** ${card.intendedUse}`);
|
|
107
|
+
L.push(`- **Specification:** ${card.specification}`);
|
|
108
|
+
L.push(`- **Key assumptions:** ${card.keyAssumptions.join(" ")}`);
|
|
109
|
+
L.push(`- **Known weaknesses:** ${card.weaknesses.join(" ")}`);
|
|
110
|
+
L.push(`- **Primary sensitivities:** ${card.sensitivities.join(" ")}`);
|
|
111
|
+
L.push(`- **Literature:** ${card.literature.join("; ")}`);
|
|
112
|
+
L.push(`- **Parameters this analysis ran with:** \`${parameterLines(use.parameters)}\``);
|
|
113
|
+
if (use.resultSummary) {
|
|
114
|
+
const s = use.resultSummary;
|
|
115
|
+
const bits = [];
|
|
116
|
+
if (s.ultimate !== undefined)
|
|
117
|
+
bits.push(`ultimate ${fmtNumber(s.ultimate)}`);
|
|
118
|
+
if (s.ibnr !== undefined)
|
|
119
|
+
bits.push(`IBNR ${fmtNumber(s.ibnr)}`);
|
|
120
|
+
if (s.unpaid !== undefined)
|
|
121
|
+
bits.push(`unpaid ${fmtNumber(s.unpaid)}`);
|
|
122
|
+
if (s.standardError !== undefined)
|
|
123
|
+
bits.push(`standard error ${fmtNumber(s.standardError)}`);
|
|
124
|
+
if (bits.length > 0)
|
|
125
|
+
L.push(`- **Indicated:** ${bits.join(", ")}`);
|
|
126
|
+
}
|
|
127
|
+
L.push("");
|
|
128
|
+
}
|
|
129
|
+
// 5. Assumptions and judgments.
|
|
130
|
+
L.push("## 5. Assumptions and judgments");
|
|
131
|
+
L.push("");
|
|
132
|
+
if (input.ledger && input.ledger.entries.length > 0) {
|
|
133
|
+
L.push("Every recorded assumption, distinguishing machine defaults from human or agent judgment (judgment entries carry their rationale and source):");
|
|
134
|
+
L.push("");
|
|
135
|
+
L.push(...mdTable(["#", "When", "Actor", "Assumption", "Value", "Rationale / source"], input.ledger.entries.map((e) => [
|
|
136
|
+
String(e.seq),
|
|
137
|
+
e.timestamp,
|
|
138
|
+
e.actor,
|
|
139
|
+
e.field,
|
|
140
|
+
`\`${canonicalJson(e.value)}\``,
|
|
141
|
+
[e.rationale, e.source ? `(source: ${e.source})` : ""].filter(Boolean).join(" ") || "—",
|
|
142
|
+
])));
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
L.push("No assumption ledger was attached; assumptions are visible only through Section 4's parameters.");
|
|
146
|
+
}
|
|
147
|
+
L.push("");
|
|
148
|
+
// 6. Changes from the prior analysis.
|
|
149
|
+
L.push("## 6. Changes from the prior analysis");
|
|
150
|
+
L.push("");
|
|
151
|
+
if (input.priorComparison) {
|
|
152
|
+
const pc = input.priorComparison;
|
|
153
|
+
if (pc.priorLabel)
|
|
154
|
+
L.push(`Prior analysis: ${pc.priorLabel}.`);
|
|
155
|
+
if (pc.priorReserve !== undefined && pc.currentReserve !== undefined) {
|
|
156
|
+
L.push(`Carried indication moved from ${fmtNumber(pc.priorReserve)} to ${fmtNumber(pc.currentReserve)} (${fmtNumber(pc.currentReserve - pc.priorReserve)}).`);
|
|
157
|
+
}
|
|
158
|
+
const { added, removed, changed } = pc.changes;
|
|
159
|
+
if (added.length === 0 && removed.length === 0 && changed.length === 0) {
|
|
160
|
+
L.push("No assumption or method changes were recorded against the prior analysis.");
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
if (changed.length > 0) {
|
|
164
|
+
L.push("");
|
|
165
|
+
L.push(...mdTable(["Assumption", "Prior", "Current"], changed.map((c) => [c.field, `\`${canonicalJson(c.priorValue)}\``, `\`${canonicalJson(c.currentValue)}\``])));
|
|
166
|
+
}
|
|
167
|
+
if (added.length > 0)
|
|
168
|
+
L.push(`- **New assumptions:** ${added.join(", ")}`);
|
|
169
|
+
if (removed.length > 0)
|
|
170
|
+
L.push(`- **Removed assumptions:** ${removed.join(", ")}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
L.push("No prior-analysis comparison was attached.");
|
|
175
|
+
}
|
|
176
|
+
L.push("");
|
|
177
|
+
// 7. Reliances and limitations.
|
|
178
|
+
L.push("## 7. Reliances and limitations");
|
|
179
|
+
L.push("");
|
|
180
|
+
if (input.reliances && input.reliances.length > 0) {
|
|
181
|
+
for (const r of input.reliances)
|
|
182
|
+
L.push(`- **Reliance:** ${r}`);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
L.push("- No reliances on data or analyses supplied by others were recorded.");
|
|
186
|
+
}
|
|
187
|
+
if (input.limitations && input.limitations.length > 0) {
|
|
188
|
+
for (const lim of input.limitations)
|
|
189
|
+
L.push(`- **Limitation:** ${lim}`);
|
|
190
|
+
}
|
|
191
|
+
L.push("");
|
|
192
|
+
// 8. Reproducibility.
|
|
193
|
+
L.push("## 8. Reproducibility");
|
|
194
|
+
L.push("");
|
|
195
|
+
const inputHash = fnv1a64(canonicalJson({
|
|
196
|
+
metadata: input.metadata,
|
|
197
|
+
methods: input.methods,
|
|
198
|
+
ledger: input.ledger ?? null,
|
|
199
|
+
}));
|
|
200
|
+
L.push(`This disclosure derives deterministically from its inputs (integrity tag \`${inputHash}\`, actuarial-ts v${input.sdkVersion}). Rerunning the same inputs on the same SDK version reproduces the analysis and this document byte for byte; pair with a reproducibility bundle for auditor/examiner requests under ASOP No. 21.`);
|
|
201
|
+
L.push("");
|
|
202
|
+
return L.join("\n");
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=disclosure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.js","sourceRoot":"","sources":["../src/disclosure.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/ledger.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assumption ledger: an append-only record of every assumption an analysis
|
|
3
|
+
* used, separating machine defaults from actuarial/agent judgment, feeding
|
|
4
|
+
* the ASOP 41 assumptions-and-judgments and changes-from-prior disclosures.
|
|
5
|
+
*
|
|
6
|
+
* Ground truth:
|
|
7
|
+
* - The ledger is IMMUTABLE: `recordAssumption` returns a NEW frozen ledger;
|
|
8
|
+
* the input ledger, its entries array, and every recorded entry are frozen.
|
|
9
|
+
* Nothing is ever edited or deleted — a corrected assumption is a new entry
|
|
10
|
+
* for the same field, and the LATEST entry per field is the live value.
|
|
11
|
+
* - `seq` is assigned by the ledger (entries.length + 1), never by the caller.
|
|
12
|
+
* - `rationale` is REQUIRED (throws MISSING_RATIONALE) whenever
|
|
13
|
+
* actor !== "default": undocumented judgment is exactly what the ledger
|
|
14
|
+
* exists to prevent. Machine defaults need no rationale — the method's
|
|
15
|
+
* model card documents them.
|
|
16
|
+
* - `changedAssumptions` diffs the LATEST entry per field on each side and
|
|
17
|
+
* compares values by canonical JSON, so key insertion order never causes a
|
|
18
|
+
* false "changed". Output field lists are lexicographically sorted for
|
|
19
|
+
* deterministic disclosure rendering.
|
|
20
|
+
* - Timestamps are caller-supplied ISO strings (purity: no clock reads).
|
|
21
|
+
*
|
|
22
|
+
* These utilities are designed to support the actuary's compliance with
|
|
23
|
+
* ASOP No. 41; responsibility for compliance remains with the credentialed
|
|
24
|
+
* actuary.
|
|
25
|
+
*/
|
|
26
|
+
/** Who set the assumption: the machine default, a credentialed actuary, or an AI agent. */
|
|
27
|
+
export type AssumptionActor = "default" | "actuary" | "agent";
|
|
28
|
+
/** JSON-representable assumption value (the ledger stores data, not behavior). */
|
|
29
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
30
|
+
[key: string]: JsonValue;
|
|
31
|
+
};
|
|
32
|
+
export interface AssumptionEntry {
|
|
33
|
+
/** 1-based position in the ledger; assigned by recordAssumption, never by the caller. */
|
|
34
|
+
seq: number;
|
|
35
|
+
/** Caller-supplied ISO timestamp (purity: no clock reads). */
|
|
36
|
+
timestamp: string;
|
|
37
|
+
actor: AssumptionActor;
|
|
38
|
+
/** Dotted path identifying the assumption, e.g. "chainLadder.tailFactor". */
|
|
39
|
+
field: string;
|
|
40
|
+
value: JsonValue;
|
|
41
|
+
/** The value this entry superseded, when the caller knows it. */
|
|
42
|
+
previousValue?: JsonValue;
|
|
43
|
+
/** Where the value came from (e.g. "Friedland Table 15", "rate filing 2024-07"). */
|
|
44
|
+
source?: string;
|
|
45
|
+
/** Why the value was chosen. REQUIRED when actor !== "default". */
|
|
46
|
+
rationale?: string;
|
|
47
|
+
}
|
|
48
|
+
/** A not-yet-recorded entry: everything but the ledger-assigned seq. */
|
|
49
|
+
export type NewAssumptionEntry = Omit<AssumptionEntry, "seq">;
|
|
50
|
+
export interface AssumptionLedger {
|
|
51
|
+
readonly entries: readonly AssumptionEntry[];
|
|
52
|
+
}
|
|
53
|
+
/** An empty, frozen ledger. */
|
|
54
|
+
export declare function createLedger(): AssumptionLedger;
|
|
55
|
+
/**
|
|
56
|
+
* Appends an entry, returning a NEW frozen ledger; the input ledger is
|
|
57
|
+
* untouched. Assigns seq = entries.length + 1. Throws
|
|
58
|
+
* ComplianceError("MISSING_RATIONALE") when actor !== "default" and rationale
|
|
59
|
+
* is missing or blank.
|
|
60
|
+
*/
|
|
61
|
+
export declare function recordAssumption(ledger: AssumptionLedger, entry: NewAssumptionEntry): AssumptionLedger;
|
|
62
|
+
/** Entries that represent judgment (actor !== "default"), in ledger order. */
|
|
63
|
+
export declare function judgmentEntries(ledger: AssumptionLedger): AssumptionEntry[];
|
|
64
|
+
export interface AssumptionValueChange {
|
|
65
|
+
field: string;
|
|
66
|
+
priorValue: JsonValue;
|
|
67
|
+
currentValue: JsonValue;
|
|
68
|
+
}
|
|
69
|
+
/** The ASOP 41 change-disclosure diff between two analyses' ledgers. */
|
|
70
|
+
export interface ChangedAssumptions {
|
|
71
|
+
/** Fields set in current but never set in prior. */
|
|
72
|
+
added: string[];
|
|
73
|
+
/** Fields set in prior but never set in current. */
|
|
74
|
+
removed: string[];
|
|
75
|
+
/** Fields set on both sides whose latest values differ (canonical-JSON inequality). */
|
|
76
|
+
changed: AssumptionValueChange[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Diffs the LATEST entry per field between a prior analysis's ledger and the
|
|
80
|
+
* current one. Values compare by canonical JSON (key order never matters).
|
|
81
|
+
* All output lists are sorted by field for deterministic rendering.
|
|
82
|
+
*/
|
|
83
|
+
export declare function changedAssumptions(prior: AssumptionLedger, current: AssumptionLedger): ChangedAssumptions;
|
|
84
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,2FAA2F;AAC3F,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,kFAAkF;AAClF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtG,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,CAAC;IACvB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,iEAAiE;IACjE,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;CAC9C;AAED,+BAA+B;AAC/B,wBAAgB,YAAY,IAAI,gBAAgB,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,GAAG,gBAAgB,CAStG;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,eAAe,EAAE,CAE3E;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,CAAC;IACtB,YAAY,EAAE,SAAS,CAAC;CACzB;AAED,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uFAAuF;IACvF,OAAO,EAAE,qBAAqB,EAAE,CAAC;CAClC;AASD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,gBAAgB,GACxB,kBAAkB,CAuBpB"}
|