diff --git a/.changeset/config.json b/.changeset/config.json index 7b30eb5c..670ea8a5 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -3,7 +3,7 @@ "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [ - ["@mostlyrightmd/core", "@mostlyrightmd/weather", "@mostlyrightmd/markets", "mostlyright"] + ["@mostlyrightmd/core", "@mostlyrightmd/weather", "@mostlyrightmd/markets", "@mostlyrightmd/econ", "mostlyright"] ], "linked": [], "access": "public", diff --git a/.github/workflows/release-ts.yml b/.github/workflows/release-ts.yml index ac496961..5b777699 100644 --- a/.github/workflows/release-ts.yml +++ b/.github/workflows/release-ts.yml @@ -1,14 +1,15 @@ name: Release (npm OIDC trusted publishing) -# TS-W7 TS-RELEASE-01 — publish the four TS packages to npm on every vts-* tag. +# TS-W7 TS-RELEASE-01 — publish the five TS packages to npm on every vts-* tag. # # Trusted publishing via OIDC (no NPM_TOKEN in secrets); requires # `id-token: write` permission. Setup checklist before the first tagged # release (operator-gated, mirrors Python release.yml playbook): # # 1. On npmjs.com, register each scoped package as a "pending publisher": -# @mostlyrightmd/core, @mostlyrightmd/weather, @mostlyrightmd/markets, mostlyright -# pointed at repo helloiamvu/tradewinds, workflow filename +# @mostlyrightmd/core, @mostlyrightmd/weather, @mostlyrightmd/markets, +# @mostlyrightmd/econ, mostlyright +# pointed at repo mostlyrightmd/mostlyright-sdk, workflow filename # `release-ts.yml`, environment name `npm`. # https://docs.npmjs.com/generating-provenance-statements # 2. If the `@mostlyright` npm scope is unavailable, fall back per @@ -157,6 +158,16 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + - name: Publish — @mostlyrightmd/econ + working-directory: packages-ts/econ + # pnpm publish (NOT npm publish): econ's @mostlyrightmd/core + # peerDependency is rewritten from the ^0.0.0 placeholder to ^ + # by the preflight above; pnpm also handles any workspace protocol at + # pack time. Mirrors the weather/markets scoped-package publish path. + run: pnpm publish --access public --tag ${{ steps.dist_tag.outputs.tag }} --no-git-checks + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + - name: Publish — mostlyright (meta) working-directory: packages-ts/meta # Use `pnpm publish` (NOT `npm publish`) because the meta package diff --git a/.github/workflows/test-ts.yml b/.github/workflows/test-ts.yml index 842740ba..c8ee4a40 100644 --- a/.github/workflows/test-ts.yml +++ b/.github/workflows/test-ts.yml @@ -3,15 +3,22 @@ name: Test (TypeScript) # TS-W0 / TS-CI-01 — TypeScript fast suite. # Pipeline: pnpm install -> codegen -> typecheck -> biome -> vitest -> size-limit. # +# Shape: a `test-ts-matrix` job does the work, fanning out over Node 20 + 22 +# (engines.node is ">=20"), and a separate `test-ts` job aggregates the matrix +# result to stay the single stable REQUIRED status check on `main`. +# # `test-ts` is a REQUIRED status check on `main`. A path-filtered required check # never reports for PRs that don't touch its paths, which leaves such PRs stuck # on "Expected — waiting for status" and unmergeable (e.g. a Python-only -# external fork PR). So on `pull_request` this job runs UNCONDITIONALLY and -# detects TS-relevant changes inside the job: when none changed, the heavy -# steps are skipped and the job still reports success — preserving the original -# "don't burn CI minutes when only Python source moves" intent while always -# emitting the required `test-ts` context. The `push` trigger stays -# path-filtered (off-PR pushes are not gated by required checks). +# external fork PR). So on `pull_request` the matrix legs run UNCONDITIONALLY and +# detect TS-relevant changes inside the job: when none changed, the heavy +# steps are skipped and each leg still reports success — preserving the original +# "don't burn CI minutes when only Python source moves" intent. The matrix legs +# surface as non-required contexts `test-ts-matrix (20)` / `test-ts-matrix (22)`; +# the `test-ts` gate job (needs: [test-ts-matrix], if: always()) fails unless +# every leg succeeded, so the required `test-ts` context is preserved unchanged +# and branch protection needs no edit when the Node matrix grows. The `push` +# trigger stays path-filtered (off-PR pushes are not gated by required checks). on: push: @@ -26,8 +33,12 @@ on: pull_request: {} jobs: - test-ts: + test-ts-matrix: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: ["20", "22"] steps: - uses: actions/checkout@v4 @@ -62,7 +73,7 @@ jobs: if: steps.changes.outputs.ts == 'true' uses: actions/setup-node@v4 with: - node-version: "20" + node-version: ${{ matrix.node-version }} cache: pnpm - name: Install dependencies @@ -107,3 +118,20 @@ jobs: if: steps.changes.outputs.ts == 'true' run: pnpm -r run size-limit continue-on-error: true + + # Stable required-check context. `test-ts-matrix` fans out over Node 20 + 22; + # this job aggregates their result so `test-ts` remains the single required + # status on `main` (branch protection needs no change). Fails if any matrix + # leg failed or was cancelled. + test-ts: + needs: [test-ts-matrix] + runs-on: ubuntu-latest + if: always() + steps: + - name: Gate on matrix result + run: | + if [ "${{ needs.test-ts-matrix.result }}" != "success" ]; then + echo "test-ts-matrix result: ${{ needs.test-ts-matrix.result }} — failing the required check." + exit 1 + fi + echo "test-ts-matrix succeeded on all Node versions." diff --git a/CHANGELOG.md b/CHANGELOG.md index 3842ed05..a93eaec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to `mostlyright`. The format follows [Keep a Changelog](http ## [Unreleased] +## [1.16.0] — 2026-07-14 — Economic indicators vertical: first published `mostlyrightmd-econ` / `@mostlyrightmd/econ` dist + +First release of the **econ vertical** — CPI, PPI, nonfarm payrolls, unemployment, +GDP, jobless claims, and Fed decisions for Kalshi + Polymarket — as the 4th +published PyPI dist (`mostlyrightmd-econ`) and 5th npm package +(`@mostlyrightmd/econ`), in lockstep with core/weather/markets/meta at 1.16.0. +(`1.15.0` shipped the general-first re-layering without econ, so econ debuts here.) + ### Added - **Econ surface conformance to the 1.13/1.14 source-identity contract @@ -27,6 +35,14 @@ All notable changes to `mostlyright`. The format follows [Keep a Changelog](http `dataset()`/`research()` are **not** modified (an `include_econ` covariate seam is an option-B question deferred to review); the econ↔weather firewall (`test_firewall.py`) stays green. +- **Packaging / release.** All published TS packages now declare + `engines.node >= 20` (matching the workspace root); the `test-ts` CI runs on + Node 20 **and** 22 via a matrix behind a stable required-check gate; and the + npm release path (`release-ts.yml`, `release-ts-preflight.mjs`, the changesets + `fixed` group) is wired for `@mostlyrightmd/econ` so it publishes to npm in + lockstep (PyPI was already wired in 29-01). Data-source licensing notices + completed: the FRED®/BEA required disclaimers plus the BLS "cannot vouch" + citation string; the BLS API ToS was verified permissive (no end-use controls). ## [1.15.0] — 2026-07-10 — General-first re-layering: the label axis, thin markets delegators, panels, and the contributor registry diff --git a/CLAUDE.md b/CLAUDE.md index 81ce78c3..f946fcf6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,6 +62,7 @@ This applies to every PLAN.md generated by `/gsd-plan-phase`, every PROJECT.md " - **Cache:** `$HOME/.mostlyright/cache/observations/{station}/{year}/{month}.parquet`. `filelock`-guarded. Cache-skip when queried month equals current LST month for that station (current month is incomplete; elapsed months stable). No user-visible `fresh=` kwarg. - **No preprocessing in v0.1.0.** Preserve `raw_metar` in observation rows so MetPy re-parse works (Vojtech's documented workflow). RH/feels_like preprocessing comes in Sprint 0.5+. - **Raw + preprocessed split:** quants want both. Default fetch returns raw; preprocessing is opt-in via explicit transform calls (Sprint 0.5+). +- **Data licensing:** Any change that adds/changes a data source, a fetcher, or cache persistence MUST consult [`.planning/research/DATA-LICENSING.md`](.planning/research/DATA-LICENSING.md). Per-source posture: **BLS / BEA / Fed Board = public domain** (US-gov works, 17 U.S.C. §105 — free to cache, train on, redistribute); **FRED / ALFRED = contract ToU** that bans ML/training use + store/cache/archive + restricts commercial use (St. Louis Fed is a Reserve Bank, not a federal agency). The **published default path calls agency sources directly** (public-domain) and makes NO FRED call; FRED is BYO-key opt-in (the user's own ToU acceptance) and FRED-derived rows are never persisted by default (`MOSTLYRIGHT_PERSIST_FRED=1` to opt in). Phase plans that add/change a source require a **"Data licensing"** section — same presence-check enforcement as the Dual-SDK "TS Parity" rule. (D-LIC-4) ## CWOP adapter (`mostlyright.weather.cwop`) diff --git a/docs/econ-vertical.md b/docs/econ-vertical.md index d369144a..87307d6e 100644 --- a/docs/econ-vertical.md +++ b/docs/econ-vertical.md @@ -285,11 +285,15 @@ certified by the Federal Reserve Bank of St. Louis. This product uses the Bureau of Economic Analysis (BEA) Data API but is not endorsed or certified by BEA. Nothing in this package is endorsed by, or implies endorsement by, any source agency or Reserve Bank. Please cite the source agencies when you -publish results derived from their data. +publish results derived from their data. Per the +[BLS Terms of Service](https://www.bls.gov/developers/termsOfService.htm), BLS +data additionally requires citing the retrieval date and stating: "BLS.gov +cannot vouch for the data or analyses derived from these data after the data +have been retrieved from BLS.gov." | Source | Legal basis | Cache/persist | ML/training | Notes | |---|---|---|---|---| -| BLS, BEA, DOL, Fed **Board** | US-gov works → public domain (17 U.S.C. §105) | Yes | Yes | Citation appreciated. BEA API rate limits: 100 req/min, 100 MB/min. | +| BLS, BEA, DOL, Fed **Board** | US-gov works → public domain (17 U.S.C. §105) | Yes | Yes | BLS ToS (read 2026-07-14): no end-use controls, but cite the retrieval date + the "BLS.gov cannot vouch…" disclaimer, no BLS logo. BEA API rate limits: 100 req/min, 100 MB/min. | | FRED / ALFRED (`alfred` rows) | Contract — [FRED® ToU](https://fred.stlouisfed.org/docs/api/terms_of_use.html) | **Prohibited by ToU** | **Prohibited by ToU** | Opt-in via your `FRED_API_KEY`; the keyless default path makes no FRED call. | | Jobless claims (`dol.icsa` rows) | DOL data is public domain, **but the bytes are fetched from FRED** (`ICSA`/`ICNSA` — DOL's machine path is bot-walled) | FRED ToU applies | FRED ToU applies | Same posture as `alfred` rows. | | Trading Economics | Proprietary — cannot license | n/a (never fetched) | n/a | The 48 TE-settled series ship the agency first print labeled `settlement_grade=False` (limitation 3). | diff --git a/package.json b/package.json index 4a317b78..67fd9aee 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "scripts": { "codegen": "pnpm -r run codegen", - "build": "pnpm --filter @mostlyrightmd/core run build && pnpm --filter @mostlyrightmd/weather run build && pnpm --filter @mostlyrightmd/markets run build && pnpm --filter mostlyright run build", + "build": "pnpm --filter @mostlyrightmd/core run build && pnpm --filter @mostlyrightmd/weather run build && pnpm --filter @mostlyrightmd/markets run build && pnpm --filter @mostlyrightmd/econ run build && pnpm --filter mostlyright run build", "test": "pnpm -r run test", "lint": "biome check .", "format": "biome format --write .", @@ -44,6 +44,11 @@ "path": "packages-ts/markets/dist/index.mjs", "limit": "15 KB" }, + { + "name": "@mostlyrightmd/econ (econ vertical surface, gzipped ESM)", + "path": "packages-ts/econ/dist/index.mjs", + "limit": "18 KB" + }, { "name": "mostlyright meta (W1 subset + 32-05 label axis, gzipped ESM)", "path": "packages-ts/meta/dist/index.mjs", diff --git a/packages-ts/core/package.json b/packages-ts/core/package.json index 1d213b71..51853f01 100644 --- a/packages-ts/core/package.json +++ b/packages-ts/core/package.json @@ -1,6 +1,6 @@ { "name": "@mostlyrightmd/core", - "version": "1.15.0", + "version": "1.16.0", "description": "TypeScript SDK core for quants, ML pipelines, and AI agents: types, schemas, validators, temporal-safety primitives, and the research() join over weather data + prediction-market settlements. Local-first, no hosted backend.", "keywords": [ "weather", @@ -31,6 +31,9 @@ "url": "https://github.com/mostlyrightmd/mostlyright-sdk/issues" }, "type": "module", + "engines": { + "node": ">=20" + }, "sideEffects": false, "main": "./dist/index.cjs", "module": "./dist/index.mjs", diff --git a/packages-ts/econ/package.json b/packages-ts/econ/package.json index e441a14c..1ad611bc 100644 --- a/packages-ts/econ/package.json +++ b/packages-ts/econ/package.json @@ -1,6 +1,6 @@ { "name": "@mostlyrightmd/econ", - "version": "1.15.0", + "version": "1.16.0", "description": "Economic-indicator data for TypeScript / Node — CPI, PPI, nonfarm payrolls (NFP), U3 unemployment, initial jobless claims, GDP, and Fed decisions, joined to Kalshi + Polymarket econ markets for leakage-free settlement pairs. First-print / ALFRED vintage discipline. Direct public-API access, no hosted backend.", "keywords": [ "economic-indicators", @@ -38,6 +38,9 @@ "url": "https://github.com/mostlyrightmd/mostlyright-sdk/issues" }, "type": "module", + "engines": { + "node": ">=20" + }, "main": "./dist/index.cjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", diff --git a/packages-ts/markets/package.json b/packages-ts/markets/package.json index 3f61fca0..ec037942 100644 --- a/packages-ts/markets/package.json +++ b/packages-ts/markets/package.json @@ -1,6 +1,6 @@ { "name": "@mostlyrightmd/markets", - "version": "1.15.0", + "version": "1.16.0", "description": "Prediction-market data for TypeScript / Node — Kalshi NHIGH/NLOW weather-contract resolvers, Polymarket discovery + settlement, and Kalshi + Polymarket trade history. For quants, backtesting, and ML training pipelines.", "keywords": [ "kalshi", @@ -31,6 +31,9 @@ "url": "https://github.com/mostlyrightmd/mostlyright-sdk/issues" }, "type": "module", + "engines": { + "node": ">=20" + }, "main": "./dist/index.cjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", diff --git a/packages-ts/meta/package.json b/packages-ts/meta/package.json index 82529b30..13cde3b4 100644 --- a/packages-ts/meta/package.json +++ b/packages-ts/meta/package.json @@ -1,6 +1,6 @@ { "name": "mostlyright", - "version": "1.15.0", + "version": "1.16.0", "description": "Public-data SDK for TypeScript — one import for quants, ML pipelines, and AI agents. Adapters ship weather (METAR, ASOS, GHCNh, NWS CLI) and prediction-market settlements (Kalshi NHIGH/NLOW, Polymarket) today; SEC filings, Federal Reserve series, court filings, FDA approvals, and equities are next. Local-first, no hosted backend.", "keywords": [ "weather", @@ -35,6 +35,9 @@ "url": "https://github.com/mostlyrightmd/mostlyright-sdk/issues" }, "type": "module", + "engines": { + "node": ">=20" + }, "main": "./dist/index.cjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", diff --git a/packages-ts/weather/package.json b/packages-ts/weather/package.json index e5606a4e..89be38c6 100644 --- a/packages-ts/weather/package.json +++ b/packages-ts/weather/package.json @@ -1,6 +1,6 @@ { "name": "@mostlyrightmd/weather", - "version": "1.15.0", + "version": "1.16.0", "description": "Weather data for TypeScript / Node — live METAR (AWC), ASOS archive (IEM), historical observations (GHCNh), and NWS climate text products (CLI). For quants, ML training pipelines, and weather-bot agents. Direct public-API access, no hosted backend.", "keywords": [ "weather", @@ -35,6 +35,9 @@ "url": "https://github.com/mostlyrightmd/mostlyright-sdk/issues" }, "type": "module", + "engines": { + "node": ">=20" + }, "main": "./dist/index.cjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index 0067b883..ec20a942 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mostlyrightmd" -version = "1.15.0" +version = "1.16.0" description = "Python SDK for quants, ML engineers, and AI agents — one interface to public data. Adapters ship weather + prediction-market settlements (Kalshi NHIGH/NLOW, Polymarket) today; SEC filings, Federal Reserve series, court filings, FDA approvals, and equities are next. Schema-versioned, leakage-free, local-first. Imports as `mostlyright`." readme = "README.md" license = "MIT" diff --git a/packages/econ/README.md b/packages/econ/README.md index 3620a3da..f5617688 100644 --- a/packages/econ/README.md +++ b/packages/econ/README.md @@ -16,7 +16,11 @@ This product uses the FRED® API but is not endorsed or certified by the Federal Reserve Bank of St. Louis. This product uses the Bureau of Economic Analysis (BEA) Data API but is not endorsed or certified by BEA. BLS, BEA, DOL, and Federal Reserve Board data are US-government works in the public domain; -citations to the source agencies are appreciated. Nothing in this package is +citations to the source agencies are appreciated. Per the +[BLS Terms of Service](https://www.bls.gov/developers/termsOfService.htm), when +you publish results derived from BLS data retrieved via this SDK, cite the +retrieval date and state: "BLS.gov cannot vouch for the data or analyses derived +from these data after the data have been retrieved from BLS.gov." Nothing in this package is endorsed by, or implies endorsement by, any source agency or Reserve Bank. The **keyless default path makes no FRED call**. The FRED/ALFRED vintage path is diff --git a/packages/econ/pyproject.toml b/packages/econ/pyproject.toml index 16256c2b..bf4f79a1 100644 --- a/packages/econ/pyproject.toml +++ b/packages/econ/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mostlyrightmd-econ" -version = "1.15.0" +version = "1.16.0" description = "Economic-indicator data for Python — CPI, PPI, nonfarm payrolls, unemployment, GDP, jobless claims, Fed decisions — from FRED/ALFRED, BLS, BEA, DOL, Federal Reserve. First-print vintage discipline for prediction-market settlement. Imports as `mostlyright.econ`." readme = "README.md" license = "MIT" diff --git a/packages/markets/pyproject.toml b/packages/markets/pyproject.toml index cdaff64a..5f471873 100644 --- a/packages/markets/pyproject.toml +++ b/packages/markets/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mostlyrightmd-markets" -version = "1.15.0" +version = "1.16.0" description = "Prediction-market data for Python — Kalshi NHIGH/NLOW weather-contract resolvers, Polymarket discovery + settlement, and Kalshi + Polymarket trade history. For quants, backtesting, and ML training pipelines. Imports as `mostlyright.markets`." readme = "README.md" license = "MIT" diff --git a/packages/weather/pyproject.toml b/packages/weather/pyproject.toml index bd2c6e5b..091ba2ae 100644 --- a/packages/weather/pyproject.toml +++ b/packages/weather/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mostlyrightmd-weather" -version = "1.15.0" +version = "1.16.0" description = "Weather data for Python — live METAR (AWC), ASOS archive (IEM), historical observations (GHCNh), and NWS climate text products (CLI). For quants, ML training pipelines, and weather-bot agents. Direct public-API access, no hosted backend. Imports as `mostlyright.weather`." readme = "README.md" license = "MIT" diff --git a/scripts/release-ts-preflight.mjs b/scripts/release-ts-preflight.mjs index 7f61661c..c81e9be8 100644 --- a/scripts/release-ts-preflight.mjs +++ b/scripts/release-ts-preflight.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // TS-W7 — release-ts.yml preflight. // -// Normalizes the pushed tag and asserts the four package.json versions match +// Normalizes the pushed tag and asserts the five package.json versions match // the expected version before any `pnpm publish` runs. Also rewrites the // inter-package peerDependencies range so the published packages declare // the correct cross-pin (pnpm only rewrites `workspace:*`, NOT plain @@ -19,6 +19,7 @@ const PACKAGES = [ "packages-ts/core", "packages-ts/weather", "packages-ts/markets", + "packages-ts/econ", "packages-ts/meta", ]; @@ -80,7 +81,7 @@ async function main() { // plain peerDependencies untouched (codex iter-5 P1; Phase 12 rename // moved the key from @tradewinds/core to @mostlyrightmd/core). const PEER_KEY = "@mostlyrightmd/core"; - for (const pkg of ["packages-ts/weather", "packages-ts/markets"]) { + for (const pkg of ["packages-ts/weather", "packages-ts/markets", "packages-ts/econ"]) { const path = resolve(ROOT, pkg, "package.json"); const pj = await readJson(path); if (pj.peerDependencies?.[PEER_KEY] === undefined) { diff --git a/uv.lock b/uv.lock index d7f3124b..25a26c8c 100644 --- a/uv.lock +++ b/uv.lock @@ -1629,7 +1629,7 @@ wheels = [ [[package]] name = "mostlyrightmd" -version = "1.15.0" +version = "1.16.0" source = { editable = "packages/core" } dependencies = [ { name = "httpx" }, @@ -1673,7 +1673,7 @@ provides-extras = ["parquet", "research", "polars"] [[package]] name = "mostlyrightmd-econ" -version = "1.15.0" +version = "1.16.0" source = { editable = "packages/econ" } dependencies = [ { name = "filelock" }, @@ -1703,7 +1703,7 @@ provides-extras = ["pandas"] [[package]] name = "mostlyrightmd-markets" -version = "1.15.0" +version = "1.16.0" source = { editable = "packages/markets" } dependencies = [ { name = "httpx" }, @@ -1759,7 +1759,7 @@ provides-extras = ["parquet", "polymarket", "trades", "earnings", "polars"] [[package]] name = "mostlyrightmd-weather" -version = "1.15.0" +version = "1.16.0" source = { editable = "packages/weather" } dependencies = [ { name = "filelock" },