@actuarial-ts/interchange 0.2.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.
Files changed (64) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +52 -0
  4. package/dist/convert/result.d.ts +45 -0
  5. package/dist/convert/result.d.ts.map +1 -0
  6. package/dist/convert/result.js +122 -0
  7. package/dist/convert/result.js.map +1 -0
  8. package/dist/convert/selection.d.ts +114 -0
  9. package/dist/convert/selection.d.ts.map +1 -0
  10. package/dist/convert/selection.js +383 -0
  11. package/dist/convert/selection.js.map +1 -0
  12. package/dist/convert/triangle.d.ts +49 -0
  13. package/dist/convert/triangle.d.ts.map +1 -0
  14. package/dist/convert/triangle.js +111 -0
  15. package/dist/convert/triangle.js.map +1 -0
  16. package/dist/envelope.d.ts +113 -0
  17. package/dist/envelope.d.ts.map +1 -0
  18. package/dist/envelope.js +139 -0
  19. package/dist/envelope.js.map +1 -0
  20. package/dist/index.d.ts +15 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +15 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/parse.d.ts +38 -0
  25. package/dist/parse.d.ts.map +1 -0
  26. package/dist/parse.js +48 -0
  27. package/dist/parse.js.map +1 -0
  28. package/dist/referee/crosscheck.d.ts +38 -0
  29. package/dist/referee/crosscheck.d.ts.map +1 -0
  30. package/dist/referee/crosscheck.js +212 -0
  31. package/dist/referee/crosscheck.js.map +1 -0
  32. package/dist/referee/profiles.d.ts +36 -0
  33. package/dist/referee/profiles.d.ts.map +1 -0
  34. package/dist/referee/profiles.js +80 -0
  35. package/dist/referee/profiles.js.map +1 -0
  36. package/dist/schemas/bundle.d.ts +45 -0
  37. package/dist/schemas/bundle.d.ts.map +1 -0
  38. package/dist/schemas/bundle.js +20 -0
  39. package/dist/schemas/bundle.js.map +1 -0
  40. package/dist/schemas/crosscheck.d.ts +3567 -0
  41. package/dist/schemas/crosscheck.d.ts.map +1 -0
  42. package/dist/schemas/crosscheck.js +72 -0
  43. package/dist/schemas/crosscheck.js.map +1 -0
  44. package/dist/schemas/manifest.d.ts +43 -0
  45. package/dist/schemas/manifest.d.ts.map +1 -0
  46. package/dist/schemas/manifest.js +39 -0
  47. package/dist/schemas/manifest.js.map +1 -0
  48. package/dist/schemas/result.d.ts +2163 -0
  49. package/dist/schemas/result.d.ts.map +1 -0
  50. package/dist/schemas/result.js +95 -0
  51. package/dist/schemas/result.js.map +1 -0
  52. package/dist/schemas/selection.d.ts +10388 -0
  53. package/dist/schemas/selection.d.ts.map +1 -0
  54. package/dist/schemas/selection.js +138 -0
  55. package/dist/schemas/selection.js.map +1 -0
  56. package/dist/schemas/study.d.ts +62 -0
  57. package/dist/schemas/study.d.ts.map +1 -0
  58. package/dist/schemas/study.js +35 -0
  59. package/dist/schemas/study.js.map +1 -0
  60. package/dist/schemas/triangle.d.ts +1260 -0
  61. package/dist/schemas/triangle.d.ts.map +1 -0
  62. package/dist/schemas/triangle.js +120 -0
  63. package/dist/schemas/triangle.js.map +1 -0
  64. package/package.json +66 -0
@@ -0,0 +1,113 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The interchange document envelope (spec 3.1 / 3.5).
4
+ *
5
+ * Every interchange document is an envelope around exactly one semantic
6
+ * body. The envelope carries `interchangeVersion`, `kind`, `generator`,
7
+ * `createdAt`, `extensions`, and `integrity`; the semantic body is the ONE
8
+ * kind-named object (`triangle`, `selection`, `result`, `study`,
9
+ * `report` — and for `kind: "bundle"`, per spec 3.2, the two-field
10
+ * object `{ bundle, interchange }` the outer tag is defined over).
11
+ *
12
+ * Ground truth:
13
+ * - `integrity` = fnv1a64(canonicalJson(semantic body)) — NEVER the
14
+ * envelope. Re-exporting a document through another adapter changes the
15
+ * envelope (generator, createdAt), not the tag, so appliesTo-by-tag
16
+ * linkage survives cross-language hops. FNV-1a detects ACCIDENTAL
17
+ * divergence only; tamper evidence requires host-side signing.
18
+ * - `governance` (StudyDoc) sits beside the semantic body: it is neither
19
+ * envelope nor integrity-covered; adapters round-trip it opaquely.
20
+ * - Version acceptance (spec 3.5): wrong-major documents are refused with
21
+ * `UNSUPPORTED_VERSION`; same-major unknown minors are accepted, unknown
22
+ * fields are preserved (schemas are passthrough), and
23
+ * `governance`/`extensions` round-trip opaquely.
24
+ * - `createdAt` is caller-supplied (purity rule) — this module never reads
25
+ * a clock.
26
+ */
27
+ /** The interchange spec version this package writes. */
28
+ export declare const INTERCHANGE_SPEC_VERSION = "1.0.0";
29
+ /** The spec major this package accepts (spec 3.5: readers accept same-major). */
30
+ export declare const INTERCHANGE_SPEC_MAJOR = 1;
31
+ /**
32
+ * This package's version, stamped into `generator` by default. A sync test
33
+ * asserts it matches package.json so it cannot silently drift.
34
+ */
35
+ export declare const INTERCHANGE_PACKAGE_VERSION = "0.2.0";
36
+ export interface GeneratorStamp {
37
+ name: string;
38
+ version: string;
39
+ }
40
+ /** Default `generator` stamp for documents authored by this package. */
41
+ export declare const DEFAULT_GENERATOR: GeneratorStamp;
42
+ export declare const DOCUMENT_KINDS: readonly ["triangle", "selection", "method-result", "stochastic-result", "study", "bundle", "crosscheck-report"];
43
+ export type DocumentKind = (typeof DOCUMENT_KINDS)[number];
44
+ /** A 16-hex-char fnv1a64 tag. */
45
+ export declare const integritySchema: z.ZodString;
46
+ export declare const generatorSchema: z.ZodObject<{
47
+ name: z.ZodString;
48
+ version: z.ZodString;
49
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
50
+ name: z.ZodString;
51
+ version: z.ZodString;
52
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
53
+ name: z.ZodString;
54
+ version: z.ZodString;
55
+ }, z.ZodTypeAny, "passthrough">>;
56
+ /**
57
+ * The shared envelope fields for a document of the given kind. Doc schemas
58
+ * spread this shape and add their semantic body key(s); every object is
59
+ * passthrough so unknown same-major minor fields are preserved, keeping
60
+ * integrity tags stable across a parse → re-serialize hop.
61
+ */
62
+ export declare function envelopeShape<K extends DocumentKind>(kind: K): {
63
+ interchangeVersion: z.ZodString;
64
+ kind: z.ZodLiteral<K>;
65
+ generator: z.ZodObject<{
66
+ name: z.ZodString;
67
+ version: z.ZodString;
68
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
69
+ name: z.ZodString;
70
+ version: z.ZodString;
71
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
72
+ name: z.ZodString;
73
+ version: z.ZodString;
74
+ }, z.ZodTypeAny, "passthrough">>;
75
+ createdAt: z.ZodString;
76
+ extensions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
77
+ integrity: z.ZodString;
78
+ };
79
+ /** Minimal structural view of a document for integrity/version helpers. */
80
+ export interface DocumentLike {
81
+ kind: string;
82
+ [key: string]: unknown;
83
+ }
84
+ /**
85
+ * Extracts the semantic body the integrity tag is defined over. Throws
86
+ * BAD_INTERCHANGE for unknown kinds or a missing body key.
87
+ */
88
+ export declare function semanticBodyOf(doc: DocumentLike): unknown;
89
+ /** integrity = fnv1a64(canonicalJson(semantic body)) — spec 3.1. */
90
+ export declare function computeIntegrity(doc: DocumentLike): string;
91
+ /** Returns the document with a freshly computed integrity tag. */
92
+ export declare function stampIntegrity<T extends DocumentLike>(doc: DocumentLike & Omit<T, "integrity">): T;
93
+ export interface IntegrityCheck {
94
+ ok: boolean;
95
+ /** The tag recomputed from the semantic body. */
96
+ expected: string;
97
+ /** The tag the document claims. */
98
+ actual: string | null;
99
+ }
100
+ /** Recomputes the tag from the semantic body and compares to the stated one. */
101
+ export declare function verifyIntegrity(doc: DocumentLike): IntegrityCheck;
102
+ export interface ParsedVersion {
103
+ major: number;
104
+ minor: number;
105
+ patch: number;
106
+ }
107
+ /**
108
+ * Version acceptance (spec 3.5): parses `interchangeVersion` and refuses
109
+ * wrong-major documents with UNSUPPORTED_VERSION. Unparseable versions are
110
+ * BAD_INTERCHANGE (a malformed document, not a future one).
111
+ */
112
+ export declare function acceptVersion(version: unknown): ParsedVersion;
113
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,cAG/B,CAAC;AAEF,eAAO,MAAM,cAAc,kHAQjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAiB3D,iCAAiC;AACjC,eAAO,MAAM,eAAe,aAAqC,CAAC;AAElE,eAAO,MAAM,eAAe;;;;;;;;;gCAEZ,CAAC;AAEjB;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EAAE,IAAI,EAAE,CAAC;;;;;;;;;;;;;;;;EAS5D;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAoBzD;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE1D;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,CAAC,SAAS,YAAY,EACnD,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,GACvC,CAAC,CAEH;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,cAAc,CAIjE;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAe7D"}
@@ -0,0 +1,139 @@
1
+ import { ReservingError, canonicalJson, fnv1a64 } from "@actuarial-ts/core";
2
+ import { z } from "zod";
3
+ /**
4
+ * The interchange document envelope (spec 3.1 / 3.5).
5
+ *
6
+ * Every interchange document is an envelope around exactly one semantic
7
+ * body. The envelope carries `interchangeVersion`, `kind`, `generator`,
8
+ * `createdAt`, `extensions`, and `integrity`; the semantic body is the ONE
9
+ * kind-named object (`triangle`, `selection`, `result`, `study`,
10
+ * `report` — and for `kind: "bundle"`, per spec 3.2, the two-field
11
+ * object `{ bundle, interchange }` the outer tag is defined over).
12
+ *
13
+ * Ground truth:
14
+ * - `integrity` = fnv1a64(canonicalJson(semantic body)) — NEVER the
15
+ * envelope. Re-exporting a document through another adapter changes the
16
+ * envelope (generator, createdAt), not the tag, so appliesTo-by-tag
17
+ * linkage survives cross-language hops. FNV-1a detects ACCIDENTAL
18
+ * divergence only; tamper evidence requires host-side signing.
19
+ * - `governance` (StudyDoc) sits beside the semantic body: it is neither
20
+ * envelope nor integrity-covered; adapters round-trip it opaquely.
21
+ * - Version acceptance (spec 3.5): wrong-major documents are refused with
22
+ * `UNSUPPORTED_VERSION`; same-major unknown minors are accepted, unknown
23
+ * fields are preserved (schemas are passthrough), and
24
+ * `governance`/`extensions` round-trip opaquely.
25
+ * - `createdAt` is caller-supplied (purity rule) — this module never reads
26
+ * a clock.
27
+ */
28
+ /** The interchange spec version this package writes. */
29
+ export const INTERCHANGE_SPEC_VERSION = "1.0.0";
30
+ /** The spec major this package accepts (spec 3.5: readers accept same-major). */
31
+ export const INTERCHANGE_SPEC_MAJOR = 1;
32
+ /**
33
+ * This package's version, stamped into `generator` by default. A sync test
34
+ * asserts it matches package.json so it cannot silently drift.
35
+ */
36
+ export const INTERCHANGE_PACKAGE_VERSION = "0.2.0";
37
+ /** Default `generator` stamp for documents authored by this package. */
38
+ export const DEFAULT_GENERATOR = {
39
+ name: "@actuarial-ts/interchange",
40
+ version: INTERCHANGE_PACKAGE_VERSION,
41
+ };
42
+ export const DOCUMENT_KINDS = [
43
+ "triangle",
44
+ "selection",
45
+ "method-result",
46
+ "stochastic-result",
47
+ "study",
48
+ "bundle",
49
+ "crosscheck-report",
50
+ ];
51
+ /**
52
+ * kind → the top-level key(s) holding the semantic body. Single-key kinds
53
+ * hash the named object itself; `bundle` hashes `{ bundle, interchange }`
54
+ * (spec 3.2's outer tag).
55
+ */
56
+ const SEMANTIC_BODY_KEYS = {
57
+ triangle: ["triangle"],
58
+ selection: ["selection"],
59
+ "method-result": ["result"],
60
+ "stochastic-result": ["result"],
61
+ study: ["study"],
62
+ bundle: ["bundle", "interchange"],
63
+ "crosscheck-report": ["report"],
64
+ };
65
+ /** A 16-hex-char fnv1a64 tag. */
66
+ export const integritySchema = z.string().regex(/^[0-9a-f]{16}$/);
67
+ export const generatorSchema = z
68
+ .object({ name: z.string().min(1), version: z.string().min(1) })
69
+ .passthrough();
70
+ /**
71
+ * The shared envelope fields for a document of the given kind. Doc schemas
72
+ * spread this shape and add their semantic body key(s); every object is
73
+ * passthrough so unknown same-major minor fields are preserved, keeping
74
+ * integrity tags stable across a parse → re-serialize hop.
75
+ */
76
+ export function envelopeShape(kind) {
77
+ return {
78
+ interchangeVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
79
+ kind: z.literal(kind),
80
+ generator: generatorSchema,
81
+ createdAt: z.string().datetime({ offset: true }),
82
+ extensions: z.record(z.unknown()).optional(),
83
+ integrity: integritySchema,
84
+ };
85
+ }
86
+ function isKnownKind(kind) {
87
+ return DOCUMENT_KINDS.includes(kind);
88
+ }
89
+ /**
90
+ * Extracts the semantic body the integrity tag is defined over. Throws
91
+ * BAD_INTERCHANGE for unknown kinds or a missing body key.
92
+ */
93
+ export function semanticBodyOf(doc) {
94
+ if (!isKnownKind(doc.kind)) {
95
+ throw new ReservingError("BAD_INTERCHANGE", `Unknown document kind "${doc.kind}"; this reader understands: ${DOCUMENT_KINDS.join(", ")}`);
96
+ }
97
+ const keys = SEMANTIC_BODY_KEYS[doc.kind];
98
+ for (const key of keys) {
99
+ if (doc[key] === undefined) {
100
+ throw new ReservingError("BAD_INTERCHANGE", `Document of kind "${doc.kind}" is missing its semantic body field "${key}"`);
101
+ }
102
+ }
103
+ if (keys.length === 1)
104
+ return doc[keys[0]];
105
+ const body = {};
106
+ for (const key of keys)
107
+ body[key] = doc[key];
108
+ return body;
109
+ }
110
+ /** integrity = fnv1a64(canonicalJson(semantic body)) — spec 3.1. */
111
+ export function computeIntegrity(doc) {
112
+ return fnv1a64(canonicalJson(semanticBodyOf(doc)));
113
+ }
114
+ /** Returns the document with a freshly computed integrity tag. */
115
+ export function stampIntegrity(doc) {
116
+ return { ...doc, integrity: computeIntegrity(doc) };
117
+ }
118
+ /** Recomputes the tag from the semantic body and compares to the stated one. */
119
+ export function verifyIntegrity(doc) {
120
+ const expected = computeIntegrity(doc);
121
+ const actual = typeof doc["integrity"] === "string" ? doc["integrity"] : null;
122
+ return { ok: actual === expected, expected, actual };
123
+ }
124
+ /**
125
+ * Version acceptance (spec 3.5): parses `interchangeVersion` and refuses
126
+ * wrong-major documents with UNSUPPORTED_VERSION. Unparseable versions are
127
+ * BAD_INTERCHANGE (a malformed document, not a future one).
128
+ */
129
+ export function acceptVersion(version) {
130
+ if (typeof version !== "string" || !/^\d+\.\d+\.\d+$/.test(version)) {
131
+ throw new ReservingError("BAD_INTERCHANGE", `interchangeVersion must be a MAJOR.MINOR.PATCH string; got ${JSON.stringify(version)}`);
132
+ }
133
+ const [major, minor, patch] = version.split(".").map(Number);
134
+ if (major !== INTERCHANGE_SPEC_MAJOR) {
135
+ throw new ReservingError("UNSUPPORTED_VERSION", `Interchange version ${version} has major ${major}; this reader accepts major ${INTERCHANGE_SPEC_MAJOR} only`);
136
+ }
137
+ return { major, minor, patch };
138
+ }
139
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export * from "./envelope.js";
2
+ export * from "./parse.js";
3
+ export * from "./schemas/triangle.js";
4
+ export * from "./schemas/selection.js";
5
+ export * from "./schemas/result.js";
6
+ export * from "./schemas/study.js";
7
+ export * from "./schemas/bundle.js";
8
+ export * from "./schemas/crosscheck.js";
9
+ export * from "./schemas/manifest.js";
10
+ export * from "./convert/triangle.js";
11
+ export * from "./convert/selection.js";
12
+ export * from "./convert/result.js";
13
+ export * from "./referee/profiles.js";
14
+ export * from "./referee/crosscheck.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export * from "./envelope.js";
2
+ export * from "./parse.js";
3
+ export * from "./schemas/triangle.js";
4
+ export * from "./schemas/selection.js";
5
+ export * from "./schemas/result.js";
6
+ export * from "./schemas/study.js";
7
+ export * from "./schemas/bundle.js";
8
+ export * from "./schemas/crosscheck.js";
9
+ export * from "./schemas/manifest.js";
10
+ export * from "./convert/triangle.js";
11
+ export * from "./convert/selection.js";
12
+ export * from "./convert/result.js";
13
+ export * from "./referee/profiles.js";
14
+ export * from "./referee/crosscheck.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { TriangleDoc } from "./schemas/triangle.js";
2
+ import type { SelectionDoc } from "./schemas/selection.js";
3
+ import type { MethodResultDoc, StochasticResultDoc } from "./schemas/result.js";
4
+ import type { StudyDoc } from "./schemas/study.js";
5
+ import type { BundleDoc } from "./schemas/bundle.js";
6
+ import type { CrosscheckReportDoc } from "./schemas/crosscheck.js";
7
+ /**
8
+ * `parseDocument` (spec 4.1): version-checked, schema-validated,
9
+ * integrity-verified, warning-channeled entry point for any interchange
10
+ * document.
11
+ *
12
+ * Order of checks:
13
+ * 1. version acceptance (spec 3.5) — wrong major → UNSUPPORTED_VERSION;
14
+ * 2. kind dispatch — unknown kind → BAD_INTERCHANGE (a new kind is a spec
15
+ * minor this reader does not know how to interpret; refusing loudly
16
+ * beats pretending);
17
+ * 3. zod validation (passthrough: unknown same-major minor fields are
18
+ * preserved, so a parse → re-serialize hop keeps the integrity tag);
19
+ * 4. integrity verification — per `strictness`, a mismatched tag either
20
+ * refuses (default; accidental divergence is what the tag exists to
21
+ * catch) or warns.
22
+ *
23
+ * Reader-side capability warnings (spec 3.2): a triangle with
24
+ * originLengthMonths 1 or 6 parses successfully and reports a warning
25
+ * that computation support is limited — a reader capability note, not a
26
+ * format error.
27
+ */
28
+ export type InterchangeDocument = TriangleDoc | SelectionDoc | MethodResultDoc | StochasticResultDoc | StudyDoc | BundleDoc | CrosscheckReportDoc;
29
+ export interface ParseDocumentOptions {
30
+ /** How to treat a failed integrity check. Default "refuse". */
31
+ strictness?: "warn" | "refuse";
32
+ }
33
+ export interface ParsedDocument {
34
+ doc: InterchangeDocument;
35
+ warnings: string[];
36
+ }
37
+ export declare function parseDocument(value: unknown, options?: ParseDocumentOptions): ParsedDocument;
38
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,mBAAmB,GAC3B,WAAW,GACX,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,QAAQ,GACR,SAAS,GACT,mBAAmB,CAAC;AAExB,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,mBAAmB,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAYD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,oBAAyB,GACjC,cAAc,CAsDhB"}
package/dist/parse.js ADDED
@@ -0,0 +1,48 @@
1
+ import { ReservingError } from "@actuarial-ts/core";
2
+ import { DOCUMENT_KINDS, acceptVersion, verifyIntegrity, } from "./envelope.js";
3
+ import { INTERCHANGE_SCHEMA_MANIFEST } from "./schemas/manifest.js";
4
+ const SCHEMA_BY_KIND = new Map(INTERCHANGE_SCHEMA_MANIFEST.map((entry) => [entry.kind, entry.schema]));
5
+ function formatZodError(error) {
6
+ return error.issues
7
+ .map((issue) => `${issue.path.length > 0 ? `$.${issue.path.join(".")}` : "$"}: ${issue.message}`)
8
+ .join("; ");
9
+ }
10
+ export function parseDocument(value, options = {}) {
11
+ const strictness = options.strictness ?? "refuse";
12
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
13
+ throw new ReservingError("BAD_INTERCHANGE", "An interchange document must be a JSON object with interchangeVersion and kind");
14
+ }
15
+ const raw = value;
16
+ acceptVersion(raw["interchangeVersion"]);
17
+ const kind = raw["kind"];
18
+ const schema = typeof kind === "string" ? SCHEMA_BY_KIND.get(kind) : undefined;
19
+ if (schema === undefined) {
20
+ throw new ReservingError("BAD_INTERCHANGE", `Unknown document kind ${JSON.stringify(kind)}; this reader understands: ${DOCUMENT_KINDS.join(", ")}`);
21
+ }
22
+ const parsed = schema.safeParse(raw);
23
+ if (!parsed.success) {
24
+ throw new ReservingError("BAD_INTERCHANGE", `Document of kind "${String(kind)}" failed schema validation: ${formatZodError(parsed.error)}`);
25
+ }
26
+ const doc = parsed.data;
27
+ const warnings = [];
28
+ const integrity = verifyIntegrity(doc);
29
+ if (!integrity.ok) {
30
+ const message = `Integrity tag mismatch on kind "${doc.kind}": document states ` +
31
+ `${integrity.actual ?? "(none)"} but the semantic body hashes to ${integrity.expected}. ` +
32
+ "The document diverged from its stated content after it was stamped.";
33
+ if (strictness === "refuse") {
34
+ throw new ReservingError("BAD_INTERCHANGE", message);
35
+ }
36
+ warnings.push(message);
37
+ }
38
+ if (doc.kind === "triangle") {
39
+ const cadence = doc.triangle.originLengthMonths;
40
+ if (cadence === 1 || cadence === 6) {
41
+ warnings.push(`originLengthMonths ${cadence} (${cadence === 1 ? "monthly" : "semiannual"}) parsed ` +
42
+ "successfully, but actuarial-ts computes natively on 12- and 3-month cadences; " +
43
+ "computation support for this triangle is limited");
44
+ }
45
+ }
46
+ return { doc, warnings };
47
+ }
48
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type GeneratorStamp } from "../envelope.js";
2
+ import { type MethodResultDoc } from "../schemas/result.js";
3
+ import { type SelectionDoc } from "../schemas/selection.js";
4
+ import { type CrosscheckReportDoc } from "../schemas/crosscheck.js";
5
+ /**
6
+ * The referee (spec 5): deterministic cross-implementation comparison of
7
+ * two MethodResultDocs. NOT an agent (G5) — no judgment, no persuasion,
8
+ * just tags, deviations, tolerances, and a verdict.
9
+ *
10
+ * - Comparability: same triangle tag; same selection tag or both null;
11
+ * convention profiles must not conflict; origin sets must match.
12
+ * - Tolerance: explicit option > shared known profile > the
13
+ * deterministic-cl default (with a warning). mack1993-vw compares SEs at
14
+ * its own SE tolerance; a profile with SEs out of scope skips them.
15
+ * - requested ≠ effective (`effectiveParameters` present on either side)
16
+ * downgrades the comparison with a comparability warning (spec 3.2).
17
+ * - `verified-by-value`: within tolerance but the selection both results
18
+ * replayed is value-only — the engines applied the same values rather
19
+ * than independently recomputing, and the verdict says so.
20
+ */
21
+ export interface CrosscheckOptions {
22
+ a: MethodResultDoc;
23
+ b: MethodResultDoc;
24
+ /** Overrides the profile tolerance. A bare number applies to central
25
+ * estimates AND standard errors. */
26
+ tolerance?: number | {
27
+ central: number;
28
+ standardError?: number;
29
+ };
30
+ /** The selection both results applied, when one exists — enables the
31
+ * verified-by-value classification. */
32
+ selection?: SelectionDoc;
33
+ /** ISO timestamp for the report envelope (caller-supplied; purity rule). */
34
+ createdAt: string;
35
+ generator?: GeneratorStamp;
36
+ }
37
+ export declare function crosscheck(options: CrosscheckOptions): CrosscheckReportDoc;
38
+ //# sourceMappingURL=crosscheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crosscheck.d.ts","sourceRoot":"","sources":["../../src/referee/crosscheck.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,cAAc,EAGpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,0BAA0B,CAAC;AAGlC;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,eAAe,CAAC;IACnB,CAAC,EAAE,eAAe,CAAC;IACnB;wCACoC;IACpC,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE;2CACuC;IACvC,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAmED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,mBAAmB,CAwM1E"}