modelrig 0.0.1 → 0.2.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 (420) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/LICENSE +201 -0
  3. package/README.md +145 -8
  4. package/data/PROVENANCE.md +19 -0
  5. package/data/pricing-manual.json +22 -0
  6. package/data/pricing-map.json +46362 -0
  7. package/data/pricing-overlay.json +419 -0
  8. package/dist/adapters/anthropic.d.ts +90 -0
  9. package/dist/adapters/anthropic.d.ts.map +1 -0
  10. package/dist/adapters/anthropic.js +296 -0
  11. package/dist/adapters/build-adapters.d.ts +11 -0
  12. package/dist/adapters/build-adapters.d.ts.map +1 -0
  13. package/dist/adapters/build-adapters.js +45 -0
  14. package/dist/adapters/deepseek.d.ts +47 -0
  15. package/dist/adapters/deepseek.d.ts.map +1 -0
  16. package/dist/adapters/deepseek.js +216 -0
  17. package/dist/adapters/gemini.d.ts +44 -0
  18. package/dist/adapters/gemini.d.ts.map +1 -0
  19. package/dist/adapters/gemini.js +262 -0
  20. package/dist/adapters/grok.d.ts +53 -0
  21. package/dist/adapters/grok.d.ts.map +1 -0
  22. package/dist/adapters/grok.js +232 -0
  23. package/dist/adapters/openai-compat.d.ts +80 -0
  24. package/dist/adapters/openai-compat.d.ts.map +1 -0
  25. package/dist/adapters/openai-compat.js +244 -0
  26. package/dist/adapters/openai-stream.d.ts +58 -0
  27. package/dist/adapters/openai-stream.d.ts.map +1 -0
  28. package/dist/adapters/openai-stream.js +120 -0
  29. package/dist/adapters/openai.d.ts +55 -0
  30. package/dist/adapters/openai.d.ts.map +1 -0
  31. package/dist/adapters/openai.js +281 -0
  32. package/dist/adapters/sampling.d.ts +28 -0
  33. package/dist/adapters/sampling.d.ts.map +1 -0
  34. package/dist/adapters/sampling.js +34 -0
  35. package/dist/adapters/tool-mapping.d.ts +92 -0
  36. package/dist/adapters/tool-mapping.d.ts.map +1 -0
  37. package/dist/adapters/tool-mapping.js +143 -0
  38. package/dist/artifacts/artifact.d.ts +137 -0
  39. package/dist/artifacts/artifact.d.ts.map +1 -0
  40. package/dist/artifacts/artifact.js +377 -0
  41. package/dist/artifacts/content-uploader.d.ts +87 -0
  42. package/dist/artifacts/content-uploader.d.ts.map +1 -0
  43. package/dist/artifacts/content-uploader.js +124 -0
  44. package/dist/artifacts/index.d.ts +63 -0
  45. package/dist/artifacts/index.d.ts.map +1 -0
  46. package/dist/artifacts/index.js +80 -0
  47. package/dist/artifacts/run-context.d.ts +129 -0
  48. package/dist/artifacts/run-context.d.ts.map +1 -0
  49. package/dist/artifacts/run-context.js +208 -0
  50. package/dist/artifacts/scrub.d.ts +60 -0
  51. package/dist/artifacts/scrub.d.ts.map +1 -0
  52. package/dist/artifacts/scrub.js +139 -0
  53. package/dist/artifacts/step.d.ts +26 -0
  54. package/dist/artifacts/step.d.ts.map +1 -0
  55. package/dist/artifacts/step.js +37 -0
  56. package/dist/artifacts/taint.d.ts +63 -0
  57. package/dist/artifacts/taint.d.ts.map +1 -0
  58. package/dist/artifacts/taint.js +76 -0
  59. package/dist/bakeoff/cache-sim.d.ts +99 -0
  60. package/dist/bakeoff/cache-sim.d.ts.map +1 -0
  61. package/dist/bakeoff/cache-sim.js +126 -0
  62. package/dist/bakeoff/engine.d.ts +52 -0
  63. package/dist/bakeoff/engine.d.ts.map +1 -0
  64. package/dist/bakeoff/engine.js +163 -0
  65. package/dist/bakeoff/eval-cases.d.ts +96 -0
  66. package/dist/bakeoff/eval-cases.d.ts.map +1 -0
  67. package/dist/bakeoff/eval-cases.js +105 -0
  68. package/dist/bakeoff/replay.d.ts +52 -0
  69. package/dist/bakeoff/replay.d.ts.map +1 -0
  70. package/dist/bakeoff/replay.js +94 -0
  71. package/dist/bakeoff/report.d.ts +41 -0
  72. package/dist/bakeoff/report.d.ts.map +1 -0
  73. package/dist/bakeoff/report.js +142 -0
  74. package/dist/bakeoff/samples.d.ts +77 -0
  75. package/dist/bakeoff/samples.d.ts.map +1 -0
  76. package/dist/bakeoff/samples.js +148 -0
  77. package/dist/bakeoff/stats.d.ts +13 -0
  78. package/dist/bakeoff/stats.d.ts.map +1 -0
  79. package/dist/bakeoff/stats.js +48 -0
  80. package/dist/bakeoff/types.d.ts +37 -0
  81. package/dist/bakeoff/types.d.ts.map +1 -0
  82. package/dist/bakeoff/types.js +10 -0
  83. package/dist/cli.d.ts +25 -0
  84. package/dist/cli.d.ts.map +1 -0
  85. package/dist/cli.js +590 -0
  86. package/dist/config.d.ts +204 -0
  87. package/dist/config.d.ts.map +1 -0
  88. package/dist/config.js +252 -0
  89. package/dist/deprecations.d.ts +32 -0
  90. package/dist/deprecations.d.ts.map +1 -0
  91. package/dist/deprecations.js +59 -0
  92. package/dist/feedback/coverage.d.ts +32 -0
  93. package/dist/feedback/coverage.d.ts.map +1 -0
  94. package/dist/feedback/coverage.js +95 -0
  95. package/dist/feedback/feedback.d.ts +35 -0
  96. package/dist/feedback/feedback.d.ts.map +1 -0
  97. package/dist/feedback/feedback.js +39 -0
  98. package/dist/gateway/http-protocol.d.ts +175 -0
  99. package/dist/gateway/http-protocol.d.ts.map +1 -0
  100. package/dist/gateway/http-protocol.js +105 -0
  101. package/dist/index.d.ts +242 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +576 -0
  104. package/dist/init/finder.d.ts +94 -0
  105. package/dist/init/finder.d.ts.map +1 -0
  106. package/dist/init/finder.js +343 -0
  107. package/dist/init/init-cli.d.ts +10 -0
  108. package/dist/init/init-cli.d.ts.map +1 -0
  109. package/dist/init/init-cli.js +86 -0
  110. package/dist/init/observe-cli.d.ts +19 -0
  111. package/dist/init/observe-cli.d.ts.map +1 -0
  112. package/dist/init/observe-cli.js +73 -0
  113. package/dist/init/observe.d.ts +81 -0
  114. package/dist/init/observe.d.ts.map +1 -0
  115. package/dist/init/observe.js +245 -0
  116. package/dist/init/run.d.ts +99 -0
  117. package/dist/init/run.d.ts.map +1 -0
  118. package/dist/init/run.js +281 -0
  119. package/dist/init/signatures.d.ts +39 -0
  120. package/dist/init/signatures.d.ts.map +1 -0
  121. package/dist/init/signatures.js +116 -0
  122. package/dist/matrix/aggregate.d.ts +89 -0
  123. package/dist/matrix/aggregate.d.ts.map +1 -0
  124. package/dist/matrix/aggregate.js +186 -0
  125. package/dist/query/grammar.d.ts +35 -0
  126. package/dist/query/grammar.d.ts.map +1 -0
  127. package/dist/query/grammar.js +279 -0
  128. package/dist/query/run.d.ts +8 -0
  129. package/dist/query/run.d.ts.map +1 -0
  130. package/dist/query/run.js +21 -0
  131. package/dist/registry/build.d.ts +219 -0
  132. package/dist/registry/build.d.ts.map +1 -0
  133. package/dist/registry/build.js +313 -0
  134. package/dist/registry/cache-policy.d.ts +94 -0
  135. package/dist/registry/cache-policy.d.ts.map +1 -0
  136. package/dist/registry/cache-policy.js +238 -0
  137. package/dist/registry/call-notes.d.ts +11 -0
  138. package/dist/registry/call-notes.d.ts.map +1 -0
  139. package/dist/registry/call-notes.js +110 -0
  140. package/dist/registry/claims.d.ts +63 -0
  141. package/dist/registry/claims.d.ts.map +1 -0
  142. package/dist/registry/claims.js +107 -0
  143. package/dist/registry/effective-rate.d.ts +151 -0
  144. package/dist/registry/effective-rate.d.ts.map +1 -0
  145. package/dist/registry/effective-rate.js +156 -0
  146. package/dist/registry/facts.d.ts +32 -0
  147. package/dist/registry/facts.d.ts.map +1 -0
  148. package/dist/registry/facts.js +136 -0
  149. package/dist/registry/fingerprint.d.ts +20 -0
  150. package/dist/registry/fingerprint.d.ts.map +1 -0
  151. package/dist/registry/fingerprint.js +150 -0
  152. package/dist/registry/parity.d.ts +52 -0
  153. package/dist/registry/parity.d.ts.map +1 -0
  154. package/dist/registry/parity.js +82 -0
  155. package/dist/registry/pricing-shape.d.ts +113 -0
  156. package/dist/registry/pricing-shape.d.ts.map +1 -0
  157. package/dist/registry/pricing-shape.js +123 -0
  158. package/dist/registry/pricing.d.ts +43 -0
  159. package/dist/registry/pricing.d.ts.map +1 -0
  160. package/dist/registry/pricing.js +127 -0
  161. package/dist/registry/rows.d.ts +16 -0
  162. package/dist/registry/rows.d.ts.map +1 -0
  163. package/dist/registry/rows.js +57 -0
  164. package/dist/registry/seed.d.ts +43 -0
  165. package/dist/registry/seed.d.ts.map +1 -0
  166. package/dist/registry/seed.js +97 -0
  167. package/dist/registry/select.d.ts +68 -0
  168. package/dist/registry/select.d.ts.map +1 -0
  169. package/dist/registry/select.js +141 -0
  170. package/dist/registry/staleness.d.ts +18 -0
  171. package/dist/registry/staleness.d.ts.map +1 -0
  172. package/dist/registry/staleness.js +39 -0
  173. package/dist/rigindex/bootstrap.d.ts +36 -0
  174. package/dist/rigindex/bootstrap.d.ts.map +1 -0
  175. package/dist/rigindex/bootstrap.js +97 -0
  176. package/dist/rigindex/fit.d.ts +24 -0
  177. package/dist/rigindex/fit.d.ts.map +1 -0
  178. package/dist/rigindex/fit.js +76 -0
  179. package/dist/rigindex/gates.d.ts +52 -0
  180. package/dist/rigindex/gates.d.ts.map +1 -0
  181. package/dist/rigindex/gates.js +109 -0
  182. package/dist/rigindex/graph.d.ts +31 -0
  183. package/dist/rigindex/graph.d.ts.map +1 -0
  184. package/dist/rigindex/graph.js +120 -0
  185. package/dist/rigindex/index.d.ts +23 -0
  186. package/dist/rigindex/index.d.ts.map +1 -0
  187. package/dist/rigindex/index.js +112 -0
  188. package/dist/rigindex/types.d.ts +76 -0
  189. package/dist/rigindex/types.d.ts.map +1 -0
  190. package/dist/rigindex/types.js +8 -0
  191. package/dist/routes/cache-lint.d.ts +41 -0
  192. package/dist/routes/cache-lint.d.ts.map +1 -0
  193. package/dist/routes/cache-lint.js +81 -0
  194. package/dist/routes/draft.d.ts +83 -0
  195. package/dist/routes/draft.d.ts.map +1 -0
  196. package/dist/routes/draft.js +135 -0
  197. package/dist/routes/loader.d.ts +63 -0
  198. package/dist/routes/loader.d.ts.map +1 -0
  199. package/dist/routes/loader.js +574 -0
  200. package/dist/routes/manifest.d.ts +24 -0
  201. package/dist/routes/manifest.d.ts.map +1 -0
  202. package/dist/routes/manifest.js +118 -0
  203. package/dist/routes/resolved-bundle.d.ts +79 -0
  204. package/dist/routes/resolved-bundle.d.ts.map +1 -0
  205. package/dist/routes/resolved-bundle.js +148 -0
  206. package/dist/routes/sampling-config.d.ts +32 -0
  207. package/dist/routes/sampling-config.d.ts.map +1 -0
  208. package/dist/routes/sampling-config.js +91 -0
  209. package/dist/routes/serveability.d.ts +52 -0
  210. package/dist/routes/serveability.d.ts.map +1 -0
  211. package/dist/routes/serveability.js +73 -0
  212. package/dist/routes/template.d.ts +18 -0
  213. package/dist/routes/template.d.ts.map +1 -0
  214. package/dist/routes/template.js +94 -0
  215. package/dist/run/ajv.d.ts +22 -0
  216. package/dist/run/ajv.d.ts.map +1 -0
  217. package/dist/run/ajv.js +32 -0
  218. package/dist/run/cache-handle.d.ts +58 -0
  219. package/dist/run/cache-handle.d.ts.map +1 -0
  220. package/dist/run/cache-handle.js +54 -0
  221. package/dist/run/cache-stamp.d.ts +65 -0
  222. package/dist/run/cache-stamp.d.ts.map +1 -0
  223. package/dist/run/cache-stamp.js +0 -0
  224. package/dist/run/capture-write.d.ts +33 -0
  225. package/dist/run/capture-write.d.ts.map +1 -0
  226. package/dist/run/capture-write.js +55 -0
  227. package/dist/run/cost.d.ts +26 -0
  228. package/dist/run/cost.d.ts.map +1 -0
  229. package/dist/run/cost.js +41 -0
  230. package/dist/run/dispatch.d.ts +99 -0
  231. package/dist/run/dispatch.d.ts.map +1 -0
  232. package/dist/run/dispatch.js +191 -0
  233. package/dist/run/envelope.d.ts +21 -0
  234. package/dist/run/envelope.d.ts.map +1 -0
  235. package/dist/run/envelope.js +45 -0
  236. package/dist/run/grounding.d.ts +56 -0
  237. package/dist/run/grounding.d.ts.map +1 -0
  238. package/dist/run/grounding.js +89 -0
  239. package/dist/run/raw.d.ts +88 -0
  240. package/dist/run/raw.d.ts.map +1 -0
  241. package/dist/run/raw.js +286 -0
  242. package/dist/run/record-attempt.d.ts +40 -0
  243. package/dist/run/record-attempt.d.ts.map +1 -0
  244. package/dist/run/record-attempt.js +99 -0
  245. package/dist/run/repair.d.ts +36 -0
  246. package/dist/run/repair.d.ts.map +1 -0
  247. package/dist/run/repair.js +61 -0
  248. package/dist/run/resolve.d.ts +99 -0
  249. package/dist/run/resolve.d.ts.map +1 -0
  250. package/dist/run/resolve.js +203 -0
  251. package/dist/run/retry.d.ts +19 -0
  252. package/dist/run/retry.d.ts.map +1 -0
  253. package/dist/run/retry.js +50 -0
  254. package/dist/run/run.d.ts +55 -0
  255. package/dist/run/run.d.ts.map +1 -0
  256. package/dist/run/run.js +540 -0
  257. package/dist/run/stream.d.ts +49 -0
  258. package/dist/run/stream.d.ts.map +1 -0
  259. package/dist/run/stream.js +87 -0
  260. package/dist/run/validate.d.ts +15 -0
  261. package/dist/run/validate.d.ts.map +1 -0
  262. package/dist/run/validate.js +55 -0
  263. package/dist/savings/cache-ledger.d.ts +108 -0
  264. package/dist/savings/cache-ledger.d.ts.map +1 -0
  265. package/dist/savings/cache-ledger.js +174 -0
  266. package/dist/savings/cache-reconcile.d.ts +64 -0
  267. package/dist/savings/cache-reconcile.d.ts.map +1 -0
  268. package/dist/savings/cache-reconcile.js +59 -0
  269. package/dist/savings/cache-stats.d.ts +63 -0
  270. package/dist/savings/cache-stats.d.ts.map +1 -0
  271. package/dist/savings/cache-stats.js +108 -0
  272. package/dist/savings/emit.d.ts +38 -0
  273. package/dist/savings/emit.d.ts.map +1 -0
  274. package/dist/savings/emit.js +100 -0
  275. package/dist/savings/odometer.d.ts +32 -0
  276. package/dist/savings/odometer.d.ts.map +1 -0
  277. package/dist/savings/odometer.js +70 -0
  278. package/dist/savings/swap-execute.d.ts +58 -0
  279. package/dist/savings/swap-execute.d.ts.map +1 -0
  280. package/dist/savings/swap-execute.js +130 -0
  281. package/dist/savings/swaps-client.d.ts +55 -0
  282. package/dist/savings/swaps-client.d.ts.map +1 -0
  283. package/dist/savings/swaps-client.js +95 -0
  284. package/dist/settings/api-fetcher.d.ts +39 -0
  285. package/dist/settings/api-fetcher.d.ts.map +1 -0
  286. package/dist/settings/api-fetcher.js +92 -0
  287. package/dist/settings/index.d.ts +10 -0
  288. package/dist/settings/index.d.ts.map +1 -0
  289. package/dist/settings/index.js +15 -0
  290. package/dist/settings/task-settings.d.ts +91 -0
  291. package/dist/settings/task-settings.d.ts.map +1 -0
  292. package/dist/settings/task-settings.js +116 -0
  293. package/dist/status.d.ts +77 -0
  294. package/dist/status.d.ts.map +1 -0
  295. package/dist/status.js +113 -0
  296. package/dist/telemetry/artifact-store.d.ts +48 -0
  297. package/dist/telemetry/artifact-store.d.ts.map +1 -0
  298. package/dist/telemetry/artifact-store.js +189 -0
  299. package/dist/telemetry/cache-miss-streak.d.ts +79 -0
  300. package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
  301. package/dist/telemetry/cache-miss-streak.js +99 -0
  302. package/dist/telemetry/capture.d.ts +31 -0
  303. package/dist/telemetry/capture.d.ts.map +1 -0
  304. package/dist/telemetry/capture.js +81 -0
  305. package/dist/telemetry/exporter-setup.d.ts +28 -0
  306. package/dist/telemetry/exporter-setup.d.ts.map +1 -0
  307. package/dist/telemetry/exporter-setup.js +34 -0
  308. package/dist/telemetry/exporter.d.ts +137 -0
  309. package/dist/telemetry/exporter.d.ts.map +1 -0
  310. package/dist/telemetry/exporter.js +510 -0
  311. package/dist/telemetry/health.d.ts +76 -0
  312. package/dist/telemetry/health.d.ts.map +1 -0
  313. package/dist/telemetry/health.js +92 -0
  314. package/dist/telemetry/ingest-protocol.d.ts +310 -0
  315. package/dist/telemetry/ingest-protocol.d.ts.map +1 -0
  316. package/dist/telemetry/ingest-protocol.js +363 -0
  317. package/dist/telemetry/load-error-report.d.ts +24 -0
  318. package/dist/telemetry/load-error-report.d.ts.map +1 -0
  319. package/dist/telemetry/load-error-report.js +50 -0
  320. package/dist/telemetry/otel-map.d.ts +121 -0
  321. package/dist/telemetry/otel-map.d.ts.map +1 -0
  322. package/dist/telemetry/otel-map.js +224 -0
  323. package/dist/telemetry/otel-normalize.d.ts +104 -0
  324. package/dist/telemetry/otel-normalize.d.ts.map +1 -0
  325. package/dist/telemetry/otel-normalize.js +530 -0
  326. package/dist/telemetry/otlp-emitter.d.ts +52 -0
  327. package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
  328. package/dist/telemetry/otlp-emitter.js +144 -0
  329. package/dist/telemetry/otlp-proto.d.ts +29 -0
  330. package/dist/telemetry/otlp-proto.d.ts.map +1 -0
  331. package/dist/telemetry/otlp-proto.js +266 -0
  332. package/dist/telemetry/sinks.d.ts +90 -0
  333. package/dist/telemetry/sinks.d.ts.map +1 -0
  334. package/dist/telemetry/sinks.js +180 -0
  335. package/dist/telemetry/store.d.ts +65 -0
  336. package/dist/telemetry/store.d.ts.map +1 -0
  337. package/dist/telemetry/store.js +547 -0
  338. package/dist/tenancy/api-key-format.d.ts +77 -0
  339. package/dist/tenancy/api-key-format.d.ts.map +1 -0
  340. package/dist/tenancy/api-key-format.js +110 -0
  341. package/dist/tenancy/constants.d.ts +23 -0
  342. package/dist/tenancy/constants.d.ts.map +1 -0
  343. package/dist/tenancy/constants.js +25 -0
  344. package/dist/tenancy/scrub.d.ts +47 -0
  345. package/dist/tenancy/scrub.d.ts.map +1 -0
  346. package/dist/tenancy/scrub.js +85 -0
  347. package/dist/types/config-teaching.d.ts +62 -0
  348. package/dist/types/config-teaching.d.ts.map +1 -0
  349. package/dist/types/config-teaching.js +183 -0
  350. package/dist/types/failures-teaching.d.ts +56 -0
  351. package/dist/types/failures-teaching.d.ts.map +1 -0
  352. package/dist/types/failures-teaching.js +177 -0
  353. package/dist/types/failures.d.ts +27 -0
  354. package/dist/types/failures.d.ts.map +1 -0
  355. package/dist/types/failures.js +41 -0
  356. package/dist/types/provider.d.ts +200 -0
  357. package/dist/types/provider.d.ts.map +1 -0
  358. package/dist/types/provider.js +40 -0
  359. package/dist/types/route.d.ts +205 -0
  360. package/dist/types/route.d.ts.map +1 -0
  361. package/dist/types/route.js +6 -0
  362. package/dist/types/telemetry.d.ts +206 -0
  363. package/dist/types/telemetry.d.ts.map +1 -0
  364. package/dist/types/telemetry.js +6 -0
  365. package/dist/validate-cli.d.ts +12 -0
  366. package/dist/validate-cli.d.ts.map +1 -0
  367. package/dist/validate-cli.js +57 -0
  368. package/dist/verify/capture.d.ts +66 -0
  369. package/dist/verify/capture.d.ts.map +1 -0
  370. package/dist/verify/capture.js +180 -0
  371. package/dist/verify/cli-run.d.ts +23 -0
  372. package/dist/verify/cli-run.d.ts.map +1 -0
  373. package/dist/verify/cli-run.js +57 -0
  374. package/dist/verify/diff.d.ts +48 -0
  375. package/dist/verify/diff.d.ts.map +1 -0
  376. package/dist/verify/diff.js +157 -0
  377. package/dist/verify/index.d.ts +17 -0
  378. package/dist/verify/index.d.ts.map +1 -0
  379. package/dist/verify/index.js +24 -0
  380. package/dist/verify/report.d.ts +14 -0
  381. package/dist/verify/report.d.ts.map +1 -0
  382. package/dist/verify/report.js +88 -0
  383. package/dist/verify/types.d.ts +101 -0
  384. package/dist/verify/types.d.ts.map +1 -0
  385. package/dist/verify/types.js +17 -0
  386. package/dist/verify/verify.d.ts +29 -0
  387. package/dist/verify/verify.d.ts.map +1 -0
  388. package/dist/verify/verify.js +148 -0
  389. package/dist/watch/budget.d.ts +19 -0
  390. package/dist/watch/budget.d.ts.map +1 -0
  391. package/dist/watch/budget.js +35 -0
  392. package/dist/watch/evaluate.d.ts +225 -0
  393. package/dist/watch/evaluate.d.ts.map +1 -0
  394. package/dist/watch/evaluate.js +155 -0
  395. package/dist/watch/monitor.d.ts +116 -0
  396. package/dist/watch/monitor.d.ts.map +1 -0
  397. package/dist/watch/monitor.js +199 -0
  398. package/dist/watch/proposals.d.ts +89 -0
  399. package/dist/watch/proposals.d.ts.map +1 -0
  400. package/dist/watch/proposals.js +197 -0
  401. package/dist/watch/run-record.d.ts +64 -0
  402. package/dist/watch/run-record.d.ts.map +1 -0
  403. package/dist/watch/run-record.js +86 -0
  404. package/dist/watch/run-reported.d.ts +20 -0
  405. package/dist/watch/run-reported.d.ts.map +1 -0
  406. package/dist/watch/run-reported.js +53 -0
  407. package/dist/watch/run.d.ts +73 -0
  408. package/dist/watch/run.d.ts.map +1 -0
  409. package/dist/watch/run.js +83 -0
  410. package/dist/watch/state-store.d.ts +48 -0
  411. package/dist/watch/state-store.d.ts.map +1 -0
  412. package/dist/watch/state-store.js +86 -0
  413. package/dist/watch/state.d.ts +21 -0
  414. package/dist/watch/state.d.ts.map +1 -0
  415. package/dist/watch/state.js +93 -0
  416. package/package.json +56 -14
  417. package/registry/LICENSE +20 -0
  418. package/registry/leaderboard.json +3639 -0
  419. package/registry/registry.json +7263 -0
  420. package/index.js +0 -3
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Scrub v1 — deterministic PII/PHI detection over artifact content BEFORE upload
3
+ * (E2-C chunk B, spec §3.1 / Expansion spec §7.4).
4
+ *
5
+ * Four modes, per route (default `detect` when content custody is on):
6
+ * off — no scan; upload verbatim.
7
+ * detect — scan; record FINDINGS as counts-by-type; upload verbatim. The
8
+ * findings are metadata (how many SSNs, how many emails), NEVER the
9
+ * matched values — recording the value would move the PII into the
10
+ * control-plane DB, the exact thing custody is meant to contain.
11
+ * redact — scan; upload a MASKED copy; the finding counts still travel.
12
+ * block — scan; if anything is found, REFUSE the upload (counted); the
13
+ * artifact keeps its metadata + hash, it simply stores no content.
14
+ *
15
+ * ── DETERMINISTIC ≠ DLP (honest limits) ───────────────────────────────────
16
+ * These are regex/checksum detectors, not a model. They catch well-formed SSNs,
17
+ * Luhn-valid PANs, emails, E.164/US phones, and labelled MRNs. They WILL miss
18
+ * obfuscated or free-form PII (that is scrub v2, model-assisted, out of scope).
19
+ * The custody docs page states this plainly — a caller must not read a clean
20
+ * `detect` result as a guarantee of no PII.
21
+ *
22
+ * NEVER logs a matched value. Findings are `{type, count}` only.
23
+ */
24
+ export type ScrubMode = "off" | "detect" | "redact" | "block";
25
+ /** A finding is a COUNT by type — never a value (the load-bearing invariant). */
26
+ export interface ScrubFinding {
27
+ readonly type: ScrubDetectorType;
28
+ readonly count: number;
29
+ }
30
+ export type ScrubDetectorType = "ssn" | "pan" | "email" | "phone" | "mrn";
31
+ export interface ScrubResult {
32
+ /** Findings as counts-by-type, sorted by type. Empty when nothing matched. */
33
+ readonly findings: readonly ScrubFinding[];
34
+ /** The text to upload: identical to input for off/detect, masked for redact,
35
+ * and null for block-with-findings (nothing is uploaded). */
36
+ readonly text: string | null;
37
+ /** True when `block` mode refused because findings were present. */
38
+ readonly blocked: boolean;
39
+ }
40
+ /** The per-artifact scrub record persisted on `artifacts.scrub` (migration
41
+ * 00039). COUNTS ONLY — the `findings` are `{type,count}`, never a matched
42
+ * value (the load-bearing invariant, same as the SDK counters). `mode` records
43
+ * WHICH policy ran; `blocked` whether `block` mode refused the upload. */
44
+ export interface ScrubSummary {
45
+ readonly mode: ScrubMode;
46
+ readonly blocked: boolean;
47
+ readonly findings: readonly ScrubFinding[];
48
+ }
49
+ /** Build the persisted summary from a scrub result. The only producer of the
50
+ * `artifacts.scrub` value, so the counts-not-values invariant lives in one
51
+ * place — it simply forwards `ScrubResult.findings`, which are already counts. */
52
+ export declare function summarizeScrub(mode: ScrubMode, result: ScrubResult): ScrubSummary;
53
+ /** Luhn checksum — the difference between "16 digits" and "a card number". */
54
+ export declare function luhnValid(digits: string): boolean;
55
+ /**
56
+ * Scan `text` and produce a scrub result for `mode`. Pure and deterministic.
57
+ * Never returns or logs a matched value.
58
+ */
59
+ export declare function scrubContent(text: string, mode: ScrubMode): ScrubResult;
60
+ //# sourceMappingURL=scrub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrub.d.ts","sourceRoot":"","sources":["../../src/artifacts/scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9D,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C;iEAC6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;0EAG0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;CAC5C;AAED;;kFAEkF;AAClF,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,YAAY,CAEjF;AAWD,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAejD;AA0CD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,WAAW,CA6CvE"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * Scrub v1 — deterministic PII/PHI detection over artifact content BEFORE upload
4
+ * (E2-C chunk B, spec §3.1 / Expansion spec §7.4).
5
+ *
6
+ * Four modes, per route (default `detect` when content custody is on):
7
+ * off — no scan; upload verbatim.
8
+ * detect — scan; record FINDINGS as counts-by-type; upload verbatim. The
9
+ * findings are metadata (how many SSNs, how many emails), NEVER the
10
+ * matched values — recording the value would move the PII into the
11
+ * control-plane DB, the exact thing custody is meant to contain.
12
+ * redact — scan; upload a MASKED copy; the finding counts still travel.
13
+ * block — scan; if anything is found, REFUSE the upload (counted); the
14
+ * artifact keeps its metadata + hash, it simply stores no content.
15
+ *
16
+ * ── DETERMINISTIC ≠ DLP (honest limits) ───────────────────────────────────
17
+ * These are regex/checksum detectors, not a model. They catch well-formed SSNs,
18
+ * Luhn-valid PANs, emails, E.164/US phones, and labelled MRNs. They WILL miss
19
+ * obfuscated or free-form PII (that is scrub v2, model-assisted, out of scope).
20
+ * The custody docs page states this plainly — a caller must not read a clean
21
+ * `detect` result as a guarantee of no PII.
22
+ *
23
+ * NEVER logs a matched value. Findings are `{type, count}` only.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.summarizeScrub = summarizeScrub;
27
+ exports.luhnValid = luhnValid;
28
+ exports.scrubContent = scrubContent;
29
+ /** Build the persisted summary from a scrub result. The only producer of the
30
+ * `artifacts.scrub` value, so the counts-not-values invariant lives in one
31
+ * place — it simply forwards `ScrubResult.findings`, which are already counts. */
32
+ function summarizeScrub(mode, result) {
33
+ return { mode, blocked: result.blocked, findings: result.findings };
34
+ }
35
+ /** Luhn checksum — the difference between "16 digits" and "a card number". */
36
+ function luhnValid(digits) {
37
+ const only = digits.replace(/\D/g, "");
38
+ if (only.length < 13 || only.length > 19)
39
+ return false;
40
+ let sum = 0;
41
+ let dbl = false;
42
+ for (let i = only.length - 1; i >= 0; i--) {
43
+ let d = only.charCodeAt(i) - 48;
44
+ if (dbl) {
45
+ d *= 2;
46
+ if (d > 9)
47
+ d -= 9;
48
+ }
49
+ sum += d;
50
+ dbl = !dbl;
51
+ }
52
+ return sum % 10 === 0;
53
+ }
54
+ // Order matters: PAN before phone/SSN so a 16-digit run is claimed as a card,
55
+ // not split. Each pattern is intentionally conservative — a false positive that
56
+ // masks a non-secret is cheaper than a false negative, but a pattern loose
57
+ // enough to match ordinary prose would make `block` unusable.
58
+ const DETECTORS = [
59
+ {
60
+ // PAN: 13–16 digits, optionally split by spaces/dashes in 4s, Luhn-valid.
61
+ type: "pan",
62
+ re: /\b(?:\d[ -]?){12,18}\d\b/g,
63
+ accept: luhnValid,
64
+ mask: "[REDACTED-PAN]",
65
+ },
66
+ {
67
+ // US SSN: AAA-GG-SSSS with dashes (the delimited form; bare 9-digit runs are
68
+ // too ambiguous to claim without a false-positive flood).
69
+ type: "ssn",
70
+ re: /\b\d{3}-\d{2}-\d{4}\b/g,
71
+ mask: "[REDACTED-SSN]",
72
+ },
73
+ {
74
+ type: "email",
75
+ re: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
76
+ mask: "[REDACTED-EMAIL]",
77
+ },
78
+ {
79
+ // Phone: E.164 (+1…) or US formats (parens/dashes/dots/spaces). Requires a
80
+ // grouping delimiter or leading + so bare 10-digit ids don't all match.
81
+ type: "phone",
82
+ re: /(?:\+\d{1,3}[ -]?)?(?:\(\d{3}\)|\d{3})[ .-]\d{3}[ .-]\d{4}\b/g,
83
+ mask: "[REDACTED-PHONE]",
84
+ },
85
+ {
86
+ // MRN-ish: an explicit label followed by an id. A heuristic by nature — the
87
+ // label is what makes it claimable without a false-positive flood.
88
+ type: "mrn",
89
+ re: /\bMRN\b\s*[:#]?\s*[A-Za-z0-9-]{4,}/gi,
90
+ mask: "[REDACTED-MRN]",
91
+ },
92
+ ];
93
+ /**
94
+ * Scan `text` and produce a scrub result for `mode`. Pure and deterministic.
95
+ * Never returns or logs a matched value.
96
+ */
97
+ function scrubContent(text, mode) {
98
+ if (mode === "off") {
99
+ return { findings: [], text, blocked: false };
100
+ }
101
+ const counts = new Map();
102
+ let masked = text;
103
+ for (const det of DETECTORS) {
104
+ // Fresh regex state per pass (global flag carries lastIndex otherwise).
105
+ const re = new RegExp(det.re.source, det.re.flags);
106
+ let count = 0;
107
+ const matched = [];
108
+ for (const m of text.matchAll(re)) {
109
+ const value = m[0];
110
+ if (det.accept && !det.accept(value))
111
+ continue;
112
+ count += 1;
113
+ if (mode === "redact")
114
+ matched.push(value);
115
+ }
116
+ if (count > 0) {
117
+ counts.set(det.type, count);
118
+ if (mode === "redact") {
119
+ for (const value of matched) {
120
+ // Replace literal occurrences with the mask. split/join avoids
121
+ // regex-escaping the value AND avoids putting it in any log.
122
+ masked = masked.split(value).join(det.mask);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ const findings = [...counts.entries()]
128
+ .map(([type, count]) => ({ type, count }))
129
+ .sort((a, b) => (a.type < b.type ? -1 : a.type > b.type ? 1 : 0));
130
+ const hasFindings = findings.length > 0;
131
+ if (mode === "block" && hasFindings) {
132
+ return { findings, text: null, blocked: true };
133
+ }
134
+ if (mode === "redact") {
135
+ return { findings, text: masked, blocked: false };
136
+ }
137
+ // detect (or block with no findings): upload verbatim, report counts.
138
+ return { findings, text, blocked: false };
139
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `@step` / `step()` — execution scope for NON-LLM stages (spec §1.4, §9).
3
+ *
4
+ * A step is an execution operation ("what happened"). For LLM calls `rig.run()`
5
+ * auto-creates a ground-truth step (its inference row already exists); this
6
+ * wrapper is for the OTHER stages — retrieval, transforms, tool calls, external
7
+ * APIs — which have no inference row.
8
+ *
9
+ * ── WHY THIS WRITES NO STEP ROW THIS MISSION ──────────────────────────────
10
+ * The `steps` CHECK requires EXACTLY ONE reference: ground-truth (an inference)
11
+ * XOR attested (a foreign OTLP span). A pure non-LLM stage has neither — its
12
+ * span reference arrives with OTLP INGEST (E3), and nothing writes `attested`
13
+ * rows this mission. So `step()` establishes a NAMED execution scope inside the
14
+ * active run context (chunk B attributes artifact save/load lineage to it) and
15
+ * runs the body; it does not persist a row until it has a valid reference.
16
+ *
17
+ * Instrumentation never changes the wrapped function's return value, and never
18
+ * throws into it — a disabled or absent run context just runs the body.
19
+ */
20
+ /**
21
+ * Run `fn` as a named execution step within the active run context. Returns the
22
+ * body's value unchanged (a promise if the body is async). Outside a run context
23
+ * (namespace disabled, or no run.start on this path) it simply runs the body.
24
+ */
25
+ export declare function step<T>(key: string, fn: () => T): T;
26
+ //# sourceMappingURL=step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/artifacts/step.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAOnD"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * `@step` / `step()` — execution scope for NON-LLM stages (spec §1.4, §9).
4
+ *
5
+ * A step is an execution operation ("what happened"). For LLM calls `rig.run()`
6
+ * auto-creates a ground-truth step (its inference row already exists); this
7
+ * wrapper is for the OTHER stages — retrieval, transforms, tool calls, external
8
+ * APIs — which have no inference row.
9
+ *
10
+ * ── WHY THIS WRITES NO STEP ROW THIS MISSION ──────────────────────────────
11
+ * The `steps` CHECK requires EXACTLY ONE reference: ground-truth (an inference)
12
+ * XOR attested (a foreign OTLP span). A pure non-LLM stage has neither — its
13
+ * span reference arrives with OTLP INGEST (E3), and nothing writes `attested`
14
+ * rows this mission. So `step()` establishes a NAMED execution scope inside the
15
+ * active run context (chunk B attributes artifact save/load lineage to it) and
16
+ * runs the body; it does not persist a row until it has a valid reference.
17
+ *
18
+ * Instrumentation never changes the wrapped function's return value, and never
19
+ * throws into it — a disabled or absent run context just runs the body.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.step = step;
23
+ const run_context_1 = require("./run-context");
24
+ /**
25
+ * Run `fn` as a named execution step within the active run context. Returns the
26
+ * body's value unchanged (a promise if the body is async). Outside a run context
27
+ * (namespace disabled, or no run.start on this path) it simply runs the body.
28
+ */
29
+ function step(key, fn) {
30
+ const ctx = (0, run_context_1.getActiveRunContext)();
31
+ if (ctx === null)
32
+ return fn();
33
+ // Reserve a unique step key so chunk B can attribute this scope's artifact
34
+ // saves/loads. No row is written (see header).
35
+ ctx.nextStepKey(key);
36
+ return fn();
37
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Taint propagation — downstream closure over the artifact graph (Expansion E4
3
+ * chunk C, spec §Chunk C). "If THIS artifact is bad, what derived from it?" —
4
+ * the condemn-or-clear question. Follows lineage edges forward (an edge means
5
+ * `from` was produced from / consumed `to`, so `from` is DOWNSTREAM of `to`) and
6
+ * `supersedes` chains forward (a version that supersedes a tainted one inherits
7
+ * the taint). Served as a bounded DTO the artifact page renders and the replay
8
+ * affordance (chunk A) links into.
9
+ *
10
+ * ── BOUNDED + HONEST ──────────────────────────────────────────────────────
11
+ * Real graphs can be deep, wide, or cyclic (a redaction supersedes an artifact
12
+ * that a later step also consumed). So the closure is:
13
+ * - depth-bounded (default 20) — `depthLimited` says more may exist deeper;
14
+ * - cycle-guarded (a visited set — a node is expanded once);
15
+ * - count-capped (default 500) — `truncated` says "≥ cap", never a silent cut.
16
+ * The production path is a recursive CTE with the SAME bounds (server); this pure
17
+ * function is the algorithm both the CTE golden-tests against and a caller can
18
+ * run over fetched edges without a database.
19
+ */
20
+ /** A stored lineage edge: `from` depends on `to` (kind = how). */
21
+ export interface TaintEdge {
22
+ readonly from: string;
23
+ readonly to: string;
24
+ readonly kind: "consumed" | "derived_from";
25
+ }
26
+ /** A supersession: `artifactId` supersedes `supersedesArtifactId` (a newer
27
+ * version). The superseder is downstream of what it supersedes. */
28
+ export interface Supersession {
29
+ readonly artifactId: string;
30
+ readonly supersedesArtifactId: string;
31
+ }
32
+ export interface TaintNode {
33
+ readonly id: string;
34
+ /** Hops from the root (1 = a direct descendant). */
35
+ readonly depth: number;
36
+ }
37
+ export interface TaintClosure {
38
+ readonly root: string;
39
+ /** Downstream artifacts, breadth-first (nearest first), deduped, capped. */
40
+ readonly downstream: readonly TaintNode[];
41
+ /** `downstream.length` — the count actually returned. */
42
+ readonly count: number;
43
+ /** True when the closure hit the count cap — the honest "≥ count" signal. */
44
+ readonly truncated: boolean;
45
+ /** True when the frontier reached `maxDepth` — more may exist deeper. */
46
+ readonly depthLimited: boolean;
47
+ readonly maxDepth: number;
48
+ readonly cap: number;
49
+ }
50
+ export interface TaintOptions {
51
+ /** Max hops from the root (default 20). */
52
+ readonly maxDepth?: number;
53
+ /** Max downstream nodes returned before truncation (default 500). */
54
+ readonly cap?: number;
55
+ }
56
+ export declare const TAINT_DEFAULT_MAX_DEPTH = 20;
57
+ export declare const TAINT_DEFAULT_CAP = 500;
58
+ /**
59
+ * Downstream closure from `root`. Pure and deterministic. Cycle-guarded via a
60
+ * visited set; depth-bounded; count-capped with an honest `truncated` flag.
61
+ */
62
+ export declare function computeDownstreamClosure(root: string, edges: readonly TaintEdge[], supersessions: readonly Supersession[], options?: TaintOptions): TaintClosure;
63
+ //# sourceMappingURL=taint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint.d.ts","sourceRoot":"","sources":["../../src/artifacts/taint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,kEAAkE;AAClE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC;CAC5C;AAED;mEACmE;AACnE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,aAAa,EAAE,SAAS,YAAY,EAAE,EACtC,OAAO,GAAE,YAAiB,GACzB,YAAY,CA2Cd"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Taint propagation — downstream closure over the artifact graph (Expansion E4
4
+ * chunk C, spec §Chunk C). "If THIS artifact is bad, what derived from it?" —
5
+ * the condemn-or-clear question. Follows lineage edges forward (an edge means
6
+ * `from` was produced from / consumed `to`, so `from` is DOWNSTREAM of `to`) and
7
+ * `supersedes` chains forward (a version that supersedes a tainted one inherits
8
+ * the taint). Served as a bounded DTO the artifact page renders and the replay
9
+ * affordance (chunk A) links into.
10
+ *
11
+ * ── BOUNDED + HONEST ──────────────────────────────────────────────────────
12
+ * Real graphs can be deep, wide, or cyclic (a redaction supersedes an artifact
13
+ * that a later step also consumed). So the closure is:
14
+ * - depth-bounded (default 20) — `depthLimited` says more may exist deeper;
15
+ * - cycle-guarded (a visited set — a node is expanded once);
16
+ * - count-capped (default 500) — `truncated` says "≥ cap", never a silent cut.
17
+ * The production path is a recursive CTE with the SAME bounds (server); this pure
18
+ * function is the algorithm both the CTE golden-tests against and a caller can
19
+ * run over fetched edges without a database.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.TAINT_DEFAULT_CAP = exports.TAINT_DEFAULT_MAX_DEPTH = void 0;
23
+ exports.computeDownstreamClosure = computeDownstreamClosure;
24
+ exports.TAINT_DEFAULT_MAX_DEPTH = 20;
25
+ exports.TAINT_DEFAULT_CAP = 500;
26
+ /**
27
+ * Downstream closure from `root`. Pure and deterministic. Cycle-guarded via a
28
+ * visited set; depth-bounded; count-capped with an honest `truncated` flag.
29
+ */
30
+ function computeDownstreamClosure(root, edges, supersessions, options = {}) {
31
+ const maxDepth = options.maxDepth ?? exports.TAINT_DEFAULT_MAX_DEPTH;
32
+ const cap = options.cap ?? exports.TAINT_DEFAULT_CAP;
33
+ // Adjacency: node → its direct downstream nodes. An edge (from → to) makes
34
+ // `from` downstream of `to`; a supersession makes the superseder downstream of
35
+ // what it supersedes. Both collapse into the same "who depends on X" map.
36
+ const downstreamOf = new Map();
37
+ const add = (parent, child) => {
38
+ const cur = downstreamOf.get(parent);
39
+ if (cur === undefined)
40
+ downstreamOf.set(parent, [child]);
41
+ else
42
+ cur.push(child);
43
+ };
44
+ for (const e of edges)
45
+ add(e.to, e.from);
46
+ for (const s of supersessions)
47
+ add(s.supersedesArtifactId, s.artifactId);
48
+ const visited = new Set([root]); // root is never listed as its own downstream
49
+ const downstream = [];
50
+ let truncated = false;
51
+ let depthLimited = false;
52
+ // BFS by depth so `downstream` is nearest-first and depth is well-defined.
53
+ let frontier = [root];
54
+ for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {
55
+ const next = [];
56
+ for (const node of frontier) {
57
+ for (const child of downstreamOf.get(node) ?? []) {
58
+ if (visited.has(child))
59
+ continue; // cycle / diamond guard: expand once
60
+ visited.add(child);
61
+ if (downstream.length >= cap) {
62
+ truncated = true;
63
+ continue; // keep draining `visited` so we don't re-count, but add no more
64
+ }
65
+ downstream.push({ id: child, depth });
66
+ next.push(child);
67
+ }
68
+ }
69
+ frontier = next;
70
+ }
71
+ // If we stopped because we hit maxDepth but there was still a frontier, more
72
+ // may exist deeper than we looked.
73
+ if (frontier.length > 0)
74
+ depthLimited = true;
75
+ return { root, downstream, count: downstream.length, truncated, depthLimited, maxDepth, cap };
76
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Virtual cache simulator — cache-aware-routing spec §5.4, [Briefing §26]. PURE:
3
+ * no store/clock/network. THE fix for the independent-turn evaluation fallacy:
4
+ * replay currently scores every sample COLD, so a bake-off report can never see
5
+ * that a candidate would run warm at production cadence. This walks a candidate's
6
+ * call sequence in timestamp order, maintaining a per-candidate VIRTUAL cache
7
+ * from the POLICY REGISTRY (TTL + min-cacheable + refresh-on-read), and emits a
8
+ * per-call {read, write, uncached} token split.
9
+ *
10
+ * ── SIMULATOR HONESTY (spec §5.4, §10 credibility risk) ───────────────────
11
+ * • State comes ONLY from the policy registry — never from a guessed model of
12
+ * how a provider caches. An undocumented TTL uses a CONSERVATIVE fallback
13
+ * (short), so the sim UNDER-credits rather than over-credits warmth.
14
+ * • The output is always LABELLED simulation. The odometer stays measured-only
15
+ * (this module never feeds it) — simulator output is never "verified savings".
16
+ * • Cache identity is the caller-supplied `prefixFingerprint`. A template
17
+ * mutation or a tool-order change is, by construction, a DIFFERENT
18
+ * fingerprint — so a mutation forces a miss/rewrite with no special-casing
19
+ * here (the synthetic tests exercise exactly that).
20
+ *
21
+ * A "switch-and-return" is modelled by a time GAP in this candidate's sequence:
22
+ * if the gap is within TTL the return is a read (still warm); if it exceeds TTL
23
+ * the cache has expired and the return rewrites. Nothing about the OTHER
24
+ * candidate is needed — each candidate is simulated over its own calls.
25
+ */
26
+ import type { CachePolicy } from "../registry/cache-policy";
27
+ import type { EffectiveRates } from "../registry/effective-rate";
28
+ import type { ProviderId } from "../types/provider";
29
+ /** One call in a candidate's sequence. `prefixTokens` is the cacheable prefix
30
+ * length; `promptTokens` the whole input (prefix + volatile tail). */
31
+ export interface SimCall {
32
+ readonly tsMs: number;
33
+ readonly prefixFingerprint: string;
34
+ readonly prefixTokens: number;
35
+ readonly promptTokens: number;
36
+ }
37
+ /** Per-call token split — a disjoint partition of `promptTokens`:
38
+ * `simulated_read + simulated_write + simulated_uncached === promptTokens`. */
39
+ export interface SimCallResult {
40
+ readonly simulated_read: number;
41
+ readonly simulated_write: number;
42
+ readonly simulated_uncached: number;
43
+ /** True when the cacheable prefix was served from a warm virtual cache. */
44
+ readonly hit: boolean;
45
+ }
46
+ /** The policy assumptions the sim ran under — PRINTED with every report so the
47
+ * simulation's basis is never hidden (spec §5.4 "assumptions printed"). */
48
+ export interface CacheSimAssumptions {
49
+ readonly provider: string;
50
+ readonly model: string;
51
+ readonly cacheSupported: boolean;
52
+ /** TTL used to expire virtual entries (seconds). */
53
+ readonly ttlSeconds: number;
54
+ /** false ⇒ `ttlSeconds` is the conservative fallback, not a published value. */
55
+ readonly ttlSourced: boolean;
56
+ readonly minCacheableTokens: number;
57
+ readonly refreshOnRead: boolean;
58
+ }
59
+ export interface CacheSimResult {
60
+ readonly perCall: readonly SimCallResult[];
61
+ readonly totalRead: number;
62
+ readonly totalWrite: number;
63
+ readonly totalUncached: number;
64
+ readonly hitCount: number;
65
+ readonly assumptions: CacheSimAssumptions;
66
+ }
67
+ /**
68
+ * Conservative TTL (seconds) for a provider that publishes none
69
+ * (`default_ttl_seconds: null`). Deliberately SHORT — the shortest real registry
70
+ * TTL (Anthropic 5m) — so the simulator never over-credits warmth for a provider
71
+ * whose true window is longer but undocumented (spec §5.4 honesty).
72
+ */
73
+ export declare const FALLBACK_SIM_TTL_SECONDS = 300;
74
+ export interface CacheSimOptions {
75
+ /** Policy override — injected for tests; defaults to the live registry. */
76
+ readonly policy?: CachePolicy;
77
+ }
78
+ /**
79
+ * Simulate one candidate's cache trajectory over `calls`. Calls are processed in
80
+ * ascending timestamp order (a copy is sorted; the input is not mutated). The
81
+ * per-call results are returned in that same timestamp order.
82
+ */
83
+ export declare function simulateCache(provider: ProviderId, model: string, calls: readonly SimCall[], opts?: CacheSimOptions): CacheSimResult;
84
+ /**
85
+ * Cache-ADJUSTED input cost of a simulated trajectory (spec §5.4): the read /
86
+ * write / uncached token buckets each priced at their own rate, with the
87
+ * fail-closed fallback to the input rate (dev-rule L5) when a cache rate is
88
+ * unverified. This is what the candidate WOULD pay at production cadence — the
89
+ * right-hand column of the bake-off's side-by-side.
90
+ */
91
+ export declare function simulatedInputCostUsd(sim: CacheSimResult, rates: EffectiveRates): number;
92
+ /**
93
+ * Measured-COLD input cost (spec §5.4): every input token at the list input
94
+ * rate — what independent-turn replay actually pays. The left-hand column. This
95
+ * equals `simulatedInputCostUsd` exactly when the sim produced zero reads and
96
+ * zero writes (the regression pin — no cache activity, no divergence).
97
+ */
98
+ export declare function coldInputCostUsd(sim: CacheSimResult, rates: EffectiveRates): number;
99
+ //# sourceMappingURL=cache-sim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-sim.d.ts","sourceRoot":"","sources":["../../src/bakeoff/cache-sim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;sEACsE;AACtE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;+EAC+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB;AAED;2EAC2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AASD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,IAAI,GAAE,eAAoB,GACzB,cAAc,CAkEhB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAIxF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAEnF"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ /**
3
+ * Virtual cache simulator — cache-aware-routing spec §5.4, [Briefing §26]. PURE:
4
+ * no store/clock/network. THE fix for the independent-turn evaluation fallacy:
5
+ * replay currently scores every sample COLD, so a bake-off report can never see
6
+ * that a candidate would run warm at production cadence. This walks a candidate's
7
+ * call sequence in timestamp order, maintaining a per-candidate VIRTUAL cache
8
+ * from the POLICY REGISTRY (TTL + min-cacheable + refresh-on-read), and emits a
9
+ * per-call {read, write, uncached} token split.
10
+ *
11
+ * ── SIMULATOR HONESTY (spec §5.4, §10 credibility risk) ───────────────────
12
+ * • State comes ONLY from the policy registry — never from a guessed model of
13
+ * how a provider caches. An undocumented TTL uses a CONSERVATIVE fallback
14
+ * (short), so the sim UNDER-credits rather than over-credits warmth.
15
+ * • The output is always LABELLED simulation. The odometer stays measured-only
16
+ * (this module never feeds it) — simulator output is never "verified savings".
17
+ * • Cache identity is the caller-supplied `prefixFingerprint`. A template
18
+ * mutation or a tool-order change is, by construction, a DIFFERENT
19
+ * fingerprint — so a mutation forces a miss/rewrite with no special-casing
20
+ * here (the synthetic tests exercise exactly that).
21
+ *
22
+ * A "switch-and-return" is modelled by a time GAP in this candidate's sequence:
23
+ * if the gap is within TTL the return is a read (still warm); if it exceeds TTL
24
+ * the cache has expired and the return rewrites. Nothing about the OTHER
25
+ * candidate is needed — each candidate is simulated over its own calls.
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.FALLBACK_SIM_TTL_SECONDS = void 0;
29
+ exports.simulateCache = simulateCache;
30
+ exports.simulatedInputCostUsd = simulatedInputCostUsd;
31
+ exports.coldInputCostUsd = coldInputCostUsd;
32
+ const cache_policy_1 = require("../registry/cache-policy");
33
+ /**
34
+ * Conservative TTL (seconds) for a provider that publishes none
35
+ * (`default_ttl_seconds: null`). Deliberately SHORT — the shortest real registry
36
+ * TTL (Anthropic 5m) — so the simulator never over-credits warmth for a provider
37
+ * whose true window is longer but undocumented (spec §5.4 honesty).
38
+ */
39
+ exports.FALLBACK_SIM_TTL_SECONDS = 300;
40
+ /**
41
+ * Simulate one candidate's cache trajectory over `calls`. Calls are processed in
42
+ * ascending timestamp order (a copy is sorted; the input is not mutated). The
43
+ * per-call results are returned in that same timestamp order.
44
+ */
45
+ function simulateCache(provider, model, calls, opts = {}) {
46
+ const policy = opts.policy ?? (0, cache_policy_1.getCachePolicy)(provider);
47
+ const ttlSourced = policy.cache_supported && policy.default_ttl_seconds !== null;
48
+ const ttlSeconds = policy.cache_supported && policy.default_ttl_seconds !== null
49
+ ? policy.default_ttl_seconds
50
+ : exports.FALLBACK_SIM_TTL_SECONDS;
51
+ const ttlMs = ttlSeconds * 1000;
52
+ const minCacheable = policy.min_cacheable_tokens ?? 0;
53
+ const assumptions = {
54
+ provider,
55
+ model,
56
+ cacheSupported: policy.cache_supported,
57
+ ttlSeconds,
58
+ ttlSourced,
59
+ minCacheableTokens: minCacheable,
60
+ refreshOnRead: policy.ttl_refresh_on_read,
61
+ };
62
+ const ordered = [...calls].sort((a, b) => a.tsMs - b.tsMs);
63
+ const cache = new Map();
64
+ const perCall = [];
65
+ let totalRead = 0;
66
+ let totalWrite = 0;
67
+ let totalUncached = 0;
68
+ let hitCount = 0;
69
+ for (const call of ordered) {
70
+ const prompt = Math.max(call.promptTokens, 0);
71
+ const prefix = Math.min(Math.max(call.prefixTokens, 0), prompt);
72
+ // Provider does not cache on our path, or the prefix is below the minimum
73
+ // cacheable size: caching does not engage — the whole prompt is uncached and
74
+ // NO virtual state is written (spec §5.4: min-cacheable gates the write).
75
+ if (!policy.cache_supported || prefix < minCacheable || prefix === 0) {
76
+ perCall.push({ simulated_read: 0, simulated_write: 0, simulated_uncached: prompt, hit: false });
77
+ totalUncached += prompt;
78
+ continue;
79
+ }
80
+ const entry = cache.get(call.prefixFingerprint);
81
+ const warm = entry !== undefined && call.tsMs < entry.expiresAtMs;
82
+ if (warm) {
83
+ // HIT: read the cached prefix; the volatile tail is uncached.
84
+ const read = Math.min(prefix, entry.tokens);
85
+ const uncached = prompt - read;
86
+ perCall.push({ simulated_read: read, simulated_write: 0, simulated_uncached: uncached, hit: true });
87
+ totalRead += read;
88
+ totalUncached += uncached;
89
+ hitCount += 1;
90
+ // TTL base: a read refreshes the window only when the policy says so;
91
+ // otherwise the entry keeps expiring from its WRITE time.
92
+ if (policy.ttl_refresh_on_read)
93
+ entry.expiresAtMs = call.tsMs + ttlMs;
94
+ }
95
+ else {
96
+ // MISS (cold or expired): WRITE the prefix into cache; the tail is uncached.
97
+ const uncached = prompt - prefix;
98
+ perCall.push({ simulated_read: 0, simulated_write: prefix, simulated_uncached: uncached, hit: false });
99
+ totalWrite += prefix;
100
+ totalUncached += uncached;
101
+ cache.set(call.prefixFingerprint, { tokens: prefix, expiresAtMs: call.tsMs + ttlMs });
102
+ }
103
+ }
104
+ return { perCall, totalRead, totalWrite, totalUncached, hitCount, assumptions };
105
+ }
106
+ /**
107
+ * Cache-ADJUSTED input cost of a simulated trajectory (spec §5.4): the read /
108
+ * write / uncached token buckets each priced at their own rate, with the
109
+ * fail-closed fallback to the input rate (dev-rule L5) when a cache rate is
110
+ * unverified. This is what the candidate WOULD pay at production cadence — the
111
+ * right-hand column of the bake-off's side-by-side.
112
+ */
113
+ function simulatedInputCostUsd(sim, rates) {
114
+ const readRate = rates.cacheRead ?? rates.input;
115
+ const writeRate = rates.cacheWrite ?? rates.input;
116
+ return sim.totalRead * readRate + sim.totalWrite * writeRate + sim.totalUncached * rates.input;
117
+ }
118
+ /**
119
+ * Measured-COLD input cost (spec §5.4): every input token at the list input
120
+ * rate — what independent-turn replay actually pays. The left-hand column. This
121
+ * equals `simulatedInputCostUsd` exactly when the sim produced zero reads and
122
+ * zero writes (the regression pin — no cache activity, no divergence).
123
+ */
124
+ function coldInputCostUsd(sim, rates) {
125
+ return (sim.totalRead + sim.totalWrite + sim.totalUncached) * rates.input;
126
+ }