@policyengine/calibration-tree 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -2
  3. package/package.json +73 -4
  4. package/src/calibration-build-comparison.ts +77 -0
  5. package/src/calibration-comparison-blob.ts +367 -0
  6. package/src/calibration-comparison-bundle.ts +149 -0
  7. package/src/calibration-explorer.ts +202 -0
  8. package/src/calibration-release-locator.ts +353 -0
  9. package/src/calibration-tree-artifact.ts +1974 -0
  10. package/src/calibration-tree-blob.ts +403 -0
  11. package/src/calibration-tree-bundle.ts +569 -0
  12. package/src/calibration-tree-manifest.ts +349 -0
  13. package/src/calibration-tree-publication.ts +399 -0
  14. package/src/calibration-tree-worker.ts +637 -0
  15. package/src/calibration-tree.ts +1284 -0
  16. package/src/chronicle-metadata.ts +42 -0
  17. package/src/countries.ts +355 -0
  18. package/src/geography-labels.ts +59 -0
  19. package/src/hierarchy-catalog-reader.ts +297 -0
  20. package/src/hierarchy-target-reader.ts +243 -0
  21. package/src/historical-weight-summary.ts +53 -0
  22. package/src/latest-artifact.ts +3767 -0
  23. package/src/legacy-target-reader.ts +337 -0
  24. package/src/program-label.ts +64 -0
  25. package/src/publish-calibration-tree.ts +1984 -0
  26. package/src/reforms.ts +224 -0
  27. package/src/release-cut.ts +32 -0
  28. package/src/release-record.ts +277 -0
  29. package/src/source-label.ts +5 -0
  30. package/src/source-labels.ts +71 -0
  31. package/src/staging-artifact.ts +1411 -0
  32. package/src/staging-contract.ts +916 -0
  33. package/src/structured-dimension-reader.ts +137 -0
  34. package/src/structured-target-reader.ts +76 -0
  35. package/src/target-change.ts +421 -0
  36. package/src/target-loss-attribution-manifest.ts +436 -0
  37. package/src/target-loss-attribution.ts +1012 -0
  38. package/src/target-representation.ts +69 -0
  39. package/src/target-surface-matcher.ts +266 -0
  40. package/types/next-fetch-cache.d.ts +8 -0
@@ -0,0 +1,1411 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import {
4
+ type Calibration,
5
+ type MicrocosmCountry,
6
+ asObject,
7
+ assertSafeReleaseId,
8
+ assertSafeReleaseOrBuildFolderId,
9
+ buildCalibration,
10
+ buildComparison,
11
+ latestMicrocosmCalibrationSummary,
12
+ latestMicrocosmTargetDiagnosticsPage,
13
+ loadCountryRepositoryHashedJson,
14
+ loadPointerReleaseId,
15
+ loadPublishedCutReleases,
16
+ loadRecordedReleases,
17
+ loadRelease,
18
+ loadReleases,
19
+ microcosmCountryGeography,
20
+ microcosmRepo,
21
+ type ReleaseEntry,
22
+ } from "./latest-artifact";
23
+ import { readCalibrationTreeManifest } from "./calibration-tree-blob";
24
+ import {
25
+ calibrationBuildsNewestFirst,
26
+ type CalibrationTreeManifest,
27
+ type CalibrationTreeManifestEntry,
28
+ } from "./calibration-tree-manifest";
29
+ import type { CalibrationTreeSourceArtifact } from "./calibration-tree-artifact";
30
+ import {
31
+ countryRegistration,
32
+ resolveRegisteredStagingRepository,
33
+ stagingLocalAreaPipelines,
34
+ type RepositoryEnvironment,
35
+ type ResolvedRepository,
36
+ } from "./countries";
37
+ import {
38
+ type ReformValidation,
39
+ buildReformValidation,
40
+ } from "./reforms";
41
+ import {
42
+ buildTargetChangeDataset,
43
+ type TargetChangeDataset,
44
+ } from "./target-change";
45
+ import { buildTargetChangeDatasetFromSummaryAndCalibration } from "./calibration-build-comparison";
46
+ import { loadCalibrationComparisonSource } from "./calibration-comparison-blob";
47
+ import {
48
+ IncompatibleStagingDataError,
49
+ isStructuredStagingDocument,
50
+ parseStagingCalibrationProgress,
51
+ parseStagingEvents,
52
+ parseStagingManifest,
53
+ parseStagingProgress,
54
+ parseStagingRunIndex,
55
+ validateStagingRunConsistency,
56
+ type StagingSchemaVersion,
57
+ } from "./staging-contract";
58
+
59
+ type JsonObject = Record<string, unknown>;
60
+
61
+ interface TargetChangeCacheEntry {
62
+ expiresAt: number;
63
+ promise: Promise<TargetChangeDataset | null>;
64
+ }
65
+
66
+ interface StagingCalibrationCacheEntry {
67
+ expiresAt: number;
68
+ promise: Promise<Calibration | null>;
69
+ }
70
+
71
+ const TARGET_CHANGE_FINAL_CACHE_SECONDS = 21_600;
72
+ const TARGET_CHANGE_MUTABLE_CACHE_SECONDS = 30;
73
+ const TARGET_CHANGE_CACHE_LIMIT = 8;
74
+ const STAGING_CALIBRATION_CACHE_LIMIT = 8;
75
+ const targetChangeCache = new Map<string, TargetChangeCacheEntry>();
76
+ const stagingCalibrationCache = new Map<string, StagingCalibrationCacheEntry>();
77
+
78
+ export const MICROCOSM_STAGING_HF_REPO_ENV = "POPULACE_STAGING_HF_REPO";
79
+ export const MICROCOSM_STAGING_HF_REVISION_ENV = "POPULACE_STAGING_HF_REVISION";
80
+ export type StagingRepository = ResolvedRepository;
81
+
82
+ // Resolve staging telemetry from the country registry. The exported US values
83
+ // retain the legacy API and deployment-variable behavior for existing callers.
84
+ export function stagingRepository(
85
+ country: MicrocosmCountry,
86
+ environment: RepositoryEnvironment = process.env,
87
+ ): StagingRepository | null {
88
+ return resolveRegisteredStagingRepository(country, environment);
89
+ }
90
+
91
+ export const MICROCOSM_STAGING_HF_REPO = stagingRepository("us")!.repo;
92
+ export const MICROCOSM_STAGING_HF_REVISION = stagingRepository("us")!.revision;
93
+
94
+ export async function resolveStagingRevisionSha(
95
+ country: MicrocosmCountry,
96
+ revisionOverride?: string,
97
+ ): Promise<string> {
98
+ const repository = stagingSource(country, revisionOverride);
99
+ const response = await fetch(
100
+ `https://huggingface.co/api/datasets/${repository.repo}/revision/${encodeURIComponent(repository.revision)}`,
101
+ {
102
+ ...stagingFetchOptions(0, country),
103
+ signal: AbortSignal.timeout(30_000),
104
+ },
105
+ );
106
+ if (!response.ok) {
107
+ throw new StagingFetchError(
108
+ response.status,
109
+ `revision ${repository.revision}`,
110
+ repository,
111
+ );
112
+ }
113
+ const payload = asObject(await response.json());
114
+ const sha = typeof payload.sha === "string" ? payload.sha.toLowerCase() : "";
115
+ if (!/^[0-9a-f]{40,64}$/.test(sha)) {
116
+ throw new Error(
117
+ `Hugging Face returned an invalid commit SHA for ${repository.repo}@${repository.revision}.`,
118
+ );
119
+ }
120
+ return sha;
121
+ }
122
+
123
+ // Staging telemetry is served for countries registered with the `staging`
124
+ // capability. Repository and credential selection happens in this server data
125
+ // module and never enters the API response model.
126
+ export function stagingUnavailableReason(country: MicrocosmCountry): string | null {
127
+ return stagingRepository(country)
128
+ ? null
129
+ : `${microcosmCountryGeography(country)} has no staging repository.`;
130
+ }
131
+
132
+ function requiredStagingRepository(country: MicrocosmCountry): StagingRepository {
133
+ const repository = stagingRepository(country);
134
+ if (repository) return repository;
135
+ throw new Error(
136
+ stagingUnavailableReason(country) ?? "Staging repository is not configured.",
137
+ );
138
+ }
139
+
140
+ function stagingResolveUrlFor(repository: StagingRepository, path: string): string {
141
+ return `https://huggingface.co/datasets/${repository.repo}/resolve/${repository.revision}/${path}`;
142
+ }
143
+
144
+ export function stagingResolveUrl(path: string, country: MicrocosmCountry = "us"): string {
145
+ return stagingResolveUrlFor(requiredStagingRepository(country), path);
146
+ }
147
+
148
+ function stagingTreeUrl(repository: StagingRepository): string {
149
+ return `https://huggingface.co/api/datasets/${repository.repo}/tree/${repository.revision}/runs?recursive=true`;
150
+ }
151
+
152
+ function stagingRepoUrl(repository: StagingRepository): string {
153
+ return `https://huggingface.co/api/datasets/${repository.repo}`;
154
+ }
155
+
156
+ function stagingSource(
157
+ country: MicrocosmCountry,
158
+ revisionOverride?: string,
159
+ ): StagingRepository {
160
+ const repository = requiredStagingRepository(country);
161
+ return revisionOverride
162
+ ? { ...repository, revision: revisionOverride }
163
+ : repository;
164
+ }
165
+
166
+ function unavailableStaging(country: MicrocosmCountry) {
167
+ const detail = stagingUnavailableReason(country);
168
+ if (!detail) return null;
169
+ return {
170
+ available: false as const,
171
+ source_repo: null,
172
+ revision: null,
173
+ detail,
174
+ };
175
+ }
176
+
177
+ class StagingFetchError extends Error {
178
+ constructor(
179
+ public readonly status: number,
180
+ path: string,
181
+ repository: StagingRepository,
182
+ ) {
183
+ super(stagingFetchMessage(status, path, repository));
184
+ }
185
+ }
186
+
187
+ function stagingFetchMessage(
188
+ status: number,
189
+ path: string,
190
+ repository: StagingRepository,
191
+ ): string {
192
+ if (status === 401 || status === 403) {
193
+ return (
194
+ `Staging repository ${repository.repo} is not readable by this deployment ` +
195
+ `(${status} fetching ${path}). Configure its server-side read credential.`
196
+ );
197
+ }
198
+ if (status === 404) {
199
+ return `Staging artifact not found (${path}).`;
200
+ }
201
+ return `Staging fetch failed ${status}: ${path}`;
202
+ }
203
+
204
+ function stagingToken(country: MicrocosmCountry): string | undefined {
205
+ const tokenEnv = countryRegistration(country).staging?.token_env;
206
+ if (tokenEnv) return process.env[tokenEnv];
207
+ return process.env.HF_TOKEN ?? process.env.HUGGINGFACE_TOKEN;
208
+ }
209
+
210
+ function hfHeaders(country: MicrocosmCountry): HeadersInit | undefined {
211
+ const token = stagingToken(country);
212
+ return token ? { Authorization: `Bearer ${token}` } : undefined;
213
+ }
214
+
215
+ function stagingFetchOptions(
216
+ revalidate: number,
217
+ country: MicrocosmCountry,
218
+ ): RequestInit {
219
+ return {
220
+ headers: hfHeaders(country),
221
+ ...(revalidate > 0 ? { next: { revalidate } } : { cache: "no-store" as const }),
222
+ };
223
+ }
224
+
225
+ async function stagingJson(
226
+ path: string,
227
+ revalidate: number,
228
+ country: MicrocosmCountry,
229
+ revisionOverride?: string,
230
+ ): Promise<JsonObject> {
231
+ const repository = stagingSource(country, revisionOverride);
232
+ const res = await fetch(
233
+ stagingResolveUrlFor(repository, path),
234
+ stagingFetchOptions(revalidate, country),
235
+ );
236
+ if (!res.ok) throw new StagingFetchError(res.status, path, repository);
237
+ return asObject(await res.json());
238
+ }
239
+
240
+ async function stagingJsonOrNull(
241
+ path: string,
242
+ revalidate: number,
243
+ country: MicrocosmCountry,
244
+ revisionOverride?: string,
245
+ ): Promise<JsonObject | null> {
246
+ try {
247
+ return await stagingJson(path, revalidate, country, revisionOverride);
248
+ } catch (error) {
249
+ if (error instanceof StagingFetchError && error.status !== 404) throw error;
250
+ return null;
251
+ }
252
+ }
253
+
254
+ interface HashedStagingJson {
255
+ payload: JsonObject;
256
+ sha256: string;
257
+ source: CalibrationTreeSourceArtifact;
258
+ }
259
+
260
+ async function stagingHashedJsonOrNull(
261
+ path: string,
262
+ revalidate: number,
263
+ country: MicrocosmCountry,
264
+ revisionOverride?: string,
265
+ ): Promise<HashedStagingJson | null> {
266
+ const repository = stagingSource(country, revisionOverride);
267
+ const res = await fetch(
268
+ stagingResolveUrlFor(repository, path),
269
+ stagingFetchOptions(revalidate, country),
270
+ );
271
+ if (!res.ok) {
272
+ if (res.status === 404) return null;
273
+ throw new StagingFetchError(res.status, path, repository);
274
+ }
275
+ const bytes = new Uint8Array(await res.arrayBuffer());
276
+ let parsed: unknown;
277
+ try {
278
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
279
+ } catch {
280
+ throw new IncompatibleStagingDataError(`${path} is not valid JSON.`);
281
+ }
282
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
283
+ throw new IncompatibleStagingDataError(`${path} must contain a JSON object.`);
284
+ }
285
+ const sha256 = createHash("sha256").update(bytes).digest("hex");
286
+ return {
287
+ payload: parsed as JsonObject,
288
+ sha256,
289
+ source: {
290
+ path,
291
+ sha256,
292
+ hfRepo: repository.repo,
293
+ hfCommitSha: repository.revision,
294
+ },
295
+ };
296
+ }
297
+
298
+ async function stagingTextOrNull(
299
+ path: string,
300
+ revalidate: number,
301
+ country: MicrocosmCountry,
302
+ revisionOverride?: string,
303
+ ): Promise<string | null> {
304
+ const repository = stagingSource(country, revisionOverride);
305
+ const res = await fetch(
306
+ stagingResolveUrlFor(repository, path),
307
+ stagingFetchOptions(revalidate, country),
308
+ );
309
+ if (!res.ok) {
310
+ if (res.status === 404) return null;
311
+ throw new StagingFetchError(res.status, path, repository);
312
+ }
313
+ return res.text();
314
+ }
315
+
316
+ async function stagingTree(
317
+ revalidate: number,
318
+ country: MicrocosmCountry,
319
+ revisionOverride?: string,
320
+ ): Promise<JsonObject[]> {
321
+ const repository = stagingSource(country, revisionOverride);
322
+ const entries: JsonObject[] = [];
323
+ const visited = new Set<string>();
324
+ let url: string | null = stagingTreeUrl(repository);
325
+ while (url) {
326
+ if (visited.has(url)) {
327
+ throw new Error("Staging repository tree pagination repeated a page URL.");
328
+ }
329
+ visited.add(url);
330
+ const res: Response = await fetch(
331
+ url,
332
+ stagingFetchOptions(revalidate, country),
333
+ );
334
+ if (!res.ok) throw new StagingFetchError(res.status, "runs tree", repository);
335
+ const tree: unknown = await res.json();
336
+ if (!Array.isArray(tree)) {
337
+ throw new IncompatibleStagingDataError(
338
+ "runs tree response must be an array.",
339
+ );
340
+ }
341
+ entries.push(...tree.map(asObject));
342
+ const link = res.headers.get("link") ?? "";
343
+ const next = /<([^>]+)>;\s*rel="next"/.exec(link);
344
+ url = next ? next[1] : null;
345
+ }
346
+ return entries;
347
+ }
348
+
349
+ export interface StagingRunSummary {
350
+ run_id: string;
351
+ candidate_release_id: string | null;
352
+ release_id: string | null;
353
+ country_code: string | null;
354
+ run_kind: string | null;
355
+ non_release: boolean | null;
356
+ schema_version: StagingSchemaVersion | null;
357
+ status: string | null;
358
+ stage: string | null;
359
+ started_at: string | null;
360
+ updated_at: string | null;
361
+ progress_path: string;
362
+ run_manifest_path: string;
363
+ }
364
+
365
+ export interface IncompatibleStagingRun {
366
+ run_id: string;
367
+ run_manifest_path: string;
368
+ detail: string;
369
+ }
370
+
371
+ export interface StagingRunDetail {
372
+ available: boolean;
373
+ source_repo: string | null;
374
+ revision: string | null;
375
+ detail?: string | null;
376
+ run_id: string;
377
+ candidate_release_id: string | null;
378
+ release_id: string | null;
379
+ country_code: string | null;
380
+ run_kind: string | null;
381
+ non_release: boolean | null;
382
+ schema_version: StagingSchemaVersion | null;
383
+ delivery: JsonObject | null;
384
+ progress: JsonObject | null;
385
+ run_manifest: JsonObject | null;
386
+ calibration_progress: JsonObject | null;
387
+ events: JsonObject[];
388
+ has_calibration: boolean;
389
+ calibration: ReturnType<typeof latestMicrocosmCalibrationSummary> | null;
390
+ reform_validation: ReformValidation | null;
391
+ build_manifest: JsonObject | null;
392
+ release_manifest: JsonObject | null;
393
+ }
394
+
395
+ function stringValue(value: unknown): string | null {
396
+ return typeof value === "string" && value.trim() ? value : null;
397
+ }
398
+
399
+ function booleanValue(value: unknown): boolean | null {
400
+ return typeof value === "boolean" ? value : null;
401
+ }
402
+
403
+ function schemaVersionValue(value: unknown): StagingSchemaVersion | null {
404
+ return value === 1 || value === 2 || value === 3 ? value : null;
405
+ }
406
+
407
+ function objectOrNull(value: unknown): JsonObject | null {
408
+ return value != null && typeof value === "object" && !Array.isArray(value)
409
+ ? (value as JsonObject)
410
+ : null;
411
+ }
412
+
413
+ export function stagingTargetChangeCacheTtlSeconds(status: unknown): number {
414
+ return ["passed", "published", "completed", "blocked", "failed"].includes(
415
+ String(status ?? "").trim(),
416
+ )
417
+ ? TARGET_CHANGE_FINAL_CACHE_SECONDS
418
+ : TARGET_CHANGE_MUTABLE_CACHE_SECONDS;
419
+ }
420
+
421
+ function summaryFromProgress(runId: string, progress: JsonObject | null): StagingRunSummary {
422
+ const candidate = stringValue(progress?.candidate_release_id);
423
+ return {
424
+ run_id: runId,
425
+ candidate_release_id: candidate,
426
+ release_id: stringValue(progress?.release_id),
427
+ country_code: stringValue(progress?.country_code),
428
+ run_kind: stringValue(progress?.run_kind),
429
+ non_release: booleanValue(progress?.non_release),
430
+ schema_version: schemaVersionValue(progress?.schema_version),
431
+ status: stringValue(progress?.status),
432
+ stage: stringValue(progress?.stage),
433
+ started_at: stringValue(progress?.started_at),
434
+ updated_at: stringValue(progress?.updated_at),
435
+ progress_path: `runs/${runId}/progress.json`,
436
+ run_manifest_path: `runs/${runId}/run_manifest.json`,
437
+ };
438
+ }
439
+
440
+ function summaryFromManifest(
441
+ runId: string,
442
+ manifest: JsonObject,
443
+ ): StagingRunSummary {
444
+ return {
445
+ run_id: runId,
446
+ candidate_release_id: stringValue(manifest.candidate_release_id),
447
+ release_id: stringValue(manifest.release_id),
448
+ country_code: stringValue(manifest.country_code),
449
+ run_kind: stringValue(manifest.run_kind),
450
+ non_release: booleanValue(manifest.non_release),
451
+ schema_version: schemaVersionValue(manifest.schema_version),
452
+ status: stringValue(manifest.status),
453
+ stage: stringValue(manifest.stage),
454
+ started_at: stringValue(manifest.started_at),
455
+ updated_at: stringValue(manifest.updated_at),
456
+ progress_path: `runs/${runId}/progress.json`,
457
+ run_manifest_path: `runs/${runId}/run_manifest.json`,
458
+ };
459
+ }
460
+
461
+ function sortRuns(a: StagingRunSummary, b: StagingRunSummary): number {
462
+ return (
463
+ compareTimestampsDescending(a.updated_at, b.updated_at) ||
464
+ compareTimestampsDescending(a.started_at, b.started_at) ||
465
+ b.run_id.localeCompare(a.run_id)
466
+ );
467
+ }
468
+
469
+ function compareTimestampsDescending(
470
+ a: string | null,
471
+ b: string | null,
472
+ ): number {
473
+ const aTime = a == null ? Number.NEGATIVE_INFINITY : Date.parse(a);
474
+ const bTime = b == null ? Number.NEGATIVE_INFINITY : Date.parse(b);
475
+ const normalizedA = Number.isNaN(aTime) ? Number.NEGATIVE_INFINITY : aTime;
476
+ const normalizedB = Number.isNaN(bTime) ? Number.NEGATIVE_INFINITY : bTime;
477
+ if (normalizedA === normalizedB) return 0;
478
+ return normalizedB > normalizedA ? 1 : -1;
479
+ }
480
+
481
+ const RUN_PATH = /^runs\/([A-Za-z0-9][A-Za-z0-9._-]*)\//;
482
+ const RUN_MANIFEST_PATH =
483
+ /^runs\/([A-Za-z0-9][A-Za-z0-9._-]*)\/run_manifest\.json$/;
484
+
485
+ export async function loadStagingRuns(
486
+ revalidate: number,
487
+ country: MicrocosmCountry = "us",
488
+ revisionOverride?: string,
489
+ ) {
490
+ const unavailable = unavailableStaging(country);
491
+ if (unavailable) {
492
+ return {
493
+ ...unavailable,
494
+ truncated: false,
495
+ runs: [] as StagingRunSummary[],
496
+ incompatible_runs: [] as IncompatibleStagingRun[],
497
+ };
498
+ }
499
+ const repository = stagingSource(country, revisionOverride);
500
+ let treeMissing = false;
501
+ let tree: JsonObject[] = [];
502
+ try {
503
+ tree = await stagingTree(revalidate, country, revisionOverride);
504
+ } catch (error) {
505
+ if (!(error instanceof StagingFetchError) || error.status !== 404) throw error;
506
+ // A staging repo may exist before any tree listing is public.
507
+ treeMissing = true;
508
+ }
509
+
510
+ const manifestPaths = new Map<string, string>();
511
+ const listedRunIds = new Set<string>();
512
+ for (const entry of tree) {
513
+ if (entry.type !== "file" || typeof entry.path !== "string") continue;
514
+ const runMatch = RUN_PATH.exec(entry.path);
515
+ if (runMatch) listedRunIds.add(runMatch[1]);
516
+ const manifestMatch = RUN_MANIFEST_PATH.exec(entry.path);
517
+ if (manifestMatch) manifestPaths.set(manifestMatch[1], entry.path);
518
+ }
519
+
520
+ const manifestResults = await Promise.all(
521
+ [...manifestPaths].map(async ([runId, path]) => {
522
+ try {
523
+ const manifest = parseStagingManifest(
524
+ await stagingJson(path, revalidate, country, revisionOverride),
525
+ );
526
+ if (manifest.run_id !== runId) {
527
+ throw new IncompatibleStagingDataError(
528
+ `run manifest id ${String(manifest.run_id)} does not match directory ${runId}.`,
529
+ );
530
+ }
531
+ validateStagingRunConsistency(runId, { runManifest: manifest });
532
+ return { manifest, problem: null };
533
+ } catch (error) {
534
+ return {
535
+ manifest: null,
536
+ problem: {
537
+ run_id: runId,
538
+ run_manifest_path: path,
539
+ detail: error instanceof Error ? error.message : String(error),
540
+ } satisfies IncompatibleStagingRun,
541
+ };
542
+ }
543
+ }),
544
+ );
545
+ const listedManifests = manifestResults.flatMap(({ manifest }) =>
546
+ manifest == null ? [] : [manifest],
547
+ );
548
+ const incompatibleRuns = manifestResults.flatMap(({ problem }) =>
549
+ problem == null ? [] : [problem],
550
+ );
551
+ const structuredManifests = listedManifests.filter(isStructuredStagingDocument);
552
+ const structuredManifestIds = new Set(
553
+ structuredManifests.map((manifest) => String(manifest.run_id)),
554
+ );
555
+ const v1ManifestIds = new Set(
556
+ listedManifests
557
+ .filter((manifest) => manifest.schema_version === 1)
558
+ .map((manifest) => String(manifest.run_id)),
559
+ );
560
+
561
+ let index: JsonObject | null = null;
562
+ let indexedRuns: StagingRunSummary[] = [];
563
+ if (treeMissing || v1ManifestIds.size > 0) {
564
+ index = await stagingJsonOrNull(
565
+ "runs.json",
566
+ revalidate,
567
+ country,
568
+ revisionOverride,
569
+ );
570
+ if (index?.schema_version === 1) indexedRuns = parseStagingRunIndex(index);
571
+ }
572
+
573
+ // HF answers 404 (not 401/403) for private repos when auth is missing or
574
+ // expired, so "everything 404'd" is ambiguous between "no runs yet" and "we
575
+ // can't see the repo". Disambiguate via the repo API before reporting an
576
+ // empty list — a silent empty state hides a broken token.
577
+ if (index == null && treeMissing && listedManifests.length === 0) {
578
+ const repoRes = await fetch(
579
+ stagingRepoUrl(repository),
580
+ stagingFetchOptions(revalidate, country),
581
+ );
582
+ if (!repoRes.ok) {
583
+ return {
584
+ available: false,
585
+ source_repo: repository.repo,
586
+ revision: repository.revision,
587
+ detail:
588
+ `Staging repository ${repository.repo} is not visible (HTTP ${repoRes.status}). ` +
589
+ "It is private — a missing or expired HF token reads as 404, not 401.",
590
+ runs: [],
591
+ incompatible_runs: incompatibleRuns,
592
+ };
593
+ }
594
+ }
595
+
596
+ const byId = new Map<string, StagingRunSummary>(
597
+ indexedRuns.map((run) => [run.run_id, run]),
598
+ );
599
+ const v1RunIds = new Set(v1ManifestIds);
600
+ if (index?.schema_version === 1) {
601
+ for (const runId of listedRunIds) {
602
+ if (!structuredManifestIds.has(runId)) v1RunIds.add(runId);
603
+ }
604
+ }
605
+ const missing = [...v1RunIds]
606
+ .filter((runId) => !byId.has(runId))
607
+ .sort((a, b) => (a < b ? 1 : a > b ? -1 : 0));
608
+ const MAX_UNINDEXED_FETCH = 50;
609
+ const fetched = await Promise.all(
610
+ missing.slice(0, MAX_UNINDEXED_FETCH).map(async (runId) => {
611
+ const raw = await stagingJsonOrNull(
612
+ `runs/${runId}/progress.json`,
613
+ revalidate,
614
+ country,
615
+ revisionOverride,
616
+ );
617
+ const progress = raw == null ? null : parseStagingProgress(raw);
618
+ validateStagingRunConsistency(runId, { progress });
619
+ return summaryFromProgress(runId, progress);
620
+ }),
621
+ );
622
+ for (const run of fetched) byId.set(run.run_id, run);
623
+ for (const manifest of structuredManifests) {
624
+ const runId = String(manifest.run_id);
625
+ byId.set(runId, summaryFromManifest(runId, manifest));
626
+ }
627
+ const truncated = missing.length > MAX_UNINDEXED_FETCH;
628
+
629
+ return {
630
+ available: true,
631
+ source_repo: repository.repo,
632
+ revision: repository.revision,
633
+ truncated,
634
+ runs: [...byId.values()].sort(sortRuns),
635
+ incompatible_runs: incompatibleRuns,
636
+ };
637
+ }
638
+
639
+ // A build that staged its finished dataset bundle records where it went in a
640
+ // reviewed `staged_dataset` telemetry artifact: the release repository, the
641
+ // `staged/<run_id>/` prefix, the commit and every file's digest. The bundle's
642
+ // `calibration_diagnostics.json` is the same per-target artifact a release
643
+ // carries, so an unreleased candidate can be inspected through the same views.
644
+ const STAGED_BUNDLE_DIAGNOSTICS_FILE = "calibration_diagnostics.json";
645
+ // Microcosm's UK local lane stages its outputs under the dataset's own stem,
646
+ // so its per-target diagnostics arrive as `<dataset>.diagnostics.json`.
647
+ const STAGED_BUNDLE_STEM_DIAGNOSTICS_SUFFIX = ".diagnostics.json";
648
+ // A recorded file name is joined to the staged prefix in an authenticated
649
+ // release-repository URL, so it must be one path segment.
650
+ const STAGED_BUNDLE_FILE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,200}$/;
651
+ const STAGED_BUNDLE_LANDED = new Set(["uploaded", "already_staged"]);
652
+ const STAGED_BUNDLE_PREFIX = /^staged\/[A-Za-z0-9][A-Za-z0-9._-]*$/;
653
+ const GIT_COMMIT_SHA = /^[0-9a-f]{40}$/;
654
+ const SHA_256_HEX = /^[0-9a-f]{64}$/;
655
+
656
+ export interface ResolvedStagingCalibrationSource {
657
+ calibration: Calibration;
658
+ candidateReleaseId: string;
659
+ updatedAt: string | null;
660
+ stagingRepo: string;
661
+ stagingRevision: string;
662
+ sourceArtifacts: {
663
+ calibrationDiagnostics: CalibrationTreeSourceArtifact;
664
+ buildManifest: CalibrationTreeSourceArtifact | null;
665
+ releaseManifest: CalibrationTreeSourceArtifact | null;
666
+ stagingRunManifest: CalibrationTreeSourceArtifact | null;
667
+ stagingProgress: CalibrationTreeSourceArtifact | null;
668
+ stagedDatasetReceipt: CalibrationTreeSourceArtifact | null;
669
+ };
670
+ }
671
+
672
+ // The bundle's per-target diagnostics file among the files its receipt
673
+ // recorded: `calibration_diagnostics.json`, or else the one
674
+ // `<dataset>.diagnostics.json`. A bundle recording none, several stem
675
+ // files, or a stem name that is not one path segment has no target view
676
+ // rather than a guessed one. The count includes invalid names, so an
677
+ // invalid name beside a valid one still makes the receipt ambiguous.
678
+ export function stagedBundleDiagnosticsFile(files: JsonObject | null): string | null {
679
+ if (!files) return null;
680
+ if (Object.hasOwn(files, STAGED_BUNDLE_DIAGNOSTICS_FILE)) {
681
+ return STAGED_BUNDLE_DIAGNOSTICS_FILE;
682
+ }
683
+ const stemFiles = Object.keys(files).filter((name) =>
684
+ name.endsWith(STAGED_BUNDLE_STEM_DIAGNOSTICS_SUFFIX)
685
+ );
686
+ return stemFiles.length === 1 && STAGED_BUNDLE_FILE_NAME.test(stemFiles[0])
687
+ ? stemFiles[0]
688
+ : null;
689
+ }
690
+
691
+ async function loadStagedBundleCalibrationSource(
692
+ runId: string,
693
+ runManifest: JsonObject | null,
694
+ progress: JsonObject | null,
695
+ candidateReleaseId: string,
696
+ revalidate: number,
697
+ country: MicrocosmCountry,
698
+ stagingRevision: string,
699
+ runManifestSource: CalibrationTreeSourceArtifact | null,
700
+ progressSource: CalibrationTreeSourceArtifact | null,
701
+ ): Promise<ResolvedStagingCalibrationSource | null> {
702
+ const staging = stagingSource(country, stagingRevision);
703
+ const artifacts = objectOrNull(runManifest?.artifacts);
704
+ const stagedArtifact = objectOrNull(artifacts?.staged_dataset);
705
+ const receiptPath = stringValue(stagedArtifact?.staging_path);
706
+ if (!receiptPath) return null;
707
+ const receipt = await stagingHashedJsonOrNull(
708
+ receiptPath,
709
+ revalidate,
710
+ country,
711
+ stagingRevision,
712
+ );
713
+ if (!receipt) {
714
+ throw new IncompatibleStagingDataError(
715
+ "artifact staged_dataset is declared but its receipt is absent.",
716
+ );
717
+ }
718
+ if (receipt.sha256 !== stringValue(stagedArtifact?.sha256)) {
719
+ throw new IncompatibleStagingDataError(
720
+ "artifact staged_dataset digest does not match its run manifest declaration.",
721
+ );
722
+ }
723
+ const delivery = receipt.payload;
724
+ // A skipped, failed or disabled staging leaves nothing to read.
725
+ if (!STAGED_BUNDLE_LANDED.has(String(delivery.status))) return null;
726
+ if (stringValue(delivery.run_id) !== runId) {
727
+ throw new IncompatibleStagingDataError("staged dataset receipt names another run.");
728
+ }
729
+ const repository = stringValue(delivery.repository);
730
+ const prefix = stringValue(delivery.prefix);
731
+ const revision = stringValue(delivery.revision);
732
+ if (!repository || !prefix || !revision) {
733
+ throw new IncompatibleStagingDataError(
734
+ "staged dataset receipt is missing its repository, prefix or revision.",
735
+ );
736
+ }
737
+ // The release credential is only ever sent to the country's registered
738
+ // release repository, never to a repository a telemetry file names.
739
+ if (repository !== microcosmRepo(country)) {
740
+ throw new IncompatibleStagingDataError(
741
+ `staged dataset repository ${repository} is not ${microcosmCountryGeography(country)}'s ` +
742
+ "registered release repository; staged bundles are read only from there.",
743
+ );
744
+ }
745
+ if (!STAGED_BUNDLE_PREFIX.test(prefix) || prefix !== `staged/${runId}`) {
746
+ throw new IncompatibleStagingDataError("staged dataset prefix is not staged/<run_id>.");
747
+ }
748
+ if (!GIT_COMMIT_SHA.test(revision)) {
749
+ throw new IncompatibleStagingDataError("staged dataset revision is not a commit sha.");
750
+ }
751
+ const files = objectOrNull(delivery.files);
752
+ const diagnosticsFile = stagedBundleDiagnosticsFile(files);
753
+ // A bundle without calibration diagnostics (a spine, say) has no target view.
754
+ if (!diagnosticsFile) return null;
755
+ const declared = objectOrNull(files?.[diagnosticsFile]);
756
+ const expectedDigest = stringValue(declared?.sha256);
757
+ if (!expectedDigest || !SHA_256_HEX.test(expectedDigest)) return null;
758
+ const diagnostics = await loadCountryRepositoryHashedJson(
759
+ `${prefix}/${diagnosticsFile}`,
760
+ revalidate,
761
+ country,
762
+ revision,
763
+ );
764
+ if (!diagnostics) {
765
+ throw new IncompatibleStagingDataError(
766
+ `staged bundle ${prefix} records ${diagnosticsFile} but the file is absent at revision ${revision}.`,
767
+ );
768
+ }
769
+ if (diagnostics.sha256 !== expectedDigest) {
770
+ throw new IncompatibleStagingDataError(
771
+ `staged bundle ${diagnosticsFile} does not match the digest the run recorded.`,
772
+ );
773
+ }
774
+ const updatedAt = stringValue(progress?.updated_at) ??
775
+ stringValue(runManifest?.updated_at);
776
+ const calibration = buildCalibration(
777
+ diagnostics.payload,
778
+ candidateReleaseId,
779
+ updatedAt,
780
+ {},
781
+ {},
782
+ {},
783
+ country,
784
+ "huggingface_staged_bundle",
785
+ diagnostics.sha256,
786
+ revision,
787
+ );
788
+ return {
789
+ calibration,
790
+ candidateReleaseId,
791
+ updatedAt,
792
+ stagingRepo: staging.repo,
793
+ stagingRevision,
794
+ sourceArtifacts: {
795
+ calibrationDiagnostics: {
796
+ path: `${prefix}/${diagnosticsFile}`,
797
+ sha256: diagnostics.sha256,
798
+ hfRepo: repository,
799
+ hfCommitSha: revision,
800
+ },
801
+ buildManifest: null,
802
+ releaseManifest: null,
803
+ stagingRunManifest: runManifestSource,
804
+ stagingProgress: progressSource,
805
+ stagedDatasetReceipt: receipt.source,
806
+ },
807
+ };
808
+ }
809
+
810
+ export async function loadStagingCalibration(
811
+ runId: string,
812
+ revalidate: number,
813
+ country: MicrocosmCountry = "us",
814
+ ): Promise<Calibration | null> {
815
+ if (revalidate <= 0) {
816
+ return loadStagingCalibrationUncached(runId, revalidate, country);
817
+ }
818
+ const cacheKey = `${country}:${runId}:${revalidate}`;
819
+ const now = Date.now();
820
+ for (const [key, entry] of stagingCalibrationCache) {
821
+ if (entry.expiresAt <= now) stagingCalibrationCache.delete(key);
822
+ }
823
+ const cached = stagingCalibrationCache.get(cacheKey);
824
+ if (cached && cached.expiresAt > now) return cached.promise;
825
+
826
+ const promise = loadStagingCalibrationUncached(runId, revalidate, country);
827
+ stagingCalibrationCache.set(cacheKey, {
828
+ promise,
829
+ expiresAt: now + revalidate * 1000,
830
+ });
831
+ while (stagingCalibrationCache.size > STAGING_CALIBRATION_CACHE_LIMIT) {
832
+ const oldest = stagingCalibrationCache.keys().next().value;
833
+ if (typeof oldest !== "string") break;
834
+ stagingCalibrationCache.delete(oldest);
835
+ }
836
+ try {
837
+ const result = await promise;
838
+ if (!result) stagingCalibrationCache.delete(cacheKey);
839
+ return result;
840
+ } catch (error) {
841
+ stagingCalibrationCache.delete(cacheKey);
842
+ throw error;
843
+ }
844
+ }
845
+
846
+ async function loadStagingCalibrationUncached(
847
+ runId: string,
848
+ revalidate: number,
849
+ country: MicrocosmCountry,
850
+ ): Promise<Calibration | null> {
851
+ const source = await resolveStagingCalibrationSource(
852
+ runId,
853
+ revalidate,
854
+ country,
855
+ );
856
+ return source?.calibration ?? null;
857
+ }
858
+
859
+ export async function resolveStagingCalibrationSource(
860
+ runId: string,
861
+ revalidate: number,
862
+ country: MicrocosmCountry = "us",
863
+ revisionOverride?: string,
864
+ ): Promise<ResolvedStagingCalibrationSource | null> {
865
+ if (stagingUnavailableReason(country)) return null;
866
+ assertSafeReleaseId(runId, "run");
867
+ const staging = stagingSource(country, revisionOverride);
868
+ const [progressArtifact, runManifestArtifact] = await Promise.all([
869
+ stagingHashedJsonOrNull(
870
+ `runs/${runId}/progress.json`,
871
+ revalidate,
872
+ country,
873
+ staging.revision,
874
+ ),
875
+ stagingHashedJsonOrNull(
876
+ `runs/${runId}/run_manifest.json`,
877
+ revalidate,
878
+ country,
879
+ staging.revision,
880
+ ),
881
+ ]);
882
+ const progress = progressArtifact == null
883
+ ? null
884
+ : parseStagingProgress(progressArtifact.payload);
885
+ const runManifest =
886
+ runManifestArtifact == null
887
+ ? null
888
+ : parseStagingManifest(runManifestArtifact.payload);
889
+ validateStagingRunConsistency(runId, { progress, runManifest });
890
+ const candidateReleaseId =
891
+ stringValue(progress?.candidate_release_id) ??
892
+ stringValue(runManifest?.candidate_release_id) ??
893
+ runId;
894
+ const artifacts = objectOrNull(runManifest?.artifacts);
895
+ const diagnosticsArtifact = objectOrNull(artifacts?.calibration_diagnostics);
896
+ const structured = isStructuredStagingDocument(runManifest);
897
+ const diagnosticsPath = structured
898
+ ? stringValue(diagnosticsArtifact?.staging_path)
899
+ : `runs/${runId}/calibration_diagnostics.json`;
900
+ if (!diagnosticsPath) {
901
+ // No telemetry diagnostics artifact: a run that staged its dataset bundle
902
+ // carries the same diagnostics there.
903
+ return loadStagedBundleCalibrationSource(
904
+ runId,
905
+ runManifest,
906
+ progress,
907
+ candidateReleaseId,
908
+ revalidate,
909
+ country,
910
+ staging.revision,
911
+ runManifestArtifact?.source ?? null,
912
+ progressArtifact?.source ?? null,
913
+ );
914
+ }
915
+ const diagnostics = await stagingHashedJsonOrNull(
916
+ diagnosticsPath,
917
+ revalidate,
918
+ country,
919
+ staging.revision,
920
+ );
921
+ if (!diagnostics) {
922
+ if (structured && diagnosticsArtifact) {
923
+ throw new IncompatibleStagingDataError(
924
+ "artifact calibration_diagnostics is declared but absent.",
925
+ );
926
+ }
927
+ return null;
928
+ }
929
+ const expectedDigest = stringValue(diagnosticsArtifact?.sha256);
930
+ if (structured && diagnostics.sha256 !== expectedDigest) {
931
+ throw new IncompatibleStagingDataError(
932
+ `artifact calibration_diagnostics digest does not match its run manifest declaration.`,
933
+ );
934
+ }
935
+ const [buildManifest, releaseManifest] = await Promise.all([
936
+ stagingHashedJsonOrNull(
937
+ `runs/${runId}/build_manifest.json`,
938
+ revalidate,
939
+ country,
940
+ staging.revision,
941
+ ),
942
+ stagingHashedJsonOrNull(
943
+ `runs/${runId}/release_manifest.json`,
944
+ revalidate,
945
+ country,
946
+ staging.revision,
947
+ ),
948
+ ]);
949
+ const updatedAt = stringValue(progress?.updated_at) ??
950
+ stringValue(runManifest?.updated_at);
951
+ const calibration = buildCalibration(
952
+ diagnostics.payload,
953
+ candidateReleaseId,
954
+ updatedAt,
955
+ buildManifest?.payload ?? {},
956
+ releaseManifest?.payload ?? {},
957
+ {},
958
+ country,
959
+ "huggingface_live",
960
+ diagnostics.sha256,
961
+ staging.revision,
962
+ );
963
+ return {
964
+ calibration,
965
+ candidateReleaseId,
966
+ updatedAt,
967
+ stagingRepo: staging.repo,
968
+ stagingRevision: staging.revision,
969
+ sourceArtifacts: {
970
+ calibrationDiagnostics: diagnostics.source,
971
+ buildManifest: buildManifest?.source ?? null,
972
+ releaseManifest: releaseManifest?.source ?? null,
973
+ stagingRunManifest: runManifestArtifact?.source ?? null,
974
+ stagingProgress: progressArtifact?.source ?? null,
975
+ stagedDatasetReceipt: null,
976
+ },
977
+ };
978
+ }
979
+
980
+ export async function loadStagingTargetChangeDataset(
981
+ runId: string,
982
+ releaseId: string,
983
+ country: MicrocosmCountry = "us",
984
+ ): Promise<TargetChangeDataset | null> {
985
+ if (stagingUnavailableReason(country)) return null;
986
+ assertSafeReleaseId(runId, "run");
987
+ assertSafeReleaseOrBuildFolderId(releaseId, "release");
988
+ const progress = await stagingJsonOrNull(
989
+ `runs/${runId}/progress.json`,
990
+ TARGET_CHANGE_MUTABLE_CACHE_SECONDS,
991
+ country,
992
+ );
993
+ const parsedProgress = progress == null ? null : parseStagingProgress(progress);
994
+ validateStagingRunConsistency(runId, { progress: parsedProgress });
995
+ const ttlSeconds = stagingTargetChangeCacheTtlSeconds(parsedProgress?.status);
996
+ const cacheKey = `${country}:${runId}:${releaseId}`;
997
+ const now = Date.now();
998
+ for (const [key, entry] of targetChangeCache) {
999
+ if (entry.expiresAt <= now) targetChangeCache.delete(key);
1000
+ }
1001
+ const cached = targetChangeCache.get(cacheKey);
1002
+ if (cached && cached.expiresAt > now) return cached.promise;
1003
+
1004
+ const promise = Promise.all([
1005
+ loadRelease(releaseId, TARGET_CHANGE_FINAL_CACHE_SECONDS, country),
1006
+ loadStagingCalibration(runId, ttlSeconds, country),
1007
+ ]).then(([release, candidate]) =>
1008
+ candidate ? buildTargetChangeDataset(release, candidate) : null,
1009
+ );
1010
+ targetChangeCache.set(cacheKey, {
1011
+ expiresAt: now + ttlSeconds * 1000,
1012
+ promise,
1013
+ });
1014
+ while (targetChangeCache.size > TARGET_CHANGE_CACHE_LIMIT) {
1015
+ const oldest = targetChangeCache.keys().next().value;
1016
+ if (typeof oldest !== "string") break;
1017
+ targetChangeCache.delete(oldest);
1018
+ }
1019
+ try {
1020
+ const result = await promise;
1021
+ if (!result) targetChangeCache.delete(cacheKey);
1022
+ return result;
1023
+ } catch (error) {
1024
+ targetChangeCache.delete(cacheKey);
1025
+ throw error;
1026
+ }
1027
+ }
1028
+
1029
+ export async function loadStagingTargetChangeDatasetFromBuild(
1030
+ runId: string,
1031
+ currentBuildArtifactId: string,
1032
+ country: MicrocosmCountry = "us",
1033
+ ): Promise<TargetChangeDataset | null> {
1034
+ if (stagingUnavailableReason(country)) return null;
1035
+ assertSafeReleaseId(runId, "run");
1036
+ const progress = await stagingJsonOrNull(
1037
+ `runs/${runId}/progress.json`,
1038
+ TARGET_CHANGE_MUTABLE_CACHE_SECONDS,
1039
+ country,
1040
+ );
1041
+ const parsedProgress = progress == null ? null : parseStagingProgress(progress);
1042
+ validateStagingRunConsistency(runId, { progress: parsedProgress });
1043
+ const ttlSeconds = stagingTargetChangeCacheTtlSeconds(parsedProgress?.status);
1044
+ const cacheKey = `${country}:${runId}:build:${currentBuildArtifactId}`;
1045
+ const now = Date.now();
1046
+ for (const [key, entry] of targetChangeCache) {
1047
+ if (entry.expiresAt <= now) targetChangeCache.delete(key);
1048
+ }
1049
+ const cached = targetChangeCache.get(cacheKey);
1050
+ if (cached && cached.expiresAt > now) return cached.promise;
1051
+
1052
+ const promise = Promise.all([
1053
+ loadCalibrationComparisonSource(country, currentBuildArtifactId),
1054
+ loadStagingCalibration(runId, ttlSeconds, country),
1055
+ ]).then(([current, candidate]) =>
1056
+ candidate
1057
+ ? buildTargetChangeDatasetFromSummaryAndCalibration(
1058
+ {
1059
+ country,
1060
+ comparison: current.index.targetComparison,
1061
+ targets: current.targetSummaries,
1062
+ },
1063
+ candidate,
1064
+ )
1065
+ : null,
1066
+ );
1067
+ targetChangeCache.set(cacheKey, {
1068
+ promise,
1069
+ expiresAt: now + ttlSeconds * 1000,
1070
+ });
1071
+ while (targetChangeCache.size > TARGET_CHANGE_CACHE_LIMIT) {
1072
+ const oldest = targetChangeCache.keys().next().value;
1073
+ if (typeof oldest !== "string") break;
1074
+ targetChangeCache.delete(oldest);
1075
+ }
1076
+ try {
1077
+ const result = await promise;
1078
+ if (!result) targetChangeCache.delete(cacheKey);
1079
+ return result;
1080
+ } catch (error) {
1081
+ targetChangeCache.delete(cacheKey);
1082
+ throw error;
1083
+ }
1084
+ }
1085
+
1086
+ export async function loadStagingRun(
1087
+ runId: string,
1088
+ revalidate: number,
1089
+ country: MicrocosmCountry = "us",
1090
+ ): Promise<StagingRunDetail> {
1091
+ const unavailable = unavailableStaging(country);
1092
+ if (unavailable) {
1093
+ return {
1094
+ ...unavailable,
1095
+ run_id: runId,
1096
+ candidate_release_id: null,
1097
+ release_id: null,
1098
+ country_code: null,
1099
+ run_kind: null,
1100
+ non_release: null,
1101
+ schema_version: null,
1102
+ delivery: null,
1103
+ progress: null,
1104
+ run_manifest: null,
1105
+ calibration_progress: null,
1106
+ events: [],
1107
+ has_calibration: false,
1108
+ calibration: null,
1109
+ reform_validation: null,
1110
+ build_manifest: null,
1111
+ release_manifest: null,
1112
+ };
1113
+ }
1114
+ assertSafeReleaseId(runId, "run");
1115
+ const repository = stagingSource(country);
1116
+ const [
1117
+ progressRaw,
1118
+ runManifestRaw,
1119
+ calibrationProgressRaw,
1120
+ eventsText,
1121
+ cal,
1122
+ reformValidationRaw,
1123
+ ] = await Promise.all([
1124
+ stagingJsonOrNull(`runs/${runId}/progress.json`, revalidate, country),
1125
+ stagingJsonOrNull(`runs/${runId}/run_manifest.json`, revalidate, country),
1126
+ stagingJsonOrNull(
1127
+ `runs/${runId}/calibration_progress.json`,
1128
+ revalidate,
1129
+ country,
1130
+ ),
1131
+ stagingTextOrNull(`runs/${runId}/events.ndjson`, revalidate, country),
1132
+ loadStagingCalibration(runId, revalidate, country),
1133
+ stagingJsonOrNull(`runs/${runId}/reform_validation.json`, revalidate, country),
1134
+ ]);
1135
+ const progress = progressRaw == null ? null : parseStagingProgress(progressRaw);
1136
+ const runManifest =
1137
+ runManifestRaw == null ? null : parseStagingManifest(runManifestRaw);
1138
+ const calibrationProgress =
1139
+ calibrationProgressRaw == null
1140
+ ? null
1141
+ : parseStagingCalibrationProgress(calibrationProgressRaw);
1142
+ const events = parseStagingEvents(eventsText);
1143
+ validateStagingRunConsistency(runId, {
1144
+ progress,
1145
+ runManifest,
1146
+ calibrationProgress,
1147
+ events,
1148
+ });
1149
+ const candidateReleaseId =
1150
+ stringValue(progress?.candidate_release_id) ??
1151
+ stringValue(runManifest?.candidate_release_id) ??
1152
+ runId;
1153
+ const identity = progress ?? runManifest;
1154
+ return {
1155
+ available: true,
1156
+ source_repo: repository.repo,
1157
+ revision: repository.revision,
1158
+ run_id: runId,
1159
+ candidate_release_id: candidateReleaseId,
1160
+ release_id: stringValue(identity?.release_id),
1161
+ country_code: stringValue(identity?.country_code),
1162
+ run_kind: stringValue(identity?.run_kind),
1163
+ non_release: booleanValue(identity?.non_release),
1164
+ schema_version: schemaVersionValue(identity?.schema_version),
1165
+ delivery: objectOrNull(identity?.delivery),
1166
+ progress,
1167
+ run_manifest: runManifest,
1168
+ calibration_progress: calibrationProgress,
1169
+ events,
1170
+ has_calibration: cal != null,
1171
+ calibration: cal ? latestMicrocosmCalibrationSummary(cal) : null,
1172
+ reform_validation: reformValidationRaw
1173
+ ? buildReformValidation(
1174
+ reformValidationRaw,
1175
+ candidateReleaseId,
1176
+ stringValue(progress?.updated_at),
1177
+ )
1178
+ : null,
1179
+ build_manifest: cal?.build_manifest ?? null,
1180
+ release_manifest: cal?.release_manifest ?? null,
1181
+ };
1182
+ }
1183
+
1184
+ // Telemetry only (progress, manifest, calibration progress, events), without
1185
+ // the candidate diagnostics loadStagingRun also resolves. The build monitor
1186
+ // reads every run this way to time stages across runs.
1187
+ export async function loadStagingRunTelemetry(
1188
+ runId: string,
1189
+ revalidate: number,
1190
+ country: MicrocosmCountry = "us",
1191
+ ) {
1192
+ assertSafeReleaseId(runId, "run");
1193
+ const [progressRaw, runManifestRaw, calibrationProgressRaw, eventsText] =
1194
+ await Promise.all([
1195
+ stagingJsonOrNull(`runs/${runId}/progress.json`, revalidate, country),
1196
+ stagingJsonOrNull(`runs/${runId}/run_manifest.json`, revalidate, country),
1197
+ stagingJsonOrNull(`runs/${runId}/calibration_progress.json`, revalidate, country),
1198
+ stagingTextOrNull(`runs/${runId}/events.ndjson`, revalidate, country),
1199
+ ]);
1200
+ const progress = progressRaw == null ? null : parseStagingProgress(progressRaw);
1201
+ const runManifest =
1202
+ runManifestRaw == null ? null : parseStagingManifest(runManifestRaw);
1203
+ const calibrationProgress =
1204
+ calibrationProgressRaw == null
1205
+ ? null
1206
+ : parseStagingCalibrationProgress(calibrationProgressRaw);
1207
+ const events = parseStagingEvents(eventsText);
1208
+ validateStagingRunConsistency(runId, {
1209
+ progress,
1210
+ runManifest,
1211
+ calibrationProgress,
1212
+ events,
1213
+ });
1214
+ return {
1215
+ run_id: runId,
1216
+ progress,
1217
+ run_manifest: runManifest,
1218
+ calibration_progress: calibrationProgress,
1219
+ events,
1220
+ };
1221
+ }
1222
+
1223
+ export async function loadStagingReformValidationRaw(
1224
+ runId: string,
1225
+ revalidate: number,
1226
+ country: MicrocosmCountry = "us",
1227
+ ): Promise<JsonObject | null> {
1228
+ if (stagingUnavailableReason(country)) return null;
1229
+ assertSafeReleaseId(runId, "run");
1230
+ return stagingJsonOrNull(
1231
+ `runs/${runId}/reform_validation.json`,
1232
+ revalidate,
1233
+ country,
1234
+ );
1235
+ }
1236
+
1237
+ export async function loadStagingTargetDiagnostics(
1238
+ requestUrl: string,
1239
+ runId: string,
1240
+ revalidate: number,
1241
+ country: MicrocosmCountry = "us",
1242
+ ) {
1243
+ const unavailable = unavailableStaging(country);
1244
+ if (unavailable) return { ...unavailable, run_id: runId };
1245
+ const cal = await loadStagingCalibration(runId, revalidate, country);
1246
+ if (!cal) {
1247
+ return {
1248
+ available: false,
1249
+ run_id: runId,
1250
+ detail: "This staging run has not uploaded calibration_diagnostics.json yet.",
1251
+ };
1252
+ }
1253
+ return latestMicrocosmTargetDiagnosticsPage(requestUrl, cal);
1254
+ }
1255
+
1256
+ // --- which release a staging candidate is compared with -----------------
1257
+ // A national candidate is compared with the country's current release, the
1258
+ // build the dashboard manifest marks latest (for the UK, the one
1259
+ // latest-national.json names). A local-area candidate calibrates local
1260
+ // geographies the national release does not, so it is compared with the
1261
+ // local-area release instead. That release has no pointer file and is never
1262
+ // promoted, so its most recently published build, as the dashboard manifest
1263
+ // records it, is used. A run is a local-area candidate when its run
1264
+ // manifest's pipeline id is one the country registers as local-area: no
1265
+ // staged receipt or manifest records a dataset role, and the dataset file
1266
+ // names change between builds.
1267
+
1268
+ export type StagingComparisonBasis = "current_release" | "newest_local_area_release";
1269
+
1270
+ export interface StagingComparisonRelease {
1271
+ release_id: string;
1272
+ basis: StagingComparisonBasis;
1273
+ /** The run's pipeline builds local-area candidates. */
1274
+ local_area_candidate: boolean;
1275
+ }
1276
+
1277
+ export interface StagingComparisonReleaseDependencies {
1278
+ runPipelineId(runId: string, country: MicrocosmCountry): Promise<string | null>;
1279
+ currentReleaseId(country: MicrocosmCountry): Promise<string>;
1280
+ newestLocalAreaReleaseId(country: MicrocosmCountry): Promise<string | null>;
1281
+ }
1282
+
1283
+ /** The `pipeline.id` a staging run's manifest records, or null without one. */
1284
+ export async function stagingRunPipelineId(
1285
+ runId: string,
1286
+ revalidate: number,
1287
+ country: MicrocosmCountry,
1288
+ ): Promise<string | null> {
1289
+ assertSafeReleaseId(runId, "run");
1290
+ const manifest = await stagingJsonOrNull(`runs/${runId}/run_manifest.json`, revalidate, country);
1291
+ const pipelineId = asObject(manifest?.pipeline).id;
1292
+ return typeof pipelineId === "string" && pipelineId.trim() ? pipelineId.trim() : null;
1293
+ }
1294
+
1295
+ /**
1296
+ * The most recently published release build whose release is local-area, by
1297
+ * the dataset roles `releases` carries (read from releases.json, or from each
1298
+ * release manifest, as the release picker reads them) and the publication
1299
+ * time the dashboard manifest records. A build releases.json marks withdrawn
1300
+ * is never chosen.
1301
+ */
1302
+ export function newestPublishedLocalAreaRelease(
1303
+ manifest: CalibrationTreeManifest,
1304
+ country: MicrocosmCountry,
1305
+ releases: readonly ReleaseEntry[],
1306
+ ): CalibrationTreeManifestEntry | null {
1307
+ const localAreaReleases = new Set(
1308
+ releases
1309
+ .filter((release) => release.is_local_area && release.withdrawn !== true)
1310
+ .map((release) => release.release_id),
1311
+ );
1312
+ const builds = (manifest.countries[country]?.builds ?? []).filter(
1313
+ (build) =>
1314
+ build.kind === "release" &&
1315
+ build.releaseId != null &&
1316
+ localAreaReleases.has(build.releaseId),
1317
+ );
1318
+ return calibrationBuildsNewestFirst(builds)[0] ?? null;
1319
+ }
1320
+
1321
+ /**
1322
+ * The releases a local-area Staging candidate may be compared with, with
1323
+ * their roles. A repository with releases.json lists the builds it names and
1324
+ * nothing else; one without lists the folders on main and its published
1325
+ * tagged builds. A releases.json that cannot be read or is refused throws,
1326
+ * so the candidate gets no baseline.
1327
+ */
1328
+ export async function stagingBaselineReleases(
1329
+ revalidate: number,
1330
+ country: MicrocosmCountry,
1331
+ manifest: CalibrationTreeManifest,
1332
+ ): Promise<ReleaseEntry[]> {
1333
+ const recorded = await loadRecordedReleases(revalidate, country, manifest);
1334
+ if (recorded) return recorded;
1335
+ // The published tagged builds are the ones the folder listing cannot name.
1336
+ const folders = await loadReleases(revalidate, country);
1337
+ const tagged = await loadPublishedCutReleases(revalidate, country, manifest, folders);
1338
+ return [...folders, ...tagged];
1339
+ }
1340
+
1341
+ function defaultStagingComparisonReleaseDependencies(
1342
+ revalidate: number,
1343
+ ): StagingComparisonReleaseDependencies {
1344
+ return {
1345
+ runPipelineId: (runId, country) => stagingRunPipelineId(runId, revalidate, country),
1346
+ currentReleaseId: async (country) =>
1347
+ (await loadPointerReleaseId(revalidate, country)).release_id,
1348
+ newestLocalAreaReleaseId: async (country) => {
1349
+ const { manifest } = await readCalibrationTreeManifest();
1350
+ const releases = await stagingBaselineReleases(revalidate, country, manifest);
1351
+ return newestPublishedLocalAreaRelease(manifest, country, releases)?.releaseId ?? null;
1352
+ },
1353
+ };
1354
+ }
1355
+
1356
+ export async function resolveStagingComparisonRelease(
1357
+ runId: string,
1358
+ country: MicrocosmCountry,
1359
+ dependencies: StagingComparisonReleaseDependencies =
1360
+ defaultStagingComparisonReleaseDependencies(300),
1361
+ ): Promise<StagingComparisonRelease> {
1362
+ const localAreaPipelines = stagingLocalAreaPipelines(country);
1363
+ const pipelineId = localAreaPipelines.length
1364
+ ? await dependencies.runPipelineId(runId, country)
1365
+ : null;
1366
+ const localAreaCandidate = pipelineId != null && localAreaPipelines.includes(pipelineId);
1367
+ if (localAreaCandidate) {
1368
+ const localAreaRelease = await dependencies.newestLocalAreaReleaseId(country);
1369
+ if (localAreaRelease) {
1370
+ return {
1371
+ release_id: localAreaRelease,
1372
+ basis: "newest_local_area_release",
1373
+ local_area_candidate: true,
1374
+ };
1375
+ }
1376
+ }
1377
+ return {
1378
+ release_id: await dependencies.currentReleaseId(country),
1379
+ basis: "current_release",
1380
+ local_area_candidate: localAreaCandidate,
1381
+ };
1382
+ }
1383
+
1384
+ /** A staging run compared with a release, as `/microcosm/staging/compare` returns it. */
1385
+ export type StagingComparison = Awaited<ReturnType<typeof loadStagingComparison>>;
1386
+
1387
+ export async function loadStagingComparison(
1388
+ runId: string,
1389
+ releaseId: string,
1390
+ revalidate: number,
1391
+ country: MicrocosmCountry = "us",
1392
+ ) {
1393
+ const unavailable = unavailableStaging(country);
1394
+ if (unavailable) return { ...unavailable, run_id: runId };
1395
+ const [release, staging] = await Promise.all([
1396
+ loadRelease(releaseId || "latest", revalidate, country),
1397
+ loadStagingCalibration(runId, revalidate, country),
1398
+ ]);
1399
+ if (!staging) {
1400
+ return {
1401
+ available: false,
1402
+ run_id: runId,
1403
+ detail: "This staging run has not uploaded calibration_diagnostics.json yet.",
1404
+ };
1405
+ }
1406
+ return {
1407
+ available: true,
1408
+ run_id: runId,
1409
+ ...buildComparison(release, staging),
1410
+ };
1411
+ }