modelrig 0.9.0 → 0.11.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 +227 -0
- package/README.md +51 -27
- 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 +20 -0
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +207 -171
- package/dist/artifacts/index.d.ts +3 -1
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +8 -1
- 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 +14 -1
- package/dist/bakeoff/quality.d.ts.map +1 -1
- package/dist/bakeoff/quality.js +10 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +4 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -0
- package/dist/doctor-cli.d.ts +7 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +68 -0
- package/dist/doctor-preflight.d.ts +64 -0
- package/dist/doctor-preflight.d.ts.map +1 -0
- package/dist/doctor-preflight.js +167 -0
- package/dist/feedback/coverage.d.ts.map +1 -1
- package/dist/feedback/coverage.js +9 -2
- package/dist/feedback/grade.d.ts +8 -1
- package/dist/feedback/grade.d.ts.map +1 -1
- package/dist/feedback/grade.js +4 -0
- package/dist/gateway/http-protocol.d.ts +19 -0
- package/dist/gateway/http-protocol.d.ts.map +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 +31 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +71 -8
- 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/registry/cache-policy.d.ts.map +1 -1
- package/dist/registry/cache-policy.js +22 -0
- package/dist/registry/pricing-shape.d.ts +38 -8
- package/dist/registry/pricing-shape.d.ts.map +1 -1
- package/dist/registry/pricing-shape.js +40 -12
- 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/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 +27 -54
- 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 +19 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -1
- package/dist/routes/resolved-bundle.js +24 -0
- package/dist/routes/screen-loader.d.ts +1 -1
- package/dist/routes/screen-loader.d.ts.map +1 -1
- package/dist/routes/screen-loader.js +8 -1
- package/dist/run/accept.d.ts +3 -0
- package/dist/run/accept.d.ts.map +1 -1
- package/dist/run/accept.js +1 -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 +25 -3
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +26 -4
- 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 +96 -0
- package/dist/run/raw-finalize.d.ts.map +1 -0
- package/dist/run/raw-finalize.js +283 -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 +49 -0
- package/dist/run/raw-search-cost.d.ts.map +1 -0
- package/dist/run/raw-search-cost.js +79 -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 +8 -0
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +26 -12
- package/dist/run/record-call.d.ts +104 -0
- package/dist/run/record-call.d.ts.map +1 -0
- package/dist/run/record-call.js +277 -0
- 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 +9 -4
- package/dist/run/run.d.ts +30 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +75 -148
- 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/settings/grading-guide.d.ts +27 -1
- package/dist/settings/grading-guide.d.ts.map +1 -1
- package/dist/status.d.ts +6 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +4 -1
- package/dist/telemetry/artifact-store.d.ts.map +1 -1
- package/dist/telemetry/artifact-store.js +11 -0
- package/dist/telemetry/attempt-meta.d.ts +66 -1
- package/dist/telemetry/attempt-meta.d.ts.map +1 -1
- package/dist/telemetry/attempt-meta.js +27 -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/grade-mappers.d.ts +5 -2
- package/dist/telemetry/grade-mappers.d.ts.map +1 -1
- package/dist/telemetry/grade-mappers.js +8 -2
- package/dist/telemetry/grades-sql.d.ts +4 -1
- package/dist/telemetry/grades-sql.d.ts.map +1 -1
- package/dist/telemetry/grades-sql.js +26 -3
- package/dist/telemetry/ingest-protocol.d.ts +26 -2
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +32 -29
- package/dist/telemetry/lanes.d.ts +31 -0
- package/dist/telemetry/lanes.d.ts.map +1 -0
- package/dist/telemetry/lanes.js +41 -0
- package/dist/telemetry/org-identity.d.ts +47 -0
- package/dist/telemetry/org-identity.d.ts.map +1 -0
- package/dist/telemetry/org-identity.js +100 -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 +13 -0
- package/dist/tenancy/api-key-format.d.ts +16 -1
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +17 -0
- package/dist/types/provider.d.ts +20 -3
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +1 -0
- package/dist/types/route.d.ts +76 -0
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +30 -2
- package/dist/types/telemetry.d.ts.map +1 -1
- package/docs/agent-skill/SKILL.md +75 -5
- package/docs/instrumentation.md +98 -36
- package/docs/llms.txt +96 -16
- package/docs/managed-serving.md +150 -0
- package/docs/mcp-oracle.md +75 -2
- package/docs/migration-playbook.md +5 -4
- package/docs/quickstart.md +169 -83
- package/package.json +3 -2
- package/registry/registry.json +82 -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
|
@@ -36,17 +36,18 @@ CREATE TABLE IF NOT EXISTS grades (
|
|
|
36
36
|
grader TEXT,
|
|
37
37
|
source TEXT,
|
|
38
38
|
org_id TEXT,
|
|
39
|
-
created_by TEXT
|
|
39
|
+
created_by TEXT,
|
|
40
|
+
criteria TEXT
|
|
40
41
|
);
|
|
41
42
|
CREATE INDEX IF NOT EXISTS idx_grades_subject ON grades (subject_kind, subject_id);
|
|
42
43
|
`;
|
|
43
44
|
const INSERT_GRADE_SQL = `
|
|
44
45
|
INSERT OR IGNORE INTO grades (
|
|
45
46
|
id, ts, subject_kind, subject_id, score, scale_max, scale_label, comment,
|
|
46
|
-
kind, grader, source, org_id, created_by
|
|
47
|
+
kind, grader, source, org_id, created_by, criteria
|
|
47
48
|
) VALUES (
|
|
48
49
|
@id, @ts, @subject_kind, @subject_id, @score, @scale_max, @scale_label, @comment,
|
|
49
|
-
@kind, @grader, @source, @org_id, @created_by
|
|
50
|
+
@kind, @grader, @source, @org_id, @created_by, @criteria
|
|
50
51
|
)`;
|
|
51
52
|
/** Prepare the grade insert statement against an open handle. INSERT OR IGNORE:
|
|
52
53
|
* a grade id is unique, and a re-inserted id (e.g. the backfill racing a live
|
|
@@ -70,6 +71,10 @@ function gradeBindParams(row) {
|
|
|
70
71
|
source: row.source,
|
|
71
72
|
org_id: row.orgId,
|
|
72
73
|
created_by: row.createdBy,
|
|
74
|
+
// F4: the per-criterion breakdown is stored as a JSON string (or null for a
|
|
75
|
+
// single-score grade). One column, no sidecar table locally — the server is
|
|
76
|
+
// where it fans out to `grade_criteria`.
|
|
77
|
+
criteria: row.criteria !== undefined ? JSON.stringify(row.criteria) : null,
|
|
73
78
|
};
|
|
74
79
|
}
|
|
75
80
|
/** Read one SQLite grade row back into a GradeRow. */
|
|
@@ -88,8 +93,26 @@ function toGradeRow(r) {
|
|
|
88
93
|
source: r.source,
|
|
89
94
|
orgId: r.org_id ?? null,
|
|
90
95
|
createdBy: r.created_by ?? null,
|
|
96
|
+
// F4: parse the JSON `criteria` column back. Null (pre-F4 or single-score) ⇒
|
|
97
|
+
// the field is ABSENT on the GradeRow (spread-iff), so the wire stays
|
|
98
|
+
// byte-identical for a plain grade. A malformed value degrades to absent
|
|
99
|
+
// rather than throwing on the export read.
|
|
100
|
+
...parseCriteriaColumn(r.criteria),
|
|
91
101
|
};
|
|
92
102
|
}
|
|
103
|
+
/** Narrow the stored JSON `criteria` column to a spread-iff-present GradeRow
|
|
104
|
+
* fragment. Malformed / null ⇒ `{}` (field absent). Never throws on the read. */
|
|
105
|
+
function parseCriteriaColumn(raw) {
|
|
106
|
+
if (raw === null)
|
|
107
|
+
return {};
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(raw);
|
|
110
|
+
return Array.isArray(parsed) ? { criteria: parsed } : {};
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
93
116
|
/** Backfill `grades` from the local `feedback` table, if it exists (grade
|
|
94
117
|
* primitive, GP-1). Same mapping as migration 00070's feedback→grades leg.
|
|
95
118
|
* Idempotent (INSERT OR IGNORE keyed on the source row id). Runs inside the
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* holds a credential that can write any row in the database.
|
|
32
32
|
*/
|
|
33
33
|
import type { FailureClass } from "../types/failures";
|
|
34
|
+
import type { EvalCaseOrigin } from "../types/telemetry";
|
|
34
35
|
import type { ResolvedRouteBundle } from "../routes/resolved-bundle";
|
|
35
36
|
export { foreignOrgGrades } from "./grade-mappers";
|
|
36
37
|
/** The path the api sink posts to. Spelled once. */
|
|
@@ -129,6 +130,20 @@ export interface WireGrade {
|
|
|
129
130
|
readonly ts: string | null;
|
|
130
131
|
/** The grade's OWN org, when it differs from the exporter's (feedback doctrine). */
|
|
131
132
|
readonly org_id?: string;
|
|
133
|
+
/** OPTIONAL per-criterion breakdown (call-qa F4). Carried on the wire so a
|
|
134
|
+
* client-recorded HUMAN scorecard reaches the server, which fans it out to
|
|
135
|
+
* `grade_criteria` (kind=human) after the parent grades row lands. NOT written
|
|
136
|
+
* to `public.grades` (no column there — `gradeToRow` drops it). Absent ⇒ a
|
|
137
|
+
* single-score grade. `turn_id` is optional on each evidence citation. */
|
|
138
|
+
readonly criteria?: readonly {
|
|
139
|
+
readonly id: string;
|
|
140
|
+
readonly score: number;
|
|
141
|
+
readonly evidence?: readonly {
|
|
142
|
+
readonly quote: string;
|
|
143
|
+
readonly turn_id?: number;
|
|
144
|
+
}[];
|
|
145
|
+
readonly comment?: string;
|
|
146
|
+
}[];
|
|
132
147
|
}
|
|
133
148
|
export interface WireEnvelope {
|
|
134
149
|
readonly envelope_key: string;
|
|
@@ -244,7 +259,7 @@ export interface WireEvalCase {
|
|
|
244
259
|
readonly task: string;
|
|
245
260
|
readonly source_artifact_id: string;
|
|
246
261
|
readonly corrected_artifact_id: string | null;
|
|
247
|
-
readonly origin:
|
|
262
|
+
readonly origin: EvalCaseOrigin;
|
|
248
263
|
readonly note: string | null;
|
|
249
264
|
readonly created_by: string | null;
|
|
250
265
|
}
|
|
@@ -305,7 +320,16 @@ export interface TableWrite {
|
|
|
305
320
|
* telemetry row. If you are about to add a table to the export, add it here
|
|
306
321
|
* and both modes gain it at once — which is the point.
|
|
307
322
|
*/
|
|
308
|
-
|
|
323
|
+
/** How `stampBatch` treats route bundles. `declaredBundles` (the HOSTED ingest,
|
|
324
|
+
* RV-1): a bundle that arrived over `/v1/ingest` is stored as route CONFIG with
|
|
325
|
+
* `synced_at = null` — readable for pins/effective/bake-offs, but never picked
|
|
326
|
+
* by the hosted gateway, which serves only `synced_at`-stamped bundles (written
|
|
327
|
+
* by a trusted sync path). An `ingest`-scoped key must not decide what the
|
|
328
|
+
* gateway serves. Absent ⇒ the direct-mode behaviour (`synced_at = now`). */
|
|
329
|
+
export interface StampOptions {
|
|
330
|
+
readonly declaredBundles?: boolean;
|
|
331
|
+
}
|
|
332
|
+
export declare function stampBatch(batch: IngestBatch, tenancy: Tenancy, opts?: StampOptions): TableWrite[];
|
|
309
333
|
/** What `/v1/ingest` answers. Counts only — a per-row error list on a
|
|
310
334
|
* fire-and-forget telemetry path is a payload nobody reads and a leak surface
|
|
311
335
|
* nobody audits. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-protocol.d.ts","sourceRoot":"","sources":["../../src/telemetry/ingest-protocol.ts"],"names":[],"mappings":"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
|
|
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;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAIrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,oDAAoD;AACpD,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC;;;;6DAI6D;AAC7D,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC;;+EAE+E;AAC/E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAE5D;kBACkB;AAClB,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;;;+EAG2E;IAC3E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C;;;2EAGuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;mEAK+D;IAC/D,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;oDAMgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,YAAY,EAAE,WAAW,GAAG,KAAK,GAAG,UAAU,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;8EAI0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS;QAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,EAAE,CAAC;CACL;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1F,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;2EAIuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IACtC;sBACkB;IAClB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;oDAEoD;AACpD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAClE;;kFAE8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;oEAKoE;AACpE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,cAAc,GAAG,UAAU,CAAC;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;oEAEoE;AACpE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;yEAGqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC;CAC5C;AAED;;;;kBAIkB;AAClB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1C;;;;wBAIoB;IACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3C;AAED;gDACgD;AAChD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB;;8CAE0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/C;2CACuC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC;gFAC4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACtD;oFACgF;IAChF,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC9C,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;mEACmE;AACnE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAClD,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;2EACuE;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH;;;;;6EAK6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,YAAiB,GAAG,UAAU,EAAE,CA+RtG;AAED;;oBAEoB;AACpB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD;qCACiC;IACjC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD"}
|
|
@@ -52,14 +52,7 @@ exports.INGEST_PROTOCOL_VERSION = 2;
|
|
|
52
52
|
exports.INGEST_PROTOCOL_VERSION_V1 = 1;
|
|
53
53
|
/** Default ingest host — telemetry-ingestion-boundary.md §2.1. */
|
|
54
54
|
exports.DEFAULT_INGEST_URL = "https://api.modelrig.ai";
|
|
55
|
-
|
|
56
|
-
* Turn a batch plus a tenant into the writes it becomes.
|
|
57
|
-
*
|
|
58
|
-
* THE conformance seam. Both transports call this; nothing else builds a
|
|
59
|
-
* telemetry row. If you are about to add a table to the export, add it here
|
|
60
|
-
* and both modes gain it at once — which is the point.
|
|
61
|
-
*/
|
|
62
|
-
function stampBatch(batch, tenancy) {
|
|
55
|
+
function stampBatch(batch, tenancy, opts = {}) {
|
|
63
56
|
const writes = [];
|
|
64
57
|
const now = new Date().toISOString();
|
|
65
58
|
if (batch.routes !== undefined && batch.routes.length > 0) {
|
|
@@ -103,28 +96,38 @@ function stampBatch(batch, tenancy) {
|
|
|
103
96
|
merge: true,
|
|
104
97
|
rows: taskRows,
|
|
105
98
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// `updated_at`, the row's metadata timestamp.
|
|
123
|
-
...(r.bundle !== undefined
|
|
124
|
-
? { bundle: r.bundle, bundle_sha: r.bundle_sha ?? null, synced_at: now }
|
|
125
|
-
: {}),
|
|
126
|
-
})),
|
|
99
|
+
const routeRow = (r) => ({
|
|
100
|
+
org_id: tenancy.org_id,
|
|
101
|
+
route: r.route,
|
|
102
|
+
version: r.version,
|
|
103
|
+
candidates: r.candidates,
|
|
104
|
+
capture: r.capture,
|
|
105
|
+
updated_at: now,
|
|
106
|
+
// Phase D (spec §13): the resolved bundle + its hash + the sync stamp.
|
|
107
|
+
// Written only when the route carries a bundle, so an older SDK's
|
|
108
|
+
// metadata-only mirror leaves any existing bundle intact (a merge
|
|
109
|
+
// upsert touches only the columns present in the row). `synced_at` is
|
|
110
|
+
// the BUNDLE's timestamp — stamped iff a bundle synced through a trusted
|
|
111
|
+
// path — distinct from `updated_at`, the row's metadata timestamp.
|
|
112
|
+
...(r.bundle !== undefined
|
|
113
|
+
? { bundle: r.bundle, bundle_sha: r.bundle_sha ?? null, synced_at: opts.declaredBundles === true ? null : now }
|
|
114
|
+
: {}),
|
|
127
115
|
});
|
|
116
|
+
// TWO writes, split by bundle presence: a PostgREST bulk insert requires
|
|
117
|
+
// every row to carry the SAME keys (PGRST102), so one route whose bundle was
|
|
118
|
+
// dropped must not fail — or null out — its neighbours' bundles.
|
|
119
|
+
const withBundle = batch.routes.filter((r) => r.bundle !== undefined);
|
|
120
|
+
const withoutBundle = batch.routes.filter((r) => r.bundle === undefined);
|
|
121
|
+
for (const group of [withBundle, withoutBundle]) {
|
|
122
|
+
if (group.length === 0)
|
|
123
|
+
continue;
|
|
124
|
+
writes.push({
|
|
125
|
+
table: "routes",
|
|
126
|
+
onConflict: "org_id,route,version",
|
|
127
|
+
merge: true,
|
|
128
|
+
rows: group.map(routeRow),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
128
131
|
}
|
|
129
132
|
if (batch.runs !== undefined && batch.runs.length > 0) {
|
|
130
133
|
writes.push({
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE lane classifier every read surface uses (OBS-1). A telemetry row's
|
|
3
|
+
* `tags.lane` names how ModelRig came to hold it:
|
|
4
|
+
* • absent / anything else — a ROUTED call (it walked a route's ladder; its
|
|
5
|
+
* quality signal is schema conformance).
|
|
6
|
+
* • `"raw"` — a raw-lane BYOK passthrough ModelRig dispatched but never
|
|
7
|
+
* validated (`rig.runRaw`).
|
|
8
|
+
* • `"external"` — a RECORDED call: the customer's own code made it and
|
|
9
|
+
* reported it through `rig.recordCall`; ModelRig neither dispatched nor
|
|
10
|
+
* validated it.
|
|
11
|
+
* Raw and external rows are never routed: they never enter ladder or
|
|
12
|
+
* conformance math, and their quality signal is `rig.grade`.
|
|
13
|
+
*
|
|
14
|
+
* Pure, dependency-free (the console imports it through `@modelrig-core`).
|
|
15
|
+
* The billing path (`modelrig-server` usage-aggregation `laneOf`) deliberately
|
|
16
|
+
* keeps its own literal so a money decision imports nothing from here.
|
|
17
|
+
*/
|
|
18
|
+
export declare const RAW_LANE = "raw";
|
|
19
|
+
export declare const EXTERNAL_LANE = "external";
|
|
20
|
+
/** The call lane a read surface renders. */
|
|
21
|
+
export type CallLane = "routes" | "raw" | "external";
|
|
22
|
+
/** True when a row with this `tags.lane` walked a route (enters ladder and
|
|
23
|
+
* conformance math). False for `raw` and `external`. */
|
|
24
|
+
export declare function isRoutedLane(lane: unknown): boolean;
|
|
25
|
+
/** Three-way classification of a `tags.lane` value. */
|
|
26
|
+
export declare function callLaneOf(lane: unknown): CallLane;
|
|
27
|
+
/** Console badge copy for a recorded (external) call. User-facing copy says
|
|
28
|
+
* "recorded call", never "lane". */
|
|
29
|
+
export declare const RECORDED_BADGE = "recorded \u00B7 unverified";
|
|
30
|
+
export declare const RECORDED_TOOLTIP = "Your code made this call; ModelRig recorded what you reported (tokens, tier, latency). It did not dispatch or validate it.";
|
|
31
|
+
//# sourceMappingURL=lanes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lanes.d.ts","sourceRoot":"","sources":["../../src/telemetry/lanes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,aAAa,aAAa,CAAC;AAExC,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,CAAC;AAErD;wDACwD;AACxD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEnD;AAED,uDAAuD;AACvD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAIlD;AAED;oCACoC;AACpC,eAAO,MAAM,cAAc,+BAA0B,CAAC;AACtD,eAAO,MAAM,gBAAgB,+HACiG,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The ONE lane classifier every read surface uses (OBS-1). A telemetry row's
|
|
4
|
+
* `tags.lane` names how ModelRig came to hold it:
|
|
5
|
+
* • absent / anything else — a ROUTED call (it walked a route's ladder; its
|
|
6
|
+
* quality signal is schema conformance).
|
|
7
|
+
* • `"raw"` — a raw-lane BYOK passthrough ModelRig dispatched but never
|
|
8
|
+
* validated (`rig.runRaw`).
|
|
9
|
+
* • `"external"` — a RECORDED call: the customer's own code made it and
|
|
10
|
+
* reported it through `rig.recordCall`; ModelRig neither dispatched nor
|
|
11
|
+
* validated it.
|
|
12
|
+
* Raw and external rows are never routed: they never enter ladder or
|
|
13
|
+
* conformance math, and their quality signal is `rig.grade`.
|
|
14
|
+
*
|
|
15
|
+
* Pure, dependency-free (the console imports it through `@modelrig-core`).
|
|
16
|
+
* The billing path (`modelrig-server` usage-aggregation `laneOf`) deliberately
|
|
17
|
+
* keeps its own literal so a money decision imports nothing from here.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.RECORDED_TOOLTIP = exports.RECORDED_BADGE = exports.EXTERNAL_LANE = exports.RAW_LANE = void 0;
|
|
21
|
+
exports.isRoutedLane = isRoutedLane;
|
|
22
|
+
exports.callLaneOf = callLaneOf;
|
|
23
|
+
exports.RAW_LANE = "raw";
|
|
24
|
+
exports.EXTERNAL_LANE = "external";
|
|
25
|
+
/** True when a row with this `tags.lane` walked a route (enters ladder and
|
|
26
|
+
* conformance math). False for `raw` and `external`. */
|
|
27
|
+
function isRoutedLane(lane) {
|
|
28
|
+
return lane !== exports.RAW_LANE && lane !== exports.EXTERNAL_LANE;
|
|
29
|
+
}
|
|
30
|
+
/** Three-way classification of a `tags.lane` value. */
|
|
31
|
+
function callLaneOf(lane) {
|
|
32
|
+
if (lane === exports.RAW_LANE)
|
|
33
|
+
return "raw";
|
|
34
|
+
if (lane === exports.EXTERNAL_LANE)
|
|
35
|
+
return "external";
|
|
36
|
+
return "routes";
|
|
37
|
+
}
|
|
38
|
+
/** Console badge copy for a recorded (external) call. User-facing copy says
|
|
39
|
+
* "recorded call", never "lane". */
|
|
40
|
+
exports.RECORDED_BADGE = "recorded · unverified";
|
|
41
|
+
exports.RECORDED_TOOLTIP = "Your code made this call; ModelRig recorded what you reported (tokens, tier, latency). It did not dispatch or validate it.";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first-flush org line + the `expectOrg` mismatch signal (REL-1, ruling M5).
|
|
3
|
+
*
|
|
4
|
+
* A VALID key minted in the WRONG org is the failure the AUTH FAILED latch in
|
|
5
|
+
* sinks.ts cannot see: every POST is a 200, and the runs land in someone else's
|
|
6
|
+
* console. (Six weeks of InferWealth pipeline telemetry went to Nunexa this
|
|
7
|
+
* way.) So on the first successful flush in each process the api sink asks
|
|
8
|
+
* `GET /v1/whoami` once — through the same `whoamiPreflight` helper that
|
|
9
|
+
* `modelrig doctor` uses — and logs which org it is exporting to:
|
|
10
|
+
*
|
|
11
|
+
* [modelrig] exporting to org «InferWealth» (inferwealth) as key «InferWealth2» …ab12
|
|
12
|
+
*
|
|
13
|
+
* With `createRig({ expectOrg: "<slug>" })` a different resolved slug logs
|
|
14
|
+
* `ORG MISMATCH` loudly on EVERY successful flush (ruling M5), because nobody
|
|
15
|
+
* reads boot logs. It is a code option, not an env var (P15).
|
|
16
|
+
*
|
|
17
|
+
* Contract: non-blocking (never awaited by the sink), once per process per
|
|
18
|
+
* key, never throws, never drops or delays telemetry. A failed whoami is
|
|
19
|
+
* SILENT: a 401 already has its own loud line, and a network blip must not
|
|
20
|
+
* become noise.
|
|
21
|
+
*/
|
|
22
|
+
import { type PreflightResult } from "../doctor-preflight";
|
|
23
|
+
/** The whoami call is aborted after this long, so it can never hold a
|
|
24
|
+
* process open (AbortSignal.timeout's timer is unref'd by Node). */
|
|
25
|
+
export declare const WHOAMI_TIMEOUT_MS = 5000;
|
|
26
|
+
/** TESTS ONLY — forget every key, so "once per process" cases are independent. */
|
|
27
|
+
export declare function __resetOrgIdentityForTest(): void;
|
|
28
|
+
export interface OrgIdentityInput {
|
|
29
|
+
readonly ingestUrl: string;
|
|
30
|
+
readonly apiKey: string;
|
|
31
|
+
readonly expectOrg?: string;
|
|
32
|
+
readonly fetchFn: typeof fetch;
|
|
33
|
+
/** Override WHOAMI_TIMEOUT_MS (tests). */
|
|
34
|
+
readonly timeoutMs?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Build the one-line org banner from a successful whoami. Only an ok result
|
|
37
|
+
* reaches here, and an ok result always NAMES its org (QA N14: a 2xx without
|
|
38
|
+
* one is not ok), so `orgName` is required. Never prints a placeholder glyph:
|
|
39
|
+
* the slug is shown only when the server sent one that differs from the name. */
|
|
40
|
+
export declare function formatOrgLine(orgName: string, result: PreflightResult, apiKey: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Record one successful flush. Returns immediately; the whoami (first flush
|
|
43
|
+
* only) runs in the background. Exposed as a promise-returning helper ONLY so
|
|
44
|
+
* tests can await the background work — the sink calls it with `void`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function noteSuccessfulFlush(input: OrgIdentityInput): Promise<void>;
|
|
47
|
+
//# sourceMappingURL=org-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-identity.d.ts","sourceRoot":"","sources":["../../src/telemetry/org-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGjG;oEACoE;AACpE,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAYtC,kFAAkF;AAClF,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC;IAC/B,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;iFAGiF;AACjF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9F;AAgBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B1E"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WHOAMI_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.__resetOrgIdentityForTest = __resetOrgIdentityForTest;
|
|
5
|
+
exports.formatOrgLine = formatOrgLine;
|
|
6
|
+
exports.noteSuccessfulFlush = noteSuccessfulFlush;
|
|
7
|
+
/**
|
|
8
|
+
* The first-flush org line + the `expectOrg` mismatch signal (REL-1, ruling M5).
|
|
9
|
+
*
|
|
10
|
+
* A VALID key minted in the WRONG org is the failure the AUTH FAILED latch in
|
|
11
|
+
* sinks.ts cannot see: every POST is a 200, and the runs land in someone else's
|
|
12
|
+
* console. (Six weeks of InferWealth pipeline telemetry went to Nunexa this
|
|
13
|
+
* way.) So on the first successful flush in each process the api sink asks
|
|
14
|
+
* `GET /v1/whoami` once — through the same `whoamiPreflight` helper that
|
|
15
|
+
* `modelrig doctor` uses — and logs which org it is exporting to:
|
|
16
|
+
*
|
|
17
|
+
* [modelrig] exporting to org «InferWealth» (inferwealth) as key «InferWealth2» …ab12
|
|
18
|
+
*
|
|
19
|
+
* With `createRig({ expectOrg: "<slug>" })` a different resolved slug logs
|
|
20
|
+
* `ORG MISMATCH` loudly on EVERY successful flush (ruling M5), because nobody
|
|
21
|
+
* reads boot logs. It is a code option, not an env var (P15).
|
|
22
|
+
*
|
|
23
|
+
* Contract: non-blocking (never awaited by the sink), once per process per
|
|
24
|
+
* key, never throws, never drops or delays telemetry. A failed whoami is
|
|
25
|
+
* SILENT: a 401 already has its own loud line, and a network blip must not
|
|
26
|
+
* become noise.
|
|
27
|
+
*/
|
|
28
|
+
const doctor_preflight_1 = require("../doctor-preflight");
|
|
29
|
+
const api_key_format_1 = require("../tenancy/api-key-format");
|
|
30
|
+
/** The whoami call is aborted after this long, so it can never hold a
|
|
31
|
+
* process open (AbortSignal.timeout's timer is unref'd by Node). */
|
|
32
|
+
exports.WHOAMI_TIMEOUT_MS = 5000;
|
|
33
|
+
/** Keyed by ingest origin + key, so two rigs sharing a key share one whoami. */
|
|
34
|
+
const states = new Map();
|
|
35
|
+
/** TESTS ONLY — forget every key, so "once per process" cases are independent. */
|
|
36
|
+
function __resetOrgIdentityForTest() {
|
|
37
|
+
states.clear();
|
|
38
|
+
}
|
|
39
|
+
/** Build the one-line org banner from a successful whoami. Only an ok result
|
|
40
|
+
* reaches here, and an ok result always NAMES its org (QA N14: a 2xx without
|
|
41
|
+
* one is not ok), so `orgName` is required. Never prints a placeholder glyph:
|
|
42
|
+
* the slug is shown only when the server sent one that differs from the name. */
|
|
43
|
+
function formatOrgLine(orgName, result, apiKey) {
|
|
44
|
+
const slugRaw = result.whoami?.org?.slug;
|
|
45
|
+
const slug = typeof slugRaw === "string" && slugRaw !== "" && slugRaw !== orgName ? ` (${slugRaw})` : "";
|
|
46
|
+
const keyName = result.whoami?.key?.name;
|
|
47
|
+
const keyLabel = typeof keyName === "string" && keyName !== "" ? `«${keyName}» ` : "";
|
|
48
|
+
return `[modelrig] exporting to org «${orgName}»${slug} as key ${keyLabel}${(0, api_key_format_1.redactApiKey)(apiKey)}`;
|
|
49
|
+
}
|
|
50
|
+
function mismatchLine(actual, expectOrg) {
|
|
51
|
+
return (`[modelrig] ORG MISMATCH: key resolves to «${actual}», expectOrg is «${expectOrg}» — ` +
|
|
52
|
+
`telemetry is landing in «${actual}»`);
|
|
53
|
+
}
|
|
54
|
+
function warnIfMismatch(result, expectOrg) {
|
|
55
|
+
const expected = expectOrg?.trim();
|
|
56
|
+
if (expected === undefined || expected === "")
|
|
57
|
+
return;
|
|
58
|
+
const actual = (0, doctor_preflight_1.expectedOrgMismatch)(result, expected);
|
|
59
|
+
if (actual !== null)
|
|
60
|
+
console.warn(mismatchLine(actual, expected));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Record one successful flush. Returns immediately; the whoami (first flush
|
|
64
|
+
* only) runs in the background. Exposed as a promise-returning helper ONLY so
|
|
65
|
+
* tests can await the background work — the sink calls it with `void`.
|
|
66
|
+
*/
|
|
67
|
+
function noteSuccessfulFlush(input) {
|
|
68
|
+
let origin;
|
|
69
|
+
try {
|
|
70
|
+
origin = new URL(input.ingestUrl).origin;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
}
|
|
75
|
+
const id = `${origin}|${input.apiKey}`;
|
|
76
|
+
let state = states.get(id);
|
|
77
|
+
if (state === undefined) {
|
|
78
|
+
state = { flushes: 0, resolved: null };
|
|
79
|
+
states.set(id, state);
|
|
80
|
+
}
|
|
81
|
+
state.flushes += 1;
|
|
82
|
+
const s = state;
|
|
83
|
+
if (s.flushes === 1) {
|
|
84
|
+
return (0, doctor_preflight_1.whoamiPreflight)(input.ingestUrl, input.apiKey, input.fetchFn, AbortSignal.timeout(input.timeoutMs ?? exports.WHOAMI_TIMEOUT_MS))
|
|
85
|
+
.then((result) => {
|
|
86
|
+
if (!result.ok || result.orgName === undefined)
|
|
87
|
+
return; // silent: a 401 has its own loud line
|
|
88
|
+
s.resolved = result;
|
|
89
|
+
console.log(formatOrgLine(result.orgName, result, input.apiKey));
|
|
90
|
+
warnIfMismatch(result, input.expectOrg);
|
|
91
|
+
})
|
|
92
|
+
.catch(() => {
|
|
93
|
+
// whoamiPreflight never throws, and logging must never break the sink.
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// M5: loud on EVERY flush once the org is known (flush 1 warns when whoami lands).
|
|
97
|
+
if (s.resolved !== null)
|
|
98
|
+
warnIfMismatch(s.resolved, input.expectOrg);
|
|
99
|
+
return Promise.resolve();
|
|
100
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RV-1 declare-on-startup — a rig with routes AND a control plane tells the
|
|
3
|
+
* control plane which routes it serves the moment it is created, so a route is
|
|
4
|
+
* visible (console, MCP `get_call_config`, `GET /v1/routes/:route/call-config
|
|
5
|
+
* ?include=effective`) BEFORE its first call.
|
|
6
|
+
*
|
|
7
|
+
* ── WHY A SEPARATE ONE-SHOT, WHEN THE EXPORTER ALREADY MIRRORS ROUTES ─────
|
|
8
|
+
* The exporter folds the routes mirror into its FIRST flush (one interval —
|
|
9
|
+
* 10s — after start). A short-lived process (a CLI, a cron, a lazily-built
|
|
10
|
+
* pipeline rig) that exits before that tick without `close()` never mirrors, and
|
|
11
|
+
* a long-lived one is invisible for the first interval. This sends the same
|
|
12
|
+
* metadata once, immediately. The exporter's header stays as the at-least-once
|
|
13
|
+
* retry path: the routes upsert is a merge on (org_id, route, version), so the
|
|
14
|
+
* duplicate is harmless.
|
|
15
|
+
*
|
|
16
|
+
* ── WHAT IT CARRIES (and does not) ────────────────────────────────────────
|
|
17
|
+
* route, version, candidates (provider/model), capture flag, AND the declared
|
|
18
|
+
* resolved bundle + its `bundle_sha` — the same payload the exporter's
|
|
19
|
+
* first-flush mirror has always carried (Matt's RV-1 ruling 1, 2026-10-10). The
|
|
20
|
+
* bundle is ROUTE CONFIGURATION (the authored prompt TEMPLATE with its
|
|
21
|
+
* placeholders, schema, candidates, policy — never per-call values); the control
|
|
22
|
+
* plane needs it so a call-config pin passes the eligibility gate (`loadBundle`)
|
|
23
|
+
* on a mirror-mode server. The server re-validates the bundle and recomputes the
|
|
24
|
+
* sha; once a PSR prompt has been promoted for the route, PSR's template wins
|
|
25
|
+
* over the declared one (modelrig-server ingest-route-config.ts). The org is
|
|
26
|
+
* never on the wire — the server stamps it from the key's principal (T3/T11).
|
|
27
|
+
* It travels through the SAME sink as telemetry, so in `api` mode it is a
|
|
28
|
+
* `POST /v1/ingest` with the rig's own key and needs only the `ingest` scope.
|
|
29
|
+
*
|
|
30
|
+
* ── FAIL-OPEN BY CONSTRUCTION ─────────────────────────────────────────────
|
|
31
|
+
* Fire-and-forget. Never awaited by createRig, never throws (sync or async),
|
|
32
|
+
* one console.warn on failure. It cannot change what THIS process serves (the
|
|
33
|
+
* SDK serves from its local bundles); it writes only the control-plane `routes`
|
|
34
|
+
* mirror, exactly as the exporter's first flush already does.
|
|
35
|
+
*/
|
|
36
|
+
import type { IngestBatch } from "./ingest-protocol";
|
|
37
|
+
import type { ExportedRouteMirror } from "./exporter";
|
|
38
|
+
import type { TelemetrySink } from "./sinks";
|
|
39
|
+
/** The routes-only batch (metadata + declared bundle). v1 so any server vintage
|
|
40
|
+
* accepts it (an older server keeps the metadata and ignores the bundle). */
|
|
41
|
+
export declare function buildRouteRegistrationBatch(sourceId: string, routes: readonly ExportedRouteMirror[]): IngestBatch;
|
|
42
|
+
/**
|
|
43
|
+
* Register `routes` with the control plane through `sink`, once, now. Returns
|
|
44
|
+
* the in-flight promise (always resolves — for tests and callers that want to
|
|
45
|
+
* await it); createRig ignores it. No routes ⇒ no request.
|
|
46
|
+
*/
|
|
47
|
+
export declare function registerRoutesOnStartup(sink: TelemetrySink, sourceId: string, routes: readonly ExportedRouteMirror[]): Promise<void>;
|
|
48
|
+
//# sourceMappingURL=route-registration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-registration.d.ts","sourceRoot":"","sources":["../../src/telemetry/route-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;6EAC6E;AAC7E,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACrC,WAAW,CAYb;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACrC,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RV-1 declare-on-startup — a rig with routes AND a control plane tells the
|
|
4
|
+
* control plane which routes it serves the moment it is created, so a route is
|
|
5
|
+
* visible (console, MCP `get_call_config`, `GET /v1/routes/:route/call-config
|
|
6
|
+
* ?include=effective`) BEFORE its first call.
|
|
7
|
+
*
|
|
8
|
+
* ── WHY A SEPARATE ONE-SHOT, WHEN THE EXPORTER ALREADY MIRRORS ROUTES ─────
|
|
9
|
+
* The exporter folds the routes mirror into its FIRST flush (one interval —
|
|
10
|
+
* 10s — after start). A short-lived process (a CLI, a cron, a lazily-built
|
|
11
|
+
* pipeline rig) that exits before that tick without `close()` never mirrors, and
|
|
12
|
+
* a long-lived one is invisible for the first interval. This sends the same
|
|
13
|
+
* metadata once, immediately. The exporter's header stays as the at-least-once
|
|
14
|
+
* retry path: the routes upsert is a merge on (org_id, route, version), so the
|
|
15
|
+
* duplicate is harmless.
|
|
16
|
+
*
|
|
17
|
+
* ── WHAT IT CARRIES (and does not) ────────────────────────────────────────
|
|
18
|
+
* route, version, candidates (provider/model), capture flag, AND the declared
|
|
19
|
+
* resolved bundle + its `bundle_sha` — the same payload the exporter's
|
|
20
|
+
* first-flush mirror has always carried (Matt's RV-1 ruling 1, 2026-10-10). The
|
|
21
|
+
* bundle is ROUTE CONFIGURATION (the authored prompt TEMPLATE with its
|
|
22
|
+
* placeholders, schema, candidates, policy — never per-call values); the control
|
|
23
|
+
* plane needs it so a call-config pin passes the eligibility gate (`loadBundle`)
|
|
24
|
+
* on a mirror-mode server. The server re-validates the bundle and recomputes the
|
|
25
|
+
* sha; once a PSR prompt has been promoted for the route, PSR's template wins
|
|
26
|
+
* over the declared one (modelrig-server ingest-route-config.ts). The org is
|
|
27
|
+
* never on the wire — the server stamps it from the key's principal (T3/T11).
|
|
28
|
+
* It travels through the SAME sink as telemetry, so in `api` mode it is a
|
|
29
|
+
* `POST /v1/ingest` with the rig's own key and needs only the `ingest` scope.
|
|
30
|
+
*
|
|
31
|
+
* ── FAIL-OPEN BY CONSTRUCTION ─────────────────────────────────────────────
|
|
32
|
+
* Fire-and-forget. Never awaited by createRig, never throws (sync or async),
|
|
33
|
+
* one console.warn on failure. It cannot change what THIS process serves (the
|
|
34
|
+
* SDK serves from its local bundles); it writes only the control-plane `routes`
|
|
35
|
+
* mirror, exactly as the exporter's first flush already does.
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.buildRouteRegistrationBatch = buildRouteRegistrationBatch;
|
|
39
|
+
exports.registerRoutesOnStartup = registerRoutesOnStartup;
|
|
40
|
+
const ingest_protocol_1 = require("./ingest-protocol");
|
|
41
|
+
/** The routes-only batch (metadata + declared bundle). v1 so any server vintage
|
|
42
|
+
* accepts it (an older server keeps the metadata and ignores the bundle). */
|
|
43
|
+
function buildRouteRegistrationBatch(sourceId, routes) {
|
|
44
|
+
return {
|
|
45
|
+
v: ingest_protocol_1.INGEST_PROTOCOL_VERSION_V1,
|
|
46
|
+
source: sourceId,
|
|
47
|
+
routes: routes.map((r) => ({
|
|
48
|
+
route: r.route,
|
|
49
|
+
version: r.version,
|
|
50
|
+
candidates: r.candidates.map((c) => ({ provider: c.provider, model: c.model })),
|
|
51
|
+
capture: r.capture ?? false,
|
|
52
|
+
...(r.bundle !== undefined ? { bundle: r.bundle, bundle_sha: r.bundleSha } : {}),
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Register `routes` with the control plane through `sink`, once, now. Returns
|
|
58
|
+
* the in-flight promise (always resolves — for tests and callers that want to
|
|
59
|
+
* await it); createRig ignores it. No routes ⇒ no request.
|
|
60
|
+
*/
|
|
61
|
+
function registerRoutesOnStartup(sink, sourceId, routes) {
|
|
62
|
+
if (routes.length === 0)
|
|
63
|
+
return Promise.resolve();
|
|
64
|
+
let batch;
|
|
65
|
+
try {
|
|
66
|
+
batch = buildRouteRegistrationBatch(sourceId, routes);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return Promise.resolve();
|
|
70
|
+
}
|
|
71
|
+
return Promise.resolve()
|
|
72
|
+
.then(() => sink.send(batch))
|
|
73
|
+
.catch((err) => {
|
|
74
|
+
console.warn(`[modelrig] route registration (declare-on-startup) failed — routes will still be mirrored ` +
|
|
75
|
+
`by the exporter's first flush: ${err instanceof Error ? err.message : String(err)}`);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { IngestBatch, IngestOutcome, Tenancy } from "./ingest-protocol";
|
|
23
23
|
import type { ApiExportConfig, DirectExportConfig } from "../config";
|
|
24
|
+
/** Reset the auth-failure latch — TESTS ONLY, so warn-once cases are independent
|
|
25
|
+
* of run order (mirrors deprecations.ts). */
|
|
26
|
+
export declare function __resetApiSinkWarningsForTest(): void;
|
|
24
27
|
export interface TelemetrySink {
|
|
25
28
|
/** Named so a boot banner and `/status` can say which lane is live without
|
|
26
29
|
* inspecting config — the "which mode am I in?" question got asked enough
|
|
@@ -77,6 +80,10 @@ export interface ApiSinkConfig {
|
|
|
77
80
|
* rows are being dropped must hear about it from their own process rather
|
|
78
81
|
* than by noticing a gap in a chart weeks later. */
|
|
79
82
|
readonly onOutcome?: (outcome: IngestOutcome) => void;
|
|
83
|
+
/** `createRig({ expectOrg })` (M5): the org slug this process expects its key
|
|
84
|
+
* to resolve to. A mismatch logs ORG MISMATCH on every flush (org-identity.ts);
|
|
85
|
+
* it never throws and never drops telemetry. */
|
|
86
|
+
readonly expectOrg?: string;
|
|
80
87
|
}
|
|
81
88
|
export declare function createApiSink(config: ApiSinkConfig): TelemetrySink;
|
|
82
89
|
/**
|
|
@@ -86,5 +93,7 @@ export declare function createApiSink(config: ApiSinkConfig): TelemetrySink;
|
|
|
86
93
|
* index.ts until Phase D; moved here — its natural home — to keep that file
|
|
87
94
|
* under the LOC cap.)
|
|
88
95
|
*/
|
|
89
|
-
export declare function buildTelemetrySink(exportConfig: ApiExportConfig | DirectExportConfig, sourceId: string
|
|
96
|
+
export declare function buildTelemetrySink(exportConfig: ApiExportConfig | DirectExportConfig, sourceId: string, opts?: {
|
|
97
|
+
readonly expectOrg?: string;
|
|
98
|
+
}): TelemetrySink;
|
|
90
99
|
//# sourceMappingURL=sinks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sinks.d.ts","sourceRoot":"","sources":["../../src/telemetry/sinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"sinks.d.ts","sourceRoot":"","sources":["../../src/telemetry/sinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAmBrE;6CAC6C;AAC7C,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD;AAED,MAAM,WAAW,aAAa;IAC5B;;yDAEqD;IACrD,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IAChC;;6EAEyE;IACzE,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;qCAEiC;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS;CAMxD;AAMD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,CA0CxE;AAMD,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;4EACwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC;;;wDAGoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD;;oDAEgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAKD,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAsElE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,eAAe,GAAG,kBAAkB,EAClD,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACzC,aAAa,CA2Bf"}
|