modelrig 0.8.1 → 0.10.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.
- package/CHANGELOG.md +324 -0
- package/README.md +55 -29
- package/data/PROVENANCE.md +14 -0
- package/data/pricing-map.json +26 -0
- package/dist/adapters/attempt-meta-map.d.ts +8 -1
- package/dist/adapters/attempt-meta-map.d.ts.map +1 -1
- package/dist/adapters/attempt-meta-map.js +4 -0
- package/dist/adapters/build-adapters.js +2 -2
- package/dist/adapters/gemini.d.ts +28 -1
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +38 -9
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +53 -4
- package/dist/adapters/openai-compat.d.ts +8 -2
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +8 -1
- package/dist/adapters/openai-stream.d.ts +10 -2
- package/dist/adapters/openai-stream.d.ts.map +1 -1
- package/dist/adapters/openai-stream.js +5 -1
- package/dist/adapters/openai.d.ts +10 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +57 -7
- package/dist/adapters/responses-api.d.ts +61 -0
- package/dist/adapters/responses-api.d.ts.map +1 -0
- package/dist/adapters/responses-api.js +124 -0
- package/dist/artifacts/artifact.d.ts +31 -12
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +218 -188
- package/dist/artifacts/index.d.ts +15 -5
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +19 -5
- package/dist/artifacts/run-context.d.ts +3 -24
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +3 -39
- package/dist/bakeoff/engine.d.ts +29 -0
- package/dist/bakeoff/engine.d.ts.map +1 -1
- package/dist/bakeoff/engine.js +47 -0
- package/dist/bakeoff/eval-cases-rig.d.ts +36 -0
- package/dist/bakeoff/eval-cases-rig.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases-rig.js +27 -0
- package/dist/bakeoff/eval-cases.d.ts +19 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -1
- package/dist/bakeoff/eval-cases.js +18 -1
- package/dist/bakeoff/golden-judge.d.ts +47 -0
- package/dist/bakeoff/golden-judge.d.ts.map +1 -0
- package/dist/bakeoff/golden-judge.js +49 -0
- package/dist/bakeoff/groundedness.d.ts +58 -0
- package/dist/bakeoff/groundedness.d.ts.map +1 -0
- package/dist/bakeoff/groundedness.js +165 -0
- package/dist/bakeoff/quality.d.ts +43 -0
- package/dist/bakeoff/quality.d.ts.map +1 -1
- package/dist/bakeoff/quality.js +31 -0
- package/dist/bakeoff/replay.d.ts +11 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +12 -0
- package/dist/bakeoff/report.d.ts +7 -0
- package/dist/bakeoff/report.d.ts.map +1 -1
- package/dist/bakeoff/report.js +26 -0
- package/dist/cli-judge.d.ts +12 -0
- package/dist/cli-judge.d.ts.map +1 -0
- package/dist/cli-judge.js +48 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -42
- package/dist/config.d.ts +85 -29
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +109 -47
- package/dist/detect/detector.d.ts +4 -2
- package/dist/detect/detector.d.ts.map +1 -1
- package/dist/detect/safe-harbor.d.ts +57 -0
- package/dist/detect/safe-harbor.d.ts.map +1 -0
- package/dist/detect/safe-harbor.js +278 -0
- package/dist/doctor-cli.d.ts +7 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +67 -0
- package/dist/doctor-preflight.d.ts +52 -0
- package/dist/doctor-preflight.d.ts.map +1 -0
- package/dist/doctor-preflight.js +112 -0
- package/dist/feedback/coverage.d.ts +11 -8
- package/dist/feedback/coverage.d.ts.map +1 -1
- package/dist/feedback/coverage.js +29 -16
- package/dist/feedback/grade.d.ts +58 -0
- package/dist/feedback/grade.d.ts.map +1 -0
- package/dist/feedback/grade.js +67 -0
- package/dist/gateway/http-protocol.d.ts +20 -1
- package/dist/gateway/http-protocol.d.ts.map +1 -1
- package/dist/gateway/http-protocol.js +1 -1
- package/dist/gateway/serve-client.d.ts +99 -0
- package/dist/gateway/serve-client.d.ts.map +1 -0
- package/dist/gateway/serve-client.js +360 -0
- package/dist/index.d.ts +68 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +167 -46
- package/dist/init/observe-cli.js +1 -1
- package/dist/init/observe.d.ts +2 -2
- package/dist/init/observe.d.ts.map +1 -1
- package/dist/init/observe.js +11 -7
- package/dist/mask/arm.d.ts +112 -0
- package/dist/mask/arm.d.ts.map +1 -0
- package/dist/mask/arm.js +179 -0
- package/dist/mask/index.d.ts +2 -0
- package/dist/mask/index.d.ts.map +1 -1
- package/dist/mask/index.js +7 -1
- package/dist/mask/mask-policy-cli.d.ts +12 -4
- package/dist/mask/mask-policy-cli.d.ts.map +1 -1
- package/dist/mask/mask-policy-cli.js +34 -9
- package/dist/prompts/manifest.d.ts +128 -0
- package/dist/prompts/manifest.d.ts.map +1 -0
- package/dist/prompts/manifest.js +214 -0
- package/dist/prompts/prompt-fetch.d.ts +84 -0
- package/dist/prompts/prompt-fetch.d.ts.map +1 -0
- package/dist/prompts/prompt-fetch.js +120 -0
- package/dist/prompts/prompt-resolve.d.ts +76 -0
- package/dist/prompts/prompt-resolve.d.ts.map +1 -0
- package/dist/prompts/prompt-resolve.js +93 -0
- package/dist/prompts/slot-resolver.d.ts +91 -0
- package/dist/prompts/slot-resolver.d.ts.map +1 -0
- package/dist/prompts/slot-resolver.js +135 -0
- package/dist/prompts/tools-register.d.ts +60 -0
- package/dist/prompts/tools-register.d.ts.map +1 -0
- package/dist/prompts/tools-register.js +48 -0
- package/dist/prompts/version-hash.d.ts +29 -0
- package/dist/prompts/version-hash.d.ts.map +1 -0
- package/dist/prompts/version-hash.js +54 -0
- package/dist/prompts-export-cli.d.ts +21 -0
- package/dist/prompts-export-cli.d.ts.map +1 -0
- package/dist/prompts-export-cli.js +130 -0
- package/dist/query/grammar.d.ts +2 -2
- package/dist/query/grammar.d.ts.map +1 -1
- package/dist/query/grammar.js +3 -1
- package/dist/query/saved.d.ts +13 -0
- package/dist/query/saved.d.ts.map +1 -1
- package/dist/query/saved.js +67 -1
- package/dist/receipts/types.d.ts +1 -1
- package/dist/receipts/types.d.ts.map +1 -1
- package/dist/receipts/types.js +1 -0
- package/dist/registry/build.d.ts +43 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +52 -0
- package/dist/registry/cache-policy.d.ts.map +1 -1
- package/dist/registry/cache-policy.js +22 -0
- package/dist/registry/pricing-shape.d.ts +67 -8
- package/dist/registry/pricing-shape.d.ts.map +1 -1
- package/dist/registry/pricing-shape.js +50 -13
- package/dist/registry/pricing.d.ts +6 -5
- package/dist/registry/pricing.d.ts.map +1 -1
- package/dist/registry/pricing.js +9 -5
- package/dist/registry/rows.d.ts.map +1 -1
- package/dist/registry/rows.js +1 -0
- package/dist/registry/select.d.ts +6 -1
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +11 -0
- package/dist/routes/call-config.d.ts +199 -0
- package/dist/routes/call-config.d.ts.map +1 -0
- package/dist/routes/call-config.js +343 -0
- package/dist/routes/destination-loader.d.ts +16 -0
- package/dist/routes/destination-loader.d.ts.map +1 -0
- package/dist/routes/destination-loader.js +29 -0
- package/dist/routes/draft.d.ts +7 -0
- package/dist/routes/draft.d.ts.map +1 -1
- package/dist/routes/draft.js +12 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +31 -56
- package/dist/routes/objective-loader.d.ts +12 -0
- package/dist/routes/objective-loader.d.ts.map +1 -1
- package/dist/routes/objective-loader.js +82 -0
- package/dist/routes/output-loader.d.ts +42 -0
- package/dist/routes/output-loader.d.ts.map +1 -0
- package/dist/routes/output-loader.js +112 -0
- package/dist/routes/prompt-loader.d.ts +49 -0
- package/dist/routes/prompt-loader.d.ts.map +1 -0
- package/dist/routes/prompt-loader.js +113 -0
- package/dist/routes/resolved-bundle.d.ts +69 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -1
- package/dist/routes/resolved-bundle.js +76 -0
- package/dist/routes/screen-loader.d.ts +29 -1
- package/dist/routes/screen-loader.d.ts.map +1 -1
- package/dist/routes/screen-loader.js +59 -1
- package/dist/run/accept.d.ts +5 -0
- package/dist/run/accept.d.ts.map +1 -1
- package/dist/run/accept.js +2 -0
- package/dist/run/cost.d.ts +31 -2
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +57 -2
- package/dist/run/destination.d.ts +39 -0
- package/dist/run/destination.d.ts.map +1 -0
- package/dist/run/destination.js +45 -0
- package/dist/run/dispatch.d.ts +67 -16
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +133 -29
- package/dist/run/grounding.d.ts +28 -2
- package/dist/run/grounding.d.ts.map +1 -1
- package/dist/run/grounding.js +54 -10
- package/dist/run/raw-defaults.d.ts.map +1 -1
- package/dist/run/raw-defaults.js +6 -1
- package/dist/run/raw-finalize.d.ts +50 -0
- package/dist/run/raw-finalize.d.ts.map +1 -0
- package/dist/run/raw-finalize.js +266 -0
- package/dist/run/raw-knobs.d.ts +36 -0
- package/dist/run/raw-knobs.d.ts.map +1 -0
- package/dist/run/raw-knobs.js +99 -0
- package/dist/run/raw-request.d.ts +24 -0
- package/dist/run/raw-request.d.ts.map +1 -0
- package/dist/run/raw-request.js +69 -0
- package/dist/run/raw-schema.d.ts +76 -0
- package/dist/run/raw-schema.d.ts.map +1 -0
- package/dist/run/raw-schema.js +166 -0
- package/dist/run/raw-search-cost.d.ts +48 -0
- package/dist/run/raw-search-cost.d.ts.map +1 -0
- package/dist/run/raw-search-cost.js +78 -0
- package/dist/run/raw-support.d.ts +64 -6
- package/dist/run/raw-support.d.ts.map +1 -1
- package/dist/run/raw-support.js +84 -11
- package/dist/run/raw.d.ts +25 -26
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +30 -351
- package/dist/run/record-attempt.d.ts +12 -0
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +30 -12
- package/dist/run/repair-attempt.d.ts +68 -0
- package/dist/run/repair-attempt.d.ts.map +1 -0
- package/dist/run/repair-attempt.js +180 -0
- package/dist/run/resolve-destination.d.ts +49 -0
- package/dist/run/resolve-destination.d.ts.map +1 -0
- package/dist/run/resolve-destination.js +76 -0
- package/dist/run/routing-docs.d.ts.map +1 -1
- package/dist/run/routing-docs.js +10 -5
- package/dist/run/run.d.ts +30 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +94 -172
- package/dist/run/telemetry-row.d.ts +92 -0
- package/dist/run/telemetry-row.d.ts.map +1 -0
- package/dist/run/telemetry-row.js +81 -0
- package/dist/run/validate.d.ts +12 -1
- package/dist/run/validate.d.ts.map +1 -1
- package/dist/run/validate.js +31 -0
- package/dist/run/web-search-pricing.d.ts +43 -0
- package/dist/run/web-search-pricing.d.ts.map +1 -0
- package/dist/run/web-search-pricing.js +56 -0
- package/dist/savings/odometer.d.ts +4 -0
- package/dist/savings/odometer.d.ts.map +1 -1
- package/dist/savings/odometer.js +20 -1
- package/dist/savings/swap-execute.d.ts +7 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +30 -0
- package/dist/savings/swaps-client.d.ts +10 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/screen/fixtures/probe-corpora.d.ts +23 -0
- package/dist/screen/fixtures/probe-corpora.d.ts.map +1 -0
- package/dist/screen/fixtures/probe-corpora.js +69 -0
- package/dist/screen/index.d.ts +21 -0
- package/dist/screen/index.d.ts.map +1 -0
- package/dist/screen/index.js +64 -0
- package/dist/screen/model-screen.d.ts +111 -0
- package/dist/screen/model-screen.d.ts.map +1 -0
- package/dist/screen/model-screen.js +178 -0
- package/dist/screen/patterns.d.ts +51 -0
- package/dist/screen/patterns.d.ts.map +1 -0
- package/dist/screen/patterns.js +151 -0
- package/dist/screen/phi-gate.d.ts +52 -0
- package/dist/screen/phi-gate.d.ts.map +1 -0
- package/dist/screen/phi-gate.js +86 -0
- package/dist/screen/policy.d.ts +71 -0
- package/dist/screen/policy.d.ts.map +1 -0
- package/dist/screen/policy.js +334 -0
- package/dist/screen/probe.d.ts +118 -0
- package/dist/screen/probe.d.ts.map +1 -0
- package/dist/screen/probe.js +132 -0
- package/dist/screen/screen-cli.d.ts +16 -0
- package/dist/screen/screen-cli.d.ts.map +1 -0
- package/dist/screen/screen-cli.js +178 -0
- package/dist/screen/screen.d.ts +99 -0
- package/dist/screen/screen.d.ts.map +1 -0
- package/dist/screen/screen.js +0 -0
- package/dist/screen/sidecar.d.ts +69 -0
- package/dist/screen/sidecar.d.ts.map +1 -0
- package/dist/screen/sidecar.js +145 -0
- package/dist/screen/types.d.ts +43 -2
- package/dist/screen/types.d.ts.map +1 -1
- package/dist/settings/api-fetcher.d.ts +14 -3
- package/dist/settings/api-fetcher.d.ts.map +1 -1
- package/dist/settings/api-fetcher.js +61 -10
- package/dist/settings/grading-guide.d.ts +102 -0
- package/dist/settings/grading-guide.d.ts.map +1 -0
- package/dist/settings/grading-guide.js +23 -0
- package/dist/settings/index.d.ts +3 -2
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/task-settings.d.ts +44 -7
- package/dist/settings/task-settings.d.ts.map +1 -1
- package/dist/settings/task-settings.js +53 -12
- package/dist/status.d.ts +32 -20
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +51 -30
- package/dist/telemetry/artifact-store.d.ts +5 -6
- package/dist/telemetry/artifact-store.d.ts.map +1 -1
- package/dist/telemetry/artifact-store.js +21 -24
- package/dist/telemetry/attempt-meta.d.ts +76 -1
- package/dist/telemetry/attempt-meta.d.ts.map +1 -1
- package/dist/telemetry/attempt-meta.js +33 -1
- package/dist/telemetry/exporter-setup.d.ts +2 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -1
- package/dist/telemetry/exporter-setup.js +6 -1
- package/dist/telemetry/exporter.d.ts +2 -2
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +22 -41
- package/dist/telemetry/grade-mappers.d.ts +25 -0
- package/dist/telemetry/grade-mappers.d.ts.map +1 -0
- package/dist/telemetry/grade-mappers.js +64 -0
- package/dist/telemetry/grades-sql.d.ts +56 -0
- package/dist/telemetry/grades-sql.d.ts.map +1 -0
- package/dist/telemetry/grades-sql.js +156 -0
- package/dist/telemetry/ingest-protocol.d.ts +55 -48
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +48 -83
- package/dist/telemetry/org-identity.d.ts +44 -0
- package/dist/telemetry/org-identity.d.ts.map +1 -0
- package/dist/telemetry/org-identity.js +98 -0
- package/dist/telemetry/route-registration.d.ts +48 -0
- package/dist/telemetry/route-registration.d.ts.map +1 -0
- package/dist/telemetry/route-registration.js +77 -0
- package/dist/telemetry/sinks.d.ts +10 -1
- package/dist/telemetry/sinks.d.ts.map +1 -1
- package/dist/telemetry/sinks.js +52 -6
- package/dist/telemetry/store-migrations.d.ts.map +1 -1
- package/dist/telemetry/store-migrations.js +64 -0
- package/dist/telemetry/store.d.ts +9 -6
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +8 -50
- package/dist/tenancy/api-key-format.d.ts +45 -1
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +50 -1
- package/dist/types/provider.d.ts +23 -3
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +26 -0
- package/dist/types/route.d.ts +154 -2
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +73 -48
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +32 -0
- package/dist/verify/verify.d.ts +5 -0
- package/dist/verify/verify.d.ts.map +1 -1
- package/dist/verify/verify.js +2 -0
- package/dist/watch/evaluate.d.ts +84 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +28 -0
- package/dist/watch/monitor.d.ts +8 -2
- package/dist/watch/monitor.d.ts.map +1 -1
- package/dist/watch/monitor.js +13 -5
- package/dist/watch/regret-monitor-cli.d.ts +16 -0
- package/dist/watch/regret-monitor-cli.d.ts.map +1 -0
- package/dist/watch/regret-monitor-cli.js +137 -0
- package/dist/watch/regret-monitor.d.ts +168 -0
- package/dist/watch/regret-monitor.d.ts.map +1 -0
- package/dist/watch/regret-monitor.js +304 -0
- package/dist/watch/upgrade.d.ts +62 -0
- package/dist/watch/upgrade.d.ts.map +1 -0
- package/dist/watch/upgrade.js +57 -0
- package/docs/agent-skill/SKILL.md +181 -9
- package/docs/how-it-fits.md +3 -2
- package/docs/instrumentation.md +219 -46
- package/docs/llms.txt +158 -35
- package/docs/managed-serving.md +150 -0
- package/docs/mcp-oracle.md +322 -0
- package/docs/migration-playbook.md +5 -4
- package/docs/quickstart.md +263 -89
- package/package.json +18 -4
- package/registry/leaderboard.json +74 -0
- package/registry/registry.json +232 -112
- package/screen.d.ts +16 -0
- package/templates/call-disposition-qa.json +77 -0
- package/templates/catalog-cleansing.json +77 -0
- package/templates/compliance-review.json +76 -0
- package/templates/cs-next-action.json +76 -0
- package/templates/document-extraction.json +78 -0
- package/templates/financial-classification.json +75 -0
- package/templates/lead-qualification.json +76 -0
- package/templates/medical-classification.json +71 -0
- package/templates/ticket-triage.json +76 -0
- package/dist/feedback/feedback.d.ts +0 -35
- package/dist/feedback/feedback.d.ts.map +0 -1
- package/dist/feedback/feedback.js +0 -39
package/docs/how-it-fits.md
CHANGED
|
@@ -6,7 +6,7 @@ ModelRig sits between your code and the model providers. Your repo declares **ro
|
|
|
6
6
|
|
|
7
7
|
Every call writes one telemetry row to a local SQLite file first — the run never blocks on the cloud. An async exporter mirrors rows to the console you are reading. Provider keys are the one thing that deliberately never leaves your machine; the exporter has no code path to them.
|
|
8
8
|
|
|
9
|
-
Routing is half of it. ModelRig also records the **execution graph** of your workstream — the run, its steps, and the artifacts each step produced — versioned, hashed, and lineaged, into an inspectable store you can open: when someone asks why the pipeline did that, you pull up the run and show them. This is the **standard path**, not an add-on: every pipeline execution is a run — wrap it in `run.start` / `run.scope`, name a step per model-call family (name it with `stepKey`), save the work products, and inside that context the SDK auto-stamps `run_id` for you, so the run appears on `/runs` and `/projects` with no hand-written id (the SDK auto-stamps the `step` key inside a run context too; the `stepKey` you pass names the step, and always wins). The namespace is **on by default once a control plane is configured** (a ModelRig API key, or the self-host Supabase pair); a pure local-only rig stays off,
|
|
9
|
+
Routing is half of it. ModelRig also records the **execution graph** of your workstream — the run, its steps, and the artifacts each step produced — versioned, hashed, and lineaged, into an inspectable store you can open: when someone asks why the pipeline did that, you pull up the run and show them. This is the **standard path**, not an add-on: every pipeline execution is a run — wrap it in `run.start` / `run.scope`, name a step per model-call family (name it with `stepKey`), save the work products, and inside that context the SDK auto-stamps `run_id` for you, so the run appears on `/runs` and `/projects` with no hand-written id (the SDK auto-stamps the `step` key inside a run context too; the `stepKey` you pass names the step, and always wins). The namespace is **on by default once a control plane is configured** (a ModelRig API key, or the self-host Supabase pair); a pure local-only rig stays off; to opt out of capture, set posture `off` in account settings (the console or the `set_org_settings` MCP tool) — the account posture is the control, not a deployment env var. Artifact *metadata and lineage* ride the same exporter; artifact *content* is a separate axis — the **recommended, encouraged** path, since content custody is what turns your captured prompts, outputs and evidence into analysis, but it stays consent-gated: the signup default is `managed` — every new org is created with content custody on, having accepted the published terms at signup — and opting out is one account setting (in the console or the `set_org_settings` MCP tool, set posture `off` or `metadata`, or use a `zero_retention` route). A failing artifact can be promoted to a regression case and replayed as a bake-off — see → prove → save is the loop, and the store is where seeing happens.
|
|
10
10
|
|
|
11
11
|
What is retained beyond that is your choice, per route, and there are two lanes.
|
|
12
12
|
|
|
@@ -29,6 +29,7 @@ The five-step get-started is the front door; these are the shipped surfaces it d
|
|
|
29
29
|
- **Published receipts** — publish a signed, login-free receipt of a bake-off or route at `/r/<id>` — counts, scores and hashes only, verifiable at `/v1/verify/<id>`; names aliased, content never leaves. See [Published receipts](receipts.md).
|
|
30
30
|
- **Analytics query API** — a self-describing, read-only query surface over your own telemetry (`GET /v1/analytics/meta`, `POST /v1/analytics/query`): an allowlisted SELECT grammar that returns metadata only, never content. See [Optimization loop](optimization-loop.md).
|
|
31
31
|
- **Provenance & trust** — provenance-first prompt assembly keeps third-party content out of the most-trusted slot; annotate a variable `x-trust: untrusted` to spotlight it. See [Provenance & trust](screening.md).
|
|
32
|
-
- **Bake-offs — pairwise, disagreement & regret** — replay your own traffic, judge candidates pairwise with disagreement shown, and propose the lowest-**regret** arm under a quality gate (near-optimal, not merely cheapest). See [Bake-offs & replay](bakeoffs.md) and [
|
|
32
|
+
- **Bake-offs — pairwise, disagreement & regret** — replay your own traffic, judge candidates pairwise with disagreement shown, and propose the lowest-**regret** arm under a quality gate (near-optimal, not merely cheapest). See [Bake-offs & replay](bakeoffs.md) and the [Grade protocol](grade-protocol.md).
|
|
33
|
+
- **Live routing (call-config)** — change which model serves a route *live*, no redeploy: pin a model, or run a weighted A/B (the chosen arm records on `meta.arm`). The SDK reads the route's config just-before-call (fail-open; no override ⇒ byte-identical) and overlays it onto a bundle you serve through `rig.runBundle`. Set it in the console's call-config card, or have your coding agent set it over MCP (`set_call_config`, the `route-config` scope — explicit and reversible). See [Change your route's model live](quickstart.md#change-your-routes-model-live-no-redeploy) and [The MCP oracle](mcp-oracle.md#setting-a-routes-live-config).
|
|
33
34
|
|
|
34
35
|
New claims are held to the same bar as the five steps: content custody stays early access (metadata and hashes), and pricing stays the launch-terms sentence.
|
package/docs/instrumentation.md
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
1
|
# Artifact instrumentation (runs, steps, artifacts)
|
|
2
2
|
|
|
3
|
+
**The question this page answers: how do I record what my pipeline actually did, run by run, step by step, without changing what it does?**
|
|
4
|
+
|
|
3
5
|
ModelRig can record the **execution graph** of any pipeline your code runs — the
|
|
4
6
|
run, its steps, and the artifacts each step produced (the prompt, the raw model
|
|
5
7
|
text, the parsed output, the evidence it grounded on) — with lineage,
|
|
6
|
-
|
|
8
|
+
grades, and an integrity hash for each. The console then renders that run as
|
|
7
9
|
a semantic chain you click through: *what your pipeline actually did*.
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
Recording your workstream is the **recommended, normal path** — it is what the
|
|
12
|
+
run → step → artifact graph and every downstream analysis are built on — so it is
|
|
13
|
+
**on by default when a control plane is configured** (an api-mode `rig_sk_` key,
|
|
14
|
+
or the direct-mode Supabase pair) — metadata + hashes only. A **pure local-only
|
|
15
|
+
rig** (no sink to ship to) stays off. Either way it is additive, and the **opt-out
|
|
16
|
+
is one account setting**: set posture `off` in account settings (the console or the
|
|
17
|
+
`set_org_settings` MCP tool) — the account posture is the customer control, not a
|
|
18
|
+
deployment env var. (A pure local-only rig with no control plane is inert either
|
|
19
|
+
way — `run.start` a no-op, `artifact.save` null, no rows written, your pipeline
|
|
20
|
+
byte-for-byte as before.) `modelrig status` prints the current posture (on/off + why). Storing the artifact *content bytes* on top of this metadata is the
|
|
21
|
+
second axis — the recommended, consent-gated [content custody](content-custody.md)
|
|
22
|
+
path — never blurred with the telemetry axis here.
|
|
23
|
+
|
|
24
|
+
> **What `artifact.save` keeps.** This page is the metadata axis: every saved
|
|
25
|
+
> artifact records a metadata row with a sha256 integrity hash, whatever your
|
|
26
|
+
> content setting. Whether the serialized *bytes* are kept as well is your
|
|
27
|
+
> organization's [content custody](content-custody.md) posture: new
|
|
28
|
+
> organizations are created `managed` (bytes kept in your managed store); posture
|
|
29
|
+
> `metadata` keeps hashes only and `off` captures nothing. A `zeroRetention` run
|
|
30
|
+
> refuses every artifact fail-closed at the SDK gate.
|
|
22
31
|
|
|
23
32
|
## The namespace toggle
|
|
24
33
|
|
|
25
34
|
```bash
|
|
26
|
-
# On by default once a control plane is configured — nothing to set.
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
# On by default once a control plane is configured — nothing to set. The CUSTOMER
|
|
36
|
+
# opt-out is the account posture (set posture off in account settings / the
|
|
37
|
+
# set_org_settings MCP tool), not this env var.
|
|
38
|
+
export MODELRIG_ARTIFACTS=1 # local-only namespace toggle: force ON
|
|
39
|
+
# with =1 on a rig with no control plane
|
|
29
40
|
export MODELRIG_ARTIFACT_STEPS=step_a,step_b # optional: instrument a subset
|
|
30
41
|
# (unset/empty = every instrumented step)
|
|
31
42
|
```
|
|
@@ -48,13 +59,13 @@ import { createRig, loadConfigFromEnv } from "modelrig";
|
|
|
48
59
|
|
|
49
60
|
const rig = createRig(loadConfigFromEnv());
|
|
50
61
|
|
|
51
|
-
// 1. Open a run context around the pipeline. episodeKey bridges
|
|
62
|
+
// 1. Open a run context around the pipeline. episodeKey bridges grades;
|
|
52
63
|
// it is a grouping key, not a unique id — a natural choice is your own
|
|
53
|
-
// per-run attempt id.
|
|
64
|
+
// per-run attempt id. environment fills the Env column on /runs.
|
|
54
65
|
const run = rig.artifacts.run.start({
|
|
55
66
|
pipeline: "my-pipeline",
|
|
56
67
|
episodeKey: runAttemptId,
|
|
57
|
-
environment: process.env.NODE_ENV,
|
|
68
|
+
environment: process.env.NODE_ENV, // e.g. "production", "staging", "test"
|
|
58
69
|
});
|
|
59
70
|
try {
|
|
60
71
|
for (const step of steps) {
|
|
@@ -74,10 +85,10 @@ try {
|
|
|
74
85
|
if (p && parsed) rig.artifacts.artifact.link(parsed, p, "derived_from");
|
|
75
86
|
if (raw && parsed) rig.artifacts.artifact.link(parsed, raw, "derived_from");
|
|
76
87
|
|
|
77
|
-
// 4.
|
|
88
|
+
// 4. Grades (optional, deterministic): flag conformance, degraded
|
|
78
89
|
// provenance, anything you can decide without an LLM judge.
|
|
79
|
-
if (parsed) rig.
|
|
80
|
-
|
|
90
|
+
if (parsed) rig.grade({ kind: "artifact", id: parsed.id }, {
|
|
91
|
+
score: conforms(result.json) ? 1 : 0, kind: "deterministic", grader: "schema-check",
|
|
81
92
|
});
|
|
82
93
|
}
|
|
83
94
|
run.end("succeeded");
|
|
@@ -130,19 +141,29 @@ process** (`required dimension "project" missing from run tags — costs … wil
|
|
|
130
141
|
under-attributed on /costs`) — on the routed lane and the raw lane alike. It is a
|
|
131
142
|
hygiene warning, never an error: the run proceeds.
|
|
132
143
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
`
|
|
144
|
+
### Reserved tag keys (the one list)
|
|
145
|
+
|
|
146
|
+
Any other key is yours. These are reserved:
|
|
147
|
+
|
|
148
|
+
| Key | Who sets it | What it means |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `subject` | you | Your end-customer's **opaque** id. It powers the per-customer tenant statements on `/tenants`; hash it if it looks like PII ([tenants.md](./tenants.md)). A tag named `client` or `tenant` is only a cost dimension. |
|
|
151
|
+
| `feature` | you | The product feature the call serves. |
|
|
152
|
+
| `user` | you | The end user, as an opaque id. |
|
|
153
|
+
| `session` | you | The conversation or session the call belongs to. |
|
|
154
|
+
| `cost_center` | you | The team or budget to attribute spend to. |
|
|
155
|
+
| `run_id` | **the SDK**, inside a run | The run's `episodeKey`, or its id when you gave none. **Don't set it yourself.** A value you pass overrides the stamp, so the call no longer joins its run on `/runs` and the console's Run ID group-by disagrees with `/runs`. Put your own attempt id in a key of your own, such as `pipeline_attempt_id`. |
|
|
156
|
+
| `step` | **the SDK**, inside a run | The current step key: your explicit `stepKey`, else `tags.step`, else an auto `route#n` / `provider/model#n` key. Name steps with `stepKey`. |
|
|
157
|
+
| `lane`, `zdr_enforced`, `rung`, `key_ownership` | ModelRig | Set by the SDK or the hosted gateway. You can't override them. |
|
|
158
|
+
| `replay`, `replay_capture`, `variant`, `cutover` | ModelRig tooling | Set by bake-offs and replays. |
|
|
159
|
+
|
|
160
|
+
The five keys you set are first-class group-bys in the cost and coverage views, so use them verbatim; `modelrig validate` warns about near-misses such as `costcenter` or `team`. `project` and `environment` are common conventions, not reserved.
|
|
161
|
+
|
|
162
|
+
**Inside a `run.start` / `run.scope` context the SDK stamps `run_id` and `step`
|
|
163
|
+
on every attempt row of both lanes.** Outside a run context nothing is stamped,
|
|
164
|
+
so the row is byte-identical. This is why runs are the standard path: a
|
|
165
|
+
`run.start` alone fills both `/runs` (the graph) and `/projects` (the tag tree),
|
|
166
|
+
with no hand-written id.
|
|
146
167
|
|
|
147
168
|
**How they compose.** Inside a `run.start` context, both `rig.run` and
|
|
148
169
|
`rig.runRaw` record a **ground-truth step** and carry the run's `run_id` tag, so
|
|
@@ -168,18 +189,177 @@ run.end("succeeded");
|
|
|
168
189
|
> that wrapped raw calls in `run.start` got an **empty tree**. (Raw steps are
|
|
169
190
|
> metadata only — no artifact *content* is written on the raw lane.)
|
|
170
191
|
|
|
192
|
+
## Live call-config and A/B arms
|
|
193
|
+
|
|
194
|
+
Instrumentation records *what your pipeline did*; **call-config** changes *which model
|
|
195
|
+
does it*, live, without a redeploy — and the two meet on the telemetry row. When a route
|
|
196
|
+
runs a live A/B (`mode='experiment'`), the arm that served each call is recorded on
|
|
197
|
+
`inferences.meta.arm`, so the run → step → artifact graph and the console's A/B readout can
|
|
198
|
+
group outcomes by arm. This section is how that field gets populated; the call-config API
|
|
199
|
+
itself (the resolver, the fail-open contract, the console card, and the MCP write path) is
|
|
200
|
+
in the quickstart's [Change your route's model live](quickstart.md#change-your-routes-model-live-no-redeploy).
|
|
201
|
+
|
|
202
|
+
**Overlay live call-config onto a bundle.** A route's live config is read
|
|
203
|
+
**just-before-call** through a resolver and merged over the bundle you serve through
|
|
204
|
+
`rig.runBundle()` (never `rig.runRaw` — the raw lane owns no bundle to overlay). The read
|
|
205
|
+
is fail-open and, with no override, byte-identical to the deploy-time bundle:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import {
|
|
209
|
+
createApiCallConfigFetcher, createCallConfigResolver, resolveCallConfigForRun,
|
|
210
|
+
} from "modelrig";
|
|
211
|
+
|
|
212
|
+
const resolver = createCallConfigResolver({
|
|
213
|
+
fetcher: createApiCallConfigFetcher({ ingestUrl, apiKey: process.env.MODELRIG_API_KEY! }),
|
|
214
|
+
ttlMs: 30_000, // cached; ETag-revalidated — no per-call network cost when fresh
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Per call: resolve the config, draw an arm locally (pin/no-override ⇒ arm is null).
|
|
218
|
+
const resolved = await resolver.getCallConfig(route);
|
|
219
|
+
const { bundle: runnable, arm } = resolveCallConfigForRun(bundle, resolved, { input });
|
|
220
|
+
|
|
221
|
+
// Thread the arm onto the run so it lands on inferences.meta.arm.
|
|
222
|
+
await rig.artifacts.run.scope({ pipeline: "report", episodeKey: runId }, async () => {
|
|
223
|
+
const out = await rig.runBundle(runnable, { input, tags: { subject, feature }, arm, stepKey });
|
|
224
|
+
rig.artifacts.artifact.save(out.output, { name: "section.output", type: "step_output" });
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**How `meta.arm` gets populated.** `resolveCallConfigForRun(bundle, resolved, { input, unitKey })`
|
|
229
|
+
returns `{ bundle, arm }`: for an experiment it draws one weighted arm and returns its stable
|
|
230
|
+
name; for a pin, a null/`live`/malformed resolution, or no override it returns the bundle
|
|
231
|
+
unchanged and `arm: null`. You pass that `arm` on `RunOptions.arm`, and the attempt-meta
|
|
232
|
+
producer stamps it onto **every recorded row's `meta.arm`** for that call (a non-meta-safe
|
|
233
|
+
value is dropped). **Absent `arm` ⇒ no `meta.arm`** — byte-identical to a non-experiment
|
|
234
|
+
run. Drawing is **sticky**: pass `unitKey` (or let `stickyKey` read a field from `input`) and
|
|
235
|
+
the same unit always draws the same arm, so the A/B is measured honestly across calls.
|
|
236
|
+
|
|
237
|
+
The console reads per-arm outcomes at `GET /v1/console/ab-readout?route=<route>` (samples,
|
|
238
|
+
conformance, and cost grouped by arm; non-experiment rows, which carry no arm, are ignored).
|
|
239
|
+
`meta.arm` sits in the recorded-metadata inventory alongside the rest of the attempt
|
|
240
|
+
envelope — see [content custody](content-custody.md#attempt-envelope-inferencesmeta-attemptmetav1).
|
|
241
|
+
|
|
171
242
|
## Never throws into your pipeline
|
|
172
243
|
|
|
173
244
|
Every entry point is fail-open: a telemetry-buffer write that fails is logged and
|
|
174
245
|
dropped, never thrown into your code. Instrumentation that runs *after* an
|
|
175
246
|
expensive model call must never be the thing that kills the run.
|
|
176
247
|
|
|
248
|
+
## Which org am I exporting to?
|
|
249
|
+
|
|
250
|
+
A valid key minted in the wrong org fails silently: every ingest call succeeds,
|
|
251
|
+
and the runs land in someone else's console. So the first time a process flushes
|
|
252
|
+
telemetry, the SDK asks `GET /v1/whoami` once and logs where it is exporting:
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
[modelrig] exporting to org «Acme Analytics» (acme-analytics) as key «production exporter» rig_sk_…ab12
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The call runs in the background. It never delays or drops a batch, and if it
|
|
259
|
+
fails it says nothing (a rejected key already gets its own loud `AUTH FAILED`
|
|
260
|
+
line). To have the SDK check the org for you, pass the slug you expect in code:
|
|
261
|
+
|
|
262
|
+
| Config option | Type | Default | What it does |
|
|
263
|
+
|---|---|---|---|
|
|
264
|
+
| `expectOrg` | `string` (org slug) | absent | When the key resolves to a different org, logs `[modelrig] ORG MISMATCH: key resolves to «a», expectOrg is «b» — telemetry is landing in «a»` loudly on every flush once the org is known. It never throws and never drops telemetry: the rows still land in the key's org. |
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const rig = createRig({ ...loadConfigFromEnv(), expectOrg: "acme-analytics" });
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
It is a code option, not an environment variable. To gate a deploy or CI step
|
|
271
|
+
on the same check, run `modelrig doctor --expect-org acme-analytics`. It exits 1 and
|
|
272
|
+
prints both slugs when the key belongs to a different org. More on keys,
|
|
273
|
+
orgs and the console picker: [Orgs and keys](https://modelrig.dev/orgs-and-keys.html).
|
|
274
|
+
|
|
177
275
|
## See it
|
|
178
276
|
|
|
277
|
+
Check first that the console is showing the org your key exports to:
|
|
278
|
+
|
|
279
|
+
<!-- BLOCK:CONFIRM_ORG -->
|
|
280
|
+
**Confirm the org before you trust an empty console.** Run `modelrig doctor` from the same environment your app runs in. It asks GET /v1/whoami which organization the key belongs to, and the name it prints must match the org badge in the console header. If it names a different organization, your data is landing there: switch the console to that organization, or mint a key in the one you meant (https://modelrig.dev/orgs-and-keys.html).
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npx modelrig doctor
|
|
284
|
+
# [modelrig] key rig_sk_…AbCd → org «Your Org» ✓ (ingest https://api.modelrig.ai, …)
|
|
285
|
+
|
|
286
|
+
# No CLI in that environment? Ask the API directly:
|
|
287
|
+
curl -H "Authorization: Bearer $MODELRIG_API_KEY" https://api.modelrig.ai/v1/whoami
|
|
288
|
+
```
|
|
289
|
+
<!-- /BLOCK:CONFIRM_ORG -->
|
|
290
|
+
|
|
179
291
|
The console's **Runs** tab lists every instrumented run; `/runs/[id]` is the
|
|
180
|
-
semantic chain (artifacts grouped by step, with hashes, costs, and
|
|
292
|
+
semantic chain (artifacts grouped by step, with hashes, costs, and grade
|
|
181
293
|
badges) and `/artifacts/[id]` shows one artifact's lineage, versions, and
|
|
182
|
-
|
|
294
|
+
grades. Enabling the flag also lights up the `/setup` artifacts line.
|
|
295
|
+
|
|
296
|
+
## Grades (`rig.grade`)
|
|
297
|
+
|
|
298
|
+
Capture records **what** ran; a **grade** records whether it was **good**.
|
|
299
|
+
A grade is a 0–1 **score** (with an optional comment) your code — or a human, or
|
|
300
|
+
an AI — attaches to a subject: one model call (an **inference**), a whole run
|
|
301
|
+
(an **episode**), or an artifact. It is the signal per-route
|
|
302
|
+
[optimization coverage](grade-protocol.md) is built from — the evidence level
|
|
303
|
+
that decides how much confidence a swap proposal carries.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
// One call — the inference id rides on every RunResult:
|
|
307
|
+
const result = await rig.run("example.support_summarize", { input, tags: { subject } });
|
|
308
|
+
rig.grade({ kind: "inference", id: result.meta.inferenceId }, { score: 1, kind: "human" });
|
|
309
|
+
|
|
310
|
+
// A whole run: the subject id is the run's run_id (its episodeKey, or its id).
|
|
311
|
+
rig.grade({ kind: "run", id: runAttemptId }, { score: 0.2, comment: "CAGR off by 10x", kind: "human" });
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
- **The subject** is `{ kind: "inference", id }` (`result.meta.inferenceId`),
|
|
315
|
+
`{ kind: "run", id }` (the run's `run_id` — its `episodeKey`, or its id), or
|
|
316
|
+
`{ kind: "artifact", id }`. **`opts`** is `{ score, scale?, comment?, kind,
|
|
317
|
+
source? }` — the `score` in `[0, 1]` is the primitive (up = 1, down = 0), and
|
|
318
|
+
the pass/fail verdict is derived from it against the route threshold. A subject
|
|
319
|
+
naming no known inference, run, or artifact attaches to nothing — attribution
|
|
320
|
+
is never guessed.
|
|
321
|
+
- **Emit it from a signal you already have.** Most pipelines already decide
|
|
322
|
+
pass/fail somewhere — a schema validator, a downstream accept/reject, a human
|
|
323
|
+
QA gate. Emit `rig.grade` from that (score 1 on a clean pass, 0 on a rejection)
|
|
324
|
+
rather than adding a new review step.
|
|
325
|
+
- **Never on your hot path.** The write is synchronous and local (SQLite), never a
|
|
326
|
+
network call and never a failure your code can see; the cloud mirror rides the
|
|
327
|
+
telemetry exporter's normal cadence.
|
|
328
|
+
- **Why it matters.** A route with **≥10 attached grades** reaches **Rung 1** on
|
|
329
|
+
`/coverage`; a route with no schema to conform to (an `output: text` prose
|
|
330
|
+
route, or a schema-less JSON route) gains proposal confidence only this way. Grades are also what let `/insights`
|
|
331
|
+
surface a task that is degrading.
|
|
332
|
+
- **From a non-SDK surface** (an end user clicking thumbs-down in your web app),
|
|
333
|
+
post the same fields to `POST /v1/grade` with a `rig_sk_` key carrying the
|
|
334
|
+
`grade` scope — the org is resolved from the key, never the body. See the
|
|
335
|
+
[grade protocol](grade-protocol.md) for the full row shape and the ladder.
|
|
336
|
+
|
|
337
|
+
## Promote a golden, then bake it off (`promoteToEval` → `--from-eval-cases`)
|
|
338
|
+
|
|
339
|
+
A run's artifacts are the raw material for a **durable eval case**. Promote a real
|
|
340
|
+
output into the org's eval suite and it becomes replayable evidence — the path a
|
|
341
|
+
**raw/run-based pipeline** (a `rig.runRaw` seam with no declared route) uses to
|
|
342
|
+
prove a cheaper model, alongside the route-scoped `bakeoff --route … --replay-last
|
|
343
|
+
N`.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
// Promote an artifact you saved this run into the org's eval suite.
|
|
347
|
+
const caseId = rig.artifacts.artifact.promoteToEval(handle, { task: "report.section" });
|
|
348
|
+
// `corrected` set ⇒ a golden-corrected pair; absent ⇒ a failure case.
|
|
349
|
+
// Unresolvable task ⇒ a warned no-op (returns null, never throws).
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# Replay the promoted eval cases through variants — the raw/run-based lane.
|
|
354
|
+
modelrig bakeoff --from-eval-cases report.section --variants default,cheap
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
- `promoteToEval(ref, { task?, corrected?, origin? })` binds the case to a route by
|
|
358
|
+
`task` (from `opts`, else the task the artifact was saved with this session), and
|
|
359
|
+
is also reachable from the console's one-click **"make golden"**.
|
|
360
|
+
- `--route` needs a **declared route**; `--from-eval-cases <task>` is the path for a
|
|
361
|
+
`runRaw` seam that owns no route. Either way a bake-off **measures** — it never
|
|
362
|
+
switches what serves a route; a swap is a human-approved PR.
|
|
183
363
|
|
|
184
364
|
## A reusable per-step seam
|
|
185
365
|
|
|
@@ -205,17 +385,10 @@ function recordStep(
|
|
|
205
385
|
const parsed = rig.artifacts.artifact.save(work.json, { name: `${stepKey}.output`, type: "step_output", task: stepKey, stepKey });
|
|
206
386
|
if (p && parsed) rig.artifacts.artifact.link(parsed, p, "derived_from");
|
|
207
387
|
if (raw && parsed) rig.artifacts.artifact.link(parsed, raw, "derived_from");
|
|
208
|
-
if (parsed) rig.
|
|
388
|
+
if (parsed) rig.grade({ kind: "artifact", id: parsed.id }, { score: work.conforms ? 1 : 0, kind: "deterministic", grader: "schema-check" });
|
|
209
389
|
}
|
|
210
390
|
```
|
|
211
391
|
|
|
212
392
|
Call `recordStep(step, { … })` once per stage inside the `run.start` / `run.end`
|
|
213
393
|
context above, and every entry point stays fail-open — a save that fails is
|
|
214
394
|
logged and dropped, never thrown into your pipeline.
|
|
215
|
-
|
|
216
|
-
> **In-repo example (reconstructed via onboarding-test run-2).** ModelRig's own
|
|
217
|
-
> customer-zero pipeline (the InferWealth v3 report generator) was stripped back
|
|
218
|
-
> to a clean slate to be re-onboarded through this exact doc. Its live seam is
|
|
219
|
-
> reconstructed as part of onboarding-test run-2; until then, the snippet above
|
|
220
|
-
> is the reference. Do not resurrect a deleted seam from git history — writing a
|
|
221
|
-
> fresh one is the point.
|