Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
- Before providing a Staging preview URL, request `/api/microcosm/staging/runs` for the selected country and confirm that the JSON response reports the repository as available. Checking only the HTTP status is insufficient because the route can return HTTP 200 with `available: false`. Treat 401, 403, the 404 response Hugging Face may return for an unauthorized private repository, and any `available: false` response as a failed launch.
- When investigating a discrepant Microcosm calibration target, follow [the shared investigation workflow](docs/ai/workflows/investigate-microcosm-target.md) and its linked role-specific reviews.
- Before starting the application for Cross-dataset work, configure exactly one DIR or URL artifact location for each country you will use, as described in [the Cross-dataset application configuration](docs/cross-dataset-api.md#configure-the-application).
- Adding a Microcosm country is one entry in `frontend/lib/microcosm/countries.ts`; pages are gated by the registration's capabilities and the release artifact's `country` block, never by country code (see [the spec-driven countries note](docs/spec-driven-countries.md)).
- Adding a Microcosm country is one entry in `frontend/packages/calibration-tree/src/countries.ts`; pages are gated by the registration's capabilities and the release artifact's `country` block, never by country code (see [the spec-driven countries note](docs/spec-driven-countries.md)).
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

- When investigating a discrepant Microcosm calibration target, follow [the shared investigation workflow](docs/ai/workflows/investigate-microcosm-target.md) and its linked role-specific reviews.
- Before starting the application for Cross-dataset work, configure exactly one DIR or URL artifact location for each country you will use, as described in [the Cross-dataset application configuration](docs/cross-dataset-api.md#configure-the-application).
- Adding a Microcosm country is one entry in `frontend/lib/microcosm/countries.ts`; pages are gated by the registration's capabilities and the release artifact's `country` block, never by country code (see [the spec-driven countries note](docs/spec-driven-countries.md)).
- Adding a Microcosm country is one entry in `frontend/packages/calibration-tree/src/countries.ts`; pages are gated by the registration's capabilities and the release artifact's `country` block, never by country code (see [the spec-driven countries note](docs/spec-driven-countries.md)).
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ with `POPULACE_UK_STAGING_HF_REPO` or `POPULACE_UK_STAGING_HF_REVISION`. Never
use a `NEXT_PUBLIC_` variable for a private-repository credential.

The staging contract fixtures under
`frontend/lib/microcosm/fixtures/staging-contract/` are byte-identical copies
`frontend/packages/calibration-tree/src/fixtures/staging-contract/` are byte-identical copies
of Microcosm's canonical producer fixtures. The consumer tests pin each
version's `SHA256SUMS` digest and verify every listed file. A contract change
must update the canonical Microcosm fixture, its digest manifest, this copy,
Expand Down
23 changes: 22 additions & 1 deletion docs/calibration-tree-artifacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ The calibration explorer reads precomputed schema-6 JSON from private Vercel
Blob storage. The browser does not download calibration diagnostics or rebuild
the hierarchy. Schemas 1 through 5 are unsupported.

## Code

The builder, the schema-6 types, parsers and serializers, the Blob I/O, the
release and staging readers the builder reads from, and the publisher
(`src/publish-calibration-tree.ts`, run by `bun run publish:calibration-tree`)
live in the `@policyengine/calibration-tree` workspace package at
`frontend/packages/calibration-tree/`. The dashboard imports it through its
subpath exports, such as `@policyengine/calibration-tree/calibration-tree-bundle`.
The package imports only its own modules, Node built-ins and `@vercel/blob`,
and its boundary test enforces that.

`src/fixtures/calibration-tree-golden.json` records the exact bytes the builder
writes for representative US and UK release and staging inputs, the
comparisons between them, and the manifest. The golden tests require every
change to reproduce it. Regenerate it only for an intended output change, as
`src/test-support/calibration-tree-golden-cases.ts` describes.

## Required Blob folder schema

```text
Expand Down Expand Up @@ -355,14 +372,18 @@ fails publication and therefore fails the GitHub Actions job.

## Verification

Run from `frontend/`:
Run from `frontend/`; `bun test` includes the package's tests and
`bun run lint` also typechecks the package:

```sh
bun test
bun run lint
bun run build
```

To check the package on its own, run `bun test` and `bun run typecheck` from
`frontend/packages/calibration-tree/`.

Then verify that:

1. The manifest and all parts declare schema 6.
Expand Down
6 changes: 3 additions & 3 deletions docs/spec-driven-countries.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract: they are served only by `/microcosm/datasets` from

## Code-owned metadata that remains

`COUNTRY_REGISTRY` in `frontend/lib/microcosm/countries.ts` is the only required
`COUNTRY_REGISTRY` in `frontend/packages/calibration-tree/src/countries.ts` is the only required
registration point: country unions and parsers, selector lists, dataset and
national-geography labels, public/private link behavior, and page gating read
the registration or the artifact `country` block. Overview and target-browser
Expand Down Expand Up @@ -73,10 +73,10 @@ production tables.
### Country

`release_manifest.country` is read by `releaseCountry` in
`frontend/lib/microcosm/latest-artifact.ts` and served as `country` on the
`frontend/packages/calibration-tree/src/latest-artifact.ts` and served as `country` on the
overview summary and the target-diagnostics page (client type
`MicrocosmArtifactCountry`). Registration lives in
`frontend/lib/microcosm/countries.ts`; adding a country is one entry there.
`frontend/packages/calibration-tree/src/countries.ts`; adding a country is one entry there.

```json
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/builds/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NextResponse } from "next/server";

import { parseBuildSource } from "@/lib/microcosm/build-source";
import { loadBuildRuns } from "@/lib/microcosm/build-runs";
import { parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/builds/run/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NextResponse } from "next/server";

import { parseBuildSource } from "@/lib/microcosm/build-source";
import { loadBuildRun } from "@/lib/microcosm/build-runs";
import { parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/compare/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
loadPointerReleaseId,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 21_600;
export const runtime = "nodejs";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/comparison-tree/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { gzipSync } from "node:zlib";
import {
calibrationComparisonBuildArtifactId,
calibrationComparisonPairArtifactId,
} from "@/lib/microcosm/calibration-comparison-bundle";
} from "@policyengine/calibration-tree/calibration-comparison-bundle";
import {
createCalibrationComparisonTreeHandler,
type CalibrationComparisonTreeRouteDependencies,
Expand Down
12 changes: 6 additions & 6 deletions frontend/app/api/microcosm/comparison-tree/route.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { NextResponse } from "next/server";

import { withBasePath } from "@/lib/base-path";
import { ensureCalibrationComparison } from "@/lib/microcosm/calibration-comparison-blob";
import { ensureCalibrationComparison } from "@policyengine/calibration-tree/calibration-comparison-blob";
import {
calibrationComparisonBuildArtifactId,
calibrationComparisonPairArtifactId,
} from "@/lib/microcosm/calibration-comparison-bundle";
import { getCalibrationTreeBlob } from "@/lib/microcosm/calibration-tree-blob";
} from "@policyengine/calibration-tree/calibration-comparison-bundle";
import { getCalibrationTreeBlob } from "@policyengine/calibration-tree/calibration-tree-blob";
import { immutableCalibrationTreePartResponse } from "@/lib/microcosm/calibration-tree-http";
import {
isCalibrationTreePart,
isSha256,
type CalibrationTreePart,
} from "@/lib/microcosm/calibration-tree-artifact";
} from "@policyengine/calibration-tree/calibration-tree-artifact";
import {
isCountry,
selectableCountries,
type MicrocosmCountry,
} from "@/lib/microcosm/countries";
import type { TargetChangeMode } from "@/lib/microcosm/target-change";
} from "@policyengine/calibration-tree/countries";
import type { TargetChangeMode } from "@policyengine/calibration-tree/target-change";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, test } from "bun:test";

import type { CalibrationTreeComparisonTargetDetailResponse } from "@/lib/microcosm/calibration-tree-artifact";
import type { CalibrationTreeComparisonTargetDetailResponse } from "@policyengine/calibration-tree/calibration-tree-artifact";
import {
createCalibrationComparisonTargetDetailHandler,
type CalibrationComparisonTargetDetailRouteDependencies,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { NextResponse } from "next/server";

import { loadCalibrationComparisonTargetDetail } from "@/lib/microcosm/calibration-comparison-blob";
import { isSha256 } from "@/lib/microcosm/calibration-tree-artifact";
import { loadCalibrationComparisonTargetDetail } from "@policyengine/calibration-tree/calibration-comparison-blob";
import { isSha256 } from "@policyengine/calibration-tree/calibration-tree-artifact";
import {
isCountry,
selectableCountries,
type MicrocosmCountry,
} from "@/lib/microcosm/countries";
} from "@policyengine/calibration-tree/countries";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/cross-dataset/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { NextResponse } from "next/server";
import { ArtifactError } from "@/lib/cross-dataset/artifact";
import { crossDatasetApiResponse } from "@/lib/cross-dataset/query";
import { configuredCrossDatasetReader } from "@/lib/cross-dataset/source";
import { parseCountry } from "@/lib/microcosm/latest-artifact";
import { parseCountry } from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 300;
export const runtime = "nodejs";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/releases/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
loadReleases,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 60;

Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
parseCountry,
microcosmRepo,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 21_600;
export const runtime = "nodejs";
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/api/microcosm/staging/compare/route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { NextResponse } from "next/server";

import { hasCapability } from "@/lib/microcosm/countries";
import { hasCapability } from "@policyengine/calibration-tree/countries";
import {
loadPointerReleaseId,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
import { loadStagingComparison } from "@/lib/microcosm/staging-artifact";
} from "@policyengine/calibration-tree/latest-artifact";
import { loadStagingComparison } from "@policyengine/calibration-tree/staging-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/api/microcosm/staging/run/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { NextResponse } from "next/server";

import { hasCapability } from "@/lib/microcosm/countries";
import { parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { loadStagingRun } from "@/lib/microcosm/staging-artifact";
import { hasCapability } from "@policyengine/calibration-tree/countries";
import { parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";
import { loadStagingRun } from "@policyengine/calibration-tree/staging-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/api/microcosm/staging/runs/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";

import { loadStagingRuns } from "@/lib/microcosm/staging-artifact";
import { parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { loadStagingRuns } from "@policyengine/calibration-tree/staging-artifact";
import { parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
classifyApiError,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
import { isSha256 } from "@/lib/microcosm/calibration-tree-artifact";
} from "@policyengine/calibration-tree/latest-artifact";
import { isSha256 } from "@policyengine/calibration-tree/calibration-tree-artifact";
import {
loadStagingTargetChangeDataset,
loadStagingTargetChangeDatasetFromBuild,
} from "@/lib/microcosm/staging-artifact";
import type { TargetChangeMode } from "@/lib/microcosm/target-change";
} from "@policyengine/calibration-tree/staging-artifact";
import type { TargetChangeMode } from "@policyengine/calibration-tree/target-change";
import { buildTargetChangeTree } from "@/lib/microcosm/target-change-tree";

export const dynamic = "force-dynamic";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { NextResponse } from "next/server";

import { hasCapability } from "@/lib/microcosm/countries";
import { parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { loadStagingTargetDiagnostics } from "@/lib/microcosm/staging-artifact";
import { hasCapability } from "@policyengine/calibration-tree/countries";
import { parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";
import { loadStagingTargetDiagnostics } from "@policyengine/calibration-tree/staging-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/api/microcosm/staging/target-tree/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NextResponse } from "next/server";

import { buildCalibrationTree, type CalibrationTreeTarget } from "@/lib/microcosm/calibration-tree";
import { buildCalibrationTree, type CalibrationTreeTarget } from "@policyengine/calibration-tree/calibration-tree";
import { calibrationTreeRequestState } from "@/lib/microcosm/calibration-tree-request";
import { classifyApiError, parseCountry, scrub } from "@/lib/microcosm/latest-artifact";
import { loadStagingCalibration } from "@/lib/microcosm/staging-artifact";
import { classifyApiError, parseCountry, scrub } from "@policyengine/calibration-tree/latest-artifact";
import { loadStagingCalibration } from "@policyengine/calibration-tree/staging-artifact";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/target-diagnostics/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
loadRelease,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 21_600;
export const runtime = "nodejs";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/target-investigation/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
loadRelease,
parseCountry,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 21_600;

Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/target-treemap/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
parseCountry,
microcosmTargetTreemap,
scrub,
} from "@/lib/microcosm/latest-artifact";
} from "@policyengine/calibration-tree/latest-artifact";

export const revalidate = 21_600;
export const runtime = "nodejs";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/tree-manifest/route.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, test } from "bun:test";

import { emptyCalibrationTreeManifest, withCalibrationTreeManifestEntry } from "@/lib/microcosm/calibration-tree-manifest";
import { emptyCalibrationTreeManifest, withCalibrationTreeManifestEntry } from "@policyengine/calibration-tree/calibration-tree-manifest";
import { createCalibrationTreeManifestHandler } from "./route";

test("manifest API returns one country's current immutable release identity", async () => {
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/api/microcosm/tree-manifest/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NextResponse } from "next/server";

import { readCalibrationTreeManifest } from "@/lib/microcosm/calibration-tree-blob";
import { calibrationTreeCountryManifest } from "@/lib/microcosm/calibration-tree-manifest";
import { readCalibrationTreeManifest } from "@policyengine/calibration-tree/calibration-tree-blob";
import { calibrationTreeCountryManifest } from "@policyengine/calibration-tree/calibration-tree-manifest";
import {
isCountry,
selectableCountries,
} from "@/lib/microcosm/countries";
} from "@policyengine/calibration-tree/countries";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
Expand Down
8 changes: 4 additions & 4 deletions frontend/app/api/microcosm/tree/route.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { NextResponse } from "next/server";

import { withBasePath } from "@/lib/base-path";
import { getCalibrationTreeBlob } from "@/lib/microcosm/calibration-tree-blob";
import { getCalibrationTreeBlob } from "@policyengine/calibration-tree/calibration-tree-blob";
import { immutableCalibrationTreePartResponse } from "@/lib/microcosm/calibration-tree-http";
import {
isCalibrationTreePart,
isSha256,
type CalibrationTreePart,
} from "@/lib/microcosm/calibration-tree-artifact";
import { resolveCalibrationRelease } from "@/lib/microcosm/calibration-release-locator";
} from "@policyengine/calibration-tree/calibration-tree-artifact";
import { resolveCalibrationRelease } from "@policyengine/calibration-tree/calibration-release-locator";
import {
isCountry,
selectableCountries,
type MicrocosmCountry,
} from "@/lib/microcosm/countries";
} from "@policyengine/calibration-tree/countries";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/microcosm/variable/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { promisify } from "node:util";

import { NextResponse } from "next/server";

import { microcosmRepo, scrub } from "@/lib/microcosm/latest-artifact";
import { microcosmRepo, scrub } from "@policyengine/calibration-tree/latest-artifact";
import {
HOSTED_US_RELEASE,
reviewedVariableRelease,
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/microcosm/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AppShell } from "@/components/layout/app-shell";
import { MicrocosmOverviewView } from "@/components/microcosm/microcosm-overview-view";
import { publishedReleaseSelection } from "@/lib/microcosm/calibration-selection";
import { parseCountry } from "@/lib/microcosm/countries";
import { parseCountry } from "@policyengine/calibration-tree/countries";

interface MicrocosmOverviewPageProps {
searchParams?: Promise<Record<string, string | string[] | undefined>>;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/microcosm/targets/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AppShell } from "@/components/layout/app-shell";
import { MicrocosmTargetsView } from "@/components/microcosm/microcosm-targets-view";
import { publishedReleaseSelection } from "@/lib/microcosm/calibration-selection";
import { parseCountry } from "@/lib/microcosm/countries";
import { parseCountry } from "@policyengine/calibration-tree/countries";

interface MicrocosmTargetsPageProps {
searchParams?: Promise<Record<string, string | string[] | undefined>>;
Expand Down
Loading
Loading