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,620 @@
1
+ import { SIGNAL_WEIGHTS } from '../analysis/gap-analyzer.js';
2
+ import { confidenceOf, healthBandOf, toolStabilityOf } from './skill-health-analyzer.js';
3
+ import { parseTraceIngestionSummary } from './trace-ingestion.js';
4
+ import { sumRecordCounts } from '../shared/record-count.js';
5
+ import { normalizeRfc3339Timestamp } from '../shared/timestamp.js';
6
+ const TOOL_STABILITIES = new Set([
7
+ 'stable',
8
+ 'unstable',
9
+ 'very-unstable',
10
+ 'unknown',
11
+ ]);
12
+ const HEALTH_BANDS = new Set([
13
+ 'green',
14
+ 'yellow',
15
+ 'red',
16
+ ]);
17
+ const CONFIDENCE_LEVELS = new Set([
18
+ 'high',
19
+ 'low',
20
+ 'underpowered',
21
+ ]);
22
+ const GAP_TYPES = new Set([
23
+ 'failed_search',
24
+ 'explicit_marker',
25
+ 'hedging',
26
+ 'repeated_failure',
27
+ ]);
28
+ const COVERAGE_ENTRY_TYPES = new Set([
29
+ 'principle',
30
+ 'semantic',
31
+ 'design',
32
+ 'script',
33
+ 'code',
34
+ 'other',
35
+ ]);
36
+ /**
37
+ * Parse persisted observe-health data at the storage boundary.
38
+ *
39
+ * Legacy reports may omit additive fields such as usage, confidence and
40
+ * tool-outcome coverage. Those fields are reconstructed from authoritative
41
+ * counts. Contradictory counts/rates are rejected; derived labels are
42
+ * recomputed because their threshold formula can evolve between releases.
43
+ */
44
+ export function parseSkillHealthReport(value) {
45
+ if (!isRecord(value))
46
+ return null;
47
+ if (value.kind !== undefined && value.kind !== 'observe-health')
48
+ return null;
49
+ const meta = normalizeMeta(value.meta);
50
+ const overall = normalizeOverall(value.overall, meta?.segmentCount);
51
+ if (!meta || !overall || !isRecord(value.bySkill))
52
+ return null;
53
+ const skillEntries = [];
54
+ for (const [key, rawHealth] of Object.entries(value.bySkill)) {
55
+ const health = normalizeSkillHealth(rawHealth, key);
56
+ if (!health)
57
+ return null;
58
+ skillEntries.push([key, health]);
59
+ }
60
+ const bySkill = Object.fromEntries(skillEntries);
61
+ if (!reportAggregatesAreConsistent(meta, overall, bySkill))
62
+ return null;
63
+ return {
64
+ ...(value.kind === 'observe-health' ? { kind: value.kind } : {}),
65
+ meta,
66
+ overall,
67
+ bySkill,
68
+ };
69
+ }
70
+ function normalizeMeta(value) {
71
+ if (!isRecord(value))
72
+ return null;
73
+ const generatedAt = timestamp(value.generatedAt);
74
+ const sessionCount = nonNegativeInteger(value.sessionCount);
75
+ const segmentCount = nonNegativeInteger(value.segmentCount);
76
+ const messageCount = nonNegativeInteger(value.messageCount);
77
+ const toolCallCount = nonNegativeInteger(value.toolCallCount);
78
+ const toolFailureRate = rate(value.toolFailureRate);
79
+ const rawTimeRange = isRecord(value.timeRange) ? value.timeRange : null;
80
+ const timeRange = rawTimeRange
81
+ ? {
82
+ from: rawTimeRange.from === '' ? '' : timestamp(rawTimeRange.from),
83
+ to: rawTimeRange.to === '' ? '' : timestamp(rawTimeRange.to),
84
+ }
85
+ : null;
86
+ if (!generatedAt
87
+ || timeRange?.from === undefined
88
+ || timeRange.to === undefined
89
+ || (timeRange.from === '') !== (timeRange.to === '')
90
+ || (timeRange.from !== ''
91
+ && timeRange.to !== ''
92
+ && Date.parse(timeRange.from) > Date.parse(timeRange.to))
93
+ || sessionCount == null
94
+ || segmentCount == null
95
+ || messageCount == null
96
+ || toolCallCount == null
97
+ || toolFailureRate == null
98
+ || typeof value.tracePath !== 'string'
99
+ || !(value.kbPath === null || typeof value.kbPath === 'string'))
100
+ return null;
101
+ const inferredTimestampedSegmentCount = timeRange.from === '' ? 0 : segmentCount;
102
+ const timestampedSegmentCount = value.timestampedSegmentCount === undefined
103
+ ? inferredTimestampedSegmentCount
104
+ : nonNegativeInteger(value.timestampedSegmentCount);
105
+ const excludedUntimestampedSegmentCount = value.excludedUntimestampedSegmentCount === undefined
106
+ ? 0
107
+ : nonNegativeInteger(value.excludedUntimestampedSegmentCount);
108
+ if (timestampedSegmentCount == null
109
+ || timestampedSegmentCount > segmentCount
110
+ || excludedUntimestampedSegmentCount == null
111
+ || (timeRange.from === '') !== (timestampedSegmentCount === 0))
112
+ return null;
113
+ const expectedTimestampCoverage = segmentCount > 0
114
+ ? Number((timestampedSegmentCount / segmentCount).toFixed(4))
115
+ : 1;
116
+ const timestampCoverage = value.timestampCoverage === undefined
117
+ ? expectedTimestampCoverage
118
+ : rate(value.timestampCoverage);
119
+ if (timestampCoverage == null
120
+ || !approximatelyEqual(timestampCoverage, expectedTimestampCoverage))
121
+ return null;
122
+ const outcomes = normalizeToolOutcomeCounts(toolCallCount, value.toolResolvedCount, value.toolCancelledCount, value.toolUnknownCount, value.toolOutcomeCoverage);
123
+ if (!outcomes)
124
+ return null;
125
+ if (outcomes.comparable === 0 && toolFailureRate !== 0)
126
+ return null;
127
+ const ingestion = value.ingestion === undefined
128
+ ? undefined
129
+ : parseTraceIngestionSummary(value.ingestion);
130
+ if (value.ingestion !== undefined && !ingestion)
131
+ return null;
132
+ return {
133
+ tracePath: value.tracePath,
134
+ kbPath: value.kbPath,
135
+ sessionCount,
136
+ segmentCount,
137
+ messageCount,
138
+ timestampedSegmentCount,
139
+ timestampCoverage,
140
+ excludedUntimestampedSegmentCount,
141
+ toolCallCount,
142
+ toolResolvedCount: outcomes.resolved,
143
+ toolCancelledCount: outcomes.cancelled,
144
+ toolUnknownCount: outcomes.unknown,
145
+ toolOutcomeCoverage: outcomes.coverage,
146
+ toolFailureRate,
147
+ timeRange: { from: timeRange.from, to: timeRange.to },
148
+ generatedAt,
149
+ ...(ingestion ? { ingestion } : {}),
150
+ };
151
+ }
152
+ function normalizeOverall(value, segmentCount) {
153
+ if (!isRecord(value) || segmentCount == null)
154
+ return null;
155
+ const gapRate = rate(value.gapRate);
156
+ const weightedGapRate = rate(value.weightedGapRate);
157
+ const healthBand = stringEnum(value.healthBand, HEALTH_BANDS);
158
+ const suppliedConfidence = value.confidence === undefined
159
+ ? undefined
160
+ : stringEnum(value.confidence, CONFIDENCE_LEVELS);
161
+ if (gapRate == null
162
+ || weightedGapRate == null
163
+ || weightedGapRate > gapRate
164
+ || !healthBand
165
+ || (value.confidence !== undefined && !suppliedConfidence)) {
166
+ return null;
167
+ }
168
+ return {
169
+ gapRate,
170
+ weightedGapRate,
171
+ healthBand: healthBandOf(weightedGapRate),
172
+ confidence: confidenceOf(segmentCount),
173
+ };
174
+ }
175
+ function normalizeSkillHealth(value, key) {
176
+ if (!isRecord(value) || typeof value.skillName !== 'string' || value.skillName !== key)
177
+ return null;
178
+ const segmentCount = nonNegativeInteger(value.segmentCount);
179
+ const toolCallCount = nonNegativeInteger(value.toolCallCount);
180
+ const toolFailureCount = nonNegativeInteger(value.toolFailureCount);
181
+ const toolFailureRate = rate(value.toolFailureRate);
182
+ if (segmentCount == null
183
+ || toolCallCount == null
184
+ || toolFailureCount == null
185
+ || toolFailureRate == null)
186
+ return null;
187
+ const outcomes = normalizeToolOutcomeCounts(toolCallCount, value.toolResolvedCount, value.toolCancelledCount, value.toolUnknownCount, value.toolOutcomeCoverage);
188
+ if (!outcomes || toolFailureCount > outcomes.comparable)
189
+ return null;
190
+ const expectedFailureRate = outcomes.comparable > 0
191
+ ? Number((toolFailureCount / outcomes.comparable).toFixed(4))
192
+ : 0;
193
+ if (!approximatelyEqual(toolFailureRate, expectedFailureRate))
194
+ return null;
195
+ const gap = normalizeGap(value.gap, key, segmentCount);
196
+ const coverage = value.coverage === null || value.coverage === undefined
197
+ ? null
198
+ : normalizeCoverage(value.coverage);
199
+ const usage = value.usage === undefined ? emptyUsage() : normalizeUsage(value.usage, segmentCount);
200
+ const suppliedConfidence = value.confidence === undefined
201
+ ? undefined
202
+ : stringEnum(value.confidence, CONFIDENCE_LEVELS);
203
+ const suppliedStability = value.stability === undefined
204
+ ? undefined
205
+ : stringEnum(value.stability, TOOL_STABILITIES);
206
+ if (!gap
207
+ || coverage === undefined
208
+ || !usage
209
+ || (value.confidence !== undefined && !suppliedConfidence)
210
+ || (value.stability !== undefined && !suppliedStability))
211
+ return null;
212
+ const confidence = confidenceOf(segmentCount);
213
+ const stability = toolStabilityOf(toolFailureRate, outcomes.comparable, toolCallCount);
214
+ if (value.testSetPath !== undefined
215
+ && value.testSetPath !== null
216
+ && typeof value.testSetPath !== 'string')
217
+ return null;
218
+ if (value.testSetHash !== undefined
219
+ && value.testSetHash !== null
220
+ && typeof value.testSetHash !== 'string')
221
+ return null;
222
+ return {
223
+ skillName: key,
224
+ segmentCount,
225
+ toolCallCount,
226
+ toolFailureCount,
227
+ toolResolvedCount: outcomes.resolved,
228
+ toolCancelledCount: outcomes.cancelled,
229
+ toolUnknownCount: outcomes.unknown,
230
+ toolOutcomeCoverage: outcomes.coverage,
231
+ toolFailureRate,
232
+ stability,
233
+ confidence,
234
+ usage,
235
+ coverage,
236
+ gap,
237
+ };
238
+ }
239
+ function normalizeToolOutcomeCounts(total, rawResolved, rawCancelled, rawUnknown, rawCoverage) {
240
+ const suppliedResolved = rawResolved === undefined ? undefined : nonNegativeInteger(rawResolved);
241
+ const suppliedCancelled = rawCancelled === undefined ? undefined : nonNegativeInteger(rawCancelled);
242
+ const suppliedUnknown = rawUnknown === undefined ? undefined : nonNegativeInteger(rawUnknown);
243
+ if ((rawResolved !== undefined && suppliedResolved == null)
244
+ || (rawCancelled !== undefined && suppliedCancelled == null)
245
+ || (rawUnknown !== undefined && suppliedUnknown == null))
246
+ return null;
247
+ const resolved = suppliedResolved ?? (suppliedUnknown === undefined ? total : total - suppliedUnknown);
248
+ const cancelled = suppliedCancelled ?? 0;
249
+ const unknown = suppliedUnknown ?? total - resolved;
250
+ const comparable = resolved - cancelled;
251
+ if (resolved < 0
252
+ || cancelled < 0
253
+ || unknown < 0
254
+ || comparable < 0
255
+ || resolved + unknown !== total)
256
+ return null;
257
+ const coverage = total > 0 ? Number((resolved / total).toFixed(4)) : 1;
258
+ if (rawCoverage !== undefined) {
259
+ const suppliedCoverage = rate(rawCoverage);
260
+ if (suppliedCoverage == null || !approximatelyEqual(suppliedCoverage, coverage))
261
+ return null;
262
+ }
263
+ return { resolved, comparable, cancelled, unknown, coverage };
264
+ }
265
+ function normalizeGap(value, skillName, segmentCount) {
266
+ if (!isRecord(value))
267
+ return null;
268
+ const gapRate = rate(value.gapRate);
269
+ const weightedGapRate = rate(value.weightedGapRate);
270
+ if (gapRate == null || weightedGapRate == null || weightedGapRate > gapRate)
271
+ return null;
272
+ if (!Array.isArray(value.signals))
273
+ return null;
274
+ const signals = value.signals.map(normalizeGapSignal);
275
+ if (signals.some((signal) => signal === null))
276
+ return null;
277
+ const typedSignals = signals;
278
+ const sampleCount = value.sampleCount === undefined
279
+ ? segmentCount
280
+ : nonNegativeInteger(value.sampleCount);
281
+ const signalSampleIds = new Set(typedSignals.map((signal) => signal.sampleId));
282
+ const derivedSamplesWithGap = signalSampleIds.size;
283
+ const samplesWithGap = value.samplesWithGap === undefined
284
+ ? derivedSamplesWithGap
285
+ : nonNegativeInteger(value.samplesWithGap);
286
+ if (sampleCount == null
287
+ || sampleCount !== segmentCount
288
+ || samplesWithGap == null
289
+ || samplesWithGap > sampleCount
290
+ || samplesWithGap !== derivedSamplesWithGap)
291
+ return null;
292
+ const expectedGapRate = sampleCount > 0
293
+ ? Number((samplesWithGap / sampleCount).toFixed(4))
294
+ : 0;
295
+ const maxWeightBySample = new Map();
296
+ for (const signal of typedSignals) {
297
+ maxWeightBySample.set(signal.sampleId, Math.max(maxWeightBySample.get(signal.sampleId) ?? 0, signal.weight));
298
+ }
299
+ const expectedWeightedGapRate = sampleCount > 0
300
+ ? Number(([...maxWeightBySample.values()].reduce((sum, weight) => sum + weight, 0)
301
+ / sampleCount).toFixed(4))
302
+ : 0;
303
+ if (!approximatelyEqual(gapRate, expectedGapRate)
304
+ || !approximatelyEqual(weightedGapRate, expectedWeightedGapRate))
305
+ return null;
306
+ const byType = normalizeGapCounts(value.byType, typedSignals);
307
+ if (!byType)
308
+ return null;
309
+ if ((value.variant !== undefined && value.variant !== skillName)
310
+ || (value.testSetPath !== undefined
311
+ && value.testSetPath !== null
312
+ && typeof value.testSetPath !== 'string')
313
+ || (value.testSetHash !== undefined
314
+ && value.testSetHash !== null
315
+ && typeof value.testSetHash !== 'string'))
316
+ return null;
317
+ return {
318
+ variant: skillName,
319
+ sampleCount,
320
+ samplesWithGap,
321
+ gapRate,
322
+ weightedGapRate,
323
+ ...(value.testSetPath === null || typeof value.testSetPath === 'string'
324
+ ? { testSetPath: value.testSetPath }
325
+ : {}),
326
+ ...(value.testSetHash === null || typeof value.testSetHash === 'string'
327
+ ? { testSetHash: value.testSetHash }
328
+ : {}),
329
+ signals: typedSignals,
330
+ byType,
331
+ };
332
+ }
333
+ function normalizeGapSignal(value) {
334
+ if (!isRecord(value))
335
+ return null;
336
+ const type = stringEnum(value.type, GAP_TYPES);
337
+ const weight = rate(value.weight);
338
+ if (typeof value.sampleId !== 'string'
339
+ || !type
340
+ || typeof value.context !== 'string'
341
+ || weight == null
342
+ || !approximatelyEqual(weight, SIGNAL_WEIGHTS[type])
343
+ || (value.turn !== undefined && nonNegativeInteger(value.turn) == null)
344
+ || (value.evidence !== undefined && !isRecord(value.evidence)))
345
+ return null;
346
+ if (value.classifierVerdict !== undefined) {
347
+ if (!isRecord(value.classifierVerdict)
348
+ || typeof value.classifierVerdict.isUncertainty !== 'boolean'
349
+ || rate(value.classifierVerdict.confidence) == null
350
+ || typeof value.classifierVerdict.reason !== 'string')
351
+ return null;
352
+ }
353
+ return {
354
+ sampleId: value.sampleId,
355
+ type,
356
+ context: value.context,
357
+ weight,
358
+ ...(value.turn !== undefined ? { turn: value.turn } : {}),
359
+ ...(value.evidence !== undefined
360
+ ? { evidence: value.evidence }
361
+ : {}),
362
+ ...(value.classifierVerdict !== undefined
363
+ ? {
364
+ classifierVerdict: {
365
+ isUncertainty: value.classifierVerdict.isUncertainty,
366
+ confidence: value.classifierVerdict.confidence,
367
+ reason: value.classifierVerdict.reason,
368
+ },
369
+ }
370
+ : {}),
371
+ };
372
+ }
373
+ function normalizeGapCounts(value, signals) {
374
+ if (value === undefined) {
375
+ return {
376
+ failed_search: signals.filter((signal) => signal.type === 'failed_search').length,
377
+ explicit_marker: signals.filter((signal) => signal.type === 'explicit_marker').length,
378
+ hedging: signals.filter((signal) => signal.type === 'hedging').length,
379
+ repeated_failure: signals.filter((signal) => signal.type === 'repeated_failure').length,
380
+ };
381
+ }
382
+ if (!isRecord(value))
383
+ return null;
384
+ const failedSearch = nonNegativeInteger(value.failed_search);
385
+ const explicitMarker = nonNegativeInteger(value.explicit_marker);
386
+ const hedging = nonNegativeInteger(value.hedging);
387
+ const repeatedFailure = nonNegativeInteger(value.repeated_failure);
388
+ if (failedSearch == null || explicitMarker == null || hedging == null || repeatedFailure == null)
389
+ return null;
390
+ const normalized = {
391
+ failed_search: failedSearch,
392
+ explicit_marker: explicitMarker,
393
+ hedging,
394
+ repeated_failure: repeatedFailure,
395
+ };
396
+ const expected = normalizeGapCounts(undefined, signals);
397
+ return expected
398
+ && Object.keys(normalized).every((key) => normalized[key] === expected[key])
399
+ ? normalized
400
+ : null;
401
+ }
402
+ function normalizeCoverage(value) {
403
+ if (!isRecord(value) || !Array.isArray(value.entries) || !Array.isArray(value.uncoveredFiles))
404
+ return undefined;
405
+ const entries = value.entries.map((entry) => {
406
+ const type = isRecord(entry) ? stringEnum(entry.type, COVERAGE_ENTRY_TYPES) : undefined;
407
+ if (!isRecord(entry)
408
+ || typeof entry.path !== 'string'
409
+ || !type
410
+ || typeof entry.accessed !== 'boolean'
411
+ || nonNegativeInteger(entry.accessCount) == null
412
+ || (entry.lineCount !== undefined && nonNegativeInteger(entry.lineCount) == null)
413
+ || (entry.accessed && entry.accessCount === 0)
414
+ || (!entry.accessed && entry.accessCount !== 0))
415
+ return null;
416
+ return {
417
+ path: entry.path,
418
+ type,
419
+ accessed: entry.accessed,
420
+ accessCount: entry.accessCount,
421
+ ...(entry.lineCount !== undefined ? { lineCount: entry.lineCount } : {}),
422
+ };
423
+ });
424
+ const filesCovered = nonNegativeInteger(value.filesCovered);
425
+ const filesTotal = nonNegativeInteger(value.filesTotal);
426
+ const fileCoverageRate = rate(value.fileCoverageRate);
427
+ const grepPatternsUsed = nonNegativeInteger(value.grepPatternsUsed);
428
+ const overallRate = rate(value.overallRate);
429
+ if (entries.some((entry) => entry === null)
430
+ || value.uncoveredFiles.some((path) => typeof path !== 'string')
431
+ || filesCovered == null
432
+ || filesTotal == null
433
+ || filesCovered > filesTotal
434
+ || fileCoverageRate == null
435
+ || grepPatternsUsed == null
436
+ || overallRate == null)
437
+ return undefined;
438
+ const typedEntries = entries;
439
+ if (new Set(typedEntries.map((entry) => entry.path)).size !== typedEntries.length
440
+ || new Set(value.uncoveredFiles).size !== value.uncoveredFiles.length)
441
+ return undefined;
442
+ const derivedCovered = typedEntries.filter((entry) => entry.accessed).length;
443
+ const derivedUncovered = typedEntries.filter((entry) => !entry.accessed).map((entry) => entry.path);
444
+ const expectedFileCoverageRate = filesTotal > 0
445
+ ? Number((filesCovered / filesTotal).toFixed(2))
446
+ : 0;
447
+ const grepBonus = grepPatternsUsed > 0
448
+ ? Math.min(1, grepPatternsUsed / Math.max(5, filesTotal))
449
+ : 0;
450
+ const expectedOverallRate = Number((fileCoverageRate * 0.6 + grepBonus * 0.4).toFixed(2));
451
+ if (filesTotal !== typedEntries.length
452
+ || filesCovered !== derivedCovered
453
+ || !approximatelyEqual(fileCoverageRate, expectedFileCoverageRate)
454
+ || !sameStringSet(value.uncoveredFiles, derivedUncovered)
455
+ || !approximatelyEqual(overallRate, expectedOverallRate))
456
+ return undefined;
457
+ return {
458
+ entries: typedEntries,
459
+ filesCovered,
460
+ filesTotal,
461
+ fileCoverageRate,
462
+ uncoveredFiles: derivedUncovered,
463
+ grepPatternsUsed,
464
+ overallRate,
465
+ };
466
+ }
467
+ function normalizeUsage(value, segmentCount) {
468
+ if (!isRecord(value))
469
+ return null;
470
+ const integerFields = [
471
+ 'inputTokens',
472
+ 'outputTokens',
473
+ 'cacheReadTokens',
474
+ 'cacheCreationTokens',
475
+ 'totalTokens',
476
+ 'numTurns',
477
+ 'avgTokensPerSegment',
478
+ 'avgDurationMsPerSegment',
479
+ ];
480
+ const normalized = Object.fromEntries(integerFields.map((field) => [field, nonNegativeInteger(value[field])]));
481
+ const durationMs = nonNegativeNumber(value.durationMs);
482
+ if (Object.values(normalized).some((entry) => entry == null) || durationMs == null)
483
+ return null;
484
+ const hasTokenCoverage = value.tokenObservedSegmentCount !== undefined
485
+ || value.tokenCoverage !== undefined;
486
+ const tokenObservedSegmentCount = hasTokenCoverage
487
+ ? nonNegativeInteger(value.tokenObservedSegmentCount)
488
+ : 0;
489
+ const tokenCoverage = hasTokenCoverage
490
+ ? rate(value.tokenCoverage)
491
+ : 0;
492
+ if (tokenObservedSegmentCount == null
493
+ || tokenCoverage == null
494
+ || tokenObservedSegmentCount > segmentCount)
495
+ return null;
496
+ const usage = {
497
+ ...normalized,
498
+ durationMs,
499
+ tokenObservedSegmentCount,
500
+ tokenCoverage,
501
+ };
502
+ const expectedTotal = usage.inputTokens
503
+ + usage.outputTokens
504
+ + usage.cacheReadTokens
505
+ + usage.cacheCreationTokens;
506
+ const tokenDivisor = usage.tokenObservedSegmentCount || 1;
507
+ const durationDivisor = segmentCount || 1;
508
+ if (!Number.isSafeInteger(expectedTotal)
509
+ || usage.totalTokens !== expectedTotal
510
+ || (hasTokenCoverage
511
+ && usage.avgTokensPerSegment !== Math.round(expectedTotal / tokenDivisor))
512
+ || usage.avgDurationMsPerSegment !== Math.round(usage.durationMs / durationDivisor)
513
+ || (hasTokenCoverage
514
+ && !approximatelyEqual(usage.tokenCoverage, segmentCount > 0 ? usage.tokenObservedSegmentCount / segmentCount : 1)))
515
+ return null;
516
+ return usage;
517
+ }
518
+ function reportAggregatesAreConsistent(meta, overall, bySkill) {
519
+ const skills = Object.values(bySkill);
520
+ const segmentCount = safeCountSum(skills.map((health) => health.segmentCount));
521
+ const toolCallCount = safeCountSum(skills.map((health) => health.toolCallCount));
522
+ const toolResolvedCount = safeCountSum(skills.map((health) => health.toolResolvedCount ?? health.toolCallCount));
523
+ const toolCancelledCount = safeCountSum(skills.map((health) => health.toolCancelledCount ?? 0));
524
+ const toolUnknownCount = safeCountSum(skills.map((health) => health.toolUnknownCount ?? 0));
525
+ const toolFailureCount = safeCountSum(skills.map((health) => health.toolFailureCount));
526
+ const gapSampleCount = safeCountSum(skills.map((health) => health.gap.sampleCount));
527
+ const samplesWithGap = safeCountSum(skills.map((health) => health.gap.samplesWithGap));
528
+ const weightedGapTotal = safeFiniteSum(skills.map((health) => health.gap.weightedGapRate * health.gap.sampleCount));
529
+ if (segmentCount === undefined
530
+ || toolCallCount === undefined
531
+ || toolResolvedCount === undefined
532
+ || toolCancelledCount === undefined
533
+ || toolUnknownCount === undefined
534
+ || toolFailureCount === undefined
535
+ || gapSampleCount === undefined
536
+ || samplesWithGap === undefined
537
+ || weightedGapTotal === undefined)
538
+ return false;
539
+ const comparable = toolResolvedCount - toolCancelledCount;
540
+ const expectedFailureRate = comparable > 0
541
+ ? Number((toolFailureCount / comparable).toFixed(4))
542
+ : 0;
543
+ const expectedGapRate = segmentCount > 0
544
+ ? Number((samplesWithGap / segmentCount).toFixed(4))
545
+ : 0;
546
+ const expectedWeightedGapRate = segmentCount > 0
547
+ ? Number((weightedGapTotal / segmentCount).toFixed(4))
548
+ : 0;
549
+ return segmentCount === meta.segmentCount
550
+ && gapSampleCount === meta.segmentCount
551
+ && toolCallCount === meta.toolCallCount
552
+ && toolResolvedCount === meta.toolResolvedCount
553
+ && toolCancelledCount === meta.toolCancelledCount
554
+ && toolUnknownCount === meta.toolUnknownCount
555
+ && approximatelyEqual(meta.toolFailureRate, expectedFailureRate)
556
+ && approximatelyEqual(overall.gapRate, expectedGapRate)
557
+ && approximatelyEqual(overall.weightedGapRate, expectedWeightedGapRate);
558
+ }
559
+ function safeCountSum(values) {
560
+ try {
561
+ return sumRecordCounts(...values);
562
+ }
563
+ catch {
564
+ return undefined;
565
+ }
566
+ }
567
+ function safeFiniteSum(values) {
568
+ let total = 0;
569
+ for (const value of values) {
570
+ if (!Number.isFinite(value) || value < 0)
571
+ return undefined;
572
+ total += value;
573
+ if (!Number.isFinite(total) || total > Number.MAX_SAFE_INTEGER)
574
+ return undefined;
575
+ }
576
+ return total;
577
+ }
578
+ function sameStringSet(left, right) {
579
+ return left.length === right.length
580
+ && left.every((entry) => right.includes(entry))
581
+ && right.every((entry) => left.includes(entry));
582
+ }
583
+ function emptyUsage() {
584
+ return {
585
+ inputTokens: 0,
586
+ outputTokens: 0,
587
+ cacheReadTokens: 0,
588
+ cacheCreationTokens: 0,
589
+ totalTokens: 0,
590
+ tokenObservedSegmentCount: 0,
591
+ tokenCoverage: 0,
592
+ durationMs: 0,
593
+ numTurns: 0,
594
+ avgTokensPerSegment: 0,
595
+ avgDurationMsPerSegment: 0,
596
+ };
597
+ }
598
+ function timestamp(value) {
599
+ return normalizeRfc3339Timestamp(value);
600
+ }
601
+ function nonNegativeInteger(value) {
602
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
603
+ }
604
+ function nonNegativeNumber(value) {
605
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
606
+ }
607
+ function rate(value) {
608
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1
609
+ ? value
610
+ : undefined;
611
+ }
612
+ function approximatelyEqual(left, right) {
613
+ return Math.abs(left - right) <= 0.0001;
614
+ }
615
+ function stringEnum(value, values) {
616
+ return typeof value === 'string' && values.has(value) ? value : undefined;
617
+ }
618
+ function isRecord(value) {
619
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
620
+ }
@@ -1,4 +1,3 @@
1
1
  export declare const PROMPTS_DIR: string;
2
2
  export declare const SOFT_STANDARD_PROMPT_ID = "llm-enhanced-review";
3
3
  export declare const SOFT_STANDARD_PROMPT_VERSION = "2026-05-22.v7";
4
- export declare const DEFAULT_LLM_ENHANCED_REVIEW_MODEL = "sonnet";
@@ -6,4 +6,3 @@ import { fileURLToPath } from 'node:url';
6
6
  export const PROMPTS_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'prompts');
7
7
  export const SOFT_STANDARD_PROMPT_ID = 'llm-enhanced-review';
8
8
  export const SOFT_STANDARD_PROMPT_VERSION = '2026-05-22.v7';
9
- export const DEFAULT_LLM_ENHANCED_REVIEW_MODEL = 'sonnet';
@@ -1,4 +1,4 @@
1
- export { DEFAULT_LLM_ENHANCED_REVIEW_MODEL, PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
1
+ export { PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
2
2
  export type { ExtractSkillSoftStandardsOptions, LlmEnhancedChecklistStatus, LlmEnhancedSkillType, LlmEnhancedUserFeeling, LlmEnhancedVerdict, ResolveSkillStandardsOptions, ResolvedSkillStandard, ResolvedSkillStandardKind, ResolvedSkillStandardSource, ResolvedSkillStandards, RuntimeMatchedSignal, RuntimeNodeResult, RuntimeNodeVerdict, RuntimeSignal, RuntimeSignalOp, RuntimeSignalRef, RuntimeSignalType, RuntimeStandardNode, RuntimeStandardNodeKind, RuntimeStandardNodeSourceHint, RuntimeTrigger, RuntimeTriggerWindowScope, SkillDerivedStandard, SkillDerivedStandardKind, SkillDerivedStandardStatus, SkillDerivedStandards, SkillLlmEnhancedReviewSections, SkillLlmEnhancedRuntimeEvidence, SkillLlmRuntimeNodeAssessment, SkillLlmTypeSpecificChecklistItem, } from './types.js';
3
3
  export { loadSkillDerivedStandards, resolveSkillStandards, skillDerivedStandardsDir, skillDerivedStandardsPath, updateSkillDerivedStandardStatus, } from './skill-standards-store.js';
4
4
  export { extractSkillSoftStandards } from './llm-extractor.js';
@@ -1,4 +1,4 @@
1
- export { DEFAULT_LLM_ENHANCED_REVIEW_MODEL, PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
1
+ export { PROMPTS_DIR, SOFT_STANDARD_PROMPT_ID, SOFT_STANDARD_PROMPT_VERSION, } from './constants.js';
2
2
  export { loadSkillDerivedStandards, resolveSkillStandards, skillDerivedStandardsDir, skillDerivedStandardsPath, updateSkillDerivedStandardStatus, } from './skill-standards-store.js';
3
3
  export { extractSkillSoftStandards } from './llm-extractor.js';
4
4
  import { normalizeRuntimeSignals, normalizeRuntimeTriggers, normalizeSignalOpForType, } from './llm-extractor.js';