@actuarial-ts/interchange 0.2.0 → 0.3.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/README.md +28 -1
- package/dist/convert/result.d.ts +4 -4
- package/dist/convert/result.js +3 -3
- package/dist/convert/result.js.map +1 -1
- package/dist/envelope.d.ts +1 -1
- package/dist/envelope.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +49 -0
- package/dist/parse.js.map +1 -1
- package/dist/referee/crosscheck.d.ts +12 -0
- package/dist/referee/crosscheck.d.ts.map +1 -1
- package/dist/referee/crosscheck.js +109 -9
- package/dist/referee/crosscheck.js.map +1 -1
- package/dist/referee/crosscheckStochastic.d.ts +24 -0
- package/dist/referee/crosscheckStochastic.d.ts.map +1 -0
- package/dist/referee/crosscheckStochastic.js +367 -0
- package/dist/referee/crosscheckStochastic.js.map +1 -0
- package/dist/schemas/result.d.ts +552 -0
- package/dist/schemas/result.d.ts.map +1 -1
- package/dist/schemas/result.js +52 -0
- package/dist/schemas/result.js.map +1 -1
- package/package.json +4 -2
- package/src/convert/result.ts +212 -0
- package/src/convert/selection.ts +565 -0
- package/src/convert/triangle.ts +208 -0
- package/src/envelope.ts +193 -0
- package/src/index.ts +15 -0
- package/src/parse.ts +175 -0
- package/src/referee/crosscheck.ts +459 -0
- package/src/referee/crosscheckStochastic.ts +488 -0
- package/src/referee/profiles.ts +113 -0
- package/src/schemas/bundle.ts +64 -0
- package/src/schemas/crosscheck.ts +84 -0
- package/src/schemas/manifest.ts +75 -0
- package/src/schemas/result.ts +180 -0
- package/src/schemas/selection.ts +175 -0
- package/src/schemas/study.ts +98 -0
- package/src/schemas/triangle.ts +138 -0
package/dist/schemas/result.js
CHANGED
|
@@ -73,11 +73,63 @@ export const stochasticSummarySchema = z
|
|
|
73
73
|
percentiles: z.record(z.number().finite()),
|
|
74
74
|
})
|
|
75
75
|
.passthrough();
|
|
76
|
+
/**
|
|
77
|
+
* How much a consumer may rely on re-running this result.
|
|
78
|
+
*
|
|
79
|
+
* A seed is NOT the same guarantee as reproducibility: it removes one source
|
|
80
|
+
* of variance, but the engine underneath may still be non-deterministic. This
|
|
81
|
+
* field says which promise the document actually carries, so an actuary knows
|
|
82
|
+
* whether they hold a derivation anyone can regenerate or an observation
|
|
83
|
+
* somebody recorded.
|
|
84
|
+
*
|
|
85
|
+
* - `seeded-reproducible` — re-running with this seed reproduces this document
|
|
86
|
+
* byte-for-byte. @actuarial-ts/core's own stochastic layer is this
|
|
87
|
+
* (packages/core/test/odpBootstrap.test.ts pins it), because it uses a seeded
|
|
88
|
+
* PRNG with no ambient randomness.
|
|
89
|
+
* - `witnessed` — the engine is NOT byte-reproducible even under a fixed seed.
|
|
90
|
+
* The document is an integrity-checked record of what that engine produced on
|
|
91
|
+
* that run, not something a reviewer can regenerate. Still legitimate ASOP
|
|
92
|
+
* No. 56 evidence — it just supports an attestation, not a replay.
|
|
93
|
+
*
|
|
94
|
+
* Absent means unstated (documents written before this field existed); treat
|
|
95
|
+
* an absent value as unknown, never as a reproducibility guarantee.
|
|
96
|
+
*
|
|
97
|
+
* Deterministic methods do not carry this field: kind `method-result` already
|
|
98
|
+
* implies reproducibility, and the frozen conformance corpus proves it across
|
|
99
|
+
* three independent shores.
|
|
100
|
+
*/
|
|
101
|
+
export const reproducibilitySchema = z.enum(["seeded-reproducible", "witnessed"]);
|
|
102
|
+
/**
|
|
103
|
+
* The engine's own self-check: it ran the identical seeded request more than
|
|
104
|
+
* once and reports whether the runs agreed. This is what lets a
|
|
105
|
+
* non-reproducible engine be HONEST rather than silently unstable — the
|
|
106
|
+
* instability is measured and disclosed on the document instead of surfacing
|
|
107
|
+
* later as a mysteriously failing test.
|
|
108
|
+
*/
|
|
109
|
+
export const stabilityCheckSchema = z
|
|
110
|
+
.object({
|
|
111
|
+
/** How many independent runs of the identical seeded request were compared (>= 2). */
|
|
112
|
+
repeats: z.number().int().min(2),
|
|
113
|
+
/** True when every repeat produced the identical semantic body. */
|
|
114
|
+
byteIdentical: z.boolean(),
|
|
115
|
+
/**
|
|
116
|
+
* Worst relative deviation observed across repeats on the summary mean,
|
|
117
|
+
* using the cross-shore definition |a-b| / max(|a|,|b|). Null when not
|
|
118
|
+
* computable. Zero with byteIdentical=false means the bodies differed
|
|
119
|
+
* somewhere other than the summary mean.
|
|
120
|
+
*/
|
|
121
|
+
maxRelativeDeviation: z.number().finite().nonnegative().nullable(),
|
|
122
|
+
})
|
|
123
|
+
.passthrough();
|
|
76
124
|
export const stochasticResultBodySchema = z
|
|
77
125
|
.object({
|
|
78
126
|
...resultCommonShape,
|
|
79
127
|
seed: z.number().int().optional(),
|
|
80
128
|
nSims: z.number().int().positive(),
|
|
129
|
+
/** Which reproducibility promise this document carries; see the schema doc. */
|
|
130
|
+
reproducibility: reproducibilitySchema.optional(),
|
|
131
|
+
/** The engine's repeat-run self-check, when it performed one. */
|
|
132
|
+
stability: stabilityCheckSchema.optional(),
|
|
81
133
|
summary: stochasticSummarySchema,
|
|
82
134
|
byOrigin: z.array(z.object({ origin: z.string().min(1) }).passthrough()),
|
|
83
135
|
samplesRef: samplesRefSchema.optional(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/schemas/result.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/schemas/result.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuarial-ts/interchange",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The actuarial-interchange format for the actuarial-ts SDK: language-neutral, versioned interchange documents (triangles, selections, method results, studies, bundles, crosscheck reports) with RFC 8785 canonicalization, semantic-body integrity tags, an intent/value coherence rule, and the cross-implementation referee. Bridges actuarial-ts with chainladder-python and R ChainLadder.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
+
"src",
|
|
18
19
|
"README.md",
|
|
19
20
|
"LICENSE",
|
|
20
21
|
"NOTICE"
|
|
@@ -52,10 +53,11 @@
|
|
|
52
53
|
"emit-schema": "npm run build && node --experimental-strip-types scripts/emit-schema.ts"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
|
-
"@actuarial-ts/core": "^0.
|
|
56
|
+
"@actuarial-ts/core": "^0.3.0",
|
|
56
57
|
"zod": "^3.25.76"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
60
|
+
"@types/node": "^22.10.5",
|
|
59
61
|
"typescript": "^5.7.3",
|
|
60
62
|
"vitest": "^3.0.5",
|
|
61
63
|
"zod-to-json-schema": "^3.25.2"
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BenktanderResult,
|
|
3
|
+
type BornhuetterFergusonResult,
|
|
4
|
+
type ChainLadderResult,
|
|
5
|
+
type MackResult,
|
|
6
|
+
ReservingError,
|
|
7
|
+
} from "@actuarial-ts/core";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_GENERATOR,
|
|
10
|
+
INTERCHANGE_SPEC_VERSION,
|
|
11
|
+
type GeneratorStamp,
|
|
12
|
+
stampIntegrity,
|
|
13
|
+
} from "../envelope.js";
|
|
14
|
+
import type { TriangleDoc } from "../schemas/triangle.js";
|
|
15
|
+
import type { SelectionDoc } from "../schemas/selection.js";
|
|
16
|
+
import {
|
|
17
|
+
type EngineStamp,
|
|
18
|
+
type MethodResultBody,
|
|
19
|
+
type MethodResultDoc,
|
|
20
|
+
type MethodResultRow,
|
|
21
|
+
methodResultDocSchema,
|
|
22
|
+
} from "../schemas/result.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* core method results → MethodResultDoc, stamping `appliesTo` (spec 3.2 /
|
|
26
|
+
* 4.1).
|
|
27
|
+
*
|
|
28
|
+
* Converts the deterministic quartet — ChainLadderResult, MackResult,
|
|
29
|
+
* BornhuetterFergusonResult, BenktanderResult. Further methods (Cape Cod,
|
|
30
|
+
* Clark, Munich, the stochastic layer, ...) are NOT yet converted and
|
|
31
|
+
* throw; adding one is a spec-minor change. Method names use the actuarial-ts namespace
|
|
32
|
+
* (unprefixed discriminants); `clpy:`/`rcl:` are reserved for the other
|
|
33
|
+
* shores.
|
|
34
|
+
*
|
|
35
|
+
* Row vocabulary is the spec's: `unpaid` carries what core's Mack calls
|
|
36
|
+
* `reserve` (identical quantity, interchange field name).
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export type ConvertibleResult =
|
|
40
|
+
| ChainLadderResult
|
|
41
|
+
| MackResult
|
|
42
|
+
| BornhuetterFergusonResult
|
|
43
|
+
| BenktanderResult;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The engine stamp for results computed by @actuarial-ts/core. A sync test
|
|
47
|
+
* pins the version to the installed core package so it cannot drift.
|
|
48
|
+
*/
|
|
49
|
+
export const CORE_ENGINE: EngineStamp = { name: "actuarial-ts", version: "0.3.0" };
|
|
50
|
+
|
|
51
|
+
export interface ResultToDocOptions {
|
|
52
|
+
/** The triangle document the result was computed from. */
|
|
53
|
+
triangleDoc: TriangleDoc;
|
|
54
|
+
/** The selection document used, when one exists; null/omitted = none
|
|
55
|
+
* (e.g. Mack on its own volume-weighted factors). */
|
|
56
|
+
selectionDoc?: SelectionDoc | null;
|
|
57
|
+
/** ISO timestamp for the envelope (caller-supplied; purity rule). */
|
|
58
|
+
createdAt: string;
|
|
59
|
+
/** Convention profile the run aligns to (referee comparability input). */
|
|
60
|
+
conventionProfile?: string;
|
|
61
|
+
/** Requested-parameter echo; defaults to {}. */
|
|
62
|
+
parameters?: Record<string, unknown>;
|
|
63
|
+
/** Effective parameters when the engine deviated from requested. */
|
|
64
|
+
effectiveParameters?: Record<string, unknown>;
|
|
65
|
+
engine?: EngineStamp;
|
|
66
|
+
generator?: GeneratorStamp;
|
|
67
|
+
extensions?: Record<string, unknown>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface MappedResult {
|
|
71
|
+
method: string;
|
|
72
|
+
rows: MethodResultRow[];
|
|
73
|
+
totals: MethodResultBody["totals"];
|
|
74
|
+
warnings: string[];
|
|
75
|
+
/** Basis to cross-check against the triangle's measure; null = untyped. */
|
|
76
|
+
basis: string | null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function mapResult(result: ConvertibleResult): MappedResult {
|
|
80
|
+
switch (result.method) {
|
|
81
|
+
case "chainLadder":
|
|
82
|
+
return {
|
|
83
|
+
method: "chainLadder",
|
|
84
|
+
rows: result.rows.map((r) => ({
|
|
85
|
+
origin: r.origin,
|
|
86
|
+
ultimate: r.ultimate,
|
|
87
|
+
unpaid: r.unpaid,
|
|
88
|
+
})),
|
|
89
|
+
totals: { ultimate: result.totals.ultimate, unpaid: result.totals.unpaid },
|
|
90
|
+
warnings: [...result.warnings],
|
|
91
|
+
basis: result.basis,
|
|
92
|
+
};
|
|
93
|
+
case "mack":
|
|
94
|
+
return {
|
|
95
|
+
method: "mack",
|
|
96
|
+
rows: result.rows.map((r) => ({
|
|
97
|
+
origin: r.origin,
|
|
98
|
+
ultimate: r.ultimate,
|
|
99
|
+
unpaid: r.reserve,
|
|
100
|
+
standardError: r.standardError,
|
|
101
|
+
})),
|
|
102
|
+
totals: {
|
|
103
|
+
ultimate: result.totals.ultimate,
|
|
104
|
+
unpaid: result.totals.reserve,
|
|
105
|
+
standardError: result.totals.standardError,
|
|
106
|
+
},
|
|
107
|
+
warnings: [...result.warnings],
|
|
108
|
+
basis: null,
|
|
109
|
+
};
|
|
110
|
+
case "bornhuetterFerguson":
|
|
111
|
+
return {
|
|
112
|
+
method: "bornhuetterFerguson",
|
|
113
|
+
rows: result.rows.map((r) => ({
|
|
114
|
+
origin: r.origin,
|
|
115
|
+
ultimate: r.ultimate,
|
|
116
|
+
unpaid: r.unpaid,
|
|
117
|
+
})),
|
|
118
|
+
totals: { ultimate: result.totals.ultimate, unpaid: result.totals.unpaid },
|
|
119
|
+
warnings: [...result.warnings],
|
|
120
|
+
basis: result.basis,
|
|
121
|
+
};
|
|
122
|
+
case "benktander":
|
|
123
|
+
return {
|
|
124
|
+
method: "benktander",
|
|
125
|
+
rows: result.rows.map((r) => ({
|
|
126
|
+
origin: r.origin,
|
|
127
|
+
ultimate: r.ultimate,
|
|
128
|
+
unpaid: r.unpaid,
|
|
129
|
+
})),
|
|
130
|
+
totals: { ultimate: result.totals.ultimate, unpaid: result.totals.unpaid },
|
|
131
|
+
warnings: [...result.warnings],
|
|
132
|
+
basis: result.basis,
|
|
133
|
+
};
|
|
134
|
+
default: {
|
|
135
|
+
const method = (result as { method?: string }).method ?? "(unknown)";
|
|
136
|
+
throw new ReservingError(
|
|
137
|
+
"BAD_INTERCHANGE",
|
|
138
|
+
`resultToDoc does not support method "${method}" yet; it converts chainLadder, ` +
|
|
139
|
+
"mack, bornhuetterFerguson, and benktander",
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function resultToDoc(
|
|
146
|
+
result: ConvertibleResult,
|
|
147
|
+
options: ResultToDocOptions,
|
|
148
|
+
): MethodResultDoc {
|
|
149
|
+
const selectionDoc = options.selectionDoc ?? null;
|
|
150
|
+
if (
|
|
151
|
+
selectionDoc !== null &&
|
|
152
|
+
selectionDoc.selection.appliesTo.triangleIntegrity !== options.triangleDoc.integrity
|
|
153
|
+
) {
|
|
154
|
+
throw new ReservingError(
|
|
155
|
+
"BAD_INTERCHANGE",
|
|
156
|
+
`The selection document applies to triangle ${selectionDoc.selection.appliesTo.triangleIntegrity} ` +
|
|
157
|
+
`but the supplied triangle document's integrity is ${options.triangleDoc.integrity}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const mapped = mapResult(result);
|
|
162
|
+
if (mapped.basis !== null && mapped.basis !== options.triangleDoc.triangle.measure) {
|
|
163
|
+
throw new ReservingError(
|
|
164
|
+
"BAD_INTERCHANGE",
|
|
165
|
+
`Result basis "${mapped.basis}" does not match the triangle document's measure ` +
|
|
166
|
+
`"${options.triangleDoc.triangle.measure}"`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const engine: EngineStamp = { ...(options.engine ?? CORE_ENGINE) };
|
|
171
|
+
if (options.conventionProfile !== undefined) {
|
|
172
|
+
engine.conventionProfile = options.conventionProfile;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const body: MethodResultBody = {
|
|
176
|
+
appliesTo: {
|
|
177
|
+
triangleIntegrity: options.triangleDoc.integrity,
|
|
178
|
+
selectionIntegrity: selectionDoc?.integrity ?? null,
|
|
179
|
+
},
|
|
180
|
+
engine,
|
|
181
|
+
method: mapped.method,
|
|
182
|
+
parameters: options.parameters ?? {},
|
|
183
|
+
rows: mapped.rows,
|
|
184
|
+
totals: mapped.totals,
|
|
185
|
+
};
|
|
186
|
+
// Authoring convention (shared with the Python adapter): `warnings` is
|
|
187
|
+
// omitted when empty, so a warning-free result hashes identically no
|
|
188
|
+
// matter which shore authored it.
|
|
189
|
+
if (mapped.warnings.length > 0) body.warnings = mapped.warnings;
|
|
190
|
+
if (options.effectiveParameters !== undefined) {
|
|
191
|
+
body.effectiveParameters = options.effectiveParameters;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const doc = stampIntegrity<MethodResultDoc>({
|
|
195
|
+
interchangeVersion: INTERCHANGE_SPEC_VERSION,
|
|
196
|
+
kind: "method-result",
|
|
197
|
+
generator: options.generator ?? DEFAULT_GENERATOR,
|
|
198
|
+
createdAt: options.createdAt,
|
|
199
|
+
extensions: options.extensions ?? {},
|
|
200
|
+
result: body,
|
|
201
|
+
});
|
|
202
|
+
const checked = methodResultDocSchema.safeParse(doc);
|
|
203
|
+
if (!checked.success) {
|
|
204
|
+
throw new ReservingError(
|
|
205
|
+
"BAD_INTERCHANGE",
|
|
206
|
+
`resultToDoc produced an invalid document: ${checked.error.issues
|
|
207
|
+
.map((i) => `${i.path.join(".") || "$"}: ${i.message}`)
|
|
208
|
+
.join("; ")}`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return checked.data;
|
|
212
|
+
}
|