@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/ledger.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
import { canonicalJson, ComplianceError } from "./bundle.js";
|
|
27
|
+
/** An empty, frozen ledger. */
|
|
28
|
+
export function createLedger() {
|
|
29
|
+
return Object.freeze({ entries: Object.freeze([]) });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Appends an entry, returning a NEW frozen ledger; the input ledger is
|
|
33
|
+
* untouched. Assigns seq = entries.length + 1. Throws
|
|
34
|
+
* ComplianceError("MISSING_RATIONALE") when actor !== "default" and rationale
|
|
35
|
+
* is missing or blank.
|
|
36
|
+
*/
|
|
37
|
+
export function recordAssumption(ledger, entry) {
|
|
38
|
+
if (entry.actor !== "default" && (entry.rationale === undefined || entry.rationale.trim() === "")) {
|
|
39
|
+
throw new ComplianceError("MISSING_RATIONALE", `assumption "${entry.field}" set by actor "${entry.actor}" requires a rationale; only actor "default" may omit one`);
|
|
40
|
+
}
|
|
41
|
+
const recorded = Object.freeze({ ...entry, seq: ledger.entries.length + 1 });
|
|
42
|
+
return Object.freeze({ entries: Object.freeze([...ledger.entries, recorded]) });
|
|
43
|
+
}
|
|
44
|
+
/** Entries that represent judgment (actor !== "default"), in ledger order. */
|
|
45
|
+
export function judgmentEntries(ledger) {
|
|
46
|
+
return ledger.entries.filter((e) => e.actor !== "default");
|
|
47
|
+
}
|
|
48
|
+
/** Latest entry per field; ledger order is seq order, so the last write wins. */
|
|
49
|
+
function latestByField(ledger) {
|
|
50
|
+
const latest = new Map();
|
|
51
|
+
for (const entry of ledger.entries)
|
|
52
|
+
latest.set(entry.field, entry);
|
|
53
|
+
return latest;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Diffs the LATEST entry per field between a prior analysis's ledger and the
|
|
57
|
+
* current one. Values compare by canonical JSON (key order never matters).
|
|
58
|
+
* All output lists are sorted by field for deterministic rendering.
|
|
59
|
+
*/
|
|
60
|
+
export function changedAssumptions(prior, current) {
|
|
61
|
+
const priorLatest = latestByField(prior);
|
|
62
|
+
const currentLatest = latestByField(current);
|
|
63
|
+
const added = [];
|
|
64
|
+
const removed = [];
|
|
65
|
+
const changed = [];
|
|
66
|
+
const fields = [...new Set([...priorLatest.keys(), ...currentLatest.keys()])].sort();
|
|
67
|
+
for (const field of fields) {
|
|
68
|
+
const before = priorLatest.get(field);
|
|
69
|
+
const after = currentLatest.get(field);
|
|
70
|
+
if (before === undefined) {
|
|
71
|
+
if (after !== undefined)
|
|
72
|
+
added.push(field);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (after === undefined) {
|
|
76
|
+
removed.push(field);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (canonicalJson(before.value) !== canonicalJson(after.value)) {
|
|
80
|
+
changed.push({ field, priorValue: before.value, currentValue: after.value });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { added, removed, changed };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimate metadata: the typed identification of what an unpaid-claim
|
|
3
|
+
* estimate IS — its intended purpose and users, the intended measure, the
|
|
4
|
+
* gross/net and LAE basis, and the accounting/valuation/review dates
|
|
5
|
+
* (ASOP 43 terminology; the disclosure generator renders these under
|
|
6
|
+
* ASOP 41).
|
|
7
|
+
*
|
|
8
|
+
* Ground truth:
|
|
9
|
+
* - `validateMetadata` VALIDATES, it does not construct: metadata is often
|
|
10
|
+
* built up field-by-field over the course of an analysis, so callers keep
|
|
11
|
+
* plain objects and ask for the problem list whenever they need to know
|
|
12
|
+
* whether the metadata is disclosure-ready. Empty array = valid.
|
|
13
|
+
* - Validation is defensive at runtime (built-up metadata may have been cast
|
|
14
|
+
* from a partial), so required-field presence and enum membership are
|
|
15
|
+
* checked even though the types already say so.
|
|
16
|
+
* - Dates are caller-supplied ISO strings (yyyy-mm-dd), checked for real
|
|
17
|
+
* calendar validity (leap years included); the module never reads a clock.
|
|
18
|
+
* - `percentile` is a fraction strictly between 0 and 1 (e.g. 0.75 for the
|
|
19
|
+
* 75th percentile) and is only meaningful — and only allowed — when
|
|
20
|
+
* intendedMeasure.kind === "specified-percentile".
|
|
21
|
+
*
|
|
22
|
+
* These utilities are designed to support the actuary's compliance with
|
|
23
|
+
* ASOP Nos. 41 and 43; responsibility for compliance remains with the
|
|
24
|
+
* credentialed actuary.
|
|
25
|
+
*/
|
|
26
|
+
export declare const INTENDED_MEASURE_KINDS: readonly ["central-estimate", "high-estimate", "low-estimate", "specified-percentile", "range"];
|
|
27
|
+
export type IntendedMeasureKind = (typeof INTENDED_MEASURE_KINDS)[number];
|
|
28
|
+
export interface IntendedMeasure {
|
|
29
|
+
kind: IntendedMeasureKind;
|
|
30
|
+
/** Fraction in (0, 1), e.g. 0.75; required iff kind === "specified-percentile". */
|
|
31
|
+
percentile?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare const GROSS_NET_BASES: readonly ["gross", "net-of-reinsurance", "net-of-salvage-subro", "net-all"];
|
|
34
|
+
export type GrossNetBasis = (typeof GROSS_NET_BASES)[number];
|
|
35
|
+
export declare const LAE_TREATMENTS: readonly ["excluding-lae", "including-all-lae", "dcc-only", "aao-only"];
|
|
36
|
+
export type LaeTreatment = (typeof LAE_TREATMENTS)[number];
|
|
37
|
+
export interface EstimateBasis {
|
|
38
|
+
grossNet: GrossNetBasis;
|
|
39
|
+
laeTreatment: LaeTreatment;
|
|
40
|
+
}
|
|
41
|
+
export interface EstimateMetadata {
|
|
42
|
+
/** Why the estimate exists (e.g. "unpaid claim estimate for the 2025 annual statement"). */
|
|
43
|
+
intendedPurpose: string;
|
|
44
|
+
/** Who may rely on the estimate. */
|
|
45
|
+
intendedUsers?: string[];
|
|
46
|
+
intendedMeasure: IntendedMeasure;
|
|
47
|
+
basis: EstimateBasis;
|
|
48
|
+
/** ISO date (yyyy-mm-dd) used to separate paid from unpaid (ASOP 43 accounting date). */
|
|
49
|
+
accountingDate: string;
|
|
50
|
+
/** ISO date through which transactions are reflected in the data (ASOP 43 valuation date). */
|
|
51
|
+
valuationDate: string;
|
|
52
|
+
/** ISO cutoff for information reflected in the analysis (ASOP 41 review date), when later than the valuation date. */
|
|
53
|
+
reviewDate?: string;
|
|
54
|
+
scopeNotes?: string;
|
|
55
|
+
/** ISO 4217-style currency label (e.g. "USD"); informational, not validated against a table. */
|
|
56
|
+
currency?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns the list of problems keeping `metadata` from being disclosure-ready;
|
|
60
|
+
* an empty array means valid. Never throws — validation, not construction.
|
|
61
|
+
*/
|
|
62
|
+
export declare function validateMetadata(metadata: EstimateMetadata): string[];
|
|
63
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,eAAO,MAAM,sBAAsB,iGAMzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,6EAKlB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,cAAc,yEAKjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,4FAA4F;IAC5F,eAAe,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,aAAa,EAAE,MAAM,CAAC;IACtB,sHAAsH;IACtH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA+BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAwErE"}
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimate metadata: the typed identification of what an unpaid-claim
|
|
3
|
+
* estimate IS — its intended purpose and users, the intended measure, the
|
|
4
|
+
* gross/net and LAE basis, and the accounting/valuation/review dates
|
|
5
|
+
* (ASOP 43 terminology; the disclosure generator renders these under
|
|
6
|
+
* ASOP 41).
|
|
7
|
+
*
|
|
8
|
+
* Ground truth:
|
|
9
|
+
* - `validateMetadata` VALIDATES, it does not construct: metadata is often
|
|
10
|
+
* built up field-by-field over the course of an analysis, so callers keep
|
|
11
|
+
* plain objects and ask for the problem list whenever they need to know
|
|
12
|
+
* whether the metadata is disclosure-ready. Empty array = valid.
|
|
13
|
+
* - Validation is defensive at runtime (built-up metadata may have been cast
|
|
14
|
+
* from a partial), so required-field presence and enum membership are
|
|
15
|
+
* checked even though the types already say so.
|
|
16
|
+
* - Dates are caller-supplied ISO strings (yyyy-mm-dd), checked for real
|
|
17
|
+
* calendar validity (leap years included); the module never reads a clock.
|
|
18
|
+
* - `percentile` is a fraction strictly between 0 and 1 (e.g. 0.75 for the
|
|
19
|
+
* 75th percentile) and is only meaningful — and only allowed — when
|
|
20
|
+
* intendedMeasure.kind === "specified-percentile".
|
|
21
|
+
*
|
|
22
|
+
* These utilities are designed to support the actuary's compliance with
|
|
23
|
+
* ASOP Nos. 41 and 43; responsibility for compliance remains with the
|
|
24
|
+
* credentialed actuary.
|
|
25
|
+
*/
|
|
26
|
+
export const INTENDED_MEASURE_KINDS = [
|
|
27
|
+
"central-estimate",
|
|
28
|
+
"high-estimate",
|
|
29
|
+
"low-estimate",
|
|
30
|
+
"specified-percentile",
|
|
31
|
+
"range",
|
|
32
|
+
];
|
|
33
|
+
export const GROSS_NET_BASES = [
|
|
34
|
+
"gross",
|
|
35
|
+
"net-of-reinsurance",
|
|
36
|
+
"net-of-salvage-subro",
|
|
37
|
+
"net-all",
|
|
38
|
+
];
|
|
39
|
+
export const LAE_TREATMENTS = [
|
|
40
|
+
"excluding-lae",
|
|
41
|
+
"including-all-lae",
|
|
42
|
+
"dcc-only",
|
|
43
|
+
"aao-only",
|
|
44
|
+
];
|
|
45
|
+
const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
46
|
+
/** True for a well-formed yyyy-mm-dd string naming a real calendar date. */
|
|
47
|
+
function isIsoDate(value) {
|
|
48
|
+
const match = ISO_DATE.exec(value);
|
|
49
|
+
if (!match)
|
|
50
|
+
return false;
|
|
51
|
+
const year = Number(match[1]);
|
|
52
|
+
const month = Number(match[2]);
|
|
53
|
+
const day = Number(match[3]);
|
|
54
|
+
if (month < 1 || month > 12)
|
|
55
|
+
return false;
|
|
56
|
+
const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
57
|
+
const daysInMonth = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
|
|
58
|
+
return day >= 1 && day <= daysInMonth;
|
|
59
|
+
}
|
|
60
|
+
function isNonEmptyString(value) {
|
|
61
|
+
return typeof value === "string" && value.trim() !== "";
|
|
62
|
+
}
|
|
63
|
+
function checkDate(problems, name, value, required) {
|
|
64
|
+
if (value === undefined) {
|
|
65
|
+
if (required)
|
|
66
|
+
problems.push(`${name} is required (ISO yyyy-mm-dd)`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (typeof value !== "string" || !isIsoDate(value)) {
|
|
70
|
+
problems.push(`${name} must be a valid ISO date (yyyy-mm-dd); got ${JSON.stringify(value)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns the list of problems keeping `metadata` from being disclosure-ready;
|
|
75
|
+
* an empty array means valid. Never throws — validation, not construction.
|
|
76
|
+
*/
|
|
77
|
+
export function validateMetadata(metadata) {
|
|
78
|
+
const problems = [];
|
|
79
|
+
if (!isNonEmptyString(metadata.intendedPurpose)) {
|
|
80
|
+
problems.push("intendedPurpose is required and must be a non-empty string");
|
|
81
|
+
}
|
|
82
|
+
if (metadata.intendedUsers !== undefined) {
|
|
83
|
+
if (!Array.isArray(metadata.intendedUsers)) {
|
|
84
|
+
problems.push("intendedUsers, when provided, must be an array of non-empty strings");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
metadata.intendedUsers.forEach((user, index) => {
|
|
88
|
+
if (!isNonEmptyString(user)) {
|
|
89
|
+
problems.push(`intendedUsers[${index}] must be a non-empty string`);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const measure = metadata.intendedMeasure;
|
|
95
|
+
if (measure === undefined) {
|
|
96
|
+
problems.push("intendedMeasure is required");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (!INTENDED_MEASURE_KINDS.includes(measure.kind)) {
|
|
100
|
+
problems.push(`intendedMeasure.kind must be one of ${INTENDED_MEASURE_KINDS.join(", ")}; got ${JSON.stringify(measure.kind)}`);
|
|
101
|
+
}
|
|
102
|
+
if (measure.kind === "specified-percentile") {
|
|
103
|
+
const p = measure.percentile;
|
|
104
|
+
if (p === undefined) {
|
|
105
|
+
problems.push('intendedMeasure.percentile is required when kind is "specified-percentile"');
|
|
106
|
+
}
|
|
107
|
+
else if (typeof p !== "number" || !Number.isFinite(p) || p <= 0 || p >= 1) {
|
|
108
|
+
problems.push(`intendedMeasure.percentile must be a fraction strictly between 0 and 1 (e.g. 0.75); got ${JSON.stringify(p)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (measure.percentile !== undefined) {
|
|
112
|
+
problems.push(`intendedMeasure.percentile is only meaningful when kind is "specified-percentile"; got kind ${JSON.stringify(measure.kind)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const basis = metadata.basis;
|
|
116
|
+
if (basis === undefined) {
|
|
117
|
+
problems.push("basis is required");
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
if (!GROSS_NET_BASES.includes(basis.grossNet)) {
|
|
121
|
+
problems.push(`basis.grossNet must be one of ${GROSS_NET_BASES.join(", ")}; got ${JSON.stringify(basis.grossNet)}`);
|
|
122
|
+
}
|
|
123
|
+
if (!LAE_TREATMENTS.includes(basis.laeTreatment)) {
|
|
124
|
+
problems.push(`basis.laeTreatment must be one of ${LAE_TREATMENTS.join(", ")}; got ${JSON.stringify(basis.laeTreatment)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
checkDate(problems, "accountingDate", metadata.accountingDate, true);
|
|
128
|
+
checkDate(problems, "valuationDate", metadata.valuationDate, true);
|
|
129
|
+
checkDate(problems, "reviewDate", metadata.reviewDate, false);
|
|
130
|
+
if (metadata.scopeNotes !== undefined && !isNonEmptyString(metadata.scopeNotes)) {
|
|
131
|
+
problems.push("scopeNotes, when provided, must be a non-empty string");
|
|
132
|
+
}
|
|
133
|
+
if (metadata.currency !== undefined && !isNonEmptyString(metadata.currency)) {
|
|
134
|
+
problems.push("currency, when provided, must be a non-empty string");
|
|
135
|
+
}
|
|
136
|
+
return problems;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASOP No. 56 (Modeling) model cards.
|
|
3
|
+
*
|
|
4
|
+
* ASOP 56 asks an actuary who relies on models designed by others to
|
|
5
|
+
* disclose the extent of reliance and to maintain a basic understanding of
|
|
6
|
+
* the model: its basic operations, dependencies, sensitivities, and known
|
|
7
|
+
* weaknesses. These cards ARE that content for every method the SDK ships —
|
|
8
|
+
* ready to drop into workpapers or the generated disclosure.
|
|
9
|
+
*
|
|
10
|
+
* The cards describe the implementations in @actuarial-ts/core as built and
|
|
11
|
+
* tested (each specification matches the code and its published-value test
|
|
12
|
+
* pins), not idealized textbook variants. They are designed to support the
|
|
13
|
+
* actuary's compliance with ASOP No. 56; responsibility for compliance
|
|
14
|
+
* remains with the credentialed actuary.
|
|
15
|
+
*/
|
|
16
|
+
export type MethodId = "chainLadder" | "mack" | "bornhuetterFerguson" | "benktander" | "capeCod" | "expectedClaims" | "frequencySeverity" | "berquistCaseAdequacy" | "berquistSettlement" | "tailFitting" | "cappingIlf" | "trend" | "onLevel" | "munichChainLadder" | "odpBootstrap" | "merzWuthrich" | "clarkLdf" | "clarkCapeCod" | "ulae" | "discountUnpaid" | "caseOutstanding" | "fisherLange" | "salvageSubro" | "netOfRecoveries";
|
|
17
|
+
export interface ModelCard {
|
|
18
|
+
method: MethodId;
|
|
19
|
+
title: string;
|
|
20
|
+
intendedUse: string;
|
|
21
|
+
specification: string;
|
|
22
|
+
keyAssumptions: string[];
|
|
23
|
+
weaknesses: string[];
|
|
24
|
+
sensitivities: string[];
|
|
25
|
+
literature: string[];
|
|
26
|
+
}
|
|
27
|
+
export declare const MODEL_CARDS: Record<MethodId, ModelCard>;
|
|
28
|
+
/** Every method id the disclosure generator recognizes. */
|
|
29
|
+
export declare const MODEL_CARD_IDS: MethodId[];
|
|
30
|
+
//# sourceMappingURL=modelCards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelCards.d.ts","sourceRoot":"","sources":["../src/modelCards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,MAAM,GACN,qBAAqB,GACrB,YAAY,GACZ,SAAS,GACT,gBAAgB,GAChB,mBAAmB,GACnB,sBAAsB,GACtB,oBAAoB,GACpB,aAAa,GACb,YAAY,GACZ,OAAO,GACP,SAAS,GACT,mBAAmB,GACnB,cAAc,GACd,cAAc,GACd,UAAU,GACV,cAAc,GACd,MAAM,GACN,gBAAgB,GAChB,iBAAiB,GACjB,aAAa,GACb,cAAc,GACd,iBAAiB,CAAC;AAEtB,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CA0dnD,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,EAA+B,QAAQ,EAAE,CAAC"}
|