modelrig 0.1.0 → 0.3.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 +158 -0
- package/README.md +53 -11
- package/data/PROVENANCE.md +19 -0
- package/data/pricing-manual.json +22 -0
- package/data/pricing-map.json +46362 -0
- package/data/pricing-overlay.json +419 -0
- package/dist/adapters/anthropic.d.ts +50 -6
- package/dist/adapters/anthropic.d.ts.map +1 -1
- package/dist/adapters/anthropic.js +123 -29
- package/dist/adapters/build-adapters.d.ts +11 -0
- package/dist/adapters/build-adapters.d.ts.map +1 -0
- package/dist/adapters/build-adapters.js +45 -0
- package/dist/adapters/deepseek.d.ts +6 -0
- package/dist/adapters/deepseek.d.ts.map +1 -1
- package/dist/adapters/deepseek.js +54 -1
- package/dist/adapters/gemini.d.ts +10 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +78 -7
- package/dist/adapters/grok.d.ts +9 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +67 -3
- package/dist/adapters/openai-compat.d.ts +6 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +58 -1
- package/dist/adapters/openai-stream.d.ts +58 -0
- package/dist/adapters/openai-stream.d.ts.map +1 -0
- package/dist/adapters/openai-stream.js +120 -0
- package/dist/adapters/openai.d.ts +6 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +60 -1
- package/dist/adapters/sampling.d.ts +28 -0
- package/dist/adapters/sampling.d.ts.map +1 -0
- package/dist/adapters/sampling.js +34 -0
- package/dist/adapters/tool-mapping.d.ts +92 -0
- package/dist/adapters/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/tool-mapping.js +143 -0
- package/dist/artifacts/artifact.d.ts +137 -0
- package/dist/artifacts/artifact.d.ts.map +1 -0
- package/dist/artifacts/artifact.js +377 -0
- package/dist/artifacts/content-uploader.d.ts +87 -0
- package/dist/artifacts/content-uploader.d.ts.map +1 -0
- package/dist/artifacts/content-uploader.js +124 -0
- package/dist/artifacts/index.d.ts +63 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +80 -0
- package/dist/artifacts/run-context.d.ts +129 -0
- package/dist/artifacts/run-context.d.ts.map +1 -0
- package/dist/artifacts/run-context.js +208 -0
- package/dist/artifacts/scrub.d.ts +60 -0
- package/dist/artifacts/scrub.d.ts.map +1 -0
- package/dist/artifacts/scrub.js +139 -0
- package/dist/artifacts/step.d.ts +26 -0
- package/dist/artifacts/step.d.ts.map +1 -0
- package/dist/artifacts/step.js +37 -0
- package/dist/artifacts/taint.d.ts +63 -0
- package/dist/artifacts/taint.d.ts.map +1 -0
- package/dist/artifacts/taint.js +76 -0
- package/dist/bakeoff/cache-sim.d.ts +99 -0
- package/dist/bakeoff/cache-sim.d.ts.map +1 -0
- package/dist/bakeoff/cache-sim.js +126 -0
- package/dist/bakeoff/eval-cases.d.ts +96 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases.js +105 -0
- package/dist/bakeoff/report.d.ts +41 -0
- package/dist/bakeoff/report.d.ts.map +1 -0
- package/dist/bakeoff/report.js +142 -0
- package/dist/bakeoff/samples.d.ts +15 -0
- package/dist/bakeoff/samples.d.ts.map +1 -1
- package/dist/bakeoff/samples.js +20 -0
- package/dist/cli.d.ts +1 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +134 -116
- package/dist/config.d.ts +100 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +104 -0
- package/dist/deprecations.d.ts +32 -0
- package/dist/deprecations.d.ts.map +1 -0
- package/dist/deprecations.js +59 -0
- package/dist/gateway/http-protocol.d.ts +175 -0
- package/dist/gateway/http-protocol.d.ts.map +1 -0
- package/dist/gateway/http-protocol.js +105 -0
- package/dist/index.d.ts +106 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -138
- package/dist/init/finder.d.ts +15 -0
- package/dist/init/finder.d.ts.map +1 -1
- package/dist/init/finder.js +46 -0
- package/dist/init/init-cli.d.ts +10 -0
- package/dist/init/init-cli.d.ts.map +1 -0
- package/dist/init/init-cli.js +86 -0
- package/dist/init/observe-cli.d.ts +19 -0
- package/dist/init/observe-cli.d.ts.map +1 -0
- package/dist/init/observe-cli.js +73 -0
- package/dist/init/observe.d.ts +81 -0
- package/dist/init/observe.d.ts.map +1 -0
- package/dist/init/observe.js +245 -0
- package/dist/registry/build.d.ts +94 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +125 -4
- package/dist/registry/cache-policy.d.ts +94 -0
- package/dist/registry/cache-policy.d.ts.map +1 -0
- package/dist/registry/cache-policy.js +238 -0
- package/dist/registry/call-notes.d.ts.map +1 -1
- package/dist/registry/call-notes.js +40 -2
- package/dist/registry/effective-rate.d.ts +151 -0
- package/dist/registry/effective-rate.d.ts.map +1 -0
- package/dist/registry/effective-rate.js +156 -0
- package/dist/registry/facts.d.ts.map +1 -1
- package/dist/registry/facts.js +16 -0
- package/dist/registry/parity.d.ts +26 -0
- package/dist/registry/parity.d.ts.map +1 -1
- package/dist/registry/parity.js +43 -2
- package/dist/registry/pricing-shape.d.ts +113 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -0
- package/dist/registry/pricing-shape.js +123 -0
- package/dist/registry/pricing.d.ts +25 -1
- package/dist/registry/pricing.d.ts.map +1 -1
- package/dist/registry/pricing.js +64 -6
- package/dist/rigindex/bootstrap.d.ts +36 -0
- package/dist/rigindex/bootstrap.d.ts.map +1 -0
- package/dist/rigindex/bootstrap.js +97 -0
- package/dist/rigindex/fit.d.ts +24 -0
- package/dist/rigindex/fit.d.ts.map +1 -0
- package/dist/rigindex/fit.js +76 -0
- package/dist/rigindex/gates.d.ts +52 -0
- package/dist/rigindex/gates.d.ts.map +1 -0
- package/dist/rigindex/gates.js +109 -0
- package/dist/rigindex/graph.d.ts +31 -0
- package/dist/rigindex/graph.d.ts.map +1 -0
- package/dist/rigindex/graph.js +120 -0
- package/dist/rigindex/index.d.ts +23 -0
- package/dist/rigindex/index.d.ts.map +1 -0
- package/dist/rigindex/index.js +112 -0
- package/dist/rigindex/types.d.ts +76 -0
- package/dist/rigindex/types.d.ts.map +1 -0
- package/dist/rigindex/types.js +8 -0
- package/dist/routes/cache-lint.d.ts +41 -0
- package/dist/routes/cache-lint.d.ts.map +1 -0
- package/dist/routes/cache-lint.js +81 -0
- package/dist/routes/loader.d.ts +48 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +167 -0
- package/dist/routes/resolved-bundle.d.ts +79 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -0
- package/dist/routes/resolved-bundle.js +148 -0
- package/dist/routes/sampling-config.d.ts +32 -0
- package/dist/routes/sampling-config.d.ts.map +1 -0
- package/dist/routes/sampling-config.js +91 -0
- package/dist/run/ajv.d.ts +22 -0
- package/dist/run/ajv.d.ts.map +1 -0
- package/dist/run/ajv.js +32 -0
- package/dist/run/cache-handle.d.ts +58 -0
- package/dist/run/cache-handle.d.ts.map +1 -0
- package/dist/run/cache-handle.js +54 -0
- package/dist/run/cache-stamp.d.ts +65 -0
- package/dist/run/cache-stamp.d.ts.map +1 -0
- package/dist/run/cache-stamp.js +0 -0
- package/dist/run/capture-write.d.ts +33 -0
- package/dist/run/capture-write.d.ts.map +1 -0
- package/dist/run/capture-write.js +55 -0
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +1 -1
- package/dist/run/dispatch.d.ts +99 -0
- package/dist/run/dispatch.d.ts.map +1 -0
- package/dist/run/dispatch.js +191 -0
- package/dist/run/raw.d.ts +130 -0
- package/dist/run/raw.d.ts.map +1 -0
- package/dist/run/raw.js +363 -0
- package/dist/run/record-attempt.d.ts +40 -0
- package/dist/run/record-attempt.d.ts.map +1 -0
- package/dist/run/record-attempt.js +99 -0
- package/dist/run/resolve.d.ts +75 -2
- package/dist/run/resolve.d.ts.map +1 -1
- package/dist/run/resolve.js +126 -4
- package/dist/run/run.d.ts +14 -0
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +0 -0
- package/dist/run/stream.d.ts +49 -0
- package/dist/run/stream.d.ts.map +1 -0
- package/dist/run/stream.js +87 -0
- package/dist/run/validate.d.ts.map +1 -1
- package/dist/run/validate.js +6 -7
- package/dist/savings/cache-ledger.d.ts +108 -0
- package/dist/savings/cache-ledger.d.ts.map +1 -0
- package/dist/savings/cache-ledger.js +174 -0
- package/dist/savings/cache-reconcile.d.ts +64 -0
- package/dist/savings/cache-reconcile.d.ts.map +1 -0
- package/dist/savings/cache-reconcile.js +59 -0
- package/dist/savings/cache-stats.d.ts +63 -0
- package/dist/savings/cache-stats.d.ts.map +1 -0
- package/dist/savings/cache-stats.js +108 -0
- package/dist/savings/emit.d.ts +13 -0
- package/dist/savings/emit.d.ts.map +1 -1
- package/dist/savings/emit.js +25 -0
- package/dist/savings/swap-execute.d.ts +14 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +44 -1
- package/dist/savings/swaps-client.d.ts +14 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/savings/swaps-client.js +16 -2
- package/dist/settings/api-fetcher.d.ts +39 -0
- package/dist/settings/api-fetcher.d.ts.map +1 -0
- package/dist/settings/api-fetcher.js +92 -0
- package/dist/settings/index.d.ts +10 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/task-settings.d.ts +91 -0
- package/dist/settings/task-settings.d.ts.map +1 -0
- package/dist/settings/task-settings.js +116 -0
- package/dist/status.d.ts +77 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +113 -0
- package/dist/telemetry/artifact-store.d.ts +48 -0
- package/dist/telemetry/artifact-store.d.ts.map +1 -0
- package/dist/telemetry/artifact-store.js +189 -0
- package/dist/telemetry/cache-miss-streak.d.ts +79 -0
- package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
- package/dist/telemetry/cache-miss-streak.js +99 -0
- package/dist/telemetry/capture.d.ts +3 -0
- package/dist/telemetry/capture.d.ts.map +1 -1
- package/dist/telemetry/capture.js +15 -8
- package/dist/telemetry/exporter-setup.d.ts +28 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -0
- package/dist/telemetry/exporter-setup.js +34 -0
- package/dist/telemetry/exporter.d.ts +75 -0
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +324 -47
- package/dist/telemetry/health.d.ts +76 -0
- package/dist/telemetry/health.d.ts.map +1 -0
- package/dist/telemetry/health.js +92 -0
- package/dist/telemetry/ingest-protocol.d.ts +152 -3
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +204 -4
- package/dist/telemetry/load-error-report.d.ts +24 -0
- package/dist/telemetry/load-error-report.d.ts.map +1 -0
- package/dist/telemetry/load-error-report.js +50 -0
- package/dist/telemetry/otel-map.d.ts +121 -0
- package/dist/telemetry/otel-map.d.ts.map +1 -0
- package/dist/telemetry/otel-map.js +224 -0
- package/dist/telemetry/otel-normalize.d.ts +104 -0
- package/dist/telemetry/otel-normalize.d.ts.map +1 -0
- package/dist/telemetry/otel-normalize.js +530 -0
- package/dist/telemetry/otlp-emitter.d.ts +52 -0
- package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
- package/dist/telemetry/otlp-emitter.js +144 -0
- package/dist/telemetry/otlp-proto.d.ts +29 -0
- package/dist/telemetry/otlp-proto.d.ts.map +1 -0
- package/dist/telemetry/otlp-proto.js +266 -0
- package/dist/telemetry/sinks.d.ts +37 -1
- package/dist/telemetry/sinks.d.ts.map +1 -1
- package/dist/telemetry/sinks.js +121 -30
- package/dist/telemetry/store.d.ts +28 -1
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +218 -3
- package/dist/tenancy/api-key-format.d.ts +15 -5
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +24 -5
- package/dist/types/config-teaching.d.ts +62 -0
- package/dist/types/config-teaching.d.ts.map +1 -0
- package/dist/types/config-teaching.js +183 -0
- package/dist/types/provider.d.ts +147 -1
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +21 -1
- package/dist/types/route.d.ts +79 -1
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +117 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts +12 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate-cli.js +57 -0
- package/dist/verify/capture.d.ts +66 -0
- package/dist/verify/capture.d.ts.map +1 -0
- package/dist/verify/capture.js +180 -0
- package/dist/verify/cli-run.d.ts +23 -0
- package/dist/verify/cli-run.d.ts.map +1 -0
- package/dist/verify/cli-run.js +57 -0
- package/dist/verify/diff.d.ts +48 -0
- package/dist/verify/diff.d.ts.map +1 -0
- package/dist/verify/diff.js +157 -0
- package/dist/verify/index.d.ts +17 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +24 -0
- package/dist/verify/report.d.ts +14 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/report.js +88 -0
- package/dist/verify/types.d.ts +101 -0
- package/dist/verify/types.d.ts.map +1 -0
- package/dist/verify/types.js +17 -0
- package/dist/verify/verify.d.ts +29 -0
- package/dist/verify/verify.d.ts.map +1 -0
- package/dist/verify/verify.js +148 -0
- package/dist/watch/evaluate.d.ts +162 -3
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +61 -0
- package/dist/watch/monitor.d.ts +116 -0
- package/dist/watch/monitor.d.ts.map +1 -0
- package/dist/watch/monitor.js +199 -0
- package/dist/watch/proposals.d.ts +20 -4
- package/dist/watch/proposals.d.ts.map +1 -1
- package/dist/watch/proposals.js +31 -3
- package/dist/watch/run.d.ts +33 -0
- package/dist/watch/run.d.ts.map +1 -1
- package/dist/watch/run.js +39 -0
- package/package.json +7 -1
- package/registry/LICENSE +20 -0
- package/registry/leaderboard.json +3639 -0
- package/registry/registry.json +7263 -0
- package/dist/telemetry/supabase-exporter.d.ts +0 -64
- package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
- package/dist/telemetry/supabase-exporter.js +0 -211
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observed-health aggregation — G-4 (observed-health/spec.md §3.1, §4.1).
|
|
3
|
+
*
|
|
4
|
+
* One home for the per-endpoint latency/TTFB percentile + error-rate + min-n
|
|
5
|
+
* math, shared by the live store reader (store.ts `readEndpointHealth`) and the
|
|
6
|
+
* observed-layer rollup (registry/build-observed.ts). Keeping the math here —
|
|
7
|
+
* not in run.ts (at the 700-LOC cap) — is deliberate.
|
|
8
|
+
*
|
|
9
|
+
* THE RIGINDEX WALL (spec §4.4, load-bearing): this module feeds routing +
|
|
10
|
+
* console surfaces ONLY. It must NEVER be imported by registry/build-leaderboard.ts
|
|
11
|
+
* or the matrix/Bradley-Terry path — production telemetry never produces rank
|
|
12
|
+
* (eval-methodology-and-rigindex.md:19). The import-guard test
|
|
13
|
+
* (health-rigindex-wall.test.ts) is the tripwire; do not weaken it.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProviderId } from "../types/provider";
|
|
16
|
+
/** Spec §4.1 example: below 20 samples, percentiles/error-rate surface as null. */
|
|
17
|
+
export declare const DEFAULT_HEALTH_MIN_N = 20;
|
|
18
|
+
export interface HealthPercentiles {
|
|
19
|
+
readonly p50: number;
|
|
20
|
+
readonly p90: number;
|
|
21
|
+
readonly p99: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Per-endpoint observed health over a rolling window. Percentiles + errorRate
|
|
25
|
+
* are `null` under the min-n gate (thin data must not read as a confident zero);
|
|
26
|
+
* `sampleN` is always reported so the surface can say "n too low", not "healthy".
|
|
27
|
+
*/
|
|
28
|
+
export interface EndpointHealth {
|
|
29
|
+
readonly provider: ProviderId;
|
|
30
|
+
readonly model: string;
|
|
31
|
+
readonly windowStart: string;
|
|
32
|
+
readonly sampleN: number;
|
|
33
|
+
readonly latencyMs: HealthPercentiles | null;
|
|
34
|
+
readonly ttfbMs: HealthPercentiles | null;
|
|
35
|
+
readonly errorRate: number | null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The minimal row shape the aggregation needs. Both the local SQLite store and
|
|
39
|
+
* the hosted rollup can project their rows onto this, so the math is identical
|
|
40
|
+
* on both lanes (spec §3.1).
|
|
41
|
+
*/
|
|
42
|
+
export interface HealthInputRow {
|
|
43
|
+
readonly provider: string;
|
|
44
|
+
readonly model: string;
|
|
45
|
+
readonly ts: string;
|
|
46
|
+
readonly latency_ms: number;
|
|
47
|
+
readonly ttfb_ms: number | null;
|
|
48
|
+
readonly failure_class: string | null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Nearest-rank percentile over a pre-sorted ascending array. Matches the
|
|
52
|
+
* convention already used by build-observed.ts so the two lanes agree.
|
|
53
|
+
*/
|
|
54
|
+
export declare function percentile(sorted: readonly number[], p: number): number | null;
|
|
55
|
+
/**
|
|
56
|
+
* p50/p90/p99 over a set of values, dropping non-positive samples (a zero or
|
|
57
|
+
* negative latency/TTFB is a non-measurement, not a fast call). `null` when no
|
|
58
|
+
* positive sample remains.
|
|
59
|
+
*/
|
|
60
|
+
export declare function computePercentiles(values: readonly number[]): HealthPercentiles | null;
|
|
61
|
+
export interface HealthWindowOptions {
|
|
62
|
+
readonly windowMinutes: number;
|
|
63
|
+
readonly minN: number;
|
|
64
|
+
/** Reference "now" in epoch ms — injected for deterministic windowing/tests. */
|
|
65
|
+
readonly now: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Aggregate windowed telemetry rows into per-(provider, model) health.
|
|
69
|
+
*
|
|
70
|
+
* Window: rows whose ts is within [now - windowMinutes, now]. Rows with an
|
|
71
|
+
* unparseable ts are dropped, never thrown on. Output is sorted by provider then
|
|
72
|
+
* model for deterministic rollups. Below `minN`, percentiles + errorRate are
|
|
73
|
+
* `null` (min-n gate) while `sampleN` is still reported.
|
|
74
|
+
*/
|
|
75
|
+
export declare function aggregateEndpointHealth(rows: readonly HealthInputRow[], opts: HealthWindowOptions): EndpointHealth[];
|
|
76
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/telemetry/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,mFAAmF;AACnF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI9E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,GAAG,IAAI,CAStF;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAMD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,cAAc,EAAE,EAC/B,IAAI,EAAE,mBAAmB,GACxB,cAAc,EAAE,CAoClB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Observed-health aggregation — G-4 (observed-health/spec.md §3.1, §4.1).
|
|
4
|
+
*
|
|
5
|
+
* One home for the per-endpoint latency/TTFB percentile + error-rate + min-n
|
|
6
|
+
* math, shared by the live store reader (store.ts `readEndpointHealth`) and the
|
|
7
|
+
* observed-layer rollup (registry/build-observed.ts). Keeping the math here —
|
|
8
|
+
* not in run.ts (at the 700-LOC cap) — is deliberate.
|
|
9
|
+
*
|
|
10
|
+
* THE RIGINDEX WALL (spec §4.4, load-bearing): this module feeds routing +
|
|
11
|
+
* console surfaces ONLY. It must NEVER be imported by registry/build-leaderboard.ts
|
|
12
|
+
* or the matrix/Bradley-Terry path — production telemetry never produces rank
|
|
13
|
+
* (eval-methodology-and-rigindex.md:19). The import-guard test
|
|
14
|
+
* (health-rigindex-wall.test.ts) is the tripwire; do not weaken it.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DEFAULT_HEALTH_MIN_N = void 0;
|
|
18
|
+
exports.percentile = percentile;
|
|
19
|
+
exports.computePercentiles = computePercentiles;
|
|
20
|
+
exports.aggregateEndpointHealth = aggregateEndpointHealth;
|
|
21
|
+
/** Spec §4.1 example: below 20 samples, percentiles/error-rate surface as null. */
|
|
22
|
+
exports.DEFAULT_HEALTH_MIN_N = 20;
|
|
23
|
+
/**
|
|
24
|
+
* Nearest-rank percentile over a pre-sorted ascending array. Matches the
|
|
25
|
+
* convention already used by build-observed.ts so the two lanes agree.
|
|
26
|
+
*/
|
|
27
|
+
function percentile(sorted, p) {
|
|
28
|
+
if (sorted.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
const index = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length));
|
|
31
|
+
return sorted[index];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* p50/p90/p99 over a set of values, dropping non-positive samples (a zero or
|
|
35
|
+
* negative latency/TTFB is a non-measurement, not a fast call). `null` when no
|
|
36
|
+
* positive sample remains.
|
|
37
|
+
*/
|
|
38
|
+
function computePercentiles(values) {
|
|
39
|
+
const sorted = values.filter((v) => v > 0).sort((a, b) => a - b);
|
|
40
|
+
if (sorted.length === 0)
|
|
41
|
+
return null;
|
|
42
|
+
return {
|
|
43
|
+
// percentile() only returns null for an empty array, ruled out above.
|
|
44
|
+
p50: percentile(sorted, 50),
|
|
45
|
+
p90: percentile(sorted, 90),
|
|
46
|
+
p99: percentile(sorted, 99),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Grouping-key separator: neither a ProviderId nor a model id contains a pipe,
|
|
50
|
+
// so the split back into (provider, model) is unambiguous.
|
|
51
|
+
const KEY_SEP = "|";
|
|
52
|
+
/**
|
|
53
|
+
* Aggregate windowed telemetry rows into per-(provider, model) health.
|
|
54
|
+
*
|
|
55
|
+
* Window: rows whose ts is within [now - windowMinutes, now]. Rows with an
|
|
56
|
+
* unparseable ts are dropped, never thrown on. Output is sorted by provider then
|
|
57
|
+
* model for deterministic rollups. Below `minN`, percentiles + errorRate are
|
|
58
|
+
* `null` (min-n gate) while `sampleN` is still reported.
|
|
59
|
+
*/
|
|
60
|
+
function aggregateEndpointHealth(rows, opts) {
|
|
61
|
+
const windowStartMs = opts.now - opts.windowMinutes * 60000;
|
|
62
|
+
const windowStart = new Date(windowStartMs).toISOString();
|
|
63
|
+
const byEndpoint = new Map();
|
|
64
|
+
for (const row of rows) {
|
|
65
|
+
const t = Date.parse(row.ts);
|
|
66
|
+
if (Number.isNaN(t) || t < windowStartMs || t > opts.now)
|
|
67
|
+
continue;
|
|
68
|
+
const key = `${row.provider}${KEY_SEP}${row.model}`;
|
|
69
|
+
const list = byEndpoint.get(key) ?? [];
|
|
70
|
+
list.push(row);
|
|
71
|
+
byEndpoint.set(key, list);
|
|
72
|
+
}
|
|
73
|
+
const out = [];
|
|
74
|
+
for (const [key, group] of byEndpoint) {
|
|
75
|
+
const [provider, model] = key.split(KEY_SEP);
|
|
76
|
+
const sampleN = group.length;
|
|
77
|
+
const gated = sampleN < opts.minN;
|
|
78
|
+
const errorCount = group.filter((r) => r.failure_class !== null).length;
|
|
79
|
+
out.push({
|
|
80
|
+
provider: provider,
|
|
81
|
+
model,
|
|
82
|
+
windowStart,
|
|
83
|
+
sampleN,
|
|
84
|
+
latencyMs: gated ? null : computePercentiles(group.map((r) => r.latency_ms)),
|
|
85
|
+
ttfbMs: gated
|
|
86
|
+
? null
|
|
87
|
+
: computePercentiles(group.map((r) => r.ttfb_ms).filter((t) => t !== null)),
|
|
88
|
+
errorRate: gated ? null : errorCount / sampleN,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return out.sort((a, b) => a.provider === b.provider ? a.model.localeCompare(b.model) : a.provider.localeCompare(b.provider));
|
|
92
|
+
}
|
|
@@ -31,11 +31,19 @@
|
|
|
31
31
|
* already holds a credential that can write any row in the database.
|
|
32
32
|
*/
|
|
33
33
|
import type { FailureClass } from "../types/failures";
|
|
34
|
+
import type { ResolvedRouteBundle } from "../routes/resolved-bundle";
|
|
34
35
|
/** The path the api sink posts to. Spelled once. */
|
|
35
36
|
export declare const INGEST_PATH = "/v1/ingest";
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
38
|
-
|
|
37
|
+
/** The CURRENT protocol version — the maximum the SDK can speak (ruling d).
|
|
38
|
+
* v2 = v1 + the optional runs/steps/artifacts sections. A server that does not
|
|
39
|
+
* recognise the version refuses the batch rather than guessing; the SDK sends
|
|
40
|
+
* v2 ONLY when the artifact namespace is active (spec §1.3), otherwise it keeps
|
|
41
|
+
* sending v1 batches byte-identical to before v2 existed. */
|
|
42
|
+
export declare const INGEST_PROTOCOL_VERSION = 2;
|
|
43
|
+
/** The v1 baseline — batches carrying only the pre-artifact sections announce
|
|
44
|
+
* this and remain valid forever. The exporter uses it when artifacts are
|
|
45
|
+
* disabled (byte-identical to today) and for the pre-loop load-error batch. */
|
|
46
|
+
export declare const INGEST_PROTOCOL_VERSION_V1 = 1;
|
|
39
47
|
/** Default ingest host — telemetry-ingestion-boundary.md §2.1. */
|
|
40
48
|
export declare const DEFAULT_INGEST_URL = "https://api.modelrig.ai";
|
|
41
49
|
/** The tenant stamped onto every row. Resolved from the principal, never from
|
|
@@ -67,6 +75,14 @@ export interface WireInference {
|
|
|
67
75
|
readonly served_variant: string | null;
|
|
68
76
|
readonly repaired_by: string | null;
|
|
69
77
|
readonly pricing_missing: boolean;
|
|
78
|
+
/** Cache accounting (WS-A). OPTIONAL on the wire: an older SDK never sends
|
|
79
|
+
* them, and the server defaults writes to 0 and key/fingerprint to null on
|
|
80
|
+
* absence (ingest.validInference). A current SDK always sends them; they map
|
|
81
|
+
* straight into `inferences.tokens_cache_write` etc. (migration 00049). */
|
|
82
|
+
readonly tokens_cache_write?: number;
|
|
83
|
+
readonly tokens_cache_write_1h?: number;
|
|
84
|
+
readonly cache_key?: string | null;
|
|
85
|
+
readonly prefix_fingerprint?: string | null;
|
|
70
86
|
}
|
|
71
87
|
export interface WireFeedback {
|
|
72
88
|
readonly id: string;
|
|
@@ -98,12 +114,135 @@ export interface WireRoute {
|
|
|
98
114
|
readonly model: string;
|
|
99
115
|
}>;
|
|
100
116
|
readonly capture: boolean;
|
|
117
|
+
/** Phase D (spec §13.1 rule 3): the RESOLVED bundle, file references followed
|
|
118
|
+
* and inlined at sync time, mirrored so the hosted gateway can serve the
|
|
119
|
+
* route without the customer's filesystem. Optional so a pre-Phase-D SDK
|
|
120
|
+
* still validates; a batch WITHOUT it leaves any existing mirrored bundle
|
|
121
|
+
* untouched (the routes upsert only writes the columns it carries). */
|
|
122
|
+
readonly bundle?: ResolvedRouteBundle;
|
|
123
|
+
/** Content hash of the canonical bundle (`sha256:<hex>`). Present iff
|
|
124
|
+
* `bundle` is. */
|
|
125
|
+
readonly bundle_sha?: string;
|
|
126
|
+
}
|
|
127
|
+
/** A run — one execution of a customer pipeline (protocol v2, spec §1.1).
|
|
128
|
+
* A mutable projection (start → end); `source_id` and `org_id` are stamped from
|
|
129
|
+
* the principal, never carried on the wire (T3). */
|
|
130
|
+
export interface WireRun {
|
|
131
|
+
readonly id: string;
|
|
132
|
+
readonly pipeline: string;
|
|
133
|
+
readonly pipeline_version: string | null;
|
|
134
|
+
readonly environment: string | null;
|
|
135
|
+
readonly episode_key: string | null;
|
|
136
|
+
readonly started_at: string;
|
|
137
|
+
readonly ended_at: string | null;
|
|
138
|
+
readonly status: "running" | "succeeded" | "failed" | "abandoned";
|
|
139
|
+
}
|
|
140
|
+
/** A step — one ATTEMPT of one operation within a run (protocol v2, spec §1.1).
|
|
141
|
+
* A fact (merge=false). Provenance is ground-truth (an `inferences` reference)
|
|
142
|
+
* XOR attested (a foreign OTLP span); the server drops a reference shape that
|
|
143
|
+
* violates the exactly-one CHECK (`bad_step_reference`) rather than guessing.
|
|
144
|
+
* `org_id` is stamped from the principal; for a ground-truth step
|
|
145
|
+
* `inference_source_id` is stamped to the principal's source_id. */
|
|
146
|
+
export interface WireStep {
|
|
147
|
+
readonly run_id: string;
|
|
148
|
+
readonly step_key: string;
|
|
149
|
+
readonly attempt_no: number;
|
|
150
|
+
readonly task: string | null;
|
|
151
|
+
readonly provenance: "ground-truth" | "attested";
|
|
152
|
+
readonly inference_id: string | null;
|
|
153
|
+
readonly span_trace_id: string | null;
|
|
154
|
+
readonly span_id: string | null;
|
|
155
|
+
readonly started_at: string;
|
|
156
|
+
readonly ended_at: string | null;
|
|
157
|
+
readonly failure_class: string | null;
|
|
158
|
+
/**
|
|
159
|
+
* The normalized OTLP envelope for an ATTESTED step (Expansion E3-Harvest,
|
|
160
|
+
* migration 00038: `steps.attested jsonb`). Carries `{model, provider,
|
|
161
|
+
* operation, usage{…}, scope}` for foreign-span-ingested steps; steps
|
|
162
|
+
* deliberately have no usage COLUMNS because ground-truth usage lives on
|
|
163
|
+
* `inferences`, and attested usage has nowhere else honest to live. Absent on
|
|
164
|
+
* every SDK-emitted (ground-truth) step, so v1/v2 SDK batches are unchanged
|
|
165
|
+
* and the `steps.attested` CHECK (`provenance='attested' or attested is null`)
|
|
166
|
+
* holds. Opaque `unknown` at the wire boundary (T7 — jsonb is not proof of
|
|
167
|
+
* shape); the strongly-typed producer is `otel-normalize.ts`.
|
|
168
|
+
*/
|
|
169
|
+
readonly attested?: unknown;
|
|
170
|
+
}
|
|
171
|
+
/** An artifact — durable work product METADATA (protocol v2, spec §2). Content
|
|
172
|
+
* is NEVER carried: `content_ref` is the customer's opaque URI, `content_hash`
|
|
173
|
+
* a sha256 of bytes hashed-then-discarded. A fact (merge=false). */
|
|
174
|
+
export interface WireArtifact {
|
|
175
|
+
readonly id: string;
|
|
176
|
+
readonly run_id: string | null;
|
|
177
|
+
readonly step_key: string | null;
|
|
178
|
+
readonly attempt_no: number | null;
|
|
179
|
+
readonly task: string | null;
|
|
180
|
+
readonly name: string;
|
|
181
|
+
readonly type: string;
|
|
182
|
+
readonly version: number;
|
|
183
|
+
readonly supersedes_artifact_id: string | null;
|
|
184
|
+
readonly declared_schema: unknown;
|
|
185
|
+
readonly fingerprint_cell: string | null;
|
|
186
|
+
readonly content_ref: string | null;
|
|
187
|
+
readonly content_hash: string | null;
|
|
188
|
+
readonly content_bytes: number | null;
|
|
189
|
+
readonly data_classification: string | null;
|
|
190
|
+
readonly expires_at: string | null;
|
|
191
|
+
/** Per-row scrub findings (E4 chunk 0, migration 00039) — counts-by-type +
|
|
192
|
+
* mode, NEVER matched values. Optional: absent ⇒ scrub did not run (older SDK,
|
|
193
|
+
* custody off), and the column stays null via spread-iff-present in stampBatch
|
|
194
|
+
* so v1/older artifact rows are byte-identical. Opaque here (T7). */
|
|
195
|
+
readonly scrub?: unknown;
|
|
196
|
+
}
|
|
197
|
+
/** A lineage edge between two artifacts (spec §2). A fact. */
|
|
198
|
+
export interface WireArtifactEdge {
|
|
199
|
+
readonly from_artifact_id: string;
|
|
200
|
+
readonly to_artifact_id: string;
|
|
201
|
+
readonly kind: "consumed" | "derived_from";
|
|
202
|
+
}
|
|
203
|
+
/** A promoted eval case (E4 chunk A). `corrected_artifact_id` null ⇒ a
|
|
204
|
+
* failure-case; set ⇒ a golden-corrected pair. A fact on ingest (create via
|
|
205
|
+
* promote); edits/deletes are server-side, never on this stream. `org_id` is
|
|
206
|
+
* stamped from the principal (T3), `created_by` when an authenticated user
|
|
207
|
+
* promoted it. */
|
|
208
|
+
export interface WireEvalCase {
|
|
209
|
+
readonly id: string;
|
|
210
|
+
readonly task: string;
|
|
211
|
+
readonly source_artifact_id: string;
|
|
212
|
+
readonly corrected_artifact_id: string | null;
|
|
213
|
+
readonly origin: "promoted-failure" | "human-corrected" | "manual";
|
|
214
|
+
readonly note: string | null;
|
|
215
|
+
readonly created_by: string | null;
|
|
216
|
+
}
|
|
217
|
+
/** An evaluation recorded against a SUBJECT — one of an artifact or a whole run
|
|
218
|
+
* (E5 chunk V, subject-one-of per trajectory F3). Exactly one of artifact_id /
|
|
219
|
+
* run_id is non-null; the server's validEvaluation enforces the XOR and the
|
|
220
|
+
* 00051 CHECK is the backstop. A fact. */
|
|
221
|
+
export interface WireArtifactEvaluation {
|
|
222
|
+
readonly id: string;
|
|
223
|
+
/** The artifact subject — null when this evaluates a whole run instead. */
|
|
224
|
+
readonly artifact_id: string | null;
|
|
225
|
+
/** The run subject (E5 V) — null when this evaluates an artifact. */
|
|
226
|
+
readonly run_id?: string | null;
|
|
227
|
+
readonly evaluator: string;
|
|
228
|
+
readonly evaluator_kind: "deterministic" | "model-judge" | "human";
|
|
229
|
+
readonly score: number | null;
|
|
230
|
+
readonly passed: boolean | null;
|
|
231
|
+
readonly label: string | null;
|
|
232
|
+
readonly explanation: string | null;
|
|
233
|
+
readonly created_by: string | null;
|
|
101
234
|
}
|
|
102
235
|
export interface WireManifest {
|
|
103
236
|
readonly name: string;
|
|
104
237
|
readonly dimensions: unknown;
|
|
105
238
|
readonly contribution: boolean;
|
|
106
239
|
readonly serveability: readonly unknown[];
|
|
240
|
+
/** Load-time RouteConfigError diagnostics for THIS deployment (follow-up #2)
|
|
241
|
+
* — the describeConfigFailure shape, names/diagnostics only. Optional so a
|
|
242
|
+
* pre-load_errors SDK still validates; absent is treated as `[]` (clean). A
|
|
243
|
+
* successful load sends `[]`, which clears a stale failure from a prior
|
|
244
|
+
* broken deploy. */
|
|
245
|
+
readonly load_errors?: readonly unknown[];
|
|
107
246
|
}
|
|
108
247
|
/** One flush's worth of telemetry. Every collection is optional — a flush that
|
|
109
248
|
* has only inferences sends only inferences. */
|
|
@@ -117,6 +256,16 @@ export interface IngestBatch {
|
|
|
117
256
|
readonly feedback?: readonly WireFeedback[];
|
|
118
257
|
readonly envelopes?: readonly WireEnvelope[];
|
|
119
258
|
readonly routes?: readonly WireRoute[];
|
|
259
|
+
/** Protocol v2 (spec §1). Present only when the SDK's artifact namespace is
|
|
260
|
+
* active; a v1 batch never carries them and is byte-identical to before. */
|
|
261
|
+
readonly runs?: readonly WireRun[];
|
|
262
|
+
readonly steps?: readonly WireStep[];
|
|
263
|
+
readonly artifacts?: readonly WireArtifact[];
|
|
264
|
+
readonly artifact_edges?: readonly WireArtifactEdge[];
|
|
265
|
+
readonly artifact_evaluations?: readonly WireArtifactEvaluation[];
|
|
266
|
+
/** Promoted eval cases (E4 chunk A). Present only when the SDK's artifact
|
|
267
|
+
* namespace is active and a promote happened; a v1 batch never carries them. */
|
|
268
|
+
readonly eval_cases?: readonly WireEvalCase[];
|
|
120
269
|
readonly manifest?: WireManifest;
|
|
121
270
|
/** Present when this batch advanced the exporter's inference watermark. */
|
|
122
271
|
readonly watermarkAt?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-protocol.d.ts","sourceRoot":"","sources":["../../src/telemetry/ingest-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"ingest-protocol.d.ts","sourceRoot":"","sources":["../../src/telemetry/ingest-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,14 +32,22 @@
|
|
|
32
32
|
* already holds a credential that can write any row in the database.
|
|
33
33
|
*/
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.DEFAULT_INGEST_URL = exports.INGEST_PROTOCOL_VERSION = exports.INGEST_PATH = void 0;
|
|
35
|
+
exports.DEFAULT_INGEST_URL = exports.INGEST_PROTOCOL_VERSION_V1 = exports.INGEST_PROTOCOL_VERSION = exports.INGEST_PATH = void 0;
|
|
36
36
|
exports.stampBatch = stampBatch;
|
|
37
37
|
exports.foreignOrgFeedback = foreignOrgFeedback;
|
|
38
|
+
const fingerprint_1 = require("../registry/fingerprint");
|
|
38
39
|
/** The path the api sink posts to. Spelled once. */
|
|
39
40
|
exports.INGEST_PATH = "/v1/ingest";
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
|
|
41
|
+
/** The CURRENT protocol version — the maximum the SDK can speak (ruling d).
|
|
42
|
+
* v2 = v1 + the optional runs/steps/artifacts sections. A server that does not
|
|
43
|
+
* recognise the version refuses the batch rather than guessing; the SDK sends
|
|
44
|
+
* v2 ONLY when the artifact namespace is active (spec §1.3), otherwise it keeps
|
|
45
|
+
* sending v1 batches byte-identical to before v2 existed. */
|
|
46
|
+
exports.INGEST_PROTOCOL_VERSION = 2;
|
|
47
|
+
/** The v1 baseline — batches carrying only the pre-artifact sections announce
|
|
48
|
+
* this and remain valid forever. The exporter uses it when artifacts are
|
|
49
|
+
* disabled (byte-identical to today) and for the pre-loop load-error batch. */
|
|
50
|
+
exports.INGEST_PROTOCOL_VERSION_V1 = 1;
|
|
43
51
|
/** Default ingest host — telemetry-ingestion-boundary.md §2.1. */
|
|
44
52
|
exports.DEFAULT_INGEST_URL = "https://api.modelrig.ai";
|
|
45
53
|
/**
|
|
@@ -53,6 +61,46 @@ function stampBatch(batch, tenancy) {
|
|
|
53
61
|
const writes = [];
|
|
54
62
|
const now = new Date().toISOString();
|
|
55
63
|
if (batch.routes !== undefined && batch.routes.length > 0) {
|
|
64
|
+
// Derive task identities BEFORE the routes write (spec §4, ruling a): a
|
|
65
|
+
// route implies a task. This is the derivation, not FK surgery — `routes`
|
|
66
|
+
// is untouched; the identity is a projection kept current by the same sync.
|
|
67
|
+
const seenTasks = new Set();
|
|
68
|
+
const taskRows = [];
|
|
69
|
+
for (const r of batch.routes) {
|
|
70
|
+
// Dedup by route NAME: a batch may carry several versions of one route,
|
|
71
|
+
// but they share a single task identity ((org_id, task) PK).
|
|
72
|
+
if (seenTasks.has(r.route))
|
|
73
|
+
continue;
|
|
74
|
+
seenTasks.add(r.route);
|
|
75
|
+
// Built field-by-field from the PRINCIPAL's tenancy, never spread from
|
|
76
|
+
// wire input — a client-supplied org_id must not ride in (ingest.ts:170
|
|
77
|
+
// doctrine, T3).
|
|
78
|
+
const taskRow = {
|
|
79
|
+
org_id: tenancy.org_id,
|
|
80
|
+
task: r.route,
|
|
81
|
+
source: "route-sync",
|
|
82
|
+
};
|
|
83
|
+
// spread-iff-bundle-present (the 00027 pattern): a metadata-only sync
|
|
84
|
+
// (no bundle) must NOT null-out an existing schema/fingerprint — a merge
|
|
85
|
+
// upsert touches only the columns present in the row. The fingerprint is
|
|
86
|
+
// computed server-side from the inlined schema with the SAME pure
|
|
87
|
+
// function the loader uses (fingerprintSchema); the parity golden locks
|
|
88
|
+
// the two call sites to identical output.
|
|
89
|
+
if (r.bundle !== undefined) {
|
|
90
|
+
taskRow.declared_schema = r.bundle.outputSchema ?? null;
|
|
91
|
+
taskRow.fingerprint_cell = (0, fingerprint_1.fingerprintSchema)(r.bundle.outputSchema)?.cellKey ?? null;
|
|
92
|
+
taskRow.updated_at = now;
|
|
93
|
+
}
|
|
94
|
+
taskRows.push(taskRow);
|
|
95
|
+
}
|
|
96
|
+
writes.push({
|
|
97
|
+
// merge=true: a task row is a mutable projection of the latest sync, like
|
|
98
|
+
// the routes mirror, unlike inferences. onConflict on the PK (S5).
|
|
99
|
+
table: "tasks",
|
|
100
|
+
onConflict: "org_id,task",
|
|
101
|
+
merge: true,
|
|
102
|
+
rows: taskRows,
|
|
103
|
+
});
|
|
56
104
|
writes.push({
|
|
57
105
|
table: "routes",
|
|
58
106
|
onConflict: "org_id,route,version",
|
|
@@ -64,6 +112,155 @@ function stampBatch(batch, tenancy) {
|
|
|
64
112
|
candidates: r.candidates,
|
|
65
113
|
capture: r.capture,
|
|
66
114
|
updated_at: now,
|
|
115
|
+
// Phase D (spec §13): the resolved bundle + its hash + the sync stamp.
|
|
116
|
+
// Written only when the batch carries a bundle, so an older SDK's
|
|
117
|
+
// metadata-only mirror leaves any existing bundle intact (a merge
|
|
118
|
+
// upsert touches only the columns present in the row). `synced_at` is
|
|
119
|
+
// the BUNDLE's timestamp — stamped iff a bundle synced — distinct from
|
|
120
|
+
// `updated_at`, the row's metadata timestamp.
|
|
121
|
+
...(r.bundle !== undefined
|
|
122
|
+
? { bundle: r.bundle, bundle_sha: r.bundle_sha ?? null, synced_at: now }
|
|
123
|
+
: {}),
|
|
124
|
+
})),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (batch.runs !== undefined && batch.runs.length > 0) {
|
|
128
|
+
writes.push({
|
|
129
|
+
// runs are a mutable projection (start → end): merge=true on the PK (S5).
|
|
130
|
+
table: "runs",
|
|
131
|
+
onConflict: "org_id,id",
|
|
132
|
+
merge: true,
|
|
133
|
+
rows: batch.runs.map((r) => ({
|
|
134
|
+
// Field-by-field from the principal's tenancy — org_id and source_id are
|
|
135
|
+
// NEVER carried on the wire (T3). source_id identifies the rig instance,
|
|
136
|
+
// exactly like inferences.
|
|
137
|
+
org_id: tenancy.org_id,
|
|
138
|
+
id: r.id,
|
|
139
|
+
source_id: tenancy.source_id,
|
|
140
|
+
pipeline: r.pipeline,
|
|
141
|
+
pipeline_version: r.pipeline_version,
|
|
142
|
+
environment: r.environment,
|
|
143
|
+
episode_key: r.episode_key,
|
|
144
|
+
started_at: r.started_at,
|
|
145
|
+
ended_at: r.ended_at,
|
|
146
|
+
status: r.status,
|
|
147
|
+
updated_at: now,
|
|
148
|
+
})),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (batch.steps !== undefined && batch.steps.length > 0) {
|
|
152
|
+
writes.push({
|
|
153
|
+
// A step is a FACT (one row per attempt): merge=false on the composite PK.
|
|
154
|
+
// A retry must not rewrite what already landed.
|
|
155
|
+
table: "steps",
|
|
156
|
+
onConflict: "org_id,run_id,step_key,attempt_no",
|
|
157
|
+
merge: false,
|
|
158
|
+
rows: batch.steps.map((s) => ({
|
|
159
|
+
org_id: tenancy.org_id,
|
|
160
|
+
run_id: s.run_id,
|
|
161
|
+
step_key: s.step_key,
|
|
162
|
+
attempt_no: s.attempt_no,
|
|
163
|
+
task: s.task,
|
|
164
|
+
provenance: s.provenance,
|
|
165
|
+
// A ground-truth step joins inferences(org_id, source_id, id); the
|
|
166
|
+
// source_id is the principal's, stamped here (not trusted from the wire).
|
|
167
|
+
// Attested steps carry no inference reference (span only) — null.
|
|
168
|
+
inference_source_id: s.provenance === "ground-truth" ? tenancy.source_id : null,
|
|
169
|
+
inference_id: s.inference_id,
|
|
170
|
+
span_trace_id: s.span_trace_id,
|
|
171
|
+
span_id: s.span_id,
|
|
172
|
+
started_at: s.started_at,
|
|
173
|
+
ended_at: s.ended_at,
|
|
174
|
+
failure_class: s.failure_class,
|
|
175
|
+
// spread-iff-present (the 00027 pattern): the attested envelope is
|
|
176
|
+
// written ONLY for attested steps (OTLP ingest, E3-Harvest). A
|
|
177
|
+
// ground-truth step carries no `attested`, so the column stays null and
|
|
178
|
+
// the 00038 CHECK holds. An SDK batch never sets it → byte-identical.
|
|
179
|
+
...(s.attested !== undefined ? { attested: s.attested } : {}),
|
|
180
|
+
})),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (batch.artifacts !== undefined && batch.artifacts.length > 0) {
|
|
184
|
+
writes.push({
|
|
185
|
+
table: "artifacts",
|
|
186
|
+
onConflict: "org_id,id",
|
|
187
|
+
merge: false, // an artifact metadata row is a fact; a retry must not rewrite it
|
|
188
|
+
rows: batch.artifacts.map((a) => ({
|
|
189
|
+
org_id: tenancy.org_id,
|
|
190
|
+
id: a.id,
|
|
191
|
+
run_id: a.run_id,
|
|
192
|
+
step_key: a.step_key,
|
|
193
|
+
attempt_no: a.attempt_no,
|
|
194
|
+
task: a.task,
|
|
195
|
+
name: a.name,
|
|
196
|
+
type: a.type,
|
|
197
|
+
version: a.version,
|
|
198
|
+
supersedes_artifact_id: a.supersedes_artifact_id,
|
|
199
|
+
declared_schema: a.declared_schema,
|
|
200
|
+
fingerprint_cell: a.fingerprint_cell,
|
|
201
|
+
content_ref: a.content_ref,
|
|
202
|
+
content_hash: a.content_hash,
|
|
203
|
+
content_bytes: a.content_bytes,
|
|
204
|
+
data_classification: a.data_classification,
|
|
205
|
+
expires_at: a.expires_at,
|
|
206
|
+
// spread-iff-present (00027 pattern): a batch without `scrub` (older SDK,
|
|
207
|
+
// custody off) leaves the column null rather than overwriting it.
|
|
208
|
+
...(a.scrub !== undefined ? { scrub: a.scrub } : {}),
|
|
209
|
+
})),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (batch.artifact_edges !== undefined && batch.artifact_edges.length > 0) {
|
|
213
|
+
writes.push({
|
|
214
|
+
table: "artifact_edges",
|
|
215
|
+
onConflict: "org_id,from_artifact_id,to_artifact_id,kind",
|
|
216
|
+
merge: false,
|
|
217
|
+
rows: batch.artifact_edges.map((e) => ({
|
|
218
|
+
org_id: tenancy.org_id,
|
|
219
|
+
from_artifact_id: e.from_artifact_id,
|
|
220
|
+
to_artifact_id: e.to_artifact_id,
|
|
221
|
+
kind: e.kind,
|
|
222
|
+
})),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (batch.artifact_evaluations !== undefined && batch.artifact_evaluations.length > 0) {
|
|
226
|
+
writes.push({
|
|
227
|
+
table: "artifact_evaluations",
|
|
228
|
+
onConflict: "org_id,id",
|
|
229
|
+
merge: false,
|
|
230
|
+
rows: batch.artifact_evaluations.map((v) => ({
|
|
231
|
+
org_id: tenancy.org_id,
|
|
232
|
+
id: v.id,
|
|
233
|
+
artifact_id: v.artifact_id,
|
|
234
|
+
// Subject-one-of (00051): a run-subject row carries run_id, artifact_id
|
|
235
|
+
// null; the CHECK rejects a row that sets both or neither.
|
|
236
|
+
run_id: v.run_id ?? null,
|
|
237
|
+
evaluator: v.evaluator,
|
|
238
|
+
evaluator_kind: v.evaluator_kind,
|
|
239
|
+
score: v.score,
|
|
240
|
+
passed: v.passed,
|
|
241
|
+
label: v.label,
|
|
242
|
+
explanation: v.explanation,
|
|
243
|
+
created_by: v.created_by,
|
|
244
|
+
})),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (batch.eval_cases !== undefined && batch.eval_cases.length > 0) {
|
|
248
|
+
writes.push({
|
|
249
|
+
// An eval case is created once (via promote); a retry must not rewrite it.
|
|
250
|
+
// Edits/deletes are a server-side owner action, not this stream. merge=false
|
|
251
|
+
// on the PK — idempotent by doing nothing (S5).
|
|
252
|
+
table: "eval_cases",
|
|
253
|
+
onConflict: "org_id,id",
|
|
254
|
+
merge: false,
|
|
255
|
+
rows: batch.eval_cases.map((c) => ({
|
|
256
|
+
org_id: tenancy.org_id,
|
|
257
|
+
id: c.id,
|
|
258
|
+
task: c.task,
|
|
259
|
+
source_artifact_id: c.source_artifact_id,
|
|
260
|
+
corrected_artifact_id: c.corrected_artifact_id,
|
|
261
|
+
origin: c.origin,
|
|
262
|
+
note: c.note,
|
|
263
|
+
created_by: c.created_by,
|
|
67
264
|
})),
|
|
68
265
|
});
|
|
69
266
|
}
|
|
@@ -80,6 +277,9 @@ function stampBatch(batch, tenancy) {
|
|
|
80
277
|
dimensions: batch.manifest.dimensions,
|
|
81
278
|
contribution: batch.manifest.contribution,
|
|
82
279
|
serveability: batch.manifest.serveability,
|
|
280
|
+
// [] when the load was clean — a merge upsert then clears any stale
|
|
281
|
+
// failure a prior broken deploy left on the row (follow-up #2).
|
|
282
|
+
load_errors: batch.manifest.load_errors ?? [],
|
|
83
283
|
updated_at: now,
|
|
84
284
|
},
|
|
85
285
|
],
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load-error console reporting — follow-up #2.
|
|
3
|
+
*
|
|
4
|
+
* When a route bundle fails to load, tell the console WHY. `loadRoutes` throws
|
|
5
|
+
* before the exporter loop exists, so the run-loop path never gets a chance to
|
|
6
|
+
* mirror the failure. This sends a one-shot manifest batch carrying
|
|
7
|
+
* `describeConfigFailure(error)` onto `rig_manifests.load_errors`, which drives
|
|
8
|
+
* /setup's "Define your first route" step to `failed` with what we looked for
|
|
9
|
+
* and what we found.
|
|
10
|
+
*
|
|
11
|
+
* Fire-and-forget, and best-effort by design: `createRig` is synchronous and
|
|
12
|
+
* re-throws (the rig genuinely cannot run), and telemetry must never change the
|
|
13
|
+
* error the caller sees. KNOWN LIMITATION: this only reaches the console once
|
|
14
|
+
* the app runs with an export configured (MODELRIG_API_KEY / direct creds); a
|
|
15
|
+
* first-timer who hasn't connected yet still gets the full diagnosis at their
|
|
16
|
+
* terminal via `renderConfigErrorForTerminal`.
|
|
17
|
+
*
|
|
18
|
+
* Lives here rather than in index.ts to keep that file under the LOC cap (P1) —
|
|
19
|
+
* the same relocation `buildTelemetrySink` made to `sinks.ts`.
|
|
20
|
+
*/
|
|
21
|
+
import type { RigConfig } from "../config";
|
|
22
|
+
import { RouteConfigError } from "../routes/loader";
|
|
23
|
+
export declare function reportLoadError(config: RigConfig, error: RouteConfigError): void;
|
|
24
|
+
//# sourceMappingURL=load-error-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-error-report.d.ts","sourceRoot":"","sources":["../../src/telemetry/load-error-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOpD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAoBhF"}
|