oh-my-knowledge 0.48.0 → 0.49.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 (243) hide show
  1. package/README.md +50 -18
  2. package/README.zh.md +55 -23
  3. package/dist/analysis/coverage-analyzer.d.ts +1 -0
  4. package/dist/analysis/coverage-analyzer.js +125 -62
  5. package/dist/analysis/failure-clusterer.js +2 -1
  6. package/dist/analysis/gap-analyzer.d.ts +2 -2
  7. package/dist/analysis/gap-analyzer.js +13 -3
  8. package/dist/analysis/hedging-classifier.d.ts +2 -2
  9. package/dist/analysis/hedging-classifier.js +3 -4
  10. package/dist/analysis/report-diagnostics.js +9 -7
  11. package/dist/analysis/sample-diagnostics.js +6 -6
  12. package/dist/artifact-graph/doctor.js +15 -7
  13. package/dist/assets/agent-skills/omk/SKILL.md +27 -7
  14. package/dist/assets/agent-skills/omk/references/commands.md +18 -17
  15. package/dist/authoring/evolver.d.ts +10 -6
  16. package/dist/authoring/evolver.js +496 -83
  17. package/dist/authoring/generator.d.ts +3 -3
  18. package/dist/authoring/generator.js +5 -10
  19. package/dist/authoring/sample-fixer.d.ts +8 -6
  20. package/dist/authoring/sample-fixer.js +76 -5
  21. package/dist/cli/commands/doctor.js +31 -14
  22. package/dist/cli/commands/eval/index.d.ts +3 -0
  23. package/dist/cli/commands/eval/index.js +163 -17
  24. package/dist/cli/commands/evolve.d.ts +4 -4
  25. package/dist/cli/commands/evolve.js +27 -13
  26. package/dist/cli/commands/init.js +16 -3
  27. package/dist/cli/commands/observe/inbox.js +28 -21
  28. package/dist/cli/commands/observe/index.js +20 -11
  29. package/dist/cli/commands/observe/ingest.d.ts +3 -0
  30. package/dist/cli/commands/observe/ingest.js +30 -2
  31. package/dist/cli/commands/sample.d.ts +6 -3
  32. package/dist/cli/commands/sample.js +72 -68
  33. package/dist/cli/lib/codex-model-hint.d.ts +9 -0
  34. package/dist/cli/lib/codex-model-hint.js +45 -0
  35. package/dist/cli/lib/generation-failure-hint.d.ts +2 -0
  36. package/dist/cli/lib/generation-failure-hint.js +61 -0
  37. package/dist/cli/lib/i18n-dict/common.d.ts +1 -1
  38. package/dist/cli/lib/i18n-dict/common.js +4 -0
  39. package/dist/cli/lib/i18n-dict/gen.d.ts +1 -1
  40. package/dist/cli/lib/i18n-dict/gen.js +38 -6
  41. package/dist/cli/lib/i18n-dict/help.js +6 -6
  42. package/dist/cli/lib/i18n-dict/init.d.ts +1 -1
  43. package/dist/cli/lib/i18n-dict/init.js +13 -9
  44. package/dist/cli/lib/i18n-dict/run.d.ts +1 -1
  45. package/dist/cli/lib/i18n-dict/run.js +34 -2
  46. package/dist/cli/lib/llm-failure-classifier.d.ts +2 -0
  47. package/dist/cli/lib/llm-failure-classifier.js +8 -0
  48. package/dist/cli/lib/parse-run-config.d.ts +6 -5
  49. package/dist/cli/lib/parse-run-config.js +16 -9
  50. package/dist/cli/lib/runtime-defaults.d.ts +21 -0
  51. package/dist/cli/lib/runtime-defaults.js +79 -0
  52. package/dist/diagnosis/observe-mapper.js +14 -15
  53. package/dist/diagnosis/observe-producer.js +3 -1
  54. package/dist/diagnosis/studio-projection.js +14 -7
  55. package/dist/diagnosis/types.d.ts +2 -0
  56. package/dist/diagnosis/types.js +12 -0
  57. package/dist/doctor/endpoint-rule.js +2 -1
  58. package/dist/eval-core/artifact-file-names.js +18 -1
  59. package/dist/eval-core/artifact-index.d.ts +7 -11
  60. package/dist/eval-core/artifact-index.js +139 -80
  61. package/dist/eval-core/cache.d.ts +12 -3
  62. package/dist/eval-core/cache.js +89 -29
  63. package/dist/eval-core/comparability.js +10 -6
  64. package/dist/eval-core/evaluation-execution.d.ts +2 -1
  65. package/dist/eval-core/evaluation-execution.js +122 -37
  66. package/dist/eval-core/evaluation-job.d.ts +4 -1
  67. package/dist/eval-core/evaluation-job.js +4 -1
  68. package/dist/eval-core/evaluation-reporting.d.ts +15 -13
  69. package/dist/eval-core/evaluation-reporting.js +54 -52
  70. package/dist/eval-core/execution-strategy.d.ts +2 -0
  71. package/dist/eval-core/execution-strategy.js +11 -9
  72. package/dist/eval-core/fact-checker.js +15 -7
  73. package/dist/eval-core/holdout.js +3 -2
  74. package/dist/eval-core/judge-independence.d.ts +2 -2
  75. package/dist/eval-core/mock-hook.cjs +23 -6
  76. package/dist/eval-core/mocks-runtime.js +30 -8
  77. package/dist/eval-core/report-document.d.ts +12 -0
  78. package/dist/eval-core/report-document.js +1151 -0
  79. package/dist/eval-core/report-extensions.d.ts +4 -0
  80. package/dist/eval-core/report-extensions.js +500 -0
  81. package/dist/eval-core/report-file-migration.js +7 -2
  82. package/dist/eval-core/resume-compatibility.d.ts +31 -0
  83. package/dist/eval-core/resume-compatibility.js +141 -0
  84. package/dist/eval-core/sample-fingerprint.d.ts +12 -0
  85. package/dist/eval-core/sample-fingerprint.js +193 -0
  86. package/dist/eval-core/schema.js +86 -31
  87. package/dist/eval-core/verdict.d.ts +8 -4
  88. package/dist/eval-core/verdict.js +24 -10
  89. package/dist/eval-workflows/batch-evaluation-workflow.d.ts +2 -1
  90. package/dist/eval-workflows/batch-evaluation-workflow.js +25 -12
  91. package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.d.ts +10 -5
  92. package/dist/eval-workflows/evaluation-pipeline/preflight-warnings.js +58 -21
  93. package/dist/eval-workflows/evaluation-pipeline/report-finalize.js +3 -1
  94. package/dist/eval-workflows/evaluation-pipeline/run-state.d.ts +4 -1
  95. package/dist/eval-workflows/evaluation-pipeline/run-state.js +4 -1
  96. package/dist/eval-workflows/evaluation-pipeline/test-set-hash.d.ts +6 -5
  97. package/dist/eval-workflows/evaluation-pipeline/test-set-hash.js +17 -10
  98. package/dist/eval-workflows/evaluation-pipeline.js +12 -7
  99. package/dist/eval-workflows/run-evaluation.d.ts +9 -7
  100. package/dist/eval-workflows/run-evaluation.js +79 -51
  101. package/dist/executors/anthropic-api.js +65 -9
  102. package/dist/executors/claude-cli.js +16 -79
  103. package/dist/executors/claude-protocol.d.ts +28 -0
  104. package/dist/executors/claude-protocol.js +180 -0
  105. package/dist/executors/claude-sdk-trace.js +56 -28
  106. package/dist/executors/claude-sdk.d.ts +1 -0
  107. package/dist/executors/claude-sdk.js +39 -93
  108. package/dist/executors/codex-cli-trace.js +166 -31
  109. package/dist/executors/codex-cli.d.ts +6 -8
  110. package/dist/executors/codex-cli.js +49 -151
  111. package/dist/executors/codex-protocol.d.ts +24 -0
  112. package/dist/executors/codex-protocol.js +234 -0
  113. package/dist/executors/codex-sdk.js +68 -120
  114. package/dist/executors/gemini.js +88 -13
  115. package/dist/executors/index.d.ts +2 -3
  116. package/dist/executors/index.js +5 -3
  117. package/dist/executors/openai-api.js +70 -9
  118. package/dist/executors/runtime-fingerprint.js +88 -11
  119. package/dist/executors/script-command.d.ts +8 -0
  120. package/dist/executors/script-command.js +87 -0
  121. package/dist/executors/script.js +202 -29
  122. package/dist/executors/shared.d.ts +35 -3
  123. package/dist/executors/shared.js +113 -15
  124. package/dist/grading/assertions.d.ts +1 -1
  125. package/dist/grading/assertions.js +19 -9
  126. package/dist/grading/diagnostic.d.ts +9 -2
  127. package/dist/grading/diagnostic.js +25 -2
  128. package/dist/grading/index.js +10 -4
  129. package/dist/grading/judge.js +19 -6
  130. package/dist/grading/layered-scores.d.ts +2 -3
  131. package/dist/grading/layered-scores.js +2 -3
  132. package/dist/inputs/load-samples.d.ts +1 -2
  133. package/dist/inputs/load-samples.js +23 -1
  134. package/dist/inputs/mcp-resolver.js +6 -3
  135. package/dist/inputs/sample-document.d.ts +11 -0
  136. package/dist/inputs/sample-document.js +96 -0
  137. package/dist/managed/evidence.d.ts +1 -0
  138. package/dist/managed/evidence.js +1 -1
  139. package/dist/managed/store.js +200 -91
  140. package/dist/observability/codex-trace-adapter.d.ts +5 -0
  141. package/dist/observability/codex-trace-adapter.js +850 -0
  142. package/dist/observability/experience.d.ts +32 -6
  143. package/dist/observability/experience.js +2695 -459
  144. package/dist/observability/feedback-matchers.js +16 -1
  145. package/dist/observability/inbox-view-model.d.ts +1 -1
  146. package/dist/observability/inbox-view-model.js +19 -14
  147. package/dist/observability/inbox.d.ts +7 -1
  148. package/dist/observability/inbox.js +632 -124
  149. package/dist/observability/problem-patterns.js +2 -0
  150. package/dist/observability/review-state.d.ts +6 -0
  151. package/dist/observability/review-state.js +235 -63
  152. package/dist/observability/skill-chain-advisories.js +1 -1
  153. package/dist/observability/skill-chain.js +17 -4
  154. package/dist/observability/skill-health-analyzer.d.ts +32 -7
  155. package/dist/observability/skill-health-analyzer.js +194 -121
  156. package/dist/observability/skill-health-report.d.ts +10 -0
  157. package/dist/observability/skill-health-report.js +620 -0
  158. package/dist/observability/soft-standards/constants.d.ts +0 -1
  159. package/dist/observability/soft-standards/constants.js +0 -1
  160. package/dist/observability/soft-standards/index.d.ts +1 -1
  161. package/dist/observability/soft-standards/index.js +1 -1
  162. package/dist/observability/soft-standards/llm-extractor.js +8 -10
  163. package/dist/observability/soft-standards/skill-standards-store.d.ts +2 -1
  164. package/dist/observability/soft-standards/skill-standards-store.js +59 -18
  165. package/dist/observability/soft-standards/types.d.ts +2 -2
  166. package/dist/observability/trace-adapter.d.ts +12 -7
  167. package/dist/observability/trace-adapter.js +11 -9
  168. package/dist/observability/trace-attribution.d.ts +13 -5
  169. package/dist/observability/trace-attribution.js +315 -21
  170. package/dist/observability/trace-ingestion.d.ts +9 -0
  171. package/dist/observability/trace-ingestion.js +80 -0
  172. package/dist/observability/trace-ir.d.ts +113 -0
  173. package/dist/observability/trace-ir.js +87 -0
  174. package/dist/observability/trace-segmenter.d.ts +19 -6
  175. package/dist/observability/trace-segmenter.js +377 -196
  176. package/dist/observability/trace-session-index.d.ts +19 -0
  177. package/dist/observability/trace-session-index.js +68 -0
  178. package/dist/observability/trace-source.d.ts +12 -4
  179. package/dist/observability/trace-source.js +939 -215
  180. package/dist/renderer/html-renderer.js +37 -6
  181. package/dist/renderer/icons.js +3 -0
  182. package/dist/renderer/observation-inbox-renderer.js +208 -90
  183. package/dist/renderer/skill-detail-renderer.js +452 -109
  184. package/dist/renderer/skill-health-renderer.js +69 -12
  185. package/dist/renderer/summary.js +28 -7
  186. package/dist/renderer/table.js +21 -4
  187. package/dist/renderer/test-view.d.ts +1 -0
  188. package/dist/renderer/test-view.js +44 -9
  189. package/dist/server/indexed-report-store.js +14 -18
  190. package/dist/server/job-store.js +64 -26
  191. package/dist/server/report-server.js +190 -78
  192. package/dist/server/report-store.js +57 -80
  193. package/dist/server/skill-index.js +143 -49
  194. package/dist/server/skill-insights.js +44 -5
  195. package/dist/shared/artifact-graph.d.ts +3 -0
  196. package/dist/shared/artifact-graph.js +224 -0
  197. package/dist/shared/assertion-types.d.ts +8 -0
  198. package/dist/shared/assertion-types.js +46 -0
  199. package/dist/shared/atomic-json.d.ts +8 -0
  200. package/dist/shared/atomic-json.js +33 -0
  201. package/dist/shared/diagnosis-schema.d.ts +9 -0
  202. package/dist/shared/diagnosis-schema.js +181 -0
  203. package/dist/shared/doctor-report.d.ts +3 -0
  204. package/dist/shared/doctor-report.js +103 -0
  205. package/dist/shared/evaluation-job.d.ts +6 -0
  206. package/dist/shared/evaluation-job.js +217 -0
  207. package/dist/shared/executor-result.d.ts +17 -0
  208. package/dist/shared/executor-result.js +221 -0
  209. package/dist/shared/file-lock.d.ts +12 -0
  210. package/dist/shared/file-lock.js +129 -0
  211. package/dist/shared/json-value.d.ts +5 -0
  212. package/dist/shared/json-value.js +36 -0
  213. package/dist/shared/keyed-mutex.d.ts +7 -0
  214. package/dist/shared/keyed-mutex.js +24 -0
  215. package/dist/shared/record-count.d.ts +8 -0
  216. package/dist/shared/record-count.js +43 -0
  217. package/dist/shared/sample-contract.d.ts +3 -0
  218. package/dist/shared/sample-contract.js +332 -0
  219. package/dist/shared/timestamp.d.ts +6 -0
  220. package/dist/shared/timestamp.js +64 -0
  221. package/dist/shared/token-usage.d.ts +19 -0
  222. package/dist/shared/token-usage.js +50 -0
  223. package/dist/shared/tool-call-status.d.ts +8 -0
  224. package/dist/shared/tool-call-status.js +28 -0
  225. package/dist/shared/tool-identity.d.ts +21 -0
  226. package/dist/shared/tool-identity.js +84 -0
  227. package/dist/shared/tool-search.js +73 -16
  228. package/dist/shared/trace-projection.d.ts +5 -0
  229. package/dist/shared/trace-projection.js +20 -0
  230. package/dist/shared/trace-source-kind.d.ts +3 -0
  231. package/dist/shared/trace-source-kind.js +12 -0
  232. package/dist/types/diagnosis.d.ts +2 -0
  233. package/dist/types/eval.d.ts +4 -0
  234. package/dist/types/executor.d.ts +32 -5
  235. package/dist/types/index.d.ts +1 -0
  236. package/dist/types/index.js +1 -0
  237. package/dist/types/judge.d.ts +2 -0
  238. package/dist/types/observability.d.ts +116 -9
  239. package/dist/types/report.d.ts +58 -6
  240. package/dist/types/skill-index.d.ts +7 -0
  241. package/dist/types/trace.d.ts +2 -0
  242. package/dist/types/trace.js +1 -0
  243. package/package.json +9 -5
@@ -0,0 +1,1151 @@
1
+ import { dirname, isAbsolute } from 'node:path';
2
+ import { normalizeRfc3339Timestamp } from '../shared/timestamp.js';
3
+ import { checkedSumTokenCounts } from '../shared/token-usage.js';
4
+ import { isValidMockStats, isValidToolCallInfo, isValidTurnInfo, } from '../shared/executor-result.js';
5
+ import { evaluationRequestsEqual, isValidEvaluationJob, isValidEvaluationRequest, isValidEvaluationRun, } from '../shared/evaluation-job.js';
6
+ import { isToolCallCancelled, isToolCallFailure, isToolCallSuccess, isToolCallUnknown, } from '../shared/tool-call-status.js';
7
+ import { incrementRecordCount } from '../shared/record-count.js';
8
+ import { isAnalysisResult, isSampleSnapshotRecord, isVarianceData, } from './report-extensions.js';
9
+ import { reportFilePath, safeArtifactFileStem } from './artifact-file-names.js';
10
+ function isRecord(value) {
11
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
12
+ }
13
+ function isNonNegativeNumber(value) {
14
+ return typeof value === 'number'
15
+ && Number.isFinite(value)
16
+ && value >= 0
17
+ && value <= Number.MAX_SAFE_INTEGER;
18
+ }
19
+ function isNonNegativeInteger(value) {
20
+ return Number.isSafeInteger(value) && value >= 0;
21
+ }
22
+ function isFiniteNumber(value) {
23
+ return typeof value === 'number'
24
+ && Number.isFinite(value)
25
+ && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
26
+ }
27
+ function isOptionalBoolean(value) {
28
+ return value === undefined || typeof value === 'boolean';
29
+ }
30
+ function isRate(value) {
31
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1;
32
+ }
33
+ function isScore(value) {
34
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 5;
35
+ }
36
+ function isCorrelation(value) {
37
+ return typeof value === 'number' && Number.isFinite(value) && value >= -1 && value <= 1;
38
+ }
39
+ function isStringArray(value) {
40
+ return Array.isArray(value)
41
+ && value.length > 0
42
+ && value.every((entry) => typeof entry === 'string' && entry.length > 0);
43
+ }
44
+ function isStringRecord(value) {
45
+ return isRecord(value)
46
+ && Object.values(value).every((entry) => typeof entry === 'string');
47
+ }
48
+ function isSampleHashRecord(value) {
49
+ return isRecord(value)
50
+ && Object.keys(value).every((key) => key.length > 0)
51
+ && Object.values(value).every((entry) => typeof entry === 'string' && /^[a-f0-9]{12}$/.test(entry));
52
+ }
53
+ function isRuntimePackage(value) {
54
+ return isRecord(value)
55
+ && typeof value.name === 'string'
56
+ && value.name.length > 0
57
+ && (value.version === undefined || typeof value.version === 'string')
58
+ && (value.error === undefined || typeof value.error === 'string');
59
+ }
60
+ function isRuntimeFingerprint(value) {
61
+ if (!isRecord(value)
62
+ || typeof value.executor !== 'string'
63
+ || value.executor.length === 0
64
+ || typeof value.model !== 'string'
65
+ || value.model.length === 0
66
+ || !['agent-cli', 'agent-sdk', 'api', 'script', 'unknown'].includes(String(value.runtimeKind))
67
+ || typeof value.fingerprint !== 'string'
68
+ || value.fingerprint.length === 0
69
+ || !isRecord(value.capabilities)
70
+ || !['native', 'prepended', 'none', 'unknown'].includes(String(value.capabilities.systemPrompt))
71
+ || !['reported', 'not-reported', 'unknown'].includes(String(value.capabilities.costUSD))
72
+ || !['native', 'best-effort', 'none', 'unknown'].includes(String(value.capabilities.trace))
73
+ || !['full', 'full-no-partial', 'cwd-only', 'none', 'unknown'].includes(String(value.capabilities.skillIsolation))
74
+ || (value.sdk !== undefined && !isRuntimePackage(value.sdk)))
75
+ return false;
76
+ if (value.binary === undefined)
77
+ return true;
78
+ return isRecord(value.binary)
79
+ && typeof value.binary.name === 'string'
80
+ && value.binary.name.length > 0
81
+ && ['path', 'bundled', 'none', 'unknown'].includes(String(value.binary.source))
82
+ && (value.binary.version === undefined || typeof value.binary.version === 'string')
83
+ && (value.binary.path === undefined || typeof value.binary.path === 'string')
84
+ && (value.binary.contentHash === undefined
85
+ || (typeof value.binary.contentHash === 'string'
86
+ && /^[a-f0-9]{64}$/.test(value.binary.contentHash)))
87
+ && (value.binary.package === undefined || isRuntimePackage(value.binary.package))
88
+ && (value.binary.error === undefined || typeof value.binary.error === 'string');
89
+ }
90
+ function isDiagnosticConfig(value) {
91
+ if (!isRecord(value) || typeof value.enabled !== 'boolean')
92
+ return false;
93
+ if (!value.enabled) {
94
+ return value.executor === undefined
95
+ && value.model === undefined
96
+ && value.runtime === undefined
97
+ && value.promptHash === undefined;
98
+ }
99
+ return typeof value.executor === 'string'
100
+ && value.executor.length > 0
101
+ && typeof value.model === 'string'
102
+ && value.model.length > 0
103
+ && isRuntimeFingerprint(value.runtime)
104
+ && value.runtime.executor === value.executor
105
+ && value.runtime.model === value.model
106
+ && typeof value.promptHash === 'string'
107
+ && /^[a-f0-9]{12}$/.test(value.promptHash);
108
+ }
109
+ function isOptionalNonNegativeInteger(value) {
110
+ return value === undefined || isNonNegativeInteger(value);
111
+ }
112
+ function isOptionalStringArray(value) {
113
+ return value === undefined
114
+ || (Array.isArray(value)
115
+ && value.every((entry) => typeof entry === 'string' && entry.length > 0));
116
+ }
117
+ function isCountRecord(value) {
118
+ return isRecord(value)
119
+ && Object.keys(value).every((key) => key.length > 0)
120
+ && Object.values(value).every(isNonNegativeInteger);
121
+ }
122
+ function traceProjectionIsConsistent(value) {
123
+ for (const field of [
124
+ 'fullNumTurns',
125
+ 'numSubAgents',
126
+ 'assistantTurns',
127
+ 'toolTurns',
128
+ 'numToolCalls',
129
+ 'numToolFailures',
130
+ 'numToolCancelled',
131
+ 'numToolUnknown',
132
+ ]) {
133
+ if (!isOptionalNonNegativeInteger(value[field]))
134
+ return false;
135
+ }
136
+ if ((value.toolSuccessRate !== undefined && !isRate(value.toolSuccessRate))
137
+ || (value.traceCoverage !== undefined && !isRate(value.traceCoverage))
138
+ || !isOptionalStringArray(value.toolNames)
139
+ || (value.toolDistribution !== undefined && !isCountRecord(value.toolDistribution))
140
+ || (value.turns !== undefined && (!Array.isArray(value.turns)
141
+ || !value.turns.every(isValidTurnInfo)))
142
+ || (value.toolCalls !== undefined && (!Array.isArray(value.toolCalls)
143
+ || !value.toolCalls.every(isValidToolCallInfo)))
144
+ || (value.mockStats !== undefined && !isValidMockStats(value.mockStats)))
145
+ return false;
146
+ if (Array.isArray(value.turns)) {
147
+ const assistantTurns = value.turns.filter((turn) => isRecord(turn) && turn.role === 'assistant').length;
148
+ const toolTurns = value.turns.filter((turn) => isRecord(turn) && turn.role === 'tool').length;
149
+ if ((value.assistantTurns !== undefined && value.assistantTurns !== assistantTurns)
150
+ || (value.toolTurns !== undefined && value.toolTurns !== toolTurns))
151
+ return false;
152
+ }
153
+ if (!Array.isArray(value.toolCalls)) {
154
+ return true;
155
+ }
156
+ const toolCalls = value.toolCalls;
157
+ if (value.numToolCalls !== undefined && value.numToolCalls !== toolCalls.length)
158
+ return false;
159
+ const failures = toolCalls.filter(isToolCallFailure).length;
160
+ const cancelled = toolCalls.filter(isToolCallCancelled).length;
161
+ const unknown = toolCalls.filter(isToolCallUnknown).length;
162
+ const successes = toolCalls.filter(isToolCallSuccess).length;
163
+ if ((value.numToolFailures !== undefined && value.numToolFailures !== failures)
164
+ || (value.numToolCancelled !== undefined && value.numToolCancelled !== cancelled)
165
+ || (value.numToolUnknown !== undefined && value.numToolUnknown !== unknown))
166
+ return false;
167
+ const comparable = successes + failures;
168
+ const expectedRate = comparable > 0
169
+ ? Number((successes / comparable).toFixed(2))
170
+ : undefined;
171
+ if (value.toolSuccessRate !== undefined && value.toolSuccessRate !== expectedRate)
172
+ return false;
173
+ const expectedNames = [...new Set(toolCalls.map((call) => call.tool))];
174
+ if (value.toolNames !== undefined) {
175
+ const toolNames = value.toolNames;
176
+ if (toolNames.length !== expectedNames.length
177
+ || !expectedNames.every((name) => toolNames.includes(name)))
178
+ return false;
179
+ }
180
+ if (value.toolDistribution === undefined)
181
+ return true;
182
+ if (!isCountRecord(value.toolDistribution))
183
+ return false;
184
+ const toolDistribution = value.toolDistribution;
185
+ const expectedDistribution = Object.create(null);
186
+ for (const call of toolCalls) {
187
+ incrementRecordCount(expectedDistribution, call.tool);
188
+ }
189
+ return hasExactKeys(toolDistribution, Object.keys(expectedDistribution))
190
+ && Object.entries(expectedDistribution).every(([name, count]) => toolDistribution[name] === count);
191
+ }
192
+ function isJudgeModels(value) {
193
+ return Array.isArray(value)
194
+ && value.length > 0
195
+ && value.every((entry) => isRecord(entry)
196
+ && typeof entry.executor === 'string'
197
+ && entry.executor.length > 0
198
+ && typeof entry.model === 'string'
199
+ && entry.model.length > 0
200
+ && (entry.runtime === undefined
201
+ || (isRuntimeFingerprint(entry.runtime)
202
+ && entry.runtime.executor === entry.executor
203
+ && entry.runtime.model === entry.model)));
204
+ }
205
+ function isSummaryJudgeModels(value) {
206
+ return Array.isArray(value)
207
+ && value.length > 0
208
+ && value.every((entry) => isRecord(entry)
209
+ && typeof entry.executor === 'string'
210
+ && typeof entry.model === 'string'
211
+ && entry.model.length > 0);
212
+ }
213
+ function isBaseJudgeAgreement(value) {
214
+ return isRecord(value)
215
+ && (value.pearson === undefined || isCorrelation(value.pearson))
216
+ && isNonNegativeNumber(value.meanAbsDiff)
217
+ && value.meanAbsDiff <= 4
218
+ && isNonNegativeInteger(value.pairCount);
219
+ }
220
+ function isSummaryJudgeAgreement(value) {
221
+ return isBaseJudgeAgreement(value)
222
+ && isRecord(value)
223
+ && isNonNegativeInteger(value.sampleCount);
224
+ }
225
+ function isBootstrapCI(value) {
226
+ return isRecord(value)
227
+ && isScore(value.low)
228
+ && isScore(value.high)
229
+ && isScore(value.estimate)
230
+ && value.low <= value.estimate
231
+ && value.estimate <= value.high
232
+ && isNonNegativeInteger(value.samples)
233
+ && value.samples > 0;
234
+ }
235
+ function isDiffBootstrapCI(value) {
236
+ if (!isRecord(value)
237
+ || !isFiniteNumber(value.low)
238
+ || !isFiniteNumber(value.high)
239
+ || !isFiniteNumber(value.estimate)
240
+ || value.low > value.estimate
241
+ || value.estimate > value.high
242
+ || !isNonNegativeInteger(value.samples)
243
+ || value.samples <= 0
244
+ || typeof value.significant !== 'boolean')
245
+ return false;
246
+ return value.significant === (value.low > 0 || value.high < 0);
247
+ }
248
+ function isPairComparisons(value, variants) {
249
+ if (!Array.isArray(value))
250
+ return false;
251
+ const pairs = new Set();
252
+ return value.every((entry) => {
253
+ if (!isRecord(entry)
254
+ || typeof entry.control !== 'string'
255
+ || typeof entry.treatment !== 'string'
256
+ || entry.control === entry.treatment
257
+ || !variants.includes(entry.control)
258
+ || !variants.includes(entry.treatment)
259
+ || (entry.diffBootstrapCI !== undefined
260
+ && !isDiffBootstrapCI(entry.diffBootstrapCI))
261
+ || (entry.alpha !== undefined
262
+ && (!isRate(entry.alpha) || entry.alpha <= 0)))
263
+ return false;
264
+ const key = `${entry.control}\u0000${entry.treatment}`;
265
+ if (pairs.has(key))
266
+ return false;
267
+ pairs.add(key);
268
+ return true;
269
+ });
270
+ }
271
+ function isBudget(value) {
272
+ return isRecord(value)
273
+ && ['totalUSD', 'perSampleUSD', 'perSampleMs'].every((field) => value[field] === undefined || isNonNegativeNumber(value[field]));
274
+ }
275
+ function isHumanAgreement(value, variants) {
276
+ if (!isRecord(value)
277
+ || !isFiniteNumber(value.alpha)
278
+ || value.alpha > 1
279
+ || !isRecord(value.alphaCI)
280
+ || !isFiniteNumber(value.alphaCI.low)
281
+ || !isFiniteNumber(value.alphaCI.high)
282
+ || !isFiniteNumber(value.alphaCI.estimate)
283
+ || value.alphaCI.low > value.alphaCI.estimate
284
+ || value.alphaCI.estimate > value.alphaCI.high
285
+ || !isNonNegativeInteger(value.alphaCI.samples)
286
+ || value.alphaCI.samples <= 0
287
+ || !isCorrelation(value.weightedKappa)
288
+ || !isCorrelation(value.pearson)
289
+ || !isNonNegativeInteger(value.sampleCount)
290
+ || typeof value.variant !== 'string'
291
+ || !variants.includes(value.variant)
292
+ || typeof value.goldAnnotator !== 'string'
293
+ || typeof value.goldVersion !== 'string'
294
+ || (value.contaminationWarning !== undefined && typeof value.contaminationWarning !== 'string')
295
+ || !isNonNegativeInteger(value.missingCount)
296
+ || !isNonNegativeInteger(value.unscoredCount))
297
+ return false;
298
+ return Math.abs(value.alpha - value.alphaCI.estimate) <= 1e-9;
299
+ }
300
+ function isSkillIsolation(value, variants) {
301
+ return isRecord(value)
302
+ && hasExactKeys(value, variants)
303
+ && Object.values(value).every((entry) => entry === null
304
+ || (Array.isArray(entry)
305
+ && entry.every((skill) => typeof skill === 'string' && skill.length > 0)));
306
+ }
307
+ function isGitInfo(value) {
308
+ return isRecord(value)
309
+ && typeof value.commit === 'string'
310
+ && typeof value.commitShort === 'string'
311
+ && typeof value.branch === 'string'
312
+ && typeof value.dirty === 'boolean';
313
+ }
314
+ function isVariantConfigs(value, variants, skillIsolation, request) {
315
+ if (!Array.isArray(value) || value.length !== variants.length)
316
+ return false;
317
+ const configs = new Map();
318
+ for (const entry of value) {
319
+ if (!isRecord(entry)
320
+ || typeof entry.variant !== 'string'
321
+ || !variants.includes(entry.variant)
322
+ || configs.has(entry.variant)
323
+ || !['baseline', 'skill', 'prompt', 'agent', 'workflow'].includes(String(entry.artifactKind))
324
+ || ![
325
+ 'baseline',
326
+ 'variant-name',
327
+ 'file-path',
328
+ 'git',
329
+ 'inline',
330
+ 'custom',
331
+ ].includes(String(entry.artifactSource))
332
+ || ![
333
+ 'baseline',
334
+ 'system-prompt',
335
+ 'user-prompt',
336
+ 'agent-session',
337
+ 'workflow-session',
338
+ ].includes(String(entry.executionStrategy))
339
+ || ![
340
+ 'baseline',
341
+ 'runtime-context-only',
342
+ 'artifact-injection',
343
+ ].includes(String(entry.experimentType))
344
+ || (entry.experimentRole !== 'control' && entry.experimentRole !== 'treatment')
345
+ || typeof entry.hasArtifactContent !== 'boolean'
346
+ || (entry.cwd !== null && typeof entry.cwd !== 'string')
347
+ || (entry.locator !== undefined && typeof entry.locator !== 'string')
348
+ || (entry.ref !== undefined && typeof entry.ref !== 'string')
349
+ || (entry.resolvedCommit !== undefined && typeof entry.resolvedCommit !== 'string')
350
+ || (entry.allowedSkills !== undefined
351
+ && (!Array.isArray(entry.allowedSkills)
352
+ || !entry.allowedSkills.every((skill) => typeof skill === 'string' && skill.length > 0)
353
+ || new Set(entry.allowedSkills).size !== entry.allowedSkills.length)))
354
+ return false;
355
+ configs.set(entry.variant, entry);
356
+ }
357
+ if (!variants.every((variant) => configs.has(variant)))
358
+ return false;
359
+ if (isRecord(skillIsolation)) {
360
+ for (const variant of variants) {
361
+ const configured = configs.get(variant)?.allowedSkills;
362
+ const isolated = skillIsolation[variant];
363
+ if (isolated === null
364
+ ? configured !== undefined
365
+ : JSON.stringify(configured) !== JSON.stringify(isolated))
366
+ return false;
367
+ }
368
+ }
369
+ if (isValidEvaluationRequest(request)) {
370
+ for (const artifact of request.artifacts) {
371
+ const configured = configs.get(artifact.name);
372
+ if (!configured
373
+ || configured.artifactKind !== artifact.kind
374
+ || configured.artifactSource !== artifact.source)
375
+ return false;
376
+ }
377
+ }
378
+ return true;
379
+ }
380
+ function judgeConfigsMatch(request, judgeModels) {
381
+ return request.judgeModels.length === judgeModels.length
382
+ && request.judgeModels.every((judge, index) => judge.executor === judgeModels[index]?.executor
383
+ && judge.model === judgeModels[index]?.model);
384
+ }
385
+ function embeddedLifecycleIsValid(value, expectedReportId, requireBatch = false) {
386
+ const request = value.request;
387
+ const run = value.run;
388
+ const job = value.job;
389
+ if ((request !== undefined && !isValidEvaluationRequest(request))
390
+ || (run !== undefined && !isValidEvaluationRun(run, expectedReportId))
391
+ || (job !== undefined && !isValidEvaluationJob(job)))
392
+ return false;
393
+ const reportTimestamp = normalizeRfc3339Timestamp(value.timestamp);
394
+ if (!reportTimestamp)
395
+ return false;
396
+ const reportTimestampMs = Date.parse(reportTimestamp);
397
+ const typedRequest = request === undefined ? undefined : request;
398
+ const typedRun = run === undefined ? undefined : run;
399
+ const typedJob = job === undefined ? undefined : job;
400
+ const judgeModels = value.judgeModels;
401
+ if (typedRequest !== undefined
402
+ && (typedRequest.model !== value.model
403
+ || typedRequest.executor !== value.executor
404
+ || typedRequest.noJudge !== (value.noJudge === true)
405
+ || typedRequest.effort !== value.effort
406
+ || !judgeConfigsMatch(typedRequest, judgeModels)
407
+ || (requireBatch && typedRequest.batch !== true)))
408
+ return false;
409
+ if (typedRun !== undefined
410
+ && (typedRun.status !== 'succeeded'
411
+ || typedRun.finishedAt === undefined
412
+ || Date.parse(typedRun.finishedAt) > reportTimestampMs))
413
+ return false;
414
+ if (typedJob !== undefined
415
+ && (typedJob.status !== 'succeeded'
416
+ || typedJob.runId !== expectedReportId
417
+ || typedJob.resultReportId !== expectedReportId
418
+ || typedJob.finishedAt === undefined
419
+ || Date.parse(typedJob.finishedAt) > reportTimestampMs
420
+ || typedJob.request.model !== value.model
421
+ || typedJob.request.executor !== value.executor
422
+ || typedJob.request.noJudge !== (value.noJudge === true)
423
+ || typedJob.request.effort !== value.effort
424
+ || !judgeConfigsMatch(typedJob.request, judgeModels)
425
+ || (requireBatch && typedJob.request.batch !== true)))
426
+ return false;
427
+ if (typedRequest !== undefined
428
+ && typedJob !== undefined
429
+ && !evaluationRequestsEqual(typedRequest, typedJob.request))
430
+ return false;
431
+ if (typedRun !== undefined
432
+ && typedJob !== undefined
433
+ && (typedRun.runId !== typedJob.runId
434
+ || typedRun.startedAt !== typedJob.startedAt
435
+ || typedRun.finishedAt !== typedJob.finishedAt))
436
+ return false;
437
+ return true;
438
+ }
439
+ function isEvolveMetadata(value, variants) {
440
+ if (!isRecord(value)
441
+ || typeof value.skillName !== 'string'
442
+ || value.skillName.length === 0
443
+ || (value.skillPath !== undefined
444
+ && typeof value.skillPath !== 'string')
445
+ || (value.processCostUSD !== undefined
446
+ && !isNonNegativeNumber(value.processCostUSD))
447
+ || !isOptionalBoolean(value.processCostReported))
448
+ return false;
449
+ if (value.sourceReports === undefined)
450
+ return true;
451
+ if (!Array.isArray(value.sourceReports)
452
+ || value.sourceReports.length !== variants.length)
453
+ return false;
454
+ const reportIds = new Set();
455
+ let previousRound = -1;
456
+ return value.sourceReports.every((source, index) => {
457
+ if (!isRecord(source)
458
+ || !isNonNegativeInteger(source.round)
459
+ || source.round <= previousRound
460
+ || typeof source.accepted !== 'boolean'
461
+ || !isCanonicalReportId(source.reportId)
462
+ || reportIds.has(source.reportId)
463
+ || typeof source.variant !== 'string'
464
+ || source.variant.length === 0
465
+ || variants[index] !== `round-${source.round}`)
466
+ return false;
467
+ previousRound = source.round;
468
+ reportIds.add(source.reportId);
469
+ return true;
470
+ });
471
+ }
472
+ function reportMetaExtensionsAreValid(value, expectedReportId) {
473
+ const variants = value.variants;
474
+ const isCurrentSchema = typeof value.schemaVersion === 'number'
475
+ && value.schemaVersion >= 4;
476
+ if ((value.effort !== undefined
477
+ && !['low', 'medium', 'high', 'xhigh', 'max'].includes(String(value.effort)))
478
+ || !isOptionalNonNegativeInteger(value.schemaVersion)
479
+ || (value.sampleHashes !== undefined && !isStringRecord(value.sampleHashes))
480
+ || (value.judgePromptHash !== undefined && (typeof value.judgePromptHash !== 'string'
481
+ || value.judgePromptHash.length === 0))
482
+ || (value.diagnostic !== undefined && !isDiagnosticConfig(value.diagnostic))
483
+ || (value.executorRuntime !== undefined
484
+ && (!isRuntimeFingerprint(value.executorRuntime)
485
+ || value.executorRuntime.executor !== value.executor
486
+ || value.executorRuntime.model !== value.model))
487
+ || (value.executorRuntimes !== undefined
488
+ && (!isRecord(value.executorRuntimes)
489
+ || !hasExactKeys(value.executorRuntimes, variants)
490
+ || !Object.values(value.executorRuntimes).every(isRuntimeFingerprint)
491
+ || Object.values(value.executorRuntimes).some((runtime) => isRecord(runtime)
492
+ && (runtime.executor !== value.executor
493
+ || runtime.model !== value.model))))
494
+ || !isOptionalNonNegativeInteger(value.judgeRepeat)
495
+ || (value.judgeRepeat === 0)
496
+ || !isOptionalBoolean(value.noJudge)
497
+ || (value.noJudge === true
498
+ && value.judgeModels.some((judge) => judge.runtime !== undefined))
499
+ || (isCurrentSchema
500
+ && value.noJudge !== true
501
+ && value.judgeModels.some((judge) => judge.runtime === undefined))
502
+ || (value.evaluationFramework !== undefined
503
+ && !['t-test', 'bootstrap', 'both'].includes(String(value.evaluationFramework)))
504
+ || (value.pairComparisons !== undefined
505
+ && !isPairComparisons(value.pairComparisons, variants))
506
+ || (value.debiasMode !== undefined
507
+ && (!Array.isArray(value.debiasMode)
508
+ || new Set(value.debiasMode).size !== value.debiasMode.length
509
+ || !value.debiasMode.every((mode) => mode === 'length' || mode === 'position')))
510
+ || !isOptionalBoolean(value.budgetExhausted)
511
+ || (value.budget !== undefined && !isBudget(value.budget))
512
+ || (value.humanAgreement !== undefined
513
+ && !isHumanAgreement(value.humanAgreement, variants))
514
+ || (value.skillIsolation !== undefined
515
+ && !isSkillIsolation(value.skillIsolation, variants))
516
+ || (value.variantConfigs !== undefined
517
+ && !isVariantConfigs(value.variantConfigs, variants, value.skillIsolation, value.request))
518
+ || (value.gitInfo !== undefined
519
+ && value.gitInfo !== null
520
+ && !isGitInfo(value.gitInfo))
521
+ || !isOptionalBoolean(value.layeredStats)
522
+ || (value.evolve !== undefined
523
+ && !isEvolveMetadata(value.evolve, variants)))
524
+ return false;
525
+ return embeddedLifecycleIsValid(value, expectedReportId);
526
+ }
527
+ function hasExactKeys(value, expected) {
528
+ const keys = Object.keys(value);
529
+ return keys.length === expected.length && expected.every((key) => Object.hasOwn(value, key));
530
+ }
531
+ function isVariantSummary(value) {
532
+ if (!isRecord(value))
533
+ return false;
534
+ const integerFields = ['totalSamples', 'successCount', 'errorCount'];
535
+ const numericFields = [
536
+ 'errorRate',
537
+ 'avgDurationMs',
538
+ 'avgInputTokens',
539
+ 'avgOutputTokens',
540
+ 'avgTotalTokens',
541
+ 'totalCostUSD',
542
+ 'totalExecCostUSD',
543
+ 'totalJudgeCostUSD',
544
+ 'avgCostPerSample',
545
+ 'avgNumTurns',
546
+ ];
547
+ if (!integerFields.every((field) => isNonNegativeInteger(value[field]))
548
+ || !numericFields.every((field) => isNonNegativeNumber(value[field]))
549
+ || value.successCount + value.errorCount !== value.totalSamples
550
+ || value.errorRate > 100
551
+ || !isOptionalBoolean(value.execCostReported)
552
+ || !isOptionalBoolean(value.judgeCostReported)
553
+ || (value.totalDiagnosticCostUSD !== undefined
554
+ && !isNonNegativeNumber(value.totalDiagnosticCostUSD))
555
+ || (value.tokenUsageCoverageRate !== undefined
556
+ && !isRate(value.tokenUsageCoverageRate)))
557
+ return false;
558
+ const optionalMetrics = [
559
+ 'avgFullNumTurns',
560
+ 'avgNumSubAgents',
561
+ 'avgAssistantTurns',
562
+ 'avgToolTurns',
563
+ 'avgToolCalls',
564
+ 'avgToolFailures',
565
+ 'avgToolCancelled',
566
+ 'avgToolUnknown',
567
+ 'scoreStddev',
568
+ 'scoreCV',
569
+ ];
570
+ const optionalScores = [
571
+ 'avgFactScore',
572
+ 'avgBehaviorScore',
573
+ 'avgJudgeScore',
574
+ 'avgCompositeScore',
575
+ 'minCompositeScore',
576
+ 'maxCompositeScore',
577
+ 'avgLlmScore',
578
+ 'minLlmScore',
579
+ 'maxLlmScore',
580
+ ];
581
+ if (optionalMetrics.some((field) => value[field] !== undefined && !isNonNegativeNumber(value[field]))
582
+ || optionalScores.some((field) => value[field] !== undefined && !isScore(value[field]))
583
+ || (value.avgAssertionScore !== undefined && !isScore(value.avgAssertionScore))
584
+ || (value.avgFactVerifiedRate !== undefined && !isRate(value.avgFactVerifiedRate))
585
+ || (value.toolSuccessRate !== undefined && !isRate(value.toolSuccessRate))
586
+ || (value.traceCoverageRate !== undefined && !isRate(value.traceCoverageRate))
587
+ || (value.toolDistribution !== undefined && (!isCountRecord(value.toolDistribution)
588
+ || finiteSum(Object.values(value.toolDistribution)) === undefined))
589
+ || (value.judgeAgreement !== undefined && !isSummaryJudgeAgreement(value.judgeAgreement))
590
+ || (value.judgeModels !== undefined && !isSummaryJudgeModels(value.judgeModels))
591
+ || (value.bootstrapCI !== undefined && !isBootstrapCI(value.bootstrapCI)))
592
+ return false;
593
+ if (typeof value.minCompositeScore === 'number'
594
+ && typeof value.avgCompositeScore === 'number'
595
+ && typeof value.maxCompositeScore === 'number'
596
+ && (value.minCompositeScore > value.avgCompositeScore
597
+ || value.avgCompositeScore > value.maxCompositeScore))
598
+ return false;
599
+ if (typeof value.minLlmScore === 'number'
600
+ && typeof value.avgLlmScore === 'number'
601
+ && typeof value.maxLlmScore === 'number'
602
+ && (value.minLlmScore > value.avgLlmScore
603
+ || value.avgLlmScore > value.maxLlmScore))
604
+ return false;
605
+ const totalSamples = value.totalSamples;
606
+ const errorCount = value.errorCount;
607
+ const expectedErrorRate = totalSamples > 0
608
+ ? Number((errorCount / totalSamples * 100).toFixed(1))
609
+ : 0;
610
+ return value.errorRate === expectedErrorRate;
611
+ }
612
+ function isVariantSummaryRecord(value) {
613
+ return isRecord(value)
614
+ && Object.keys(value).every((key) => key.length > 0)
615
+ && Object.values(value).every(isVariantSummary);
616
+ }
617
+ function isScoreArray(value) {
618
+ return Array.isArray(value) && value.every(isScore);
619
+ }
620
+ function isLayeredScores(value) {
621
+ return isRecord(value)
622
+ && ['factScore', 'behaviorScore', 'judgeScore'].every((field) => value[field] === undefined || isScore(value[field]));
623
+ }
624
+ function isAssertionResults(value) {
625
+ if (!isRecord(value)
626
+ || !isNonNegativeInteger(value.passed)
627
+ || !isNonNegativeInteger(value.total)
628
+ || value.passed > value.total
629
+ || !isScore(value.score)
630
+ || !Array.isArray(value.details)
631
+ || (value.judgeCostUSD !== undefined && !isNonNegativeNumber(value.judgeCostUSD))
632
+ || !isOptionalBoolean(value.judgeCostReportedByExecutor))
633
+ return false;
634
+ return value.details.every((detail) => isRecord(detail)
635
+ && typeof detail.type === 'string'
636
+ && detail.type.length > 0
637
+ && (typeof detail.value === 'string'
638
+ || (typeof detail.value === 'number'
639
+ && Number.isFinite(detail.value)))
640
+ && isNonNegativeNumber(detail.weight)
641
+ && typeof detail.passed === 'boolean'
642
+ && (detail.message === undefined || typeof detail.message === 'string')
643
+ && (detail.layer === undefined
644
+ || detail.layer === 'fact'
645
+ || detail.layer === 'behavior'));
646
+ }
647
+ function isEnsembleEntry(value) {
648
+ if (!isRecord(value)
649
+ || typeof value.judge !== 'string'
650
+ || value.judge.length === 0
651
+ || !isScore(value.score)
652
+ || (value.scoreStddev !== undefined && !isNonNegativeNumber(value.scoreStddev))
653
+ || (value.scoreSamples !== undefined && !isScoreArray(value.scoreSamples))
654
+ || !isOptionalNonNegativeInteger(value.judgeFailureCount)
655
+ || (value.reasoning !== undefined && typeof value.reasoning !== 'string')
656
+ || (value.costUSD !== undefined && !isNonNegativeNumber(value.costUSD))
657
+ || !isOptionalBoolean(value.costReportedByExecutor))
658
+ return false;
659
+ return !(Array.isArray(value.scoreSamples)
660
+ && typeof value.judgeFailureCount === 'number'
661
+ && value.judgeFailureCount > value.scoreSamples.length);
662
+ }
663
+ function isDimensionResult(value) {
664
+ return isRecord(value)
665
+ && isScore(value.score)
666
+ && typeof value.reason === 'string'
667
+ && (value.judgeCostUSD === undefined || isNonNegativeNumber(value.judgeCostUSD))
668
+ && isOptionalBoolean(value.judgeCostReportedByExecutor)
669
+ && (value.scoreSamples === undefined || isScoreArray(value.scoreSamples))
670
+ && (value.scoreStddev === undefined || isNonNegativeNumber(value.scoreStddev))
671
+ && isOptionalNonNegativeInteger(value.judgeFailureCount)
672
+ && (!Array.isArray(value.scoreSamples)
673
+ || typeof value.judgeFailureCount !== 'number'
674
+ || value.judgeFailureCount <= value.scoreSamples.length)
675
+ && (value.reasoning === undefined || typeof value.reasoning === 'string')
676
+ && (value.ensemble === undefined
677
+ || (Array.isArray(value.ensemble) && value.ensemble.every(isEnsembleEntry)))
678
+ && (value.agreement === undefined || isBaseJudgeAgreement(value.agreement));
679
+ }
680
+ function isFactCheck(value) {
681
+ if (!isRecord(value)
682
+ || !isNonNegativeInteger(value.verifiedCount)
683
+ || !isNonNegativeInteger(value.totalCount)
684
+ || value.verifiedCount > value.totalCount
685
+ || !isRate(value.verifiedRate)
686
+ || !Array.isArray(value.claims)
687
+ || value.claims.length !== value.totalCount)
688
+ return false;
689
+ const expectedRate = value.totalCount > 0
690
+ ? value.verifiedCount / value.totalCount
691
+ : 0;
692
+ if (Math.abs(value.verifiedRate - expectedRate) > 1e-9)
693
+ return false;
694
+ return value.claims.every((claim) => isRecord(claim)
695
+ && typeof claim.type === 'string'
696
+ && typeof claim.value === 'string'
697
+ && typeof claim.verified === 'boolean'
698
+ && (claim.evidence === undefined || typeof claim.evidence === 'string')) && value.claims.filter((claim) => isRecord(claim) && claim.verified === true).length === value.verifiedCount;
699
+ }
700
+ function isDiagnostic(value) {
701
+ const rootCauses = new Set([
702
+ 'skill_doc_unclear',
703
+ 'skill_doc_missing',
704
+ 'llm_misread',
705
+ 'sample_design',
706
+ 'tripwire_intentional',
707
+ ]);
708
+ const failureModes = new Set([
709
+ '工作流跳步',
710
+ '硬编码值',
711
+ '幻觉输出',
712
+ '工具误用',
713
+ '环境拦截',
714
+ '误读约束',
715
+ '其他',
716
+ ]);
717
+ return isRecord(value)
718
+ && typeof value.summary === 'string'
719
+ && typeof value.expected === 'string'
720
+ && typeof value.actual === 'string'
721
+ && Array.isArray(value.rootCause)
722
+ && value.rootCause.every((item) => typeof item === 'string' && rootCauses.has(item))
723
+ && (value.workflowChecks === undefined
724
+ || (Array.isArray(value.workflowChecks)
725
+ && value.workflowChecks.every((check) => isRecord(check)
726
+ && typeof check.step === 'string'
727
+ && typeof check.passed === 'boolean'
728
+ && typeof check.evidence === 'string')))
729
+ && (value.failureModes === undefined
730
+ || (Array.isArray(value.failureModes)
731
+ && value.failureModes.every((item) => typeof item === 'string' && failureModes.has(item))))
732
+ && isRecord(value.suggestion)
733
+ && typeof value.suggestion.skill === 'string'
734
+ && typeof value.suggestion.sample === 'string'
735
+ && typeof value.suggestion.none === 'string'
736
+ && (value.costUSD === undefined || isNonNegativeNumber(value.costUSD))
737
+ && isOptionalBoolean(value.costReportedByExecutor)
738
+ && typeof value.ok === 'boolean'
739
+ && (value.error === undefined || typeof value.error === 'string');
740
+ }
741
+ function isVariantResult(value) {
742
+ if (!isRecord(value) || typeof value.ok !== 'boolean')
743
+ return false;
744
+ const tokenFields = [
745
+ value.inputTokens,
746
+ value.outputTokens,
747
+ value.cacheReadTokens,
748
+ value.cacheCreationTokens,
749
+ ];
750
+ const expectedTotal = checkedSumTokenCounts(...tokenFields);
751
+ const numericFields = [
752
+ value.durationMs,
753
+ value.durationApiMs,
754
+ value.execCostUSD,
755
+ value.judgeCostUSD,
756
+ value.costUSD,
757
+ ];
758
+ if (expectedTotal === undefined
759
+ || !isNonNegativeInteger(value.totalTokens)
760
+ || value.totalTokens !== expectedTotal
761
+ || !numericFields.every(isNonNegativeNumber)
762
+ || !isNonNegativeInteger(value.numTurns)
763
+ || (value.attemptCount !== undefined
764
+ && (!isNonNegativeInteger(value.attemptCount) || value.attemptCount < 1))
765
+ || (value.outputPreview !== null && typeof value.outputPreview !== 'string')
766
+ || !isOptionalBoolean(value.tokenUsageReportedByExecutor)
767
+ || !isOptionalBoolean(value.costReportedByExecutor)
768
+ || !isOptionalBoolean(value.judgeCostReportedByExecutor)
769
+ || !traceProjectionIsConsistent(value))
770
+ return false;
771
+ if ((value.compositeScore !== undefined && !isScore(value.compositeScore))
772
+ || (value.layeredScores !== undefined && !isLayeredScores(value.layeredScores))
773
+ || (value.assertions !== undefined && !isAssertionResults(value.assertions))
774
+ || (value.llmScore !== undefined && !isScore(value.llmScore))
775
+ || (value.llmReason !== undefined && typeof value.llmReason !== 'string')
776
+ || (value.llmReasoning !== undefined && typeof value.llmReasoning !== 'string')
777
+ || (value.llmScoreStddev !== undefined && !isNonNegativeNumber(value.llmScoreStddev))
778
+ || (value.llmScoreSamples !== undefined && !isScoreArray(value.llmScoreSamples))
779
+ || !isOptionalNonNegativeInteger(value.llmScoreFailures)
780
+ || (Array.isArray(value.llmScoreSamples)
781
+ && typeof value.llmScoreFailures === 'number'
782
+ && value.llmScoreFailures > value.llmScoreSamples.length)
783
+ || (value.llmEnsemble !== undefined
784
+ && (!Array.isArray(value.llmEnsemble) || !value.llmEnsemble.every(isEnsembleEntry)))
785
+ || (value.llmAgreement !== undefined && !isBaseJudgeAgreement(value.llmAgreement))
786
+ || (value.dimensions !== undefined
787
+ && (!isRecord(value.dimensions)
788
+ || !Object.keys(value.dimensions).every((key) => key.length > 0)
789
+ || !Object.values(value.dimensions).every(isDimensionResult)))
790
+ || (value.factCheck !== undefined && !isFactCheck(value.factCheck))
791
+ || (value.fullOutput !== undefined && typeof value.fullOutput !== 'string')
792
+ || (value.diagnostic !== undefined && !isDiagnostic(value.diagnostic)))
793
+ return false;
794
+ if (value.timing !== undefined) {
795
+ if (!isRecord(value.timing)
796
+ || !isNonNegativeNumber(value.timing.execMs)
797
+ || !isNonNegativeNumber(value.timing.gradeMs)
798
+ || (value.timing.diagnosticMs !== undefined
799
+ && !isNonNegativeNumber(value.timing.diagnosticMs))
800
+ || !isNonNegativeNumber(value.timing.totalMs)
801
+ || !numbersEqual(value.timing.totalMs, value.timing.execMs
802
+ + value.timing.gradeMs
803
+ + (typeof value.timing.diagnosticMs === 'number' ? value.timing.diagnosticMs : 0)))
804
+ return false;
805
+ }
806
+ if (value.diagnosticCostUSD !== undefined
807
+ && !isNonNegativeNumber(value.diagnosticCostUSD))
808
+ return false;
809
+ const expectedCost = value.execCostUSD
810
+ + value.judgeCostUSD
811
+ + (typeof value.diagnosticCostUSD === 'number' ? value.diagnosticCostUSD : 0);
812
+ if (!Number.isFinite(expectedCost)
813
+ || Math.abs(value.costUSD - expectedCost) > 1e-9)
814
+ return false;
815
+ return value.error === undefined || typeof value.error === 'string';
816
+ }
817
+ function isResultEntries(value, variants) {
818
+ if (!Array.isArray(value))
819
+ return false;
820
+ const sampleIds = new Set();
821
+ return value.every((entry) => {
822
+ if (!isRecord(entry)
823
+ || typeof entry.sample_id !== 'string'
824
+ || entry.sample_id.length === 0
825
+ || sampleIds.has(entry.sample_id)
826
+ || !isRecord(entry.variants)
827
+ || !hasExactKeys(entry.variants, variants))
828
+ return false;
829
+ sampleIds.add(entry.sample_id);
830
+ const variantResults = entry.variants;
831
+ return variants.every((variant) => isVariantResult(variantResults[variant]));
832
+ });
833
+ }
834
+ function isEvaluationMeta(value, expectedReportId) {
835
+ if (!isRecord(value))
836
+ return false;
837
+ return isStringArray(value.variants)
838
+ && new Set(value.variants).size === value.variants.length
839
+ && typeof value.model === 'string'
840
+ && value.model.length > 0
841
+ && typeof value.executor === 'string'
842
+ && value.executor.length > 0
843
+ && isNonNegativeInteger(value.sampleCount)
844
+ && isNonNegativeInteger(value.taskCount)
845
+ && isNonNegativeNumber(value.totalCostUSD)
846
+ && normalizeRfc3339Timestamp(value.timestamp) !== undefined
847
+ && typeof value.cliVersion === 'string'
848
+ && typeof value.nodeVersion === 'string'
849
+ && isStringRecord(value.artifactHashes)
850
+ && isJudgeModels(value.judgeModels)
851
+ && isOptionalBoolean(value.totalCostReported)
852
+ && reportMetaExtensionsAreValid(value, expectedReportId);
853
+ }
854
+ function isBatchMeta(value, expectedReportId) {
855
+ if (!isRecord(value))
856
+ return false;
857
+ const isCurrentSchema = Number.isSafeInteger(value.schemaVersion)
858
+ && value.schemaVersion >= 4;
859
+ return value.mode === 'skill'
860
+ && isNonNegativeInteger(value.schemaVersion)
861
+ && typeof value.model === 'string'
862
+ && value.model.length > 0
863
+ && typeof value.executor === 'string'
864
+ && value.executor.length > 0
865
+ && typeof value.skillDir === 'string'
866
+ && isNonNegativeInteger(value.sampleCount)
867
+ && isNonNegativeInteger(value.taskCount)
868
+ && isNonNegativeInteger(value.totalArtifacts)
869
+ && isNonNegativeNumber(value.totalCostUSD)
870
+ && normalizeRfc3339Timestamp(value.timestamp) !== undefined
871
+ && typeof value.cliVersion === 'string'
872
+ && typeof value.nodeVersion === 'string'
873
+ && isJudgeModels(value.judgeModels)
874
+ && isOptionalBoolean(value.totalCostReported)
875
+ && (value.executorRuntime === undefined
876
+ || (isRuntimeFingerprint(value.executorRuntime)
877
+ && value.executorRuntime.executor === value.executor
878
+ && value.executorRuntime.model === value.model))
879
+ && (value.executorRuntimes === undefined
880
+ || (isRecord(value.executorRuntimes)
881
+ && Object.values(value.executorRuntimes).every(isRuntimeFingerprint)
882
+ && Object.values(value.executorRuntimes).every((runtime) => isRecord(runtime)
883
+ && runtime.executor === value.executor
884
+ && runtime.model === value.model)))
885
+ && isOptionalBoolean(value.noJudge)
886
+ && (value.noJudge !== true
887
+ || value.judgeModels.every((judge) => judge.runtime === undefined))
888
+ && (!isCurrentSchema
889
+ || value.noJudge === true
890
+ || value.judgeModels.every((judge) => judge.runtime !== undefined))
891
+ && (value.gitInfo === undefined
892
+ || value.gitInfo === null
893
+ || isGitInfo(value.gitInfo))
894
+ && embeddedLifecycleIsValid(value, expectedReportId, true);
895
+ }
896
+ function isBatchItems(value) {
897
+ if (!Array.isArray(value))
898
+ return false;
899
+ const names = new Set();
900
+ const reportIds = new Set();
901
+ return value.every((item) => {
902
+ if (!isRecord(item)
903
+ || typeof item.name !== 'string'
904
+ || item.name.length === 0
905
+ || names.has(item.name)
906
+ || typeof item.skillPath !== 'string'
907
+ || typeof item.samplesPath !== 'string'
908
+ || !isCanonicalReportId(item.reportId)
909
+ || reportIds.has(item.reportId)
910
+ || (item.reportPath !== null && typeof item.reportPath !== 'string')
911
+ || (item.status !== 'completed' && item.status !== 'failed')
912
+ || !isNonNegativeInteger(item.sampleCount)
913
+ || !isNonNegativeNumber(item.totalCostUSD)
914
+ || (item.artifactHash !== null && typeof item.artifactHash !== 'string')
915
+ || !isVariantSummaryRecord(item.summary)
916
+ || !hasExactKeys(item.summary, ['baseline', item.name])
917
+ || !Object.values(item.summary).every((variant) => variant.totalSamples === item.sampleCount)
918
+ || (item.variance !== undefined
919
+ && !isVarianceData(item.variance, ['baseline', item.name])))
920
+ return false;
921
+ names.add(item.name);
922
+ reportIds.add(item.reportId);
923
+ return true;
924
+ });
925
+ }
926
+ export function isCanonicalReportId(value) {
927
+ return typeof value === 'string'
928
+ && value.length > 0
929
+ && safeArtifactFileStem(value) === value;
930
+ }
931
+ function evaluationEnvelopeIsConsistent(meta, summary, results) {
932
+ const request = meta.request;
933
+ const requestBudget = request?.budget;
934
+ const metaBudget = meta.budget;
935
+ const budgetMatchesRequest = request === undefined
936
+ || (requestBudget?.totalUSD === metaBudget?.totalUSD
937
+ && requestBudget?.perSampleUSD === metaBudget?.perSampleUSD
938
+ && requestBudget?.perSampleMs === metaBudget?.perSampleMs);
939
+ const maxAttempts = (request?.retry ?? 0) + 1;
940
+ const attemptsMatchRequest = request === undefined
941
+ || results === undefined
942
+ || results.every((entry) => entry.variants === undefined
943
+ || Object.values(entry.variants).every((result) => (result.attemptCount ?? 1) <= maxAttempts));
944
+ if (!hasExactKeys(summary, meta.variants)
945
+ || !hasExactKeys(meta.artifactHashes, meta.variants)
946
+ || meta.taskCount !== meta.sampleCount * meta.variants.length
947
+ || !Number.isSafeInteger(meta.taskCount)
948
+ || !budgetMatchesRequest
949
+ || !attemptsMatchRequest
950
+ || (meta.budgetExhausted === true
951
+ && requestBudget?.totalUSD === undefined)
952
+ || (request !== undefined
953
+ && !hasExactKeys(Object.fromEntries(request.artifacts.map((artifact) => [artifact.name, true])), meta.variants))
954
+ || ((meta.schemaVersion ?? 0) >= 5
955
+ && (!isSampleHashRecord(meta.sampleHashes)
956
+ || (results
957
+ ? !hasExactKeys(meta.sampleHashes, results.map((entry) => entry.sample_id))
958
+ : Object.keys(meta.sampleHashes).length !== meta.sampleCount))))
959
+ return false;
960
+ return meta.variants.every((variant) => summary[variant].totalSamples === meta.sampleCount);
961
+ }
962
+ function numbersEqual(left, right, tolerance = 1e-9) {
963
+ return Number.isFinite(left)
964
+ && Number.isFinite(right)
965
+ && Math.abs(left - right) <= tolerance;
966
+ }
967
+ function finiteSum(values) {
968
+ let total = 0;
969
+ for (const value of values) {
970
+ total += value;
971
+ if (!isNonNegativeNumber(total))
972
+ return undefined;
973
+ }
974
+ return total;
975
+ }
976
+ function averageRounded(values, digits) {
977
+ const total = finiteSum(values);
978
+ if (total === undefined)
979
+ return undefined;
980
+ if (values.length === 0)
981
+ return 0;
982
+ const average = total / values.length;
983
+ return digits === undefined
984
+ ? Math.round(average)
985
+ : Number(average.toFixed(digits));
986
+ }
987
+ function coreVariantSummaryMatches(summary, entries) {
988
+ const successful = entries.filter((entry) => entry.ok);
989
+ const observedTokens = successful.filter((entry) => entry.tokenUsageReportedByExecutor !== false);
990
+ const tokenCoverage = entries.length > 0
991
+ ? Number((entries.filter((entry) => entry.tokenUsageReportedByExecutor !== false).length
992
+ / entries.length).toFixed(4))
993
+ : 1;
994
+ const durations = successful.map((entry) => entry.timing?.totalMs || entry.durationMs);
995
+ const inputTokens = averageRounded(observedTokens.map((entry) => entry.inputTokens));
996
+ const outputTokens = averageRounded(observedTokens.map((entry) => entry.outputTokens));
997
+ const totalTokens = averageRounded(observedTokens.map((entry) => entry.totalTokens));
998
+ const duration = averageRounded(durations);
999
+ const turns = averageRounded(successful.map((entry) => entry.numTurns), 1);
1000
+ const totalCost = finiteSum(successful.map((entry) => entry.costUSD));
1001
+ const execCost = finiteSum(successful.map((entry) => entry.execCostUSD));
1002
+ const judgeCost = finiteSum(successful.map((entry) => entry.judgeCostUSD));
1003
+ const diagnosticCostRaw = finiteSum(successful.map((entry) => entry.diagnosticCostUSD ?? 0));
1004
+ if (inputTokens === undefined
1005
+ || outputTokens === undefined
1006
+ || totalTokens === undefined
1007
+ || duration === undefined
1008
+ || turns === undefined
1009
+ || totalCost === undefined
1010
+ || execCost === undefined
1011
+ || judgeCost === undefined
1012
+ || diagnosticCostRaw === undefined)
1013
+ return false;
1014
+ const avgCost = successful.length > 0
1015
+ ? Number((totalCost / successful.length).toFixed(6))
1016
+ : 0;
1017
+ const expectedDiagnosticCost = diagnosticCostRaw > 0
1018
+ ? Number(diagnosticCostRaw.toFixed(6))
1019
+ : 0;
1020
+ const execCostReported = !entries.some((entry) => entry.costReportedByExecutor === false);
1021
+ const judgeCostReported = !entries.some((entry) => entry.judgeCostReportedByExecutor === false);
1022
+ return summary.avgDurationMs === duration
1023
+ && summary.avgInputTokens === inputTokens
1024
+ && summary.avgOutputTokens === outputTokens
1025
+ && summary.avgTotalTokens === totalTokens
1026
+ && summary.avgNumTurns === turns
1027
+ && numbersEqual(summary.totalCostUSD, totalCost)
1028
+ && numbersEqual(summary.totalExecCostUSD, execCost)
1029
+ && numbersEqual(summary.totalJudgeCostUSD, judgeCost)
1030
+ && numbersEqual(summary.avgCostPerSample, avgCost)
1031
+ && (tokenCoverage < 1
1032
+ ? summary.tokenUsageCoverageRate === tokenCoverage
1033
+ : summary.tokenUsageCoverageRate === undefined
1034
+ || summary.tokenUsageCoverageRate === 1)
1035
+ && (expectedDiagnosticCost > 0
1036
+ ? numbersEqual(summary.totalDiagnosticCostUSD ?? -1, expectedDiagnosticCost)
1037
+ : summary.totalDiagnosticCostUSD === undefined
1038
+ || summary.totalDiagnosticCostUSD === 0)
1039
+ && (summary.execCostReported !== false) === execCostReported
1040
+ && (summary.judgeCostReported !== false) === judgeCostReported;
1041
+ }
1042
+ function evaluationCostsAreConsistent(meta, summary, results) {
1043
+ const allResults = results.flatMap((entry) => meta.variants.map((variant) => entry.variants[variant]));
1044
+ const totalCost = finiteSum(allResults.map((entry) => entry.costUSD));
1045
+ if (totalCost === undefined || !numbersEqual(meta.totalCostUSD, Number(totalCost.toFixed(6)))) {
1046
+ return false;
1047
+ }
1048
+ const allCostReported = Object.values(summary).every((variant) => variant.execCostReported !== false && variant.judgeCostReported !== false);
1049
+ return allCostReported
1050
+ ? meta.totalCostReported === undefined || meta.totalCostReported === true
1051
+ : meta.totalCostReported === false;
1052
+ }
1053
+ function batchEnvelopeIsConsistent(meta, items) {
1054
+ const itemNames = items.map((item) => item.name);
1055
+ const sampleCount = finiteSum(items.map((item) => item.sampleCount));
1056
+ const taskCount = finiteSum(items.map((item) => item.sampleCount * Object.keys(item.summary).length));
1057
+ const totalCost = finiteSum(items.map((item) => item.totalCostUSD));
1058
+ if (sampleCount === undefined
1059
+ || taskCount === undefined
1060
+ || totalCost === undefined
1061
+ || meta.totalArtifacts !== items.length
1062
+ || meta.sampleCount !== sampleCount
1063
+ || meta.taskCount !== taskCount
1064
+ || !numbersEqual(meta.totalCostUSD, Number(totalCost.toFixed(6)))
1065
+ || (meta.executorRuntimes !== undefined
1066
+ && !hasExactKeys(meta.executorRuntimes, itemNames))
1067
+ || (meta.request !== undefined
1068
+ && !hasExactKeys(Object.fromEntries(meta.request.artifacts.map((artifact) => [artifact.name, true])), itemNames)))
1069
+ return false;
1070
+ const allCostReported = items.every((item) => Object.values(item.summary).every((variant) => variant.execCostReported !== false && variant.judgeCostReported !== false));
1071
+ return allCostReported
1072
+ ? meta.totalCostReported === undefined || meta.totalCostReported === true
1073
+ : meta.totalCostReported === false;
1074
+ }
1075
+ /**
1076
+ * Parse a persisted report at every storage boundary. Canonical report files
1077
+ * are the source of truth; index cards must never relax this contract.
1078
+ */
1079
+ export function parseReportDocument(value, fallbackId, expectedId) {
1080
+ if (!isRecord(value))
1081
+ return null;
1082
+ const kind = value.kind === 'evaluation' || value.kind === 'batch-evaluation'
1083
+ ? value.kind
1084
+ : undefined;
1085
+ const id = isCanonicalReportId(value.id) ? value.id : fallbackId;
1086
+ if (!isCanonicalReportId(value.id) || !isCanonicalReportId(id))
1087
+ return null;
1088
+ if (expectedId !== undefined && id !== expectedId)
1089
+ return null;
1090
+ if (kind === 'evaluation') {
1091
+ const meta = value.meta;
1092
+ const summary = value.summary;
1093
+ if (!isEvaluationMeta(meta, id)
1094
+ || !isVariantSummaryRecord(summary)
1095
+ || !isResultEntries(value.results, meta.variants)
1096
+ || !evaluationEnvelopeIsConsistent(meta, summary, value.results)
1097
+ || value.results.length !== meta.sampleCount
1098
+ || (value.sampleSnapshots !== undefined
1099
+ && !isSampleSnapshotRecord(value.sampleSnapshots, value.results.map((entry) => entry.sample_id)))
1100
+ || (value.analysis !== undefined
1101
+ && !isAnalysisResult(value.analysis, meta.variants, value.results))
1102
+ || (value.variance !== undefined
1103
+ && !isVarianceData(value.variance, meta.variants)))
1104
+ return null;
1105
+ for (const variant of meta.variants) {
1106
+ const variantResults = value.results.map((entry) => entry.variants[variant]);
1107
+ const successCount = variantResults.filter((entry) => entry.ok).length;
1108
+ if (summary[variant].successCount !== successCount
1109
+ || summary[variant].errorCount !== value.results.length - successCount
1110
+ || !coreVariantSummaryMatches(summary[variant], variantResults))
1111
+ return null;
1112
+ }
1113
+ if (!evaluationCostsAreConsistent(meta, summary, value.results))
1114
+ return null;
1115
+ return value;
1116
+ }
1117
+ if (kind === 'batch-evaluation'
1118
+ && value.mode === 'skill'
1119
+ && isBatchMeta(value.meta, id)
1120
+ && isBatchItems(value.items)
1121
+ && batchEnvelopeIsConsistent(value.meta, value.items)) {
1122
+ return value;
1123
+ }
1124
+ return null;
1125
+ }
1126
+ /**
1127
+ * Validate a lightweight report discovery card. The card is still only a
1128
+ * pointer: consumers must parse `path` through `parseReportDocument` before use.
1129
+ */
1130
+ export function parseReportIndexCard(value) {
1131
+ if (!isRecord(value)
1132
+ || value.domain !== 'report'
1133
+ || !isCanonicalReportId(value.id)
1134
+ || typeof value.path !== 'string'
1135
+ || !isAbsolute(value.path)
1136
+ || reportFilePath(dirname(value.path), value.id) !== value.path)
1137
+ return null;
1138
+ if (value.kind === 'evaluation'
1139
+ && isEvaluationMeta(value.meta, value.id)
1140
+ && isVariantSummaryRecord(value.summary)
1141
+ && evaluationEnvelopeIsConsistent(value.meta, value.summary)) {
1142
+ return value;
1143
+ }
1144
+ if (value.kind === 'batch-evaluation'
1145
+ && isBatchMeta(value.meta, value.id)
1146
+ && isBatchItems(value.items)
1147
+ && batchEnvelopeIsConsistent(value.meta, value.items)) {
1148
+ return value;
1149
+ }
1150
+ return null;
1151
+ }