@actuarial-ts/compliance 0.1.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 CHANGED
@@ -65,7 +65,7 @@ const markdown = generateDisclosure({
65
65
  { methodId: "mack", basisLabel: "paid", resultSummary: { standardError: mack.totals.standardError } },
66
66
  ],
67
67
  ledger,
68
- sdkVersion: "0.1.0",
68
+ sdkVersion: "0.3.0",
69
69
  generatedAt: "2026-01-05T10:15:00Z",
70
70
  });
71
71
  ```
@@ -75,7 +75,7 @@ const markdown = generateDisclosure({
75
75
  The ASB does not approve, certify, or endorse software, and no software can
76
76
  be "ASOP-compliant" on its own — compliance is a property of a credentialed
77
77
  actuary's work in context. This package is **designed to support the
78
- actuary's compliance** with ASOP Nos. 41, 43, 23, 56, and 21 by generating
78
+ actuary's compliance** with ASOP Nos. 41, 43, 23, 56, 21, and 20 by generating
79
79
  the disclosures, documentation, and audit artifacts those standards call
80
80
  for. The generated documents are draft support material for the responsible
81
81
  actuary to review, edit, and adopt.
package/dist/bundle.d.ts CHANGED
@@ -3,63 +3,81 @@
3
3
  * hash, so an analysis can state "these results came from exactly these
4
4
  * inputs, parameters, and SDK versions" and a re-run can be byte-verified.
5
5
  *
6
- * Ground truth:
7
- * - `canonicalJson` is the package's single equality oracle: object keys are
8
- * sorted recursively, arrays keep their order, numbers render via
9
- * `String(n)` except -0 which normalizes to "0" (so 0 and -0 never differ),
10
- * and anything JSON cannot faithfully represent (undefined, functions,
11
- * NaN/Infinity, bigint, symbol, non-plain objects such as Date/Map/Set,
12
- * circular references) THROWS with the offending path instead of being
13
- * silently dropped or coerced the way JSON.stringify would.
14
- * - `fnv1a64` is an integrity aid, NOT a security control (see its doc block).
6
+ * `canonicalJson` and `fnv1a64` LIVE IN @actuarial-ts/core (src/canonical.ts)
7
+ * since 0.2.0 so the interchange layer can share them without a package
8
+ * cycle; this module re-exports both, unchanged. One deliberate behavior
9
+ * change rode along: invalid canonicalization input now throws core's
10
+ * ReservingError("UNSUPPORTED_VALUE") instead of ComplianceError - same
11
+ * code, same message shape, different class (CHANGELOG 0.2.0).
12
+ *
13
+ * Ground truth (unchanged):
15
14
  * - Timestamps are caller-supplied ISO strings; this module never reads a
16
15
  * clock, so identical inputs yield byte-identical bundles.
17
- * - Browser-safe: no node builtins (TextEncoder is a web-standard global).
16
+ * - fnv1a64 is an integrity aid, NOT a security control (see its doc block
17
+ * in core).
18
+ * - Browser-safe: no node builtins.
18
19
  *
19
20
  * Error style for the whole package: `ComplianceError` with a registered
20
- * machine code, mirroring core's `ReservingError` idiom. It lives here (not
21
- * in its own module) because bundle.ts is the package's dependency-root
22
- * module — ledger.ts already imports `canonicalJson` from it. Core's
23
- * `RESERVING_ERROR_CODES` registry is a closed contract enforced against
24
- * core's own source, and compliance failures (missing rationale, unsupported
25
- * bundle values) are not reserving-input errors, so this package does not
26
- * reuse `ReservingError`.
21
+ * machine code, mirroring core's `ReservingError` idiom (bundle.ts is the
22
+ * package's dependency-root module, so the class lives here).
27
23
  *
28
24
  * These utilities are designed to support the actuary's compliance with
29
25
  * ASOP No. 41 (documentation and reproducibility of the analysis);
30
26
  * responsibility for compliance remains with the credentialed actuary.
31
27
  */
28
+ import { canonicalJson, fnv1a64 } from "@actuarial-ts/core";
29
+ import type { BundleDoc, MethodResultDoc, SelectionDoc, StochasticResultDoc, TriangleDoc } from "@actuarial-ts/interchange";
30
+ export { canonicalJson, fnv1a64 };
31
+ /**
32
+ * The wrapped reproducibility bundle: the interchange BundleDoc (spec 3.2),
33
+ * re-exported under a compliance-side name so it cannot be confused with the
34
+ * inner ReproducibilityBundle record. The dependency on
35
+ * `@actuarial-ts/interchange` is TYPE-ONLY (interchange must not import
36
+ * compliance, and it does not; the outer tag is computed here with core's
37
+ * canonicalJson/fnv1a64, matching interchange's semanticBodyOf for
38
+ * kind "bundle" exactly — the wrapped round-trip test parses the emitted doc
39
+ * with the real interchange parser so any drift fails loudly).
40
+ */
41
+ export type WrappedBundleDoc = BundleDoc;
32
42
  /**
33
43
  * Every machine-readable code a ComplianceError can carry, across all modules
34
44
  * of this package. Add the code here when introducing a new throw.
45
+ * (UNSUPPORTED_VALUE moved to core's registry with canonicalJson in 0.2.0.)
35
46
  */
36
- export declare const COMPLIANCE_ERROR_CODES: readonly ["BAD_BUNDLE", "BAD_CDF", "MISSING_RATIONALE", "UNSUPPORTED_VALUE"];
47
+ export declare const COMPLIANCE_ERROR_CODES: readonly ["BAD_BUNDLE", "BAD_CDF", "MISSING_RATIONALE"];
37
48
  export type ComplianceErrorCode = (typeof COMPLIANCE_ERROR_CODES)[number];
38
- /** Thrown for invalid compliance input (unrepresentable bundle payloads, judgment without rationale, non-positive CDFs). */
49
+ /** Thrown for invalid compliance input (bad bundles, judgment without rationale, non-positive CDFs). */
39
50
  export declare class ComplianceError extends Error {
40
51
  readonly code: ComplianceErrorCode;
41
52
  constructor(code: ComplianceErrorCode, message: string);
42
53
  }
43
54
  /**
44
- * Deterministic JSON serialization: sorted object keys (recursively), arrays
45
- * in order, no whitespace, -0 normalized to "0". Two structurally equal
46
- * values always produce the same string regardless of key insertion order.
47
- * Throws ComplianceError("UNSUPPORTED_VALUE") with the offending path, e.g.
48
- * "$.rows[2].ultimate" for any value JSON cannot faithfully represent.
55
+ * The interchange version the wrapped form is written under. Kept in literal
56
+ * sync with `@actuarial-ts/interchange`'s INTERCHANGE_SPEC_VERSION (the dep
57
+ * is type-only, so the constant cannot be imported); the wrapped round-trip
58
+ * test parses the emitted doc with the real interchange parser, which
59
+ * refuses a wrong-major version drift fails loudly.
49
60
  */
50
- export declare function canonicalJson(value: unknown): string;
61
+ export declare const WRAPPED_BUNDLE_INTERCHANGE_VERSION = "1.0.0";
51
62
  /**
52
- * FNV-1a 64-bit hash over the UTF-8 bytes of `text`, returned as a 16-hex-char
53
- * string.
54
- *
55
- * This is an INTEGRITY AID for detecting accidental divergence between a
56
- * bundle and a re-run. It is NOT a security control: FNV-1a is not collision
57
- * resistant and offers no protection against deliberate tampering. Anyone
58
- * needing tamper evidence must sign or cryptographically hash the payload
59
- * (which is exactly why the full canonical payload — not just the hash — is
60
- * stored on the bundle).
63
+ * This package's version, stamped into a wrapped bundle's `generator`
64
+ * envelope field. A sync test asserts it matches package.json so it cannot
65
+ * silently drift (mirroring interchange's INTERCHANGE_PACKAGE_VERSION
66
+ * discipline).
61
67
  */
62
- export declare function fnv1a64(text: string): string;
68
+ export declare const COMPLIANCE_PACKAGE_VERSION = "0.3.0";
69
+ /**
70
+ * The interchange mirror for a wrapped bundle (spec 3.2): the triangles the
71
+ * analysis consumed, the selections it applied, and the results it produced,
72
+ * each as an interchange document. Results are INCLUDED so a non-TS consumer
73
+ * (`load_bundle`) can honor its contract without ever parsing the TS-native
74
+ * canonical payload.
75
+ */
76
+ export interface BundleWrapInput {
77
+ triangles: TriangleDoc[];
78
+ selections: SelectionDoc[];
79
+ results: (MethodResultDoc | StochasticResultDoc)[];
80
+ }
63
81
  export interface CreateBundleInput {
64
82
  /** The data the analysis consumed (triangles, claims, exposures — anything canonicalizable). */
65
83
  inputs: unknown;
@@ -73,6 +91,28 @@ export interface CreateBundleInput {
73
91
  seeds?: unknown;
74
92
  /** Caller-supplied ISO timestamp (purity: no clock reads). */
75
93
  createdAt: string;
94
+ /**
95
+ * Optional interchange mirror (spec 3.2). When provided, the bundle is
96
+ * ALSO emitted as a wrapped BundleDoc whose OUTER integrity tag is defined
97
+ * over `{ bundle, interchange }`. Never enters the inner payload: the
98
+ * unwrapped bundle is byte-identical with or without `wrap`.
99
+ */
100
+ wrap?: BundleWrapInput;
101
+ /**
102
+ * Overrides the wrapped document's `generator` stamp. Defaults to this
103
+ * package at its current version, which is what a real analysis wants.
104
+ *
105
+ * Exists for authoring FROZEN corpora (the cross-engine conformance
106
+ * fixtures), where every byte must reproduce forever and so a stamp that
107
+ * tracks the live build cannot be used — the same reason `createdAt` is
108
+ * caller-supplied rather than read from the clock. Matches the
109
+ * `generator?` option the interchange document builders already accept.
110
+ * Wrapped-mode only; the inner payload never carries it.
111
+ */
112
+ generator?: {
113
+ name: string;
114
+ version: string;
115
+ };
76
116
  }
77
117
  export interface ReproducibilityBundle {
78
118
  /** Canonical JSON of the full bundle body; the reproducibility record itself. */
@@ -80,13 +120,37 @@ export interface ReproducibilityBundle {
80
120
  /** fnv1a64(payload) — integrity aid, not a security control. */
81
121
  hash: string;
82
122
  }
123
+ /** A ReproducibilityBundle plus its wrapped interchange form (spec 3.2). */
124
+ export interface WrappedBundleResult extends ReproducibilityBundle {
125
+ /**
126
+ * The wrapped BundleDoc: `{ bundle: { payload, hash }, interchange }` under
127
+ * an interchange envelope, with the OUTER integrity tag over the two-field
128
+ * semantic body `{ bundle, interchange }`.
129
+ */
130
+ wrapped: WrappedBundleDoc;
131
+ }
83
132
  /**
84
133
  * Packages an analysis run into a reproducibility bundle. The payload is
85
134
  * canonical, so two runs with structurally equal inputs produce byte-identical
86
135
  * payloads (and therefore identical hashes) regardless of key insertion order.
87
136
  * `seeds` is included only when provided (undefined would be unrepresentable).
137
+ *
138
+ * With `wrap` (the interchange mirror, spec 3.2) the same inner bundle is
139
+ * ALSO returned as a wrapped BundleDoc; the unwrapped `{ payload, hash }` is
140
+ * byte-identical either way (the v0.1.x compat fixture pins this).
88
141
  */
142
+ export declare function createBundle(input: CreateBundleInput & {
143
+ wrap: BundleWrapInput;
144
+ }): WrappedBundleResult;
89
145
  export declare function createBundle(input: CreateBundleInput): ReproducibilityBundle;
146
+ /** Outer-tag verification detail (wrapped mode only; spec 3.2). */
147
+ export interface OuterIntegrityCheck {
148
+ ok: boolean;
149
+ /** The tag recomputed from the `{ bundle, interchange }` semantic body. */
150
+ expected: string;
151
+ /** The tag the wrapped document claims. */
152
+ actual: string | null;
153
+ }
90
154
  export interface VerifyBundleResult {
91
155
  reproduced: boolean;
92
156
  /**
@@ -94,19 +158,31 @@ export interface VerifyBundleResult {
94
158
  * sorted order), e.g. "$.rows[1].ultimate". Present only when not
95
159
  * reproduced. A missing/extra object key reports the key's path; an array
96
160
  * length mismatch reports the first index past the shared prefix; a type
97
- * mismatch reports the node itself.
161
+ * mismatch reports the node itself. In wrapped mode, an outer-tag failure
162
+ * reports "$.integrity" (the divergent tag itself; see `outerIntegrity`
163
+ * for the expected/actual values).
98
164
  */
99
165
  mismatchPath?: string;
166
+ /** Present in wrapped mode only: the outer-tag check (spec 3.2). */
167
+ outerIntegrity?: OuterIntegrityCheck;
100
168
  }
101
169
  /**
102
170
  * Verifies a re-run against a bundle: canonicalizes `rerunResults` and
103
171
  * byte-compares it with the bundle's stored `results` segment. On mismatch,
104
172
  * reports the FIRST differing path (see VerifyBundleResult.mismatchPath).
105
173
  *
174
+ * Wrapped mode (a BundleDoc with `kind: "bundle"`, spec 3.2): additionally
175
+ * recomputes the OUTER integrity tag over `{ bundle, interchange }` and
176
+ * refuses on divergence BEFORE the inner check — a drifted interchange
177
+ * mirror fails verification with mismatchPath "$.integrity" and the
178
+ * expected/actual tags in `outerIntegrity`, even when the inner bundle is
179
+ * untouched. When the outer tag holds, the inner bundle is verified exactly
180
+ * as in unwrapped mode.
181
+ *
106
182
  * Throws ComplianceError("BAD_BUNDLE") when the payload is not a valid bundle
107
- * body, and propagates ComplianceError("UNSUPPORTED_VALUE") when
183
+ * body, and propagates ReservingError("UNSUPPORTED_VALUE") when
108
184
  * `rerunResults` itself is not canonicalizable — a result that cannot be
109
185
  * serialized cannot be verified.
110
186
  */
111
- export declare function verifyBundle(bundle: ReproducibilityBundle, rerunResults: unknown): VerifyBundleResult;
187
+ export declare function verifyBundle(bundle: ReproducibilityBundle | WrappedBundleDoc, rerunResults: unknown): VerifyBundleResult;
112
188
  //# sourceMappingURL=bundle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;GAGG;AACH,eAAO,MAAM,sBAAsB,8EAKzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,4HAA4H;AAC5H,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBACvB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAKvD;AA6DD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ5C;AAED,MAAM,WAAW,iBAAiB;IAChC,gGAAgG;IAChG,MAAM,EAAE,OAAO,CAAC;IAChB,wFAAwF;IACxF,UAAU,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAW5E;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,qBAAqB,EAAE,YAAY,EAAE,OAAO,GAAG,kBAAkB,CAerG"}
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACZ,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;AAElC;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,yDAIzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,wGAAwG;AACxG,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBACvB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAKvD;AAID;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,UAAU,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,UAAU,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,OAAO,EAAE,CAAC,eAAe,GAAG,mBAAmB,CAAC,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,iBAAiB;IAChC,gGAAgG;IAChG,MAAM,EAAE,OAAO,CAAC;IAChB,wFAAwF;IACxF,UAAU,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE;;;;OAIG;IACH,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAAG,mBAAmB,CAAC;AACxG,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAAC;AAqC9E,mEAAmE;AACnE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,cAAc,CAAC,EAAE,mBAAmB,CAAC;CACtC;AAyFD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,qBAAqB,GAAG,gBAAgB,EAChD,YAAY,EAAE,OAAO,GACpB,kBAAkB,CAEpB"}
package/dist/bundle.js CHANGED
@@ -3,43 +3,41 @@
3
3
  * hash, so an analysis can state "these results came from exactly these
4
4
  * inputs, parameters, and SDK versions" and a re-run can be byte-verified.
5
5
  *
6
- * Ground truth:
7
- * - `canonicalJson` is the package's single equality oracle: object keys are
8
- * sorted recursively, arrays keep their order, numbers render via
9
- * `String(n)` except -0 which normalizes to "0" (so 0 and -0 never differ),
10
- * and anything JSON cannot faithfully represent (undefined, functions,
11
- * NaN/Infinity, bigint, symbol, non-plain objects such as Date/Map/Set,
12
- * circular references) THROWS with the offending path instead of being
13
- * silently dropped or coerced the way JSON.stringify would.
14
- * - `fnv1a64` is an integrity aid, NOT a security control (see its doc block).
6
+ * `canonicalJson` and `fnv1a64` LIVE IN @actuarial-ts/core (src/canonical.ts)
7
+ * since 0.2.0 so the interchange layer can share them without a package
8
+ * cycle; this module re-exports both, unchanged. One deliberate behavior
9
+ * change rode along: invalid canonicalization input now throws core's
10
+ * ReservingError("UNSUPPORTED_VALUE") instead of ComplianceError - same
11
+ * code, same message shape, different class (CHANGELOG 0.2.0).
12
+ *
13
+ * Ground truth (unchanged):
15
14
  * - Timestamps are caller-supplied ISO strings; this module never reads a
16
15
  * clock, so identical inputs yield byte-identical bundles.
17
- * - Browser-safe: no node builtins (TextEncoder is a web-standard global).
16
+ * - fnv1a64 is an integrity aid, NOT a security control (see its doc block
17
+ * in core).
18
+ * - Browser-safe: no node builtins.
18
19
  *
19
20
  * Error style for the whole package: `ComplianceError` with a registered
20
- * machine code, mirroring core's `ReservingError` idiom. It lives here (not
21
- * in its own module) because bundle.ts is the package's dependency-root
22
- * module — ledger.ts already imports `canonicalJson` from it. Core's
23
- * `RESERVING_ERROR_CODES` registry is a closed contract enforced against
24
- * core's own source, and compliance failures (missing rationale, unsupported
25
- * bundle values) are not reserving-input errors, so this package does not
26
- * reuse `ReservingError`.
21
+ * machine code, mirroring core's `ReservingError` idiom (bundle.ts is the
22
+ * package's dependency-root module, so the class lives here).
27
23
  *
28
24
  * These utilities are designed to support the actuary's compliance with
29
25
  * ASOP No. 41 (documentation and reproducibility of the analysis);
30
26
  * responsibility for compliance remains with the credentialed actuary.
31
27
  */
28
+ import { canonicalJson, fnv1a64 } from "@actuarial-ts/core";
29
+ export { canonicalJson, fnv1a64 };
32
30
  /**
33
31
  * Every machine-readable code a ComplianceError can carry, across all modules
34
32
  * of this package. Add the code here when introducing a new throw.
33
+ * (UNSUPPORTED_VALUE moved to core's registry with canonicalJson in 0.2.0.)
35
34
  */
36
35
  export const COMPLIANCE_ERROR_CODES = [
37
36
  "BAD_BUNDLE",
38
37
  "BAD_CDF",
39
38
  "MISSING_RATIONALE",
40
- "UNSUPPORTED_VALUE",
41
39
  ];
42
- /** Thrown for invalid compliance input (unrepresentable bundle payloads, judgment without rationale, non-positive CDFs). */
40
+ /** Thrown for invalid compliance input (bad bundles, judgment without rationale, non-positive CDFs). */
43
41
  export class ComplianceError extends Error {
44
42
  code;
45
43
  constructor(code, message) {
@@ -48,103 +46,21 @@ export class ComplianceError extends Error {
48
46
  this.code = code;
49
47
  }
50
48
  }
51
- function isPlainObject(value) {
52
- if (value === null || typeof value !== "object" || Array.isArray(value))
53
- return false;
54
- const proto = Object.getPrototypeOf(value);
55
- return proto === Object.prototype || proto === null;
56
- }
57
- function canonicalize(value, path, seen) {
58
- if (value === null)
59
- return "null";
60
- switch (typeof value) {
61
- case "string":
62
- return JSON.stringify(value);
63
- case "boolean":
64
- return value ? "true" : "false";
65
- case "number": {
66
- if (!Number.isFinite(value)) {
67
- throw new ComplianceError("UNSUPPORTED_VALUE", `non-finite number (${String(value)}) at ${path}`);
68
- }
69
- return Object.is(value, -0) ? "0" : String(value);
70
- }
71
- case "undefined":
72
- throw new ComplianceError("UNSUPPORTED_VALUE", `undefined at ${path}`);
73
- case "function":
74
- throw new ComplianceError("UNSUPPORTED_VALUE", `function at ${path}`);
75
- case "bigint":
76
- case "symbol":
77
- throw new ComplianceError("UNSUPPORTED_VALUE", `${typeof value} at ${path}`);
78
- case "object":
79
- break;
80
- }
81
- const obj = value;
82
- if (seen.has(obj)) {
83
- throw new ComplianceError("UNSUPPORTED_VALUE", `circular reference at ${path}`);
84
- }
85
- seen.add(obj);
86
- let out;
87
- if (Array.isArray(obj)) {
88
- const parts = [];
89
- for (let i = 0; i < obj.length; i++) {
90
- parts.push(canonicalize(obj[i], `${path}[${i}]`, seen));
91
- }
92
- out = `[${parts.join(",")}]`;
93
- }
94
- else if (isPlainObject(obj)) {
95
- const keys = Object.keys(obj).sort();
96
- const parts = [];
97
- for (const key of keys) {
98
- parts.push(`${JSON.stringify(key)}:${canonicalize(obj[key], `${path}.${key}`, seen)}`);
99
- }
100
- out = `{${parts.join(",")}}`;
101
- }
102
- else {
103
- const name = obj.constructor?.name ?? "unknown";
104
- throw new ComplianceError("UNSUPPORTED_VALUE", `non-plain object (${name}) at ${path}; only plain objects, arrays, and JSON primitives are canonicalizable`);
105
- }
106
- seen.delete(obj);
107
- return out;
108
- }
109
- /**
110
- * Deterministic JSON serialization: sorted object keys (recursively), arrays
111
- * in order, no whitespace, -0 normalized to "0". Two structurally equal
112
- * values always produce the same string regardless of key insertion order.
113
- * Throws ComplianceError("UNSUPPORTED_VALUE") — with the offending path, e.g.
114
- * "$.rows[2].ultimate" — for any value JSON cannot faithfully represent.
115
- */
116
- export function canonicalJson(value) {
117
- return canonicalize(value, "$", new Set());
118
- }
119
- const FNV_OFFSET_BASIS = 0xcbf29ce484222325n;
120
- const FNV_PRIME = 0x100000001b3n;
121
- const MASK_64 = 0xffffffffffffffffn;
122
49
  /**
123
- * FNV-1a 64-bit hash over the UTF-8 bytes of `text`, returned as a 16-hex-char
124
- * string.
125
- *
126
- * This is an INTEGRITY AID for detecting accidental divergence between a
127
- * bundle and a re-run. It is NOT a security control: FNV-1a is not collision
128
- * resistant and offers no protection against deliberate tampering. Anyone
129
- * needing tamper evidence must sign or cryptographically hash the payload
130
- * (which is exactly why the full canonical payload — not just the hash — is
131
- * stored on the bundle).
50
+ * The interchange version the wrapped form is written under. Kept in literal
51
+ * sync with `@actuarial-ts/interchange`'s INTERCHANGE_SPEC_VERSION (the dep
52
+ * is type-only, so the constant cannot be imported); the wrapped round-trip
53
+ * test parses the emitted doc with the real interchange parser, which
54
+ * refuses a wrong-major version drift fails loudly.
132
55
  */
133
- export function fnv1a64(text) {
134
- const bytes = new TextEncoder().encode(text);
135
- let hash = FNV_OFFSET_BASIS;
136
- for (const byte of bytes) {
137
- hash ^= BigInt(byte);
138
- hash = (hash * FNV_PRIME) & MASK_64;
139
- }
140
- return hash.toString(16).padStart(16, "0");
141
- }
56
+ export const WRAPPED_BUNDLE_INTERCHANGE_VERSION = "1.0.0";
142
57
  /**
143
- * Packages an analysis run into a reproducibility bundle. The payload is
144
- * canonical, so two runs with structurally equal inputs produce byte-identical
145
- * payloads (and therefore identical hashes) regardless of key insertion order.
146
- * `seeds` is included only when provided (undefined would be unrepresentable).
58
+ * This package's version, stamped into a wrapped bundle's `generator`
59
+ * envelope field. A sync test asserts it matches package.json so it cannot
60
+ * silently drift (mirroring interchange's INTERCHANGE_PACKAGE_VERSION
61
+ * discipline).
147
62
  */
63
+ export const COMPLIANCE_PACKAGE_VERSION = "0.3.0";
148
64
  export function createBundle(input) {
149
65
  const body = {
150
66
  createdAt: input.createdAt,
@@ -156,7 +72,36 @@ export function createBundle(input) {
156
72
  if (input.seeds !== undefined)
157
73
  body["seeds"] = input.seeds;
158
74
  const payload = canonicalJson(body);
159
- return { payload, hash: fnv1a64(payload) };
75
+ const inner = { payload, hash: fnv1a64(payload) };
76
+ if (input.wrap === undefined)
77
+ return inner;
78
+ // The inner record is carried opaquely as the `bundle` segment; the outer
79
+ // tag is fnv1a64(canonicalJson({ bundle, interchange })) — exactly
80
+ // interchange's semanticBodyOf for kind "bundle" (spec 3.2).
81
+ const bundleSegment = { hash: inner.hash, payload: inner.payload };
82
+ const interchange = {
83
+ triangles: [...input.wrap.triangles],
84
+ selections: [...input.wrap.selections],
85
+ results: [...input.wrap.results],
86
+ };
87
+ const wrapped = {
88
+ interchangeVersion: WRAPPED_BUNDLE_INTERCHANGE_VERSION,
89
+ kind: "bundle",
90
+ generator: input.generator
91
+ ? { ...input.generator }
92
+ : { name: "@actuarial-ts/compliance", version: COMPLIANCE_PACKAGE_VERSION },
93
+ createdAt: input.createdAt,
94
+ bundle: bundleSegment,
95
+ interchange,
96
+ integrity: fnv1a64(canonicalJson({ bundle: bundleSegment, interchange })),
97
+ };
98
+ return { ...inner, wrapped };
99
+ }
100
+ function isPlainObject(value) {
101
+ if (value === null || typeof value !== "object" || Array.isArray(value))
102
+ return false;
103
+ const proto = Object.getPrototypeOf(value);
104
+ return proto === Object.prototype || proto === null;
160
105
  }
161
106
  /** First differing path between two canonicalizable structures, or null when equal. */
162
107
  function firstDifference(stored, rerun, path) {
@@ -183,17 +128,16 @@ function firstDifference(stored, rerun, path) {
183
128
  }
184
129
  return canonicalJson(stored) === canonicalJson(rerun) ? null : path;
185
130
  }
186
- /**
187
- * Verifies a re-run against a bundle: canonicalizes `rerunResults` and
188
- * byte-compares it with the bundle's stored `results` segment. On mismatch,
189
- * reports the FIRST differing path (see VerifyBundleResult.mismatchPath).
190
- *
191
- * Throws ComplianceError("BAD_BUNDLE") when the payload is not a valid bundle
192
- * body, and propagates ComplianceError("UNSUPPORTED_VALUE") when
193
- * `rerunResults` itself is not canonicalizable — a result that cannot be
194
- * serialized cannot be verified.
195
- */
196
- export function verifyBundle(bundle, rerunResults) {
131
+ /** Inner verification — the pre-wrapped behavior, unchanged byte for byte. */
132
+ function verifyUnwrapped(bundle, rerunResults) {
133
+ // The bundle's own hash first. Without this, the attestation ("these results
134
+ // came from exactly these inputs, parameters, and SDK versions") checked the
135
+ // results segment only — a bundle with rewritten inputs and hash "deadbeef"
136
+ // verified. The wrapped path always recomputed its tag; the unwrapped one
137
+ // must too.
138
+ if (fnv1a64(bundle.payload) !== bundle.hash) {
139
+ return { reproduced: false, mismatchPath: "$.hash" };
140
+ }
197
141
  let stored;
198
142
  try {
199
143
  stored = JSON.parse(bundle.payload);
@@ -211,4 +155,50 @@ export function verifyBundle(bundle, rerunResults) {
211
155
  return { reproduced: true };
212
156
  return { reproduced: false, mismatchPath: firstDifference(storedResults, rerunResults, "$") ?? "$" };
213
157
  }
158
+ function isWrappedBundleDoc(value) {
159
+ return value.kind === "bundle";
160
+ }
161
+ /** Wrapped mode: the outer tag (spec 3.2) AND the inner bundle exactly as today. */
162
+ function verifyWrapped(doc, rerunResults) {
163
+ const innerRaw = doc.bundle;
164
+ if (!isPlainObject(innerRaw) ||
165
+ typeof innerRaw["payload"] !== "string" ||
166
+ typeof innerRaw["hash"] !== "string") {
167
+ throw new ComplianceError("BAD_BUNDLE", 'wrapped bundle\'s "bundle" segment must carry the inner { payload, hash } record');
168
+ }
169
+ if (doc.interchange === undefined || doc.interchange === null) {
170
+ throw new ComplianceError("BAD_BUNDLE", 'wrapped bundle is missing its "interchange" mirror');
171
+ }
172
+ // OUTER tag over the two-field semantic body { bundle, interchange } —
173
+ // exactly interchange's semanticBodyOf for kind "bundle" (spec 3.2).
174
+ const expected = fnv1a64(canonicalJson({ bundle: doc.bundle, interchange: doc.interchange }));
175
+ const actual = typeof doc.integrity === "string" ? doc.integrity : null;
176
+ const outerIntegrity = { ok: expected === actual, expected, actual };
177
+ if (!outerIntegrity.ok) {
178
+ return { reproduced: false, mismatchPath: "$.integrity", outerIntegrity };
179
+ }
180
+ const inner = { payload: innerRaw["payload"], hash: innerRaw["hash"] };
181
+ return { ...verifyUnwrapped(inner, rerunResults), outerIntegrity };
182
+ }
183
+ /**
184
+ * Verifies a re-run against a bundle: canonicalizes `rerunResults` and
185
+ * byte-compares it with the bundle's stored `results` segment. On mismatch,
186
+ * reports the FIRST differing path (see VerifyBundleResult.mismatchPath).
187
+ *
188
+ * Wrapped mode (a BundleDoc with `kind: "bundle"`, spec 3.2): additionally
189
+ * recomputes the OUTER integrity tag over `{ bundle, interchange }` and
190
+ * refuses on divergence BEFORE the inner check — a drifted interchange
191
+ * mirror fails verification with mismatchPath "$.integrity" and the
192
+ * expected/actual tags in `outerIntegrity`, even when the inner bundle is
193
+ * untouched. When the outer tag holds, the inner bundle is verified exactly
194
+ * as in unwrapped mode.
195
+ *
196
+ * Throws ComplianceError("BAD_BUNDLE") when the payload is not a valid bundle
197
+ * body, and propagates ReservingError("UNSUPPORTED_VALUE") when
198
+ * `rerunResults` itself is not canonicalizable — a result that cannot be
199
+ * serialized cannot be verified.
200
+ */
201
+ export function verifyBundle(bundle, rerunResults) {
202
+ return isWrappedBundleDoc(bundle) ? verifyWrapped(bundle, rerunResults) : verifyUnwrapped(bundle, rerunResults);
203
+ }
214
204
  //# sourceMappingURL=bundle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { CrosscheckReportDoc } from "@actuarial-ts/interchange";
1
2
  import type { EstimateMetadata } from "./metadata.js";
2
3
  import type { AssumptionLedger, ChangedAssumptions } from "./ledger.js";
3
4
  import { type MethodId } from "./modelCards.js";
@@ -67,6 +68,13 @@ export interface DisclosureInput {
67
68
  priorComparison?: PriorComparison;
68
69
  reliances?: string[];
69
70
  limitations?: string[];
71
+ /**
72
+ * Cross-implementation referee reports (interchange spec 5), rendered as
73
+ * "## 4b. Cross-implementation verification" after Section 4. Omitted or
74
+ * empty = no Section 4b (the disclosure never claims a verification that
75
+ * was not performed).
76
+ */
77
+ crossImplementation?: CrosscheckReportDoc[];
70
78
  sdkVersion: string;
71
79
  /** Caller-supplied ISO timestamp (determinism: the generator never reads a clock). */
72
80
  generatedAt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../src/disclosure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG7D;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACjF,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;CACrB;AAkDD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA+KjE"}
1
+ {"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../src/disclosure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG7D;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACjF,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;CACrB;AA8GD,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CA0OjE"}