@actuarial-ts/core 0.8.1 → 0.10.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -12,6 +12,8 @@ export * from "./reservingAdapter.js";
12
12
  export * from "./financialTerms.js";
13
13
  export * from "./financialPipeline.js";
14
14
  export * from "./analysisRecipe.js";
15
+ export * from "./analysisExpressions.js";
16
+ export * from "./analysisFinancialUnits.js";
15
17
  export * from "./util.js";
16
18
  export * from "./canonical.js";
17
19
  export { createDiagnosticIdentityValue, createDiagnosticIdentityObject, createDiagnosticIdentityArray, iterateDiagnosticIdentityJson, fingerprintDiagnosticIdentity, compareDiagnosticIdentityDocuments, compareDiagnosticIdentityJsonChunks, } from "./diagnosticIdentityStream.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,6BAA6B,EAC7B,kCAAkC,EAClC,mCAAmC,GAGpC,MAAM,+BAA+B,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,0CAA0C,EAC1C,+BAA+B,EAC/B,+BAA+B,GAChC,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,kCAAkC,EAClC,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AAmDpC,OAAO,EAAE,yBAAyB,EAAE,kCAAkC,EAAE,MAAM,yBAAyB,CAAC;AACxG,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAK3E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,gCAAgC,EAChC,kCAAkC,GACnC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,+BAA+B,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,GAChC,MAAM,4BAA4B,CAAC;AAMpC,OAAO,EACL,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,mCAAmC,EACnC,4BAA4B,EAC5B,iCAAiC,EACjC,gDAAgD,EAChD,2CAA2C,EAC3C,iCAAiC,EACjC,qBAAqB,EACrB,4BAA4B,EAC5B,gCAAgC,EAChC,mCAAmC,EACnC,8BAA8B,EAC9B,kCAAkC,EAClC,qCAAqC,GACtC,MAAM,4BAA4B,CAAC;AAqBpC,OAAO,EACL,oCAAoC,EACpC,cAAc,EACd,qBAAqB,EACrB,kCAAkC,EAClC,iDAAiD,EACjD,oBAAoB,EACpB,2BAA2B,EAC3B,kCAAkC,EAClC,YAAY,EACZ,mBAAmB,EACnB,uCAAuC,EACvC,8CAA8C,GAC/C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,6BAA6B,EAAE,oCAAoC,EAAE,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EACL,wCAAwC,EACxC,6BAA6B,EAC7B,oCAAoC,EACpC,qDAAqD,EACrD,kCAAkC,EAClC,+BAA+B,EAC/B,qCAAqC,GACtC,MAAM,4BAA4B,CAAC;AA8CpC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** This package's runtime version. A test pins it to package.json. */
2
- export declare const CORE_PACKAGE_VERSION = "0.8.1";
2
+ export declare const CORE_PACKAGE_VERSION = "0.10.0";
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,UAAU,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,WAAW,CAAC"}
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** This package's runtime version. A test pins it to package.json. */
2
- export const CORE_PACKAGE_VERSION = "0.8.1";
2
+ export const CORE_PACKAGE_VERSION = "0.10.0";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuarial-ts/core",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "Pure, zero-dependency P&C actuarial math for TypeScript: reserving, generalized definition-driven diagnostics, trends, limits, discounting, and seeded stochastic methods with published-value validation.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -0,0 +1,223 @@
1
+ import type {
2
+ AnalysisDefinition, AnalysisDerivedMeasureDefinition, AnalysisMeasureExpression,
3
+ AnalysisResultValue, AnalysisDerivedComponent, CustomizationCapabilityFinding,
4
+ } from "./customizationContracts.js";
5
+ import { canonicalJson } from "./canonical.js";
6
+ import { isDiagnosticPlainRecord, isDiagnosticToken, snapshotDiagnosticJson } from "./diagnosticRuntime.js";
7
+ import { DiagnosticValidationError } from "./types.js";
8
+
9
+ type Factors = Readonly<Record<string, number>>;
10
+ export type CompiledAnalysisExpression = { readonly definition: AnalysisDerivedMeasureDefinition; readonly unit: string; readonly unitFactors: Factors; readonly dependencies: readonly string[] };
11
+ const invalid = (message: string, path = "$.definition.derivedMeasures", code: "invalid-configuration" | "unknown-reference" | "incompatible-semantics" | "expression-limit" | "cycle" = "invalid-configuration"): never => {
12
+ throw new DiagnosticValidationError([{ domain: "definition", code, path, message }]);
13
+ };
14
+
15
+ function normalizedFactors(raw: unknown): Factors {
16
+ if (!isDiagnosticPlainRecord(raw) || Object.keys(raw).length > 32) return invalid("Unit factors require a bounded record of integer powers");
17
+ const result: [string, number][] = [];
18
+ for (const [unit, power] of Object.entries(raw)) {
19
+ if (!isDiagnosticToken(unit) || typeof power !== "number" || !Number.isSafeInteger(power) || Math.abs(power) > 32)
20
+ return invalid("Unit factors require valid unit names and integer powers between -32 and 32");
21
+ if (power !== 0) result.push([unit, power]);
22
+ }
23
+ return Object.fromEntries(result.sort(([a], [b]) => a.localeCompare(b)));
24
+ }
25
+ function combine(left: Factors, right: Factors, direction: 1 | -1): Factors {
26
+ const result = new Map(Object.entries(left));
27
+ for (const [unit, power] of Object.entries(right)) result.set(unit, (result.get(unit) ?? 0) + direction * power);
28
+ return normalizedFactors(Object.fromEntries(result));
29
+ }
30
+ export function formatAnalysisUnit(factors: Factors): string {
31
+ const normalized = normalizedFactors(factors);
32
+ const part = (sign: 1 | -1) => Object.entries(normalized).filter(([, power]) => power * sign > 0).map(([unit, power]) => {
33
+ const atom = /[*/^()[\]{}]/.test(unit) ? `[${unit}]` : unit;
34
+ return Math.abs(power) === 1 ? atom : `${atom}^${Math.abs(power)}`;
35
+ }).join("*");
36
+ const numerator = part(1) || "1";
37
+ const denominator = part(-1);
38
+ return denominator ? `${numerator}/${denominator.includes("*") ? `(${denominator})` : denominator}` : numerator;
39
+ }
40
+
41
+ /** Validates a bounded dependency graph and resolves dimensions without evaluating any values. */
42
+ export function compileAnalysisExpressions(definition: AnalysisDefinition): readonly CompiledAnalysisExpression[] {
43
+ const derived = definition.derivedMeasures ?? [];
44
+ if (derived.length > 64) return invalid("At most 64 derived measures are supported", undefined, "expression-limit");
45
+ const base = new Map(definition.measures.map((m) => [m.id, m]));
46
+ const declarations = new Map(derived.map((m) => [m.id, m]));
47
+ if (base.size !== definition.measures.length || declarations.size !== derived.length || derived.some((m) => !isDiagnosticToken(m.id) || base.has(m.id)))
48
+ return invalid("Base and derived measure IDs must be distinct valid tokens");
49
+ const compiled = new Map<string, CompiledAnalysisExpression>();
50
+ const visiting = new Set<string>();
51
+ let totalNodes = 0;
52
+ const resolve = (id: string): Factors => {
53
+ const raw = base.get(id);
54
+ if (raw) return normalizedFactors(raw.unitFactors ?? { [raw.unit]: 1 });
55
+ const prior = compiled.get(id);
56
+ if (prior) return prior.unitFactors;
57
+ const measure = declarations.get(id);
58
+ if (!measure) return invalid(`Unknown measure ${id}`, undefined, "unknown-reference");
59
+ if (visiting.has(id)) return invalid(`Derived measure cycle at ${id}`, undefined, "cycle");
60
+ visiting.add(id);
61
+ const dependencies = new Set<string>();
62
+ const walk = (raw: unknown, depth: number, ancestors: ReadonlySet<object>): Factors => {
63
+ if (++totalNodes > 1024 || depth > 16) return invalid("Derived expressions exceed 1024 total nodes or 16 nested levels", undefined, "expression-limit");
64
+ if (!isDiagnosticPlainRecord(raw)) return invalid("Expression nodes must be objects");
65
+ if (ancestors.has(raw)) return invalid("Expression contains an object cycle", undefined, "cycle");
66
+ const next = new Set(ancestors).add(raw);
67
+ const keys: Record<string, string[]> = { measure: ["op", "measureId"], exposure: ["op", "exposureId"], constant: ["op", "value", "unitFactors"], add: ["op", "terms"], subtract: ["op", "left", "right"], multiply: ["op", "left", "right"], divide: ["op", "numerator", "denominator"] };
68
+ const allowed = typeof raw.op === "string" && Object.hasOwn(keys, raw.op) ? keys[raw.op] : undefined;
69
+ if (!allowed || Object.keys(raw).some((key) => !allowed.includes(key))) return invalid("Unknown expression operator or field");
70
+ if (raw.op === "measure") {
71
+ if (!isDiagnosticToken(raw.measureId)) return invalid("Invalid measure reference");
72
+ dependencies.add(raw.measureId);
73
+ return resolve(raw.measureId);
74
+ }
75
+ if (raw.op === "exposure") {
76
+ const exposure = definition.exposures.find((item) => item.id === raw.exposureId);
77
+ if (!exposure) return invalid(`Unknown exposure ${String(raw.exposureId)}`, undefined, "unknown-reference");
78
+ return normalizedFactors({ [exposure.unit]: 1 });
79
+ }
80
+ if (raw.op === "constant") {
81
+ if (typeof raw.value !== "number" || !Number.isFinite(raw.value)) return invalid("Constants must be finite numbers");
82
+ return normalizedFactors(raw.unitFactors);
83
+ }
84
+ if (raw.op === "add") {
85
+ if (!Array.isArray(raw.terms) || raw.terms.length < 1 || raw.terms.length > 32) return invalid("Addition requires 1 to 32 terms");
86
+ const terms = raw.terms.map((term) => walk(term, depth + 1, next));
87
+ if (terms.some((term) => canonicalJson(term) !== canonicalJson(terms[0]))) return invalid("Addition requires matching units", undefined, "incompatible-semantics");
88
+ return terms[0]!;
89
+ }
90
+ const left = walk(raw.op === "divide" ? raw.numerator : raw.left, depth + 1, next);
91
+ const right = walk(raw.op === "divide" ? raw.denominator : raw.right, depth + 1, next);
92
+ if (raw.op === "subtract") {
93
+ if (canonicalJson(left) !== canonicalJson(right)) return invalid("Subtraction requires matching units", undefined, "incompatible-semantics");
94
+ return left;
95
+ }
96
+ return combine(left, right, raw.op === "divide" ? -1 : 1);
97
+ };
98
+ const unitFactors = walk(measure.expression, 0, new Set());
99
+ if (measure.developmentSemantics !== "point-in-time") {
100
+ const dimensionlessConstant = (expression: AnalysisMeasureExpression) => expression.op === "constant" && Object.keys(normalizedFactors(expression.unitFactors)).length === 0;
101
+ const checkStage = (expression: AnalysisMeasureExpression): void => {
102
+ if (expression.op === "constant") return;
103
+ if (expression.op === "measure") {
104
+ const referenced = base.get(expression.measureId) ?? declarations.get(expression.measureId)!;
105
+ if (referenced.developmentSemantics !== measure.developmentSemantics)
106
+ invalid("Cumulative/incremental expressions require components with matching development meaning", undefined, "incompatible-semantics");
107
+ return;
108
+ }
109
+ if (expression.op === "add") { expression.terms.forEach(checkStage); return; }
110
+ if (expression.op === "subtract") { checkStage(expression.left); checkStage(expression.right); return; }
111
+ if (expression.op === "multiply" && dimensionlessConstant(expression.left)) { checkStage(expression.right); return; }
112
+ if (expression.op === "multiply" && dimensionlessConstant(expression.right)) { checkStage(expression.left); return; }
113
+ if (expression.op === "divide" && dimensionlessConstant(expression.denominator)) { checkStage(expression.numerator); return; }
114
+ invalid("Ratios, products and exposure expressions require point-in-time development meaning unless scaling by a dimensionless constant", undefined, "incompatible-semantics");
115
+ };
116
+ checkStage(measure.expression);
117
+ }
118
+ compiled.set(id, { definition: measure, unit: formatAnalysisUnit(unitFactors), unitFactors, dependencies: [...dependencies].sort() });
119
+ visiting.delete(id);
120
+ return unitFactors;
121
+ };
122
+ for (const measure of derived) resolve(measure.id);
123
+ return snapshotDiagnosticJson([...compiled.values()]);
124
+ }
125
+
126
+ /** Resolves requested outputs and their transitive statistic dependencies. */
127
+ export function analysisExpressionDependencies(compiled: readonly CompiledAnalysisExpression[], requested: ReadonlySet<string>): ReadonlySet<string> {
128
+ const dependencies = new Set(requested);
129
+ const pending = [...requested];
130
+ while (pending.length) {
131
+ const id = pending.pop()!;
132
+ for (const dependency of compiled.find((item) => item.definition.id === id)?.dependencies ?? []) {
133
+ if (!dependencies.has(dependency)) { dependencies.add(dependency); pending.push(dependency); }
134
+ }
135
+ }
136
+ return dependencies;
137
+ }
138
+
139
+ /** Executes post-aggregation expressions on one exact origin/evaluation coordinate. */
140
+ export function evaluateAnalysisExpressions(input: {
141
+ readonly definition: AnalysisDefinition;
142
+ readonly values: readonly AnalysisResultValue[];
143
+ readonly coordinates: AnalysisResultValue["coordinates"];
144
+ readonly exposures: ReadonlyMap<string, number>;
145
+ readonly exposureFindings: ReadonlyMap<string, readonly CustomizationCapabilityFinding[]>;
146
+ readonly requested: ReadonlySet<string>;
147
+ }): readonly AnalysisResultValue[] {
148
+ const compiled = compileAnalysisExpressions(input.definition);
149
+ if (compiled.length === 0) return [];
150
+ for (const id of input.requested)
151
+ if (!input.definition.measures.some((measure) => measure.id === id) && !compiled.some((item) => item.definition.id === id))
152
+ return invalid(`Unknown requested measure ${id}`, undefined, "unknown-reference");
153
+ const required = analysisExpressionDependencies(compiled, input.requested);
154
+ for (const value of input.values) {
155
+ if (canonicalJson(value.coordinates) !== canonicalJson(input.coordinates))
156
+ return invalid("Expression components must share the exact origin/evaluation coordinate", undefined, "incompatible-semantics");
157
+ const measure = input.definition.measures.find((m) => m.id === value.measureId);
158
+ if (!measure || value.unit !== measure.unit || (value.value !== null && !Number.isFinite(value.value)))
159
+ return invalid("Expression components must match declared base measures, units and finite values", undefined, "incompatible-semantics");
160
+ }
161
+ if (new Set(input.values.map((value) => value.measureId)).size !== input.values.length)
162
+ return invalid("Expression components contain duplicate measure results");
163
+ const values = new Map(input.values.map((value) => [value.measureId, value]));
164
+ const output: AnalysisResultValue[] = [];
165
+ for (const item of compiled) {
166
+ if (!required.has(item.definition.id)) continue;
167
+ const components = new Map<string, AnalysisDerivedComponent>();
168
+ const findings: CustomizationCapabilityFinding[] = [];
169
+ const unavailable = (message: string): null => {
170
+ findings.push({ code: "missing-prerequisite", capability: "derived-analysis-measures", path: `$.derivedMeasures.${item.definition.id}`, message });
171
+ return null;
172
+ };
173
+ let numerator: number | null = null;
174
+ let denominator: number | null = null;
175
+ const evaluate = (expression: AnalysisMeasureExpression, root = false): number | null => {
176
+ if (expression.op === "constant") return expression.value;
177
+ if (expression.op === "measure") {
178
+ const value = values.get(expression.measureId);
179
+ if (value) {
180
+ components.set(`measure:${expression.measureId}`, { kind: "measure", id: expression.measureId, unit: value.unit, value: value.value, status: value.status, contributingObservations: value.contributingObservations, excludedObservations: value.excludedObservations });
181
+ findings.push(...value.findings);
182
+ } else {
183
+ const unit = input.definition.measures.find((m) => m.id === expression.measureId)?.unit ?? compiled.find((m) => m.definition.id === expression.measureId)!.unit;
184
+ components.set(`measure:${expression.measureId}`, { kind: "measure", id: expression.measureId, unit, value: null, status: "unavailable", contributingObservations: 0, excludedObservations: 0 });
185
+ }
186
+ return !value || value.status !== "available" || value.value === null || value.excludedObservations > 0
187
+ ? unavailable(`Measure ${expression.measureId} requires a complete available result`) : value.value;
188
+ }
189
+ if (expression.op === "exposure") {
190
+ const value = input.exposures.get(expression.exposureId);
191
+ const exposureFindings = input.exposureFindings.get(expression.exposureId) ?? [];
192
+ findings.push(...exposureFindings);
193
+ const available = value !== undefined && Number.isFinite(value) && exposureFindings.length === 0;
194
+ components.set(`exposure:${expression.exposureId}`, { kind: "exposure", id: expression.exposureId, unit: input.definition.exposures.find((e) => e.id === expression.exposureId)!.unit, value: available ? value : null, status: available ? "available" : "unavailable", contributingObservations: 0, excludedObservations: 0 });
195
+ return available ? value : unavailable(`Exposure ${expression.exposureId} requires an available allocated result`);
196
+ }
197
+ let value: number;
198
+ if (expression.op === "add") {
199
+ const terms = expression.terms.map((term) => evaluate(term));
200
+ if (terms.some((term) => term === null)) return null;
201
+ value = terms.reduce<number>((sum, term) => sum + term!, 0);
202
+ } else {
203
+ const left = evaluate(expression.op === "divide" ? expression.numerator : expression.left);
204
+ const right = evaluate(expression.op === "divide" ? expression.denominator : expression.right);
205
+ if (root && expression.op === "divide") { numerator = left; denominator = right; }
206
+ if (left === null || right === null) return null;
207
+ if (expression.op === "divide" && right <= 0) return unavailable("Division requires a strictly positive denominator");
208
+ value = expression.op === "subtract" ? left - right : expression.op === "multiply" ? left * right : left / right;
209
+ }
210
+ return Number.isFinite(value) ? value : unavailable("Expression arithmetic overflowed; no finite result is available");
211
+ };
212
+ const value = evaluate(item.definition.expression, true);
213
+ const result: AnalysisResultValue = {
214
+ measureId: item.definition.id, unit: item.unit, coordinates: input.coordinates, value,
215
+ status: value === null ? "unavailable" : "available", contributingObservations: 0, excludedObservations: 0, exact: true,
216
+ numerator, denominator, findings: [...new Map(findings.map((finding) => [canonicalJson(finding), finding])).values()],
217
+ derivation: { stage: "post-aggregation", unitFactors: item.unitFactors, components: [...components.values()] },
218
+ };
219
+ values.set(result.measureId, result);
220
+ output.push(result);
221
+ }
222
+ return snapshotDiagnosticJson(output);
223
+ }
@@ -0,0 +1,55 @@
1
+ import type { AnalysisDefinition, AnalysisRecipe } from "./customizationContracts.js";
2
+ import { formatAnalysisUnit } from "./analysisExpressions.js";
3
+ import { DiagnosticValidationError } from "./types.js";
4
+
5
+ const incompatible = (message: string): never => {
6
+ throw new DiagnosticValidationError([{ domain: "configuration", code: "incompatible-semantics", path: "$.recipe.steps", message }]);
7
+ };
8
+
9
+ /** Resolves the declared output units of an ordered financial pipeline before calculating results. */
10
+ export function resolveAnalysisFinancialUnits(definition: AnalysisDefinition, recipe: AnalysisRecipe): AnalysisDefinition {
11
+ const step = recipe.steps.find((item) => item.kind === "apply-financial-pipeline");
12
+ if (step?.kind !== "apply-financial-pipeline") return definition;
13
+ const stages = step.stageIds.map((id) => definition.financialAdjustments?.find((item) => item.id === id));
14
+ if (!stages.some((stage) => stage?.kind === "currency")) return definition;
15
+ const rawUnits = new Map<string, Set<string>>();
16
+ for (const measure of definition.measures) {
17
+ if (measure.statistic.kind !== "sum") continue;
18
+ const id = measure.statistic.measureId;
19
+ const units = rawUnits.get(id) ?? new Set<string>();
20
+ units.add(measure.unit);
21
+ rawUnits.set(id, units);
22
+ }
23
+ const rawUnit = (id: string): string => {
24
+ const units = rawUnits.get(id);
25
+ if (!units || units.size !== 1) return incompatible(`Currency conversion needs one declared sum unit for ${id}`);
26
+ return [...units][0]!;
27
+ };
28
+ const initialUnit = rawUnit(step.amountMeasureId);
29
+ let outputUnit = initialUnit;
30
+ for (const stage of stages) {
31
+ if (!stage) continue;
32
+ if (stage.kind === "currency") {
33
+ if (stage.fromUnit !== outputUnit) return incompatible(`Currency stage ${stage.id} expects ${stage.fromUnit}, not ${outputUnit}`);
34
+ outputUnit = stage.toUnit;
35
+ } else if (stage.kind === "include-expense" || stage.kind === "exclude-expense" || stage.kind === "net-recovery") {
36
+ const id = stage.kind === "net-recovery" ? stage.recoveryMeasureId : stage.expenseMeasureId;
37
+ if (rawUnit(id) !== outputUnit) return incompatible(`Financial component ${id} must use the current pipeline unit ${outputUnit}`);
38
+ }
39
+ }
40
+ const effectiveUnit = (id: string): string => id === step.amountMeasureId ? outputUnit : definition.exposures.find((e) => e.id === id)?.unit ?? rawUnit(id);
41
+ const measures = definition.measures.map((measure) => {
42
+ const statistic = measure.statistic;
43
+ if (statistic.kind === "ratio") {
44
+ if (statistic.numeratorMeasureId !== step.amountMeasureId && statistic.denominatorMeasureId !== step.amountMeasureId) return measure;
45
+ const numerator = effectiveUnit(statistic.numeratorMeasureId);
46
+ const denominator = effectiveUnit(statistic.denominatorMeasureId);
47
+ const factors = numerator === denominator ? {} : { [numerator]: 1, [denominator]: -1 };
48
+ return { ...measure, unit: numerator === denominator ? "ratio" : formatAnalysisUnit(factors), unitFactors: factors };
49
+ }
50
+ if ("measureId" in statistic && statistic.measureId === step.amountMeasureId)
51
+ return { ...measure, unit: outputUnit, unitFactors: { [outputUnit]: 1 } };
52
+ return measure;
53
+ });
54
+ return { ...definition, measures };
55
+ }
@@ -23,6 +23,8 @@ import type {
23
23
  } from "./customizationContracts.js";
24
24
  import { calculateAnalysisStatistic } from "./descriptiveStatistics.js";
25
25
  import { calculateRecipeExposureRatio } from "./analysisRecipeStatistics.js";
26
+ import { compileAnalysisExpressions, analysisExpressionDependencies, evaluateAnalysisExpressions } from "./analysisExpressions.js";
27
+ import { resolveAnalysisFinancialUnits } from "./analysisFinancialUnits.js";
26
28
  import { compareAnalysisEvaluations, compareAnalysisResults } from "./analysisComparison.js";
27
29
  export { compareAnalysisResults } from "./analysisComparison.js";
28
30
  import { isDiagnosticToken, snapshotDiagnosticJson } from "./diagnosticRuntime.js";
@@ -75,7 +77,7 @@ function recipeIssues(
75
77
  hasCalculate = true;
76
78
  if (step.kind === "calculate")
77
79
  step.measureIds.forEach((id) => {
78
- if (!definition.measures.some((measure) => measure.id === id))
80
+ if (![...definition.measures, ...(definition.derivedMeasures ?? [])].some((measure) => measure.id === id))
79
81
  issues.push({ domain: "configuration", code: "unknown-reference", path: `$.recipe.steps[${index}].measureIds`, message: `Unknown measure ${id}` });
80
82
  });
81
83
  if (step.kind === "earn-exposure")
@@ -166,6 +168,8 @@ export function runAnalysisRecipe(input: {
166
168
  }): AnalysisResult {
167
169
  const issues = recipeIssues(input.recipe, input.definition, input.history);
168
170
  if (issues.length > 0) throw new DiagnosticValidationError(issues);
171
+ const outputDefinition = resolveAnalysisFinancialUnits(input.definition, input.recipe);
172
+ const expressions = compileAnalysisExpressions(outputDefinition);
169
173
  const prepared = prepareHistoricalDataset(input.history);
170
174
  const evaluationDate = input.evaluationDate ?? maxEvaluationDate(prepared.observations);
171
175
  const selected = selectedAt(prepared.observations, evaluationDate, input.definition.period.observationSelection);
@@ -280,16 +284,18 @@ export function runAnalysisRecipe(input: {
280
284
  if (group === undefined) groups.set(origin.originId, { label: origin.label, observations: [observation] });
281
285
  else group.observations.push(observation);
282
286
  }
283
- const measureIds = new Set(
287
+ const requestedMeasureIds = new Set(
284
288
  input.recipe.steps.filter((step) => step.kind === "calculate").flatMap((step) => step.measureIds),
285
289
  );
290
+ const measureIds = analysisExpressionDependencies(expressions, requestedMeasureIds);
286
291
  // When preparation excluded every observation, retain visible unavailable
287
292
  // output instead of hiding the preparation findings in an empty result.
288
293
  if (groups.size === 0 && prepared.findings.length > 0)
289
294
  groups.set("unassigned", { label: "Unavailable history", observations: [] });
290
295
  const values: AnalysisResultValue[] = [];
291
296
  for (const [originId, group] of [...groups].sort(([left], [right]) => left.localeCompare(right))) {
292
- for (const measure of input.definition.measures.filter((candidate) => measureIds.has(candidate.id))) {
297
+ const start = values.length;
298
+ for (const measure of outputDefinition.measures.filter((candidate) => measureIds.has(candidate.id))) {
293
299
  let measureObservations = measure.populationScopeId === input.definition.scopes.financial.id
294
300
  ? group.observations
295
301
  : group.observations.filter((observation) => reportingKeys.has(key(observation)));
@@ -357,9 +363,18 @@ export function runAnalysisRecipe(input: {
357
363
  findings: statistic.findings,
358
364
  });
359
365
  }
366
+ values.push(...evaluateAnalysisExpressions({
367
+ definition: outputDefinition,
368
+ values: values.slice(start),
369
+ coordinates: { originId, originLabel: group.label, evaluationDate },
370
+ exposures: exposedByTarget.get(originId) ?? new Map(),
371
+ exposureFindings: exposureFindingsByMeasure,
372
+ requested: requestedMeasureIds,
373
+ }));
360
374
  }
361
375
  if (originFailures.length > 0) {
362
- for (const measure of input.definition.measures.filter((candidate) => measureIds.has(candidate.id))) {
376
+ const start = values.length;
377
+ for (const measure of outputDefinition.measures.filter((candidate) => measureIds.has(candidate.id))) {
363
378
  const originFindings = originFailures
364
379
  .filter(({ observation }) => measure.populationScopeId === input.definition.scopes.financial.id || reportingKeys.has(key(observation)))
365
380
  .map(({ finding }) => finding);
@@ -378,6 +393,12 @@ export function runAnalysisRecipe(input: {
378
393
  findings: originFindings,
379
394
  });
380
395
  }
396
+ values.push(...evaluateAnalysisExpressions({
397
+ definition: outputDefinition,
398
+ values: values.slice(start),
399
+ coordinates: { originId: "unassigned", originLabel: "Unavailable origin", evaluationDate },
400
+ exposures: new Map(), exposureFindings: exposureFindingsByMeasure, requested: requestedMeasureIds,
401
+ }));
381
402
  }
382
403
  const calculationInput = {
383
404
  corePackageVersion: CORE_PACKAGE_VERSION,
@@ -13,6 +13,7 @@ export const CUSTOMIZATION_CAPABILITIES = [
13
13
  "exposure-earning",
14
14
  "typed-populations",
15
15
  "descriptive-statistics",
16
+ "derived-analysis-measures",
16
17
  "reserving-triangle-adapter",
17
18
  "bounded-execution",
18
19
  "shared-financial-terms",
@@ -44,6 +45,11 @@ export interface HistoricalSourceDefinition {
44
45
  readonly namespace: string;
45
46
  readonly artifactId: string;
46
47
  readonly mappingVersion: string;
48
+ /** Additional original files belonging to the same claim/revision namespace. */
49
+ readonly additionalArtifacts?: readonly {
50
+ readonly artifactId: string;
51
+ readonly mappingVersion: string;
52
+ }[];
47
53
  }
48
54
 
49
55
  export interface HistoricalSourceLocation {
@@ -426,12 +432,39 @@ export type AnalysisStatisticDefinition =
426
432
  export interface AnalysisMeasureDefinitionV1 {
427
433
  readonly id: string;
428
434
  readonly unit: string;
435
+ /** Optional explicit dimensions for composing already-derived units. Unit labels are otherwise opaque atoms. */
436
+ readonly unitFactors?: Readonly<Record<string, number>>;
429
437
  readonly developmentSemantics: "cumulative" | "incremental" | "point-in-time";
430
438
  readonly statistic: AnalysisStatisticDefinition;
431
439
  readonly populationScopeId: string;
432
440
  readonly condition?: AnalysisPredicate;
433
441
  }
434
442
 
443
+ export type AnalysisMeasureExpression =
444
+ | { readonly op: "measure"; readonly measureId: string }
445
+ | { readonly op: "exposure"; readonly exposureId: string }
446
+ | { readonly op: "constant"; readonly value: number; readonly unitFactors: Readonly<Record<string, number>> }
447
+ | { readonly op: "add"; readonly terms: readonly AnalysisMeasureExpression[] }
448
+ | { readonly op: "subtract" | "multiply"; readonly left: AnalysisMeasureExpression; readonly right: AnalysisMeasureExpression }
449
+ | { readonly op: "divide"; readonly numerator: AnalysisMeasureExpression; readonly denominator: AnalysisMeasureExpression };
450
+
451
+ /** Post-aggregation arithmetic. Each referenced statistic retains its own population and condition. */
452
+ export interface AnalysisDerivedMeasureDefinition {
453
+ readonly id: string;
454
+ readonly expression: AnalysisMeasureExpression;
455
+ readonly developmentSemantics: "point-in-time" | "cumulative" | "incremental";
456
+ }
457
+
458
+ export interface AnalysisDerivedComponent {
459
+ readonly kind: "measure" | "exposure";
460
+ readonly id: string;
461
+ readonly unit: string;
462
+ readonly value: number | null;
463
+ readonly status: "available" | "unavailable";
464
+ readonly contributingObservations: number;
465
+ readonly excludedObservations: number;
466
+ }
467
+
435
468
  export type AnalysisObservationSelection =
436
469
  | {
437
470
  readonly kind: "evaluation-date";
@@ -562,6 +595,7 @@ export interface AnalysisDefinition {
562
595
  readonly period: AnalysisPeriodDefinition;
563
596
  readonly exposures: readonly ExposureMeasureDefinitionV1[];
564
597
  readonly measures: readonly AnalysisMeasureDefinitionV1[];
598
+ readonly derivedMeasures?: readonly AnalysisDerivedMeasureDefinition[];
565
599
  readonly financialTerms: readonly FinancialTermDefinition[];
566
600
  readonly financialAdjustments?: readonly FinancialAmountAdjustment[];
567
601
  }
@@ -672,6 +706,12 @@ export interface AnalysisResultValue {
672
706
  readonly numerator: number | null;
673
707
  readonly denominator: number | null;
674
708
  readonly findings: readonly CustomizationCapabilityFinding[];
709
+ /** Counts on a derived value are not additive population counts; inspect each component instead. */
710
+ readonly derivation?: {
711
+ readonly stage: "post-aggregation";
712
+ readonly unitFactors: Readonly<Record<string, number>>;
713
+ readonly components: readonly AnalysisDerivedComponent[];
714
+ };
675
715
  }
676
716
 
677
717
  export interface AnalysisResult {
@@ -64,6 +64,46 @@ function inputIssues(input: HistoricalDatasetInput): DiagnosticValidationIssue[]
64
64
  path: "$.sources",
65
65
  message: "Source namespaces must be unique",
66
66
  });
67
+ const artifactsByNamespace = new Map<string, Set<string>>();
68
+ input.sources.forEach((source, index) => {
69
+ const artifacts = new Set<string>();
70
+ const entries = [source, ...(source.additionalArtifacts ?? [])];
71
+ entries.forEach((artifact, position) => {
72
+ const path = position === 0
73
+ ? `$.sources[${index}]`
74
+ : `$.sources[${index}].additionalArtifacts[${position - 1}]`;
75
+ if (!isDiagnosticToken(artifact.artifactId) || !isDiagnosticToken(artifact.mappingVersion))
76
+ issues.push({
77
+ domain: "input", code: "invalid-string", path,
78
+ message: "Source artifacts require valid artifact IDs and mapping versions",
79
+ });
80
+ if (artifacts.has(artifact.artifactId))
81
+ issues.push({
82
+ domain: "input", code: "duplicate-id", path: `${path}.artifactId`,
83
+ message: "Artifact IDs within a source namespace must be unique",
84
+ });
85
+ artifacts.add(artifact.artifactId);
86
+ });
87
+ if (source.additionalArtifacts?.length === 0)
88
+ issues.push({
89
+ domain: "input", code: "invalid-configuration", path: `$.sources[${index}].additionalArtifacts`,
90
+ message: "Omit additionalArtifacts when there are no additional source files",
91
+ });
92
+ artifactsByNamespace.set(source.namespace, artifacts);
93
+ });
94
+ const validateSource = (namespace: string, artifactId: string, path: string) => {
95
+ const artifacts = artifactsByNamespace.get(namespace);
96
+ if (!artifacts)
97
+ issues.push({
98
+ domain: "input", code: "unknown-reference", path: `${path}.sourceNamespace`,
99
+ message: "Record references an unknown source namespace",
100
+ });
101
+ else if (!artifacts.has(artifactId))
102
+ issues.push({
103
+ domain: "input", code: "invalid-input-relationship", path: `${path}.source.artifactId`,
104
+ message: "Record artifact does not match its source namespace",
105
+ });
106
+ };
67
107
  if (
68
108
  input.evaluationDates !== undefined &&
69
109
  input.evaluationDates.some(
@@ -79,21 +119,7 @@ function inputIssues(input: HistoricalDatasetInput): DiagnosticValidationIssue[]
79
119
  message: "evaluationDates must be unique, ascending real Gregorian dates",
80
120
  });
81
121
  input.records.forEach((record, index) => {
82
- const source = namespaces.get(record.sourceNamespace);
83
- if (source === undefined)
84
- issues.push({
85
- domain: "input",
86
- code: "unknown-reference",
87
- path: `$.records[${index}].sourceNamespace`,
88
- message: "Record references an unknown source namespace",
89
- });
90
- else if (source.artifactId !== record.source.artifactId)
91
- issues.push({
92
- domain: "input",
93
- code: "invalid-input-relationship",
94
- path: `$.records[${index}].source.artifactId`,
95
- message: "Record artifact does not match its source namespace",
96
- });
122
+ validateSource(record.sourceNamespace, record.source.artifactId, `$.records[${index}]`);
97
123
  if (!isRealIsoDate(record.evaluationDate) && record.grain !== "transaction")
98
124
  issues.push({
99
125
  domain: "input",
@@ -130,6 +156,9 @@ function inputIssues(input: HistoricalDatasetInput): DiagnosticValidationIssue[]
130
156
  message: "As-known revision views require correctedAt",
131
157
  });
132
158
  });
159
+ input.openingBalances?.forEach((balance, index) =>
160
+ validateSource(balance.sourceNamespace, balance.source.artifactId, `$.openingBalances[${index}]`),
161
+ );
133
162
  if (input.historyMode !== "full-snapshots" && input.evaluationDates === undefined)
134
163
  issues.push({
135
164
  domain: "input",
package/src/index.ts CHANGED
@@ -12,6 +12,8 @@ export * from "./reservingAdapter.js";
12
12
  export * from "./financialTerms.js";
13
13
  export * from "./financialPipeline.js";
14
14
  export * from "./analysisRecipe.js";
15
+ export * from "./analysisExpressions.js";
16
+ export * from "./analysisFinancialUnits.js";
15
17
  export * from "./util.js";
16
18
  export * from "./canonical.js";
17
19
  export {
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** This package's runtime version. A test pins it to package.json. */
2
- export const CORE_PACKAGE_VERSION = "0.8.1";
2
+ export const CORE_PACKAGE_VERSION = "0.10.0";