@actuarial-ts/core 0.6.1 → 0.7.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 (63) hide show
  1. package/README.md +11 -2
  2. package/dist/canonical.d.ts +11 -0
  3. package/dist/canonical.d.ts.map +1 -1
  4. package/dist/canonical.js +136 -26
  5. package/dist/canonical.js.map +1 -1
  6. package/dist/diagnosticEvidenceIntern.d.ts +16 -0
  7. package/dist/diagnosticEvidenceIntern.d.ts.map +1 -0
  8. package/dist/diagnosticEvidenceIntern.js +139 -0
  9. package/dist/diagnosticEvidenceIntern.js.map +1 -0
  10. package/dist/diagnosticExposure.d.ts.map +1 -1
  11. package/dist/diagnosticExposure.js +97 -7
  12. package/dist/diagnosticExposure.js.map +1 -1
  13. package/dist/diagnosticIdentity.d.ts.map +1 -1
  14. package/dist/diagnosticIdentity.js +6 -3
  15. package/dist/diagnosticIdentity.js.map +1 -1
  16. package/dist/diagnosticIdentityStream.d.ts +56 -0
  17. package/dist/diagnosticIdentityStream.d.ts.map +1 -0
  18. package/dist/diagnosticIdentityStream.js +472 -0
  19. package/dist/diagnosticIdentityStream.js.map +1 -0
  20. package/dist/diagnosticPreparation.d.ts +28 -0
  21. package/dist/diagnosticPreparation.d.ts.map +1 -1
  22. package/dist/diagnosticPreparation.js +160 -36
  23. package/dist/diagnosticPreparation.js.map +1 -1
  24. package/dist/diagnosticReview.d.ts +4 -1
  25. package/dist/diagnosticReview.d.ts.map +1 -1
  26. package/dist/diagnosticReview.js +203 -51
  27. package/dist/diagnosticReview.js.map +1 -1
  28. package/dist/diagnosticReviewSources.d.ts +18 -0
  29. package/dist/diagnosticReviewSources.d.ts.map +1 -0
  30. package/dist/diagnosticReviewSources.js +76 -0
  31. package/dist/diagnosticReviewSources.js.map +1 -0
  32. package/dist/diagnosticReviewStore.d.ts +88 -0
  33. package/dist/diagnosticReviewStore.d.ts.map +1 -0
  34. package/dist/diagnosticReviewStore.js +455 -0
  35. package/dist/diagnosticReviewStore.js.map +1 -0
  36. package/dist/diagnosticRunner.d.ts +25 -1
  37. package/dist/diagnosticRunner.d.ts.map +1 -1
  38. package/dist/diagnosticRunner.js +115 -7
  39. package/dist/diagnosticRunner.js.map +1 -1
  40. package/dist/fnvAccumulator.d.ts +6 -0
  41. package/dist/fnvAccumulator.d.ts.map +1 -0
  42. package/dist/fnvAccumulator.js +21 -0
  43. package/dist/fnvAccumulator.js.map +1 -0
  44. package/dist/index.d.ts +8 -5
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +5 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/version.d.ts +1 -1
  49. package/dist/version.js +1 -1
  50. package/package.json +1 -1
  51. package/src/canonical.ts +144 -26
  52. package/src/diagnosticEvidenceIntern.ts +151 -0
  53. package/src/diagnosticExposure.ts +126 -17
  54. package/src/diagnosticIdentity.ts +15 -6
  55. package/src/diagnosticIdentityStream.ts +553 -0
  56. package/src/diagnosticPreparation.ts +268 -84
  57. package/src/diagnosticReview.ts +293 -85
  58. package/src/diagnosticReviewSources.ts +85 -0
  59. package/src/diagnosticReviewStore.ts +692 -0
  60. package/src/diagnosticRunner.ts +206 -9
  61. package/src/fnvAccumulator.ts +20 -0
  62. package/src/index.ts +38 -1
  63. package/src/version.ts +1 -1
package/README.md CHANGED
@@ -7,7 +7,7 @@ The package is designed to support the actuary's compliance with the ASOPs; it d
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- npm install @actuarial-ts/core@0.6.1
10
+ npm install @actuarial-ts/core@0.7.0
11
11
  ```
12
12
 
13
13
  ESM, TypeScript-first, zero runtime dependencies, Node 20+.
@@ -77,9 +77,18 @@ The six built-in formulas are basis-independent. The factory creates ten count i
77
77
 
78
78
  All metrics are ratio-of-sums: measures are aggregated at source-group/origin/valuation, groups are mapped and merged, then division happens once. Measure-local `missing: "unknown" | "zero"` is explicit. Exposure timing is either `origin-static` or `valuation-specific`. Calendar and ordered axes derive normalized origins, valuations, development ages, and units; input rows cannot assert a trusted age.
79
79
 
80
+ Exposure reconciliation accepts at most 250,000 observations per call. Collection
81
+ capacity is independent of optional source-file/sheet/cell metadata: each record
82
+ retains the JSON depth (256 including the outer array) and one-million-node
83
+ resource guards, while the owned result is frozen by observation/cohort rather
84
+ than rechecked against a single collection-wide JSON node budget. Malformed
85
+ arrays, accessors, non-JSON metadata, and cycles still produce typed validation
86
+ errors. Nonfinite exposure values remain supported audited inputs, not usable
87
+ numeric exposure values. This is a bounded capacity, not an unlimited scale claim.
88
+
80
89
  Compilation validates the whole graph atomically: IDs, sources, role types, compatibility groups, development semantics, derivation acyclicity, expression limits, rule operands, basis/population references, and period coordinates. Authentic compiled/prepared objects are owner-branded and frozen. Formula, calculation, definition, preparation, and result identities are deterministic FNV-1a/JCS integrity aids—not cryptographic signatures.
81
90
 
82
- See the generated [formula and instance catalog](https://github.com/yerromnitsuj/actng/blob/v0.6.1/docs/reference/diagnostic-formulas.md) and [0.6 migration guide](https://github.com/yerromnitsuj/actng/blob/v0.6.1/docs/migrations/0.6-generalized-diagnostics.md).
91
+ See the generated [formula and instance catalog](https://github.com/yerromnitsuj/actng/blob/v0.7.0/docs/reference/diagnostic-formulas.md) and [0.6 migration guide](https://github.com/yerromnitsuj/actng/blob/v0.7.0/docs/migrations/0.6-generalized-diagnostics.md).
83
92
 
84
93
  ## Main method families
85
94
 
@@ -16,4 +16,15 @@ export declare function canonicalJson(value: unknown): string;
16
16
  * needing tamper evidence must sign or cryptographically hash the payload.
17
17
  */
18
18
  export declare function fnv1a64(text: string): string;
19
+ /**
20
+ * The exact integrity tag `fnv1a64(canonicalJson(value))`, without constructing
21
+ * the complete canonical string or UTF-8 byte array. Validation, key ordering,
22
+ * escaping and unsupported-value error paths match `canonicalJson`.
23
+ *
24
+ * Text and byte buffers are bounded, including for a single large string/key;
25
+ * object-key sorting, ancestor tracking and paths still scale with input shape.
26
+ * The caller's input remains in memory. This is not a constant-memory dataset
27
+ * pipeline, a collision-resistant hash, or a substitute for exact equality.
28
+ */
29
+ export declare function canonicalFnv1a64(value: unknown): string;
19
30
  //# sourceMappingURL=canonical.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAyFA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ5C"}
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AA8GA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAsBpD;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA0CvD"}
package/dist/canonical.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ReservingError } from "./types.js";
2
+ import { createFnvAccumulator } from "./fnvAccumulator.js";
2
3
  /**
3
4
  * Canonical JSON serialization and the FNV-1a integrity hash — the SDK's
4
5
  * single equality oracle, relocated here from @actuarial-ts/compliance so
@@ -32,19 +33,25 @@ function isPlainObject(value) {
32
33
  const proto = Object.getPrototypeOf(value);
33
34
  return proto === Object.prototype || proto === null;
34
35
  }
35
- function canonicalize(value, path, seen) {
36
- if (value === null)
37
- return "null";
36
+ /** One traversal owns validation and property access order for both outputs. */
37
+ function canonicalize(value, path, seen, sink) {
38
+ if (value === null) {
39
+ sink.write("null");
40
+ return;
41
+ }
38
42
  switch (typeof value) {
39
43
  case "string":
40
- return JSON.stringify(value);
44
+ sink.quote(value);
45
+ return;
41
46
  case "boolean":
42
- return value ? "true" : "false";
47
+ sink.write(value ? "true" : "false");
48
+ return;
43
49
  case "number": {
44
50
  if (!Number.isFinite(value)) {
45
51
  throw new ReservingError("UNSUPPORTED_VALUE", `non-finite number (${String(value)}) at ${path}`);
46
52
  }
47
- return Object.is(value, -0) ? "0" : String(value);
53
+ sink.write(Object.is(value, -0) ? "0" : String(value));
54
+ return;
48
55
  }
49
56
  case "undefined":
50
57
  throw new ReservingError("UNSUPPORTED_VALUE", `undefined at ${path}`);
@@ -61,28 +68,33 @@ function canonicalize(value, path, seen) {
61
68
  throw new ReservingError("UNSUPPORTED_VALUE", `circular reference at ${path}`);
62
69
  }
63
70
  seen.add(obj);
64
- let out;
65
71
  if (Array.isArray(obj)) {
66
- const parts = [];
72
+ sink.startContainer("[");
67
73
  for (let i = 0; i < obj.length; i++) {
68
- parts.push(canonicalize(obj[i], `${path}[${i}]`, seen));
74
+ if (i > 0)
75
+ sink.write(",");
76
+ canonicalize(obj[i], `${path}[${i}]`, seen, sink);
69
77
  }
70
- out = `[${parts.join(",")}]`;
78
+ sink.endContainer("]");
71
79
  }
72
80
  else if (isPlainObject(obj)) {
73
81
  const keys = Object.keys(obj).sort();
74
- const parts = [];
75
- for (const key of keys) {
76
- parts.push(`${JSON.stringify(key)}:${canonicalize(obj[key], `${path}.${key}`, seen)}`);
82
+ sink.startContainer("{");
83
+ for (let i = 0; i < keys.length; i++) {
84
+ if (i > 0)
85
+ sink.write(",");
86
+ const key = keys[i];
87
+ sink.quote(key);
88
+ sink.write(":");
89
+ canonicalize(obj[key], `${path}.${key}`, seen, sink);
77
90
  }
78
- out = `{${parts.join(",")}}`;
91
+ sink.endContainer("}");
79
92
  }
80
93
  else {
81
94
  const name = obj.constructor?.name ?? "unknown";
82
95
  throw new ReservingError("UNSUPPORTED_VALUE", `non-plain object (${name}) at ${path}; only plain objects, arrays, and JSON primitives are canonicalizable`);
83
96
  }
84
97
  seen.delete(obj);
85
- return out;
86
98
  }
87
99
  /**
88
100
  * Deterministic JSON serialization: sorted object keys (recursively), arrays
@@ -92,11 +104,57 @@ function canonicalize(value, path, seen) {
92
104
  * "$.rows[2].ultimate" — for any value JSON cannot faithfully represent.
93
105
  */
94
106
  export function canonicalJson(value) {
95
- return canonicalize(value, "$", new Set());
107
+ // Join finished subtrees as before, rather than retaining a flat token array
108
+ // for the entire input graph alongside the final serialized string.
109
+ const frames = [[]];
110
+ const write = (text) => {
111
+ frames[frames.length - 1].push(text);
112
+ };
113
+ canonicalize(value, "$", new Set(), {
114
+ write,
115
+ quote(text) {
116
+ write(JSON.stringify(text));
117
+ },
118
+ startContainer(token) {
119
+ frames.push([token]);
120
+ },
121
+ endContainer(token) {
122
+ const parts = frames.pop();
123
+ parts.push(token);
124
+ write(parts.join(""));
125
+ },
126
+ });
127
+ return frames[0].join("");
128
+ }
129
+ const UTF8_CHUNK_CODE_UNITS = 16_384;
130
+ const QUOTED_CHUNK_CODE_UNITS = 4_096;
131
+ /** A valid surrogate pair must reach native escaping/encoding together. */
132
+ function chunkEnd(text, start, limit) {
133
+ let end = Math.min(start + limit, text.length);
134
+ const before = text.charCodeAt(end - 1);
135
+ const after = text.charCodeAt(end);
136
+ if (before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff)
137
+ end -= 1;
138
+ return end;
139
+ }
140
+ /** Reuse at most 48 KiB for long strings instead of duplicating all UTF-8 bytes. */
141
+ function* utf8Chunks(text) {
142
+ const encoder = new TextEncoder();
143
+ // Retain TextEncoder's runtime coercion for untyped JavaScript callers.
144
+ if (typeof text !== "string" || text.length <= UTF8_CHUNK_CODE_UNITS) {
145
+ yield encoder.encode(text);
146
+ return;
147
+ }
148
+ // A UTF-16 code unit needs at most three UTF-8 bytes (a surrogate pair
149
+ // needs four bytes for two code units), so encodeInto always consumes a chunk.
150
+ const buffer = new Uint8Array(UTF8_CHUNK_CODE_UNITS * 3);
151
+ for (let start = 0; start < text.length;) {
152
+ const end = chunkEnd(text, start, UTF8_CHUNK_CODE_UNITS);
153
+ const { written } = encoder.encodeInto(text.slice(start, end), buffer);
154
+ yield buffer.subarray(0, written);
155
+ start = end;
156
+ }
96
157
  }
97
- const FNV_OFFSET_BASIS = 0xcbf29ce484222325n;
98
- const FNV_PRIME = 0x100000001b3n;
99
- const MASK_64 = 0xffffffffffffffffn;
100
158
  /**
101
159
  * FNV-1a 64-bit hash over the UTF-8 bytes of `text`, returned as a 16-hex-char
102
160
  * string.
@@ -107,12 +165,64 @@ const MASK_64 = 0xffffffffffffffffn;
107
165
  * needing tamper evidence must sign or cryptographically hash the payload.
108
166
  */
109
167
  export function fnv1a64(text) {
110
- const bytes = new TextEncoder().encode(text);
111
- let hash = FNV_OFFSET_BASIS;
112
- for (const byte of bytes) {
113
- hash ^= BigInt(byte);
114
- hash = (hash * FNV_PRIME) & MASK_64;
115
- }
116
- return hash.toString(16).padStart(16, "0");
168
+ const hash = createFnvAccumulator();
169
+ for (const bytes of utf8Chunks(text))
170
+ hash.update(bytes);
171
+ return hash.digest();
172
+ }
173
+ /**
174
+ * The exact integrity tag `fnv1a64(canonicalJson(value))`, without constructing
175
+ * the complete canonical string or UTF-8 byte array. Validation, key ordering,
176
+ * escaping and unsupported-value error paths match `canonicalJson`.
177
+ *
178
+ * Text and byte buffers are bounded, including for a single large string/key;
179
+ * object-key sorting, ancestor tracking and paths still scale with input shape.
180
+ * The caller's input remains in memory. This is not a constant-memory dataset
181
+ * pipeline, a collision-resistant hash, or a substitute for exact equality.
182
+ */
183
+ export function canonicalFnv1a64(value) {
184
+ const hash = createFnvAccumulator();
185
+ const encoder = new TextEncoder();
186
+ const bytes = new Uint8Array(UTF8_CHUNK_CODE_UNITS * 3);
187
+ let buffered = "";
188
+ const flush = () => {
189
+ if (!buffered.length)
190
+ return;
191
+ // Three bytes per UTF-16 code unit always fit; pairs need only four for two.
192
+ const { written } = encoder.encodeInto(buffered, bytes);
193
+ hash.update(bytes.subarray(0, written));
194
+ buffered = "";
195
+ };
196
+ const write = (text) => {
197
+ for (let start = 0; start < text.length;) {
198
+ const end = chunkEnd(text, start, UTF8_CHUNK_CODE_UNITS - buffered.length);
199
+ if (end === start) {
200
+ flush();
201
+ continue;
202
+ }
203
+ buffered += text.slice(start, end);
204
+ start = end;
205
+ if (buffered.length >= UTF8_CHUNK_CODE_UNITS - 1)
206
+ flush();
207
+ }
208
+ };
209
+ canonicalize(value, "$", new Set(), {
210
+ write,
211
+ startContainer: write,
212
+ endContainer: write,
213
+ quote(text) {
214
+ write('"');
215
+ for (let start = 0; start < text.length;) {
216
+ const end = chunkEnd(text, start, QUOTED_CHUNK_CODE_UNITS);
217
+ // Bounded native escaping retains minimal JSON escape spelling and lone
218
+ // surrogate escapes without allocating one full escaped string atom.
219
+ write(JSON.stringify(text.slice(start, end)).slice(1, -1));
220
+ start = end;
221
+ }
222
+ write('"');
223
+ },
224
+ });
225
+ flush();
226
+ return hash.digest();
117
227
  }
118
228
  //# sourceMappingURL=canonical.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Private, invocation-scoped sharing of small, newly owned evidence nodes.
3
+ * This is not a validation boundary: callers must finish normalizing/cloning
4
+ * every child first, and must never submit caller-owned objects or SDK brands.
5
+ */
6
+ export interface DiagnosticEvidenceInternOptions {
7
+ readonly maxEntries?: number;
8
+ readonly maxSignatureCharacters?: number;
9
+ readonly maxCandidateProperties?: number;
10
+ }
11
+ type EvidenceMode = "plain" | "source" | "free";
12
+ export declare function createDiagnosticEvidenceInterner(options?: DiagnosticEvidenceInternOptions): {
13
+ internOwned<T extends object>(candidate: T, mode: EvidenceMode): T;
14
+ };
15
+ export {};
16
+ //# sourceMappingURL=diagnosticEvidenceIntern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnosticEvidenceIntern.d.ts","sourceRoot":"","sources":["../src/diagnosticEvidenceIntern.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAC1C;AAED,KAAK,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AA8BhD,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,+BAAoC,GAC5C;IACD,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,CAAC,CAAC;CACpE,CAyGA"}
@@ -0,0 +1,139 @@
1
+ const DEFAULT_MAX_ENTRIES = 100_000;
2
+ const DEFAULT_MAX_SIGNATURE_CHARACTERS = 16 * 1024 * 1024;
3
+ // Wide result envelopes are usually unique; focus the budget on their small
4
+ // repeated coordinates, sources, scopes, states, and short child lists.
5
+ const DEFAULT_MAX_CANDIDATE_PROPERTIES = 10;
6
+ const MAX_CANDIDATE_STRING_CHARACTERS = 4096;
7
+ function sameOwnedNode(left, right) {
8
+ if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right))
9
+ return false;
10
+ const leftKeys = Reflect.ownKeys(left);
11
+ const rightKeys = Reflect.ownKeys(right);
12
+ if (leftKeys.length !== rightKeys.length)
13
+ return false;
14
+ return leftKeys.every((key, index) => {
15
+ if (key !== rightKeys[index])
16
+ return false;
17
+ const a = Object.getOwnPropertyDescriptor(left, key);
18
+ const b = Object.getOwnPropertyDescriptor(right, key);
19
+ return ("value" in a &&
20
+ "value" in b &&
21
+ a.enumerable === b.enumerable &&
22
+ a.configurable === b.configurable &&
23
+ a.writable === b.writable &&
24
+ Object.is(a.value, b.value));
25
+ });
26
+ }
27
+ export function createDiagnosticEvidenceInterner(options = {}) {
28
+ const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
29
+ const maxSignatureCharacters = options.maxSignatureCharacters ?? DEFAULT_MAX_SIGNATURE_CHARACTERS;
30
+ const maxCandidateProperties = options.maxCandidateProperties ?? DEFAULT_MAX_CANDIDATE_PROPERTIES;
31
+ const pool = new Map();
32
+ const childIds = new WeakMap();
33
+ let nextChildId = 1;
34
+ let signatureCharacters = 0;
35
+ return {
36
+ internOwned(candidate, mode) {
37
+ if (!Object.isFrozen(candidate))
38
+ return candidate;
39
+ const prototype = Object.getPrototypeOf(candidate);
40
+ const array = Array.isArray(candidate);
41
+ if (array
42
+ ? prototype !== Array.prototype
43
+ : prototype !== null && prototype !== Object.prototype)
44
+ return candidate;
45
+ if (array && candidate.length >= maxCandidateProperties)
46
+ return candidate;
47
+ const keys = Reflect.ownKeys(candidate);
48
+ if (keys.length > maxCandidateProperties)
49
+ return candidate;
50
+ const signatureParts = [
51
+ mode,
52
+ array ? "array" : prototype === null ? "null" : "object",
53
+ ];
54
+ // A declined candidate must not grow persistent bookkeeping. Stage at
55
+ // most this small candidate's children, including repeated references,
56
+ // and commit their IDs only if the candidate enters the bounded pool.
57
+ let pendingChildIds;
58
+ let stringCharacters = 0;
59
+ for (const key of keys) {
60
+ // Diagnostic JSON does not contain symbols. Declining unexpected
61
+ // shapes is harmless and never invokes an accessor or caller method.
62
+ if (typeof key !== "string")
63
+ return candidate;
64
+ const descriptor = Object.getOwnPropertyDescriptor(candidate, key);
65
+ if (!("value" in descriptor))
66
+ return candidate;
67
+ const value = descriptor.value;
68
+ let tokenType;
69
+ let tokenValue;
70
+ if (value === null) {
71
+ tokenType = "null";
72
+ tokenValue = null;
73
+ }
74
+ else if (typeof value === "object") {
75
+ if (!Object.isFrozen(value))
76
+ return candidate;
77
+ tokenType = "object";
78
+ const existingId = childIds.get(value);
79
+ if (existingId !== undefined)
80
+ tokenValue = existingId;
81
+ else {
82
+ pendingChildIds ??= new Map();
83
+ let pendingId = pendingChildIds.get(value);
84
+ if (pendingId === undefined) {
85
+ pendingId = nextChildId + pendingChildIds.size;
86
+ pendingChildIds.set(value, pendingId);
87
+ }
88
+ tokenValue = pendingId;
89
+ }
90
+ }
91
+ else if (typeof value === "number") {
92
+ if (!Number.isFinite(value))
93
+ return candidate;
94
+ tokenType = "number";
95
+ tokenValue = Object.is(value, -0) ? "-0" : value;
96
+ }
97
+ else if (typeof value === "string" ||
98
+ typeof value === "boolean" ||
99
+ value === undefined) {
100
+ tokenType = typeof value;
101
+ tokenValue = value;
102
+ if (typeof value === "string")
103
+ stringCharacters += value.length;
104
+ }
105
+ else
106
+ return candidate;
107
+ stringCharacters += key.length;
108
+ if (stringCharacters > MAX_CANDIDATE_STRING_CHARACTERS)
109
+ return candidate;
110
+ // Frozen data properties are necessarily non-configurable and
111
+ // non-writable. Keep the varying enumerability bit (including array
112
+ // length) and a fixed four-slot typed tuple, without temporary nested
113
+ // arrays. The independent equality check still verifies every flag.
114
+ signatureParts.push(key, descriptor.enumerable, tokenType, tokenValue);
115
+ }
116
+ const signature = JSON.stringify(signatureParts);
117
+ // An unseen child cannot occur in an existing entry: every admitted
118
+ // entry committed all its child IDs. No equality hit is skipped here.
119
+ const existing = pendingChildIds ? undefined : pool.get(signature);
120
+ // Signatures encode exact children and descriptor/order information;
121
+ // independently check equality before sharing rather than treating a
122
+ // fingerprint as proof of equality.
123
+ if (existing !== undefined && sameOwnedNode(existing, candidate))
124
+ return existing;
125
+ if (pool.size < maxEntries &&
126
+ signatureCharacters + signature.length <= maxSignatureCharacters) {
127
+ if (pendingChildIds) {
128
+ for (const [child, id] of pendingChildIds)
129
+ childIds.set(child, id);
130
+ nextChildId += pendingChildIds.size;
131
+ }
132
+ pool.set(signature, candidate);
133
+ signatureCharacters += signature.length;
134
+ }
135
+ return candidate;
136
+ },
137
+ };
138
+ }
139
+ //# sourceMappingURL=diagnosticEvidenceIntern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnosticEvidenceIntern.js","sourceRoot":"","sources":["../src/diagnosticEvidenceIntern.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"diagnosticExposure.d.ts","sourceRoot":"","sources":["../src/diagnosticExposure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AAmBpC,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;CAC5C;AAED,MAAM,MAAM,6BAA6B,GACrC;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACpD;IACE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,KAAK,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;CAC3E,CAAC;AAEN,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;CAC5C;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,CAAC;CACvD,GACD;IACE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CACxB,SAAS,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CACnE,EAAE,CAAC;IACJ,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,SAAS,kCAAkC,EAAE,CAAC;CACtE,CAAC;AAEN,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,6BAA6B,CAyB/B;AA0OD,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,SAAS,6BAA6B,EAAE,EACtD,eAAe,EAAE,QAAQ,CACvB,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,oBAAoB,CAAC,CACvD,EACD,UAAU,CAAC,EAAE,oBAAoB,GAChC,SAAS,4BAA4B,EAAE,CA4IzC"}
1
+ {"version":3,"file":"diagnosticExposure.d.ts","sourceRoot":"","sources":["../src/diagnosticExposure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AA8HpC,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;CAC5C;AAED,MAAM,MAAM,6BAA6B,GACrC;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACpD;IACE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,KAAK,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;CAC3E,CAAC;AAEN,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;CAC5C;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,CAAC;CACvD,GACD;IACE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CACxB,SAAS,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CACnE,EAAE,CAAC;IACJ,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,SAAS,kCAAkC,EAAE,CAAC;CACtE,CAAC;AAEN,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,6BAA6B,CAyB/B;AA0OD,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,SAAS,6BAA6B,EAAE,EACtD,eAAe,EAAE,QAAQ,CACvB,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,oBAAoB,CAAC,CACvD,EACD,UAAU,CAAC,EAAE,oBAAoB,GAChC,SAAS,4BAA4B,EAAE,CA8IzC"}
@@ -5,7 +5,97 @@ import { compareDiagnosticIdentityValues } from "./diagnosticOrdering.js";
5
5
  import { normalizeDiagnosticPeriodWithAxis } from "./diagnosticPeriodAxis.js";
6
6
  import { validateDiagnosticPeriodAxisInput } from "./diagnosticDefinitions.js";
7
7
  import { DiagnosticValidationError, } from "./types.js";
8
- import { diagnosticJsonPreflight, hasDiagnosticOwn, isDiagnosticPlainRecord, isDiagnosticToken, snapshotDiagnosticJson, } from "./diagnosticRuntime.js";
8
+ import { diagnosticJsonPreflight, diagnosticRecord, hasDiagnosticOwn, isDiagnosticPlainRecord, isDiagnosticToken, snapshotDiagnosticJson, MAX_DIAGNOSTIC_JSON_DEPTH, } from "./diagnosticRuntime.js";
9
+ // Bound the collection separately from each untrusted record. The generic
10
+ // million-node JSON cap otherwise rejects legitimate files at ~71k–100k rows,
11
+ // depending only on how much source provenance each observation carries.
12
+ const MAX_EXPOSURE_OBSERVATIONS = 250_000;
13
+ // JSON enumeration skips hidden properties, but the strict exposure schema
14
+ // reads recognized own fields. Refuse hidden accessors before those reads.
15
+ function hiddenExposureAccessorIssues(value, path) {
16
+ if (!isDiagnosticPlainRecord(value))
17
+ return [];
18
+ const issues = [];
19
+ for (const key of Object.getOwnPropertyNames(value)) {
20
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
21
+ if (!descriptor.enumerable && !("value" in descriptor))
22
+ issues.push({
23
+ domain: "input",
24
+ code: "invalid-json-value",
25
+ path: propertyPath(path, key),
26
+ message: "JSON objects may contain only data properties",
27
+ });
28
+ }
29
+ return issues;
30
+ }
31
+ function exposureCollectionPreflight(value) {
32
+ if (!Array.isArray(value))
33
+ return diagnosticJsonPreflight(value, "input");
34
+ if (Object.getPrototypeOf(value) !== Array.prototype)
35
+ return [
36
+ {
37
+ domain: "input",
38
+ code: "invalid-json-value",
39
+ path: "$",
40
+ message: "Value must use a plain object or array prototype",
41
+ },
42
+ ];
43
+ if (value.length > MAX_EXPOSURE_OBSERVATIONS)
44
+ return [
45
+ {
46
+ domain: "input",
47
+ code: "expression-limit",
48
+ path: "$",
49
+ message: `Exposure observation count exceeds ${MAX_EXPOSURE_OBSERVATIONS}`,
50
+ },
51
+ ];
52
+ const issues = [];
53
+ for (const key of Reflect.ownKeys(value)) {
54
+ if (key === "length")
55
+ continue;
56
+ const index = typeof key === "string" ? Number(key) : Number.NaN;
57
+ if (Number.isInteger(index) &&
58
+ index >= 0 &&
59
+ index < value.length &&
60
+ String(index) === key)
61
+ continue;
62
+ issues.push({
63
+ domain: "input",
64
+ code: "invalid-json-value",
65
+ path: typeof key === "symbol" ? "$" : propertyPath("$", key),
66
+ message: "JSON arrays may contain only indexed data properties",
67
+ });
68
+ }
69
+ for (let index = 0; index < value.length; index++) {
70
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
71
+ if (!descriptor || !("value" in descriptor)) {
72
+ issues.push({
73
+ domain: "input",
74
+ code: "invalid-json-value",
75
+ path: `$[${index}]`,
76
+ message: "JSON arrays may contain only indexed data properties",
77
+ });
78
+ continue;
79
+ }
80
+ issues.push(...hiddenExposureAccessorIssues(descriptor.value, `$[${index}]`));
81
+ if (isDiagnosticPlainRecord(descriptor.value)) {
82
+ const source = Object.getOwnPropertyDescriptor(descriptor.value, "source");
83
+ if (source && "value" in source)
84
+ issues.push(...hiddenExposureAccessorIssues(source.value, `$[${index}].source`));
85
+ }
86
+ // The outer collection used to occupy depth 1: keep the exact depth
87
+ // contract, and retain the default million-node guard for each record.
88
+ for (const issue of diagnosticJsonPreflight(descriptor.value, "input", {
89
+ maxDepth: MAX_DIAGNOSTIC_JSON_DEPTH - 1,
90
+ }))
91
+ issues.push({ ...issue, path: `$[${index}]${issue.path.slice(1)}` });
92
+ }
93
+ return issues;
94
+ }
95
+ /** Only for new SDK-owned objects whose leaves have already been validated. */
96
+ function freezeExposureRecord(value) {
97
+ return Object.freeze(Object.assign(diagnosticRecord(), value));
98
+ }
9
99
  export function auditDiagnosticNumber(value) {
10
100
  if (value !== null && typeof value !== "number")
11
101
  throw new DiagnosticValidationError([
@@ -42,7 +132,7 @@ function validateExposureArguments(observations, timingByMeasure, periodAxis) {
42
132
  // Nonfinite exposure amounts are supported audited inputs. They are the
43
133
  // only non-JSON numbers permitted here; metadata still must be finite.
44
134
  const issues = [
45
- ...diagnosticJsonPreflight(observations, "input")
135
+ ...exposureCollectionPreflight(observations)
46
136
  .filter((issue) => !(issue.code === "invalid-json-value" &&
47
137
  issue.message === "JSON numeric value must be finite" &&
48
138
  /^\$\[\d+\]\.value$/.test(issue.path)))
@@ -197,14 +287,14 @@ export function reconcileDiagnosticExposures(observations, timingByMeasure, peri
197
287
  cohort.push(observation);
198
288
  cohorts.set(identity, cohort);
199
289
  }
200
- return snapshotDiagnosticJson([...cohorts.values()]
290
+ return Object.freeze([...cohorts.values()]
201
291
  .map((cohort) => {
202
292
  const first = cohort[0];
203
293
  const timing = hasDiagnosticOwn(timingByMeasure, first.measureId)
204
294
  ? timingByMeasure[first.measureId]
205
295
  : undefined;
206
296
  const audited = cohort
207
- .map((item) => ({
297
+ .map((item) => snapshotDiagnosticJson({
208
298
  sourceGroup: item.sourceGroup,
209
299
  origin: item.origin,
210
300
  ...(item.valuation === undefined
@@ -230,7 +320,7 @@ export function reconcileDiagnosticExposures(observations, timingByMeasure, peri
230
320
  issues.push("conflict");
231
321
  const validStaticCopies = timing === "origin-static" && issues.length === 0;
232
322
  if (issues.length > 0)
233
- return Object.freeze({
323
+ return freezeExposureRecord({
234
324
  measureId: first.measureId,
235
325
  key: first.key,
236
326
  status: "invalid",
@@ -241,8 +331,8 @@ export function reconcileDiagnosticExposures(observations, timingByMeasure, peri
241
331
  const value = audited[0].value;
242
332
  if (value.status !== "observed")
243
333
  throw new Error("unreachable invalid exposure state");
244
- const sources = normalizeDiagnosticSourceLocations(audited.map((item) => item.source));
245
- return Object.freeze({
334
+ const sources = normalizeDiagnosticSourceLocations(audited.map((item) => item.source)).map((source) => snapshotDiagnosticJson(source));
335
+ return freezeExposureRecord({
246
336
  measureId: first.measureId,
247
337
  key: first.key,
248
338
  status: "valid",