@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 +2 -2
- package/dist/bundle.d.ts +114 -38
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +114 -124
- package/dist/bundle.js.map +1 -1
- package/dist/disclosure.d.ts +8 -0
- package/dist/disclosure.d.ts.map +1 -1
- package/dist/disclosure.js +109 -9
- package/dist/disclosure.js.map +1 -1
- package/package.json +5 -2
- package/src/ave.ts +132 -0
- package/src/bundle.ts +341 -0
- package/src/disclosure.ts +423 -0
- package/src/index.ts +6 -0
- package/src/ledger.ts +140 -0
- package/src/metadata.ts +189 -0
- package/src/modelCards.ts +531 -0
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.
|
|
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
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
* -
|
|
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.
|
|
21
|
-
*
|
|
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"
|
|
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 (
|
|
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
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
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
|
|
61
|
+
export declare const WRAPPED_BUNDLE_INTERCHANGE_VERSION = "1.0.0";
|
|
51
62
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
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
|
|
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
|
|
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
|
package/dist/bundle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
-
* -
|
|
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.
|
|
21
|
-
*
|
|
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 (
|
|
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
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
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
|
|
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
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
package/dist/bundle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
|
package/dist/disclosure.d.ts
CHANGED
|
@@ -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;
|
package/dist/disclosure.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|