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,137 @@
1
+ /**
2
+ * Artifact namespace — Expansion E2 chunk B (spec §2.2, §9).
3
+ *
4
+ * `save/load/link/evaluate` over a durable work product's METADATA. The
5
+ * serialized value is hashed (sha256, node:crypto — no new dep) and the bytes
6
+ * are DISCARDED; nothing but the metadata row is persisted (the 00030
7
+ * counter-annotation). Lineage v0: artifacts saved within a run get
8
+ * `derived_from` edges to artifacts `load`ed since the last save (coverage
9
+ * measured, never promised). Instrumentation never throws into customer code.
10
+ *
11
+ * ── zeroRetention (ratified invariant, named test) ────────────────────────
12
+ * A run with `zeroRetention: true` emits NO artifact rows of any kind: `save`
13
+ * refuses fail-closed at THIS gate (before any row is built) with a counted,
14
+ * logged skip. Structural, not policy-checked at the server.
15
+ */
16
+ import type { ArtifactStore } from "../telemetry/artifact-store";
17
+ import type { EvalCaseOrigin } from "../types/telemetry";
18
+ import { type ScrubMode } from "./scrub";
19
+ import type { ContentUploadInput, ContentUploadOutcome } from "./content-uploader";
20
+ /** The upload transport `save` fires content through — injected so the SDK's
21
+ * networked implementation and the tests share one seam. */
22
+ export type ArtifactContentUploader = (input: ContentUploadInput) => Promise<ContentUploadOutcome>;
23
+ /** Per-rig content-custody wiring passed to the artifact api (E2-C). Absent =
24
+ * metadata + hash only, today's behaviour. */
25
+ export interface ArtifactContentDeps {
26
+ readonly scrub: ScrubMode;
27
+ readonly upload: ArtifactContentUploader;
28
+ }
29
+ export interface ArtifactHandle {
30
+ readonly id: string;
31
+ readonly name: string;
32
+ readonly type: string;
33
+ readonly version: number;
34
+ }
35
+ export interface ArtifactSaveOptions {
36
+ readonly name: string;
37
+ readonly type: string;
38
+ readonly task?: string;
39
+ /** The pipeline step this artifact belongs to — the semantic grouping key the
40
+ * console's chain view orders on (E3 spec §2.1). E2 deferred step attribution
41
+ * ("refined when @step scopes persist, E3"); an EXPLICIT key set by the caller
42
+ * is the E3 refinement — safe under parallel step waves where an ambient
43
+ * mutable current-step would cross-attribute. Null (absent) ⇒ ungrouped. */
44
+ readonly stepKey?: string;
45
+ /** The step attempt this artifact came from (mirrors steps.attempt_no). Only
46
+ * meaningful alongside stepKey; null for artifacts saved outside a step. */
47
+ readonly attemptNo?: number;
48
+ readonly classification?: string;
49
+ /** OPAQUE customer URI (their bucket). We store the string + our hash, never content. */
50
+ readonly contentRef?: string;
51
+ /** Declared JSON Schema (fingerprinted with the same pure fn the loader uses). */
52
+ readonly schema?: object | null;
53
+ /** The artifact this one supersedes (immutable versioning; ruling c column). */
54
+ readonly supersedes?: ArtifactHandle;
55
+ readonly expiresAt?: string;
56
+ }
57
+ export interface ArtifactEvaluateOptions {
58
+ readonly evaluator: string;
59
+ readonly kind: "deterministic" | "model-judge" | "human";
60
+ readonly score?: number;
61
+ readonly passed?: boolean;
62
+ readonly label?: string;
63
+ readonly explanation?: string;
64
+ }
65
+ export interface ArtifactPromoteOptions {
66
+ readonly note?: string;
67
+ /** The route/task this case belongs to. Falls back to the task the source
68
+ * artifact was saved with this session; required (explicitly or via fallback)
69
+ * because an eval case is keyed by task. */
70
+ readonly task?: string;
71
+ /** The corrected/golden artifact — set ⇒ a golden-corrected pair. */
72
+ readonly corrected?: ArtifactHandle | string;
73
+ /** How it entered the suite. Default: `human-corrected` when `corrected` is
74
+ * set, else `promoted-failure`. */
75
+ readonly origin?: EvalCaseOrigin;
76
+ }
77
+ export interface ArtifactApi {
78
+ /** Hash the value's serialization, record metadata + inferred lineage, return
79
+ * a handle. Returns null when the namespace is disabled or a zeroRetention run
80
+ * refuses it (fail-closed). */
81
+ save(value: unknown, opts: ArtifactSaveOptions): ArtifactHandle | null;
82
+ /** Mark an artifact consumed by the current run (feeds derived_from lineage). */
83
+ load(ref: ArtifactHandle | string): void;
84
+ /** Explicit lineage edge the runtime cannot infer. */
85
+ link(from: ArtifactHandle | string, to: ArtifactHandle | string, kind: "consumed" | "derived_from"): void;
86
+ /** Record an evaluation against an artifact. */
87
+ evaluate(ref: ArtifactHandle | string, opts: ArtifactEvaluateOptions): void;
88
+ /** Promote an artifact into the org's durable eval suite (E4 chunk A) — a
89
+ * regression case replayable via `bakeoff --from-eval-cases`. `corrected` set
90
+ * ⇒ a golden-corrected pair; absent ⇒ a failure-case. The `task` binds the
91
+ * case to a route: taken from opts, else the task the artifact was saved with
92
+ * this session; unresolvable ⇒ a warned no-op (returns null, never throws).
93
+ * Returns the new case id on success. */
94
+ promoteToEval(ref: ArtifactHandle | string, opts?: ArtifactPromoteOptions): string | null;
95
+ /** Run `fn` inside a single store transaction and return its value (H8), so a
96
+ * step's several save/link/evaluate writes commit with ONE fsync. On a
97
+ * disabled/inert namespace `fn` runs directly (no store, no transaction). */
98
+ batch<T>(fn: () => T): T;
99
+ /** Await every in-flight content upload (E2-C). Content upload is fire-and-
100
+ * forget off the customer's hot path; a graceful shutdown (and the tests)
101
+ * call this so a process does not exit mid-PUT. No-op when custody is off. */
102
+ flushContent(): Promise<void>;
103
+ /** Re-attempt content uploads that came back `pending` — a 404 from the grant
104
+ * endpoint because the artifact metadata row had not yet been exported when
105
+ * the upload first fired (the 404-until-durable race, E4 chunk 0). The
106
+ * exporter calls this AFTER a confirmed flush of the artifacts stream, so by
107
+ * now the row is durable and the grant succeeds. Each call is exactly ONE
108
+ * retry per queued item (bounded 2 total, then a counted skip). NEVER throws.
109
+ * No-op when custody is off or the queue is empty. */
110
+ retryPendingContent(): Promise<void>;
111
+ /** Inferred-lineage + content-custody coverage counters (measured, never
112
+ * promised). Content counters update asynchronously as uploads settle. */
113
+ coverage(): {
114
+ readonly saves: number;
115
+ readonly inferredEdges: number;
116
+ readonly skippedZeroRetention: number;
117
+ /** Content uploads that reached the store. */
118
+ readonly contentUploaded: number;
119
+ /** Content uploads that degraded to metadata-only (refusal or transient). */
120
+ readonly contentDegraded: number;
121
+ /** Content uploads refused by the scrub `block` mode. */
122
+ readonly contentBlocked: number;
123
+ /** Content uploads awaiting the metadata-durable retry (E4 chunk 0). Drains
124
+ * to 0 as the exporter's post-flush hook re-attempts them; a still-pending
125
+ * item that exhausts its 2 retries moves to `contentDegraded`. */
126
+ readonly contentPending: number;
127
+ /** Total scrub findings (counts across types) seen this session. */
128
+ readonly scrubFindings: number;
129
+ };
130
+ }
131
+ export declare function createArtifactApi(deps: {
132
+ readonly store: ArtifactStore;
133
+ readonly enabled: boolean;
134
+ /** Content custody wiring (E2-C). Absent = metadata + hash only. */
135
+ readonly content?: ArtifactContentDeps;
136
+ }): ArtifactApi;
137
+ //# sourceMappingURL=artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/artifacts/artifact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ /**
3
+ * Artifact namespace — Expansion E2 chunk B (spec §2.2, §9).
4
+ *
5
+ * `save/load/link/evaluate` over a durable work product's METADATA. The
6
+ * serialized value is hashed (sha256, node:crypto — no new dep) and the bytes
7
+ * are DISCARDED; nothing but the metadata row is persisted (the 00030
8
+ * counter-annotation). Lineage v0: artifacts saved within a run get
9
+ * `derived_from` edges to artifacts `load`ed since the last save (coverage
10
+ * measured, never promised). Instrumentation never throws into customer code.
11
+ *
12
+ * ── zeroRetention (ratified invariant, named test) ────────────────────────
13
+ * A run with `zeroRetention: true` emits NO artifact rows of any kind: `save`
14
+ * refuses fail-closed at THIS gate (before any row is built) with a counted,
15
+ * logged skip. Structural, not policy-checked at the server.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.createArtifactApi = createArtifactApi;
19
+ const node_crypto_1 = require("node:crypto");
20
+ const fingerprint_1 = require("../registry/fingerprint");
21
+ const run_context_1 = require("./run-context");
22
+ const scrub_1 = require("./scrub");
23
+ /** Map an artifact `type` to a content-type for the object store. */
24
+ function contentTypeFor(type) {
25
+ const t = type.toLowerCase();
26
+ if (t === "json")
27
+ return "application/json";
28
+ if (t === "text" || t === "txt" || t === "md" || t === "markdown")
29
+ return "text/plain; charset=utf-8";
30
+ if (t === "csv")
31
+ return "text/csv";
32
+ if (t === "html")
33
+ return "text/html; charset=utf-8";
34
+ return "application/octet-stream";
35
+ }
36
+ function idOf(ref) {
37
+ return typeof ref === "string" ? ref : ref.id;
38
+ }
39
+ function warn(scope, err) {
40
+ console.warn(`[modelrig artifacts] ${scope} buffer write failed (dropped, run unaffected): ` +
41
+ `${err instanceof Error ? err.message : String(err)}`);
42
+ }
43
+ /** A disabled/inert namespace — every entry is a no-op (spec §1.4). */
44
+ function inertApi() {
45
+ return {
46
+ save: () => null,
47
+ load: () => { },
48
+ link: () => { },
49
+ evaluate: () => { },
50
+ promoteToEval: () => null,
51
+ batch: (fn) => fn(),
52
+ flushContent: () => Promise.resolve(),
53
+ retryPendingContent: () => Promise.resolve(),
54
+ coverage: () => ({
55
+ saves: 0,
56
+ inferredEdges: 0,
57
+ skippedZeroRetention: 0,
58
+ contentUploaded: 0,
59
+ contentDegraded: 0,
60
+ contentBlocked: 0,
61
+ contentPending: 0,
62
+ scrubFindings: 0,
63
+ }),
64
+ };
65
+ }
66
+ /** Bounded post-flush retries for a `pending` (404-until-durable) content upload
67
+ * before it becomes a counted skip (E4 chunk 0, flag 2). Two retries with the
68
+ * exporter interval between them is a multi-flush window for the metadata row to
69
+ * land — long enough for a real export lag, short enough to bound the wait. */
70
+ const CONTENT_RETRY_BUDGET = 2;
71
+ function createArtifactApi(deps) {
72
+ if (!deps.enabled)
73
+ return inertApi();
74
+ const { store, content } = deps;
75
+ let saves = 0;
76
+ let inferredEdges = 0;
77
+ let skippedZeroRetention = 0;
78
+ let contentUploaded = 0;
79
+ let contentDegraded = 0;
80
+ let contentBlocked = 0;
81
+ let scrubFindings = 0;
82
+ /** In-flight uploads; flushContent awaits them (graceful shutdown + tests). */
83
+ const pendingUploads = new Set();
84
+ /** Uploads that came back `pending` (grant 404 — metadata not yet durable),
85
+ * awaiting the exporter's post-flush retry hook. `retriesLeft` decrements once
86
+ * per hook call; at 0 the item becomes a counted skip (E4 chunk 0, flag 2). */
87
+ const pendingContent = [];
88
+ /** artifact id → the task it was saved with THIS session (E4 chunk A). Lets
89
+ * `promoteToEval(ref)` resolve the case's task without the caller re-supplying
90
+ * it. A promote of an artifact from a prior session must pass `opts.task`. */
91
+ const savedTasks = new Map();
92
+ /** Fire one content upload off the hot path. NEVER rejects into caller code —
93
+ * every outcome updates a counter (or queues a `pending` retry) and resolves. */
94
+ function fireUpload(input, upload) {
95
+ const p = upload(input)
96
+ .then((outcome) => {
97
+ if (outcome.kind === "uploaded")
98
+ contentUploaded += 1;
99
+ // A 404-until-durable race: queue for the post-flush retry rather than
100
+ // counting a degrade — the row simply has not been exported yet.
101
+ else if (outcome.kind === "pending") {
102
+ pendingContent.push({ input, retriesLeft: CONTENT_RETRY_BUDGET });
103
+ }
104
+ else
105
+ contentDegraded += 1; // "degraded" | "blocked"
106
+ })
107
+ .catch(() => {
108
+ contentDegraded += 1;
109
+ })
110
+ .finally(() => {
111
+ pendingUploads.delete(p);
112
+ });
113
+ pendingUploads.add(p);
114
+ }
115
+ /** Re-attempt every queued `pending` upload exactly once (the exporter's
116
+ * post-flush hook). Items that stay pending are re-queued with a decremented
117
+ * budget; at 0 they become a counted skip. Off/empty ⇒ a resolved no-op. */
118
+ async function retryPendingContent() {
119
+ if (content === undefined || pendingContent.length === 0)
120
+ return;
121
+ // Snapshot then clear: an item that stays pending is re-pushed with a lower
122
+ // budget, so THIS pass is exactly one retry per currently-queued item.
123
+ const batch = pendingContent.splice(0, pendingContent.length);
124
+ for (const item of batch) {
125
+ let outcome;
126
+ try {
127
+ outcome = await content.upload(item.input);
128
+ }
129
+ catch {
130
+ contentDegraded += 1; // an unexpected throw is a counted skip, never rethrown
131
+ continue;
132
+ }
133
+ if (outcome.kind === "uploaded") {
134
+ contentUploaded += 1;
135
+ }
136
+ else if (outcome.kind === "pending") {
137
+ const retriesLeft = item.retriesLeft - 1;
138
+ if (retriesLeft > 0) {
139
+ pendingContent.push({ input: item.input, retriesLeft });
140
+ }
141
+ else {
142
+ contentDegraded += 1; // exhausted the bounded retries → metadata-only
143
+ console.warn(`[modelrig artifacts] content for artifact ${item.input.artifactId} still not durable ` +
144
+ `after ${CONTENT_RETRY_BUDGET} post-flush retries — metadata-only (counted skip).`);
145
+ }
146
+ }
147
+ else {
148
+ contentDegraded += 1; // degraded | blocked on retry → counted skip
149
+ }
150
+ }
151
+ }
152
+ return {
153
+ save(value, opts) {
154
+ const ctx = (0, run_context_1.getActiveRunContext)();
155
+ // zeroRetention: refuse fail-closed BEFORE hashing or building any row.
156
+ if (ctx !== null && ctx.zeroRetention) {
157
+ skippedZeroRetention += 1;
158
+ console.warn(`[modelrig artifacts] zeroRetention run — artifact "${opts.name}" NOT recorded ` +
159
+ "(fail-closed at the SDK gate; no metadata, no hash persisted).");
160
+ return null;
161
+ }
162
+ // Hash the serialization, then DISCARD the bytes — metadata + hash only.
163
+ const serialized = typeof value === "string" ? value : JSON.stringify(value ?? null);
164
+ const bytes = Buffer.byteLength(serialized, "utf8");
165
+ const contentHash = `sha256:${(0, node_crypto_1.createHash)("sha256").update(serialized).digest("hex")}`;
166
+ const schema = opts.schema ?? null;
167
+ const id = (0, node_crypto_1.randomUUID)();
168
+ const version = opts.supersedes !== undefined ? opts.supersedes.version + 1 : 1;
169
+ // Custody applies only when a rig content policy exists AND the caller left
170
+ // the bytes to us (a caller-supplied contentRef = their own store; managed
171
+ // custody must not double-home it).
172
+ const custodyApplies = content !== undefined && opts.contentRef === undefined;
173
+ // Scrub is computed HERE (before the row is written) so its counts-only
174
+ // summary can ride the immutable artifact row (00039). Only when custody
175
+ // applies; null otherwise (custody off ⇒ nothing was scanned).
176
+ const scrubbed = custodyApplies && content !== undefined ? (0, scrub_1.scrubContent)(serialized, content.scrub) : null;
177
+ const scrubSummary = scrubbed !== null && content !== undefined ? (0, scrub_1.summarizeScrub)(content.scrub, scrubbed) : null;
178
+ if (scrubbed !== null)
179
+ scrubFindings += scrubbed.findings.reduce((n, f) => n + f.count, 0);
180
+ try {
181
+ store.recordArtifact({
182
+ id,
183
+ runId: ctx?.runId ?? null,
184
+ // E3: step attribution is now an explicit caller-supplied key (see
185
+ // ArtifactSaveOptions.stepKey). Absent ⇒ null, exactly as before.
186
+ stepKey: opts.stepKey ?? null,
187
+ attemptNo: opts.attemptNo ?? null,
188
+ task: opts.task ?? null,
189
+ name: opts.name,
190
+ type: opts.type,
191
+ version,
192
+ supersedesArtifactId: opts.supersedes?.id ?? null,
193
+ declaredSchema: schema,
194
+ fingerprintCell: (0, fingerprint_1.fingerprintSchema)(schema)?.cellKey ?? null,
195
+ contentRef: opts.contentRef ?? null,
196
+ contentHash,
197
+ contentBytes: bytes,
198
+ dataClassification: opts.classification ?? null,
199
+ expiresAt: opts.expiresAt ?? null,
200
+ // Per-row scrub findings ride the original (scanned) row (00039).
201
+ scrub: scrubSummary,
202
+ });
203
+ saves += 1;
204
+ if (opts.task !== undefined)
205
+ savedTasks.set(id, opts.task); // for promoteToEval (chunk A)
206
+ // Lineage v0: derived_from edges to everything loaded since the last save.
207
+ if (ctx !== null) {
208
+ for (const loadedId of ctx.takeLoadedIds()) {
209
+ if (loadedId === id)
210
+ continue; // edges_no_self
211
+ store.recordArtifactEdge({ fromArtifactId: id, toArtifactId: loadedId, kind: "derived_from" });
212
+ inferredEdges += 1;
213
+ }
214
+ }
215
+ }
216
+ catch (err) {
217
+ warn("save", err);
218
+ return null;
219
+ }
220
+ // ── Content custody (E2-C) ──────────────────────────────────────────
221
+ // Off by default: only when a rig has configured content custody. The
222
+ // metadata row above is written regardless — content is layered on, never
223
+ // a precondition. zeroRetention already returned above, so we never reach
224
+ // here for a zeroRetention run (structural, not re-checked).
225
+ if (content !== undefined && scrubbed !== null) {
226
+ if (scrubbed.blocked) {
227
+ // `block` mode found PII/PHI → content upload refused (counted). The
228
+ // artifact keeps its metadata + hash; it simply stores no content.
229
+ contentBlocked += 1;
230
+ console.warn(`[modelrig artifacts] scrub blocked content for "${opts.name}" ` +
231
+ `(${scrubbed.findings.length} finding type(s)); metadata + hash kept, no content stored.`);
232
+ }
233
+ else if (content.scrub === "redact" && scrubbed.findings.length > 0 && scrubbed.text !== null) {
234
+ // Redaction is a SUPERSEDING version (immutability): the original row
235
+ // keeps its hash and stores NO content; a new version records the
236
+ // masked content's hash and uploads the masked bytes.
237
+ const maskedSerialized = scrubbed.text;
238
+ const maskedBytes = Buffer.byteLength(maskedSerialized, "utf8");
239
+ const maskedHash = `sha256:${(0, node_crypto_1.createHash)("sha256").update(maskedSerialized).digest("hex")}`;
240
+ const redactedId = (0, node_crypto_1.randomUUID)();
241
+ const redactedVersion = version + 1;
242
+ try {
243
+ store.recordArtifact({
244
+ id: redactedId,
245
+ runId: ctx?.runId ?? null,
246
+ stepKey: opts.stepKey ?? null,
247
+ attemptNo: opts.attemptNo ?? null,
248
+ task: opts.task ?? null,
249
+ name: opts.name,
250
+ type: opts.type,
251
+ version: redactedVersion,
252
+ supersedesArtifactId: id, // supersedes the original (ruling c column)
253
+ declaredSchema: schema,
254
+ fingerprintCell: (0, fingerprint_1.fingerprintSchema)(schema)?.cellKey ?? null,
255
+ contentRef: null,
256
+ contentHash: maskedHash,
257
+ contentBytes: maskedBytes,
258
+ dataClassification: opts.classification ?? null,
259
+ expiresAt: opts.expiresAt ?? null,
260
+ // Findings ride the original scanned row; the masked version stores
261
+ // no PII, so its own scrub is null (avoid double-counting).
262
+ scrub: null,
263
+ });
264
+ saves += 1;
265
+ fireUpload({
266
+ artifactId: redactedId,
267
+ contentType: contentTypeFor(opts.type),
268
+ body: Buffer.from(maskedSerialized, "utf8"),
269
+ contentHash: maskedHash,
270
+ }, content.upload);
271
+ // The live version is the redacted one — hand its handle back.
272
+ return { id: redactedId, name: opts.name, type: opts.type, version: redactedVersion };
273
+ }
274
+ catch (err) {
275
+ warn("save (redacted version)", err);
276
+ // Fall through to returning the original handle (metadata-only).
277
+ }
278
+ }
279
+ else {
280
+ // off / detect / redact-with-no-findings: upload the bytes verbatim.
281
+ fireUpload({
282
+ artifactId: id,
283
+ contentType: contentTypeFor(opts.type),
284
+ body: Buffer.from(scrubbed.text ?? serialized, "utf8"),
285
+ contentHash,
286
+ }, content.upload);
287
+ }
288
+ }
289
+ return { id, name: opts.name, type: opts.type, version };
290
+ },
291
+ load(ref) {
292
+ (0, run_context_1.getActiveRunContext)()?.noteLoad(idOf(ref));
293
+ },
294
+ link(from, to, kind) {
295
+ const fromId = idOf(from);
296
+ const toId = idOf(to);
297
+ if (fromId === toId)
298
+ return; // edges_no_self
299
+ try {
300
+ store.recordArtifactEdge({ fromArtifactId: fromId, toArtifactId: toId, kind });
301
+ }
302
+ catch (err) {
303
+ warn("link", err);
304
+ }
305
+ },
306
+ evaluate(ref, opts) {
307
+ try {
308
+ store.recordArtifactEvaluation({
309
+ id: (0, node_crypto_1.randomUUID)(),
310
+ artifactId: idOf(ref),
311
+ runId: null,
312
+ evaluator: opts.evaluator,
313
+ evaluatorKind: opts.kind,
314
+ score: opts.score ?? null,
315
+ passed: opts.passed ?? null,
316
+ label: opts.label ?? null,
317
+ explanation: opts.explanation ?? null,
318
+ createdBy: null,
319
+ });
320
+ }
321
+ catch (err) {
322
+ warn("evaluate", err);
323
+ }
324
+ },
325
+ promoteToEval(ref, opts) {
326
+ const sourceArtifactId = idOf(ref);
327
+ // Resolve the task: explicit wins, else the task this artifact was saved
328
+ // with this session. Unresolvable ⇒ a warned no-op (eval_cases needs task).
329
+ const task = opts?.task ?? savedTasks.get(sourceArtifactId);
330
+ if (task === undefined) {
331
+ console.warn(`[modelrig artifacts] promoteToEval("${sourceArtifactId}") skipped: no task known for this ` +
332
+ "artifact (it was not saved this session) — pass { task } to promote it.");
333
+ return null;
334
+ }
335
+ const correctedArtifactId = opts?.corrected !== undefined ? idOf(opts.corrected) : null;
336
+ const origin = opts?.origin ?? (correctedArtifactId !== null ? "human-corrected" : "promoted-failure");
337
+ const id = (0, node_crypto_1.randomUUID)();
338
+ try {
339
+ store.recordEvalCase({
340
+ id,
341
+ task,
342
+ sourceArtifactId,
343
+ correctedArtifactId,
344
+ origin,
345
+ note: opts?.note ?? null,
346
+ createdBy: null,
347
+ });
348
+ }
349
+ catch (err) {
350
+ warn("promoteToEval", err);
351
+ return null;
352
+ }
353
+ return id;
354
+ },
355
+ batch(fn) {
356
+ return store.batch(fn);
357
+ },
358
+ async flushContent() {
359
+ // Settle every in-flight upload. Individual failures already resolve (they
360
+ // update contentDegraded), so allSettled never throws here.
361
+ await Promise.allSettled([...pendingUploads]);
362
+ },
363
+ retryPendingContent,
364
+ coverage() {
365
+ return {
366
+ saves,
367
+ inferredEdges,
368
+ skippedZeroRetention,
369
+ contentUploaded,
370
+ contentDegraded,
371
+ contentBlocked,
372
+ contentPending: pendingContent.length,
373
+ scrubFindings,
374
+ };
375
+ },
376
+ };
377
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Managed content upload path — E2-C chunk A (spec §2.4).
3
+ *
4
+ * When a rig has opted a route into content custody, `save` records the metadata
5
+ * row (as always) and THEN hands the serialized bytes here. This module talks to
6
+ * modelrig-server's grant endpoint, receives a short-lived presigned PUT, and
7
+ * uploads the bytes straight to the object store — the bytes NEVER touch our
8
+ * control-plane database, only the customer-designated store.
9
+ *
10
+ * ── THE POISON LESSON, APPLIED ────────────────────────────────────────────
11
+ * A deterministic refusal (403 posture-off, 409 already has content, 413 too
12
+ * big, 422 malformed) is NOT retried — it will fail identically forever, and
13
+ * retrying a poison request is how a fail-closed refusal turns into a hot loop.
14
+ * Every refusal DEGRADES to metadata-only: the artifact still exists (its row
15
+ * was written before we were called), it simply has no stored content.
16
+ * Degradation is counted and warned, never thrown — this runs off the
17
+ * customer's hot path and must never surface as a failed run.
18
+ *
19
+ * ── THE 404-UNTIL-DURABLE RACE (E4 chunk 0, flag 2) ───────────────────────
20
+ * A 404 is the ONE 4xx that is NOT deterministic. The grant endpoint verifies
21
+ * the artifact metadata row exists (and belongs to the org — T11) before
22
+ * issuing a URL, but that row reaches the control plane on the exporter's NEXT
23
+ * flush — so a content upload fired during `save` races ahead of its own
24
+ * metadata and 404s until the row lands. TRANSIENT by nature: it clears once
25
+ * the metadata is durable. So a 404 returns a distinct `pending` outcome that
26
+ * the exporter's post-flush hook re-attempts (bounded: 2 retries, then a
27
+ * counted skip). A genuinely foreign/missing artifact 404s the same way and
28
+ * simply exhausts those retries into the metadata-only end state — delayed, but
29
+ * never a hot loop.
30
+ *
31
+ * ── C2 ────────────────────────────────────────────────────────────────────
32
+ * The api key rides in an Authorization header, never a URL. The presigned URL
33
+ * and the content hash are NEVER logged. Warnings name the artifact + a status,
34
+ * nothing else.
35
+ */
36
+ export type ContentUploadOutcome =
37
+ /** Bytes are in the store; `contentRef` is the server's canonical pointer. */
38
+ {
39
+ readonly kind: "uploaded";
40
+ readonly contentRef: string;
41
+ }
42
+ /** Metadata-only fallback (deterministic refusal or transient failure). The
43
+ * `status` is the grant HTTP status when there was one, else null. */
44
+ | {
45
+ readonly kind: "degraded";
46
+ readonly reason: string;
47
+ readonly status: number | null;
48
+ }
49
+ /** The artifact metadata row is not yet durable in the control plane — a 404
50
+ * from the grant endpoint (which verifies the row before issuing a URL, T11).
51
+ * TRANSIENT: it clears once the exporter flushes the metadata. NOT counted as
52
+ * a degrade; the caller queues it for the post-flush hook to re-attempt
53
+ * (bounded 2 retries, then a counted skip). E4 chunk 0, flag 2. */
54
+ | {
55
+ readonly kind: "pending";
56
+ readonly reason: string;
57
+ readonly status: 404;
58
+ }
59
+ /** The scrub layer BLOCKED upload (chunk B). Distinct from degraded: this is a
60
+ * policy refusal, not a failure. */
61
+ | {
62
+ readonly kind: "blocked";
63
+ readonly reason: string;
64
+ };
65
+ export interface ContentUploadConfig {
66
+ /** Full grant endpoint, e.g. https://server/v1/artifacts/uploads. */
67
+ readonly uploadsUrl: string;
68
+ /** `rig_sk_` key carrying the `artifact-write` scope. Header only (C2). */
69
+ readonly apiKey: string;
70
+ /** Client-side ceiling — a short-circuit before the round trip; the server
71
+ * enforces the authoritative one. */
72
+ readonly maxBytes: number;
73
+ }
74
+ export interface ContentUploadInput {
75
+ readonly artifactId: string;
76
+ readonly contentType: string;
77
+ /** Serialized bytes to upload — already scrubbed by the caller (chunk B). */
78
+ readonly body: Buffer;
79
+ /** `sha256:<hex>` of `body`. */
80
+ readonly contentHash: string;
81
+ }
82
+ /**
83
+ * Upload one artifact's content. NEVER throws — every failure resolves to a
84
+ * `degraded` outcome the caller records as a metadata-only skip.
85
+ */
86
+ export declare function uploadArtifactContent(input: ContentUploadInput, config: ContentUploadConfig, fetchFn?: typeof fetch): Promise<ContentUploadOutcome>;
87
+ //# sourceMappingURL=content-uploader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-uploader.d.ts","sourceRoot":"","sources":["../../src/artifacts/content-uploader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,MAAM,oBAAoB;AAC9B,8EAA8E;AAC5E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC5D;sEACsE;GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AACxF;;;;mEAImE;GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAA;CAAE;AAC7E;oCACoC;GAClC;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;yCACqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAeD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAoE/B"}