@mostlyrightmd/core 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/internal/cache/types.ts","../../src/internal/cache/memory.ts","../../src/internal/cache/indexeddb.ts","../../src/internal/cache/versionedCacheStore.ts","../../src/data/generated/stations.ts","../../src/snapshot.ts","../../src/internal/cache/skip-rules.ts","../../src/internal/cache/keys.ts"],"sourcesContent":["// CacheStore — pluggable key/value contract for the @mostlyrightmd/core cache\n// layer. Three concrete implementations land in TS-W3:\n// - MemoryStore — Map-backed, no persistence (Cloudflare Workers default).\n// - FsStore — node:fs/promises + proper-lockfile (Node default).\n// - IndexedDBStore — idb + Web Locks API (browser; plan 02).\n//\n// `defaultCacheStore()` (plan 02) auto-detects at runtime per\n// TS-SDK-DESIGN §5.4.\n\n/** Cache entry envelope with optional TTL. */\nexport interface CacheEntry<T = unknown> {\n readonly value: T;\n /** Epoch ms when the entry expires. Absence = no expiry. */\n readonly expiresAt?: number;\n}\n\n/** Optional setters for cache writes. */\nexport interface CacheSetOptions {\n /** Time-to-live in milliseconds. Implementations may honor or ignore. */\n readonly ttlMs?: number;\n}\n\n/**\n * Pluggable key/value cache contract used throughout the SDK.\n *\n * All methods are async — concrete implementations may resolve immediately\n * (MemoryStore) or do I/O (FsStore / IndexedDBStore).\n *\n * Semantic contract:\n * - `get<T>(key)` returns the stored value or `null` on miss. NEVER throws\n * on miss.\n * - `set<T>(key, value, opts?)` overwrites. ttlMs is implementation-honored\n * (MemoryStore + IndexedDBStore honor it; FsStore ignores in v0.1).\n * - `delete(key)` is a no-op on miss; returns void.\n * - `withLock<T>(key, fn)` runs `fn` under a key-scoped exclusive lock and\n * releases on settle (resolve OR throw). Nested calls to the same key\n * serialize; calls to different keys MAY run in parallel.\n */\nexport interface CacheStore {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void>;\n delete(key: string): Promise<void>;\n withLock<T>(key: string, fn: () => Promise<T>): Promise<T>;\n}\n\n/**\n * Canonical lock identifier for a given cache key.\n *\n * Pure — same key → same lock id. Used by FsStore (proper-lockfile sidecar)\n * and IndexedDBStore (`navigator.locks.request(...)` name).\n */\nexport function lockKeyFor(key: string): string {\n return `mostlyright:cache:lock:${key}`;\n}\n\n/**\n * Canonical cache schema version stamp (Phase 21 21-03).\n *\n * Must match Python `mostlyright.weather.cache._cache_schema_version`\n * (set in Phase 18 18-08 to \"v2-phase18-integer-f\" after the ASOS\n * integer-°F precision fix). Embedded by `versionedCacheStore` into\n * every cache write so pre-bump entries silently re-fetch.\n *\n * Bump this string when a cache-shape change ships; existing cached\n * values invalidate on next read with no operator action required.\n */\nexport const CACHE_SCHEMA_VERSION = \"v2-phase18-integer-f\";\n","// MemoryStore — Map-backed CacheStore for ephemeral runtimes (Cloudflare\n// Workers, jsdom test envs without persistence). NOT shared across\n// processes — per-instance state.\n//\n// Value isolation via `structuredClone`: callers can mutate stored objects\n// after `.set()` without leaking changes back. Honors ttlMs with lazy\n// eviction at `.get()` time.\n//\n// withLock uses a per-key promise chain — pending lock-acquisitions queue\n// behind the current holder and run in FIFO order on settle.\n\nimport type { CacheEntry, CacheSetOptions, CacheStore } from \"./types.js\";\n\n/**\n * In-memory cache. Per-instance state; two MemoryStore instances do NOT\n * share state.\n *\n * - Values cloned via `structuredClone` so post-`set` mutation can't leak.\n * - ttlMs honored with lazy eviction on `get`.\n * - withLock serializes nested calls via a per-key promise chain.\n */\nexport class MemoryStore implements CacheStore {\n readonly #entries = new Map<string, CacheEntry<unknown>>();\n readonly #chain = new Map<string, Promise<unknown>>();\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const e = this.#entries.get(key);\n if (e === undefined) return null;\n if (e.expiresAt !== undefined && Date.now() >= e.expiresAt) {\n this.#entries.delete(key);\n return null;\n }\n // Defensive clone on read too — callers can't mutate stored value via\n // the returned reference either.\n return structuredClone(e.value) as T;\n }\n\n async set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void> {\n const cloned = structuredClone(value);\n const entry: CacheEntry<unknown> =\n opts?.ttlMs !== undefined\n ? { value: cloned, expiresAt: Date.now() + opts.ttlMs }\n : { value: cloned };\n this.#entries.set(key, entry);\n }\n\n async delete(key: string): Promise<void> {\n this.#entries.delete(key);\n }\n\n /**\n * Enumerate live (non-expired) keys with the given prefix.\n *\n * TS-W6 Wave 1: `availability()` uses this to count cached observation\n * months and climate years per station. Expired entries are evicted as a\n * side effect (same lazy-eviction policy as `.get`).\n */\n async listKeys(prefix: string): Promise<ReadonlyArray<string>> {\n const now = Date.now();\n const out: string[] = [];\n for (const [key, entry] of this.#entries) {\n if (entry.expiresAt !== undefined && now >= entry.expiresAt) {\n this.#entries.delete(key);\n continue;\n }\n if (key.startsWith(prefix)) {\n out.push(key);\n }\n }\n return Object.freeze(out);\n }\n\n async withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.#chain.get(key) ?? Promise.resolve();\n // Chain `fn` after `prev` regardless of whether `prev` resolved or\n // rejected — the lock holder's failure shouldn't poison the queue.\n const next = prev.then(\n () => fn(),\n () => fn(),\n );\n // Store an absorber as the new tail so a later prev.then() handles\n // both branches without producing an unhandled-rejection warning. The\n // caller still receives the original `next` promise (including any\n // rejection from `fn`).\n const absorbed = next.then(\n () => undefined,\n () => undefined,\n );\n this.#chain.set(key, absorbed);\n absorbed.finally(() => {\n if (this.#chain.get(key) === absorbed) {\n this.#chain.delete(key);\n }\n });\n return next;\n }\n}\n","// IndexedDBStore — idb + Web Locks API CacheStore for browsers.\n//\n// Per TS-CACHE-02, the canonical IndexedDB DB name is `mostlyright-cache-v1`.\n// Object store: `entries`. Schema: key = string, value = CacheEntry<T>.\n//\n// withLock prefers `navigator.locks.request(name, ...)` (Web Locks API,\n// Chrome 69+, Firefox 96+, Safari 15.4+; all production-browser baselines).\n// When `navigator.locks` is unavailable (jsdom default), falls back to the\n// same per-key in-process promise chain used by MemoryStore / FsStore —\n// edge runtimes (Workers without web-locks polyfills) get the in-process\n// guarantee at least.\n//\n// ttlMs is honored via lazy eviction at `get` time (matches FsStore).\n\nimport { type IDBPDatabase, openDB } from \"idb\";\n\nimport type { CacheEntry, CacheSetOptions, CacheStore } from \"./types.js\";\nimport { lockKeyFor } from \"./types.js\";\n\n/** Canonical DB name. Re-exported via the cache barrel. */\nexport const DB_NAME = \"mostlyright-cache-v1\";\n\nconst STORE_NAME = \"entries\";\nconst SCHEMA_VERSION = 1;\n\nexport interface IndexedDBStoreOptions {\n /** Override the DB name. Tests pass unique values per case so they don't pollute each other. */\n readonly dbName?: string;\n}\n\ninterface WebLocksApi {\n request: <T>(\n name: string,\n options: { mode: \"exclusive\" },\n fn: () => Promise<T> | T,\n ) => Promise<T>;\n}\n\nfunction getWebLocks(): WebLocksApi | null {\n if (typeof navigator === \"undefined\") return null;\n const nav = navigator as unknown as { locks?: WebLocksApi };\n return nav.locks ?? null;\n}\n\n/**\n * Browser CacheStore backed by IndexedDB (via idb) + Web Locks API.\n *\n * When `navigator.locks` is unavailable (jsdom, edge runtimes without\n * Web Locks), falls back to a per-key in-process promise chain.\n */\nexport class IndexedDBStore implements CacheStore {\n readonly #dbName: string;\n readonly #dbPromise: Promise<IDBPDatabase>;\n readonly #chain = new Map<string, Promise<unknown>>();\n\n constructor(opts: IndexedDBStoreOptions = {}) {\n this.#dbName = opts.dbName ?? DB_NAME;\n this.#dbPromise = openDB(this.#dbName, SCHEMA_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n },\n });\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const db = await this.#dbPromise;\n const entry = (await db.get(STORE_NAME, key)) as CacheEntry<T> | undefined;\n if (entry === undefined) return null;\n if (entry.expiresAt !== undefined && Date.now() >= entry.expiresAt) {\n // Lazy-evict — best-effort; ignore failures.\n try {\n await db.delete(STORE_NAME, key);\n } catch {\n // ignore\n }\n return null;\n }\n return entry.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void> {\n const db = await this.#dbPromise;\n const entry: CacheEntry<T> =\n opts?.ttlMs !== undefined ? { value, expiresAt: Date.now() + opts.ttlMs } : { value };\n await db.put(STORE_NAME, entry, key);\n }\n\n async delete(key: string): Promise<void> {\n const db = await this.#dbPromise;\n await db.delete(STORE_NAME, key);\n }\n\n /**\n * Enumerate keys with the given prefix using IndexedDB's bounded range\n * query. Live keys only — expired entries are lazy-evicted on read by\n * `get()`, so a stale-but-not-yet-evicted entry can appear here; callers\n * who care about expiration should `get()` to confirm.\n *\n * TS-W6 Wave 1: `availability()` uses this to count observation months and\n * climate years for a station.\n */\n async listKeys(prefix: string): Promise<ReadonlyArray<string>> {\n const db = await this.#dbPromise;\n // Build an inclusive lower bound and an exclusive upper bound using the\n // next-codepoint trick. IndexedDB's IDBKeyRange handles string ordering\n // by UTF-16 code units, which matches JS string comparison; we use the\n // Unicode max-codepoint as the upper sentinel so any key starting with\n // `prefix` lands inside the range.\n const range = IDBKeyRange.bound(prefix, `${prefix}￿`, false, false);\n const keys = (await db.getAllKeys(STORE_NAME, range)) as IDBValidKey[];\n const out: string[] = [];\n for (const k of keys) {\n if (typeof k === \"string\" && k.startsWith(prefix)) {\n out.push(k);\n }\n }\n return Object.freeze(out);\n }\n\n async withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const locks = getWebLocks();\n if (locks !== null) {\n // Web Locks API — production-browser path. Cross-tab safe.\n return locks.request<T>(lockKeyFor(key), { mode: \"exclusive\" }, () => fn());\n }\n // Fallback for jsdom / edge runtimes without navigator.locks: in-process\n // per-key promise chain (FIFO; matches MemoryStore semantics).\n const prev = this.#chain.get(key) ?? Promise.resolve();\n const next = prev.then(\n () => fn(),\n () => fn(),\n );\n const absorbed = next.then(\n () => undefined,\n () => undefined,\n );\n this.#chain.set(key, absorbed);\n absorbed.finally(() => {\n if (this.#chain.get(key) === absorbed) this.#chain.delete(key);\n });\n return next;\n }\n}\n","// versionedCacheStore — Phase 21 21-03.\n//\n// Schema-version invariant for the TS cache, matching Python's Phase 18\n// 18-08 invariant. Wraps any underlying CacheStore so reads with a stale\n// `_cache_schema_version` field return null (cache miss → re-fetch),\n// matching the parquet-metadata-based invariant on the Python side.\n//\n// Before: TS cache was generic key/value with no version stamping. After\n// Phase 18 lifted the ASOS integer-°F precision fix, pre-Phase-18 user\n// caches (with 0.06°F float values) would silently return stale values\n// on next call instead of re-fetching. Python embeds the version into\n// parquet metadata (pyarrow `kv_metadata`); TS embeds it as a sidecar\n// field in the stored JSON value.\n//\n// Wire-up: `defaultCacheStore()` wraps each concrete store\n// (IndexedDBStore / FsStore / MemoryStore) via this adapter so consumers\n// see the same `CacheStore` interface. The version wrap/unwrap is\n// invisible from the caller's perspective.\n//\n// Bump `CACHE_SCHEMA_VERSION` in `./types.ts` when the next cache-shape\n// change ships; existing cached values silently invalidate.\n\nimport type { CacheEntry, CacheSetOptions, CacheStore } from \"./types.js\";\n\n/** Sentinel field name embedded in every cached value. */\nconst VERSION_FIELD = \"_cache_schema_version\" as const;\n\n/** Wrapper shape stored under each key. */\nexport interface VersionedEntry<T = unknown> {\n readonly value: T;\n readonly _cache_schema_version: string;\n}\n\nfunction isVersionedEntry(v: unknown): v is VersionedEntry<unknown> {\n if (v === null || typeof v !== \"object\") return false;\n if (!(VERSION_FIELD in (v as Record<string, unknown>))) return false;\n return typeof (v as Record<string, unknown>)[VERSION_FIELD] === \"string\";\n}\n\n// Optional extension surface — some concrete stores (MemoryStore,\n// IndexedDBStore) expose `listKeys(prefix)` beyond the CacheStore\n// contract. The adapter forwards it transparently when present so\n// `availability()` and friends keep working.\ninterface ListKeysCapable {\n listKeys(prefix: string): Promise<ReadonlyArray<string>>;\n}\n\nfunction hasListKeys(s: CacheStore): s is CacheStore & ListKeysCapable {\n return typeof (s as Partial<ListKeysCapable>).listKeys === \"function\";\n}\n\nclass VersionedCacheStore implements CacheStore, ListKeysCapable {\n readonly #inner: CacheStore;\n readonly #version: string;\n\n constructor(inner: CacheStore, version: string) {\n if (typeof version !== \"string\" || version.length === 0) {\n throw new TypeError(\"versionedCacheStore: version must be a non-empty string\");\n }\n this.#inner = inner;\n this.#version = version;\n }\n\n /**\n * Test/diagnostics seam: return the underlying store so tests can assert\n * which concrete backend `defaultCacheStore()` selected. NOT a production\n * API — production code MUST use the wrapped store so version\n * invalidation fires on stale reads.\n *\n * @internal\n */\n __peekInner(): CacheStore {\n return this.#inner;\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const raw = await this.#inner.get<unknown>(key);\n if (raw === null) return null;\n if (!isVersionedEntry(raw)) {\n // Pre-21-03 cache entry (no version wrapper). Treat as miss; caller\n // will re-fetch with the new wrapper on the next set.\n return null;\n }\n if (raw._cache_schema_version !== this.#version) {\n // Mismatched schema version — stale. Treat as miss.\n return null;\n }\n return raw.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void> {\n const wrapped: VersionedEntry<T> = {\n value,\n [VERSION_FIELD]: this.#version,\n } as VersionedEntry<T>;\n await this.#inner.set(key, wrapped, opts);\n }\n\n async delete(key: string): Promise<void> {\n await this.#inner.delete(key);\n }\n\n async withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n return this.#inner.withLock(key, fn);\n }\n\n async listKeys(prefix: string): Promise<ReadonlyArray<string>> {\n if (hasListKeys(this.#inner)) {\n return this.#inner.listKeys(prefix);\n }\n return Object.freeze([]);\n }\n}\n\n/**\n * Wrap any CacheStore so reads validate `_cache_schema_version` and\n * writes embed it. The wrapper is transparent — callers continue to use\n * the same `CacheStore` interface.\n *\n * @param inner underlying store (MemoryStore / IndexedDBStore / FsStore)\n * @param version the schema version to embed; non-matching reads miss\n */\nexport function versionedCacheStore(inner: CacheStore, version: string): CacheStore {\n return new VersionedCacheStore(inner, version);\n}\n\n// Re-export the canonical version constant alongside the adapter — the\n// constant lives in `./types.ts` (single source of truth) but is\n// surfaced here too so callers writing\n// `versionedCacheStore(inner, CACHE_SCHEMA_VERSION)` import both from\n// the same module.\nexport { CACHE_SCHEMA_VERSION } from \"./types.js\";\n\n/**\n * Internal helper for tests + diagnostics: expose the raw envelope shape\n * so callers can pre-seed an underlying store with the wrapped shape\n * without round-tripping through this adapter.\n */\nexport function wrapForCache<T>(value: T, version: string): VersionedEntry<T> {\n return { value, [VERSION_FIELD]: version } as VersionedEntry<T>;\n}\n","// AUTO-GENERATED by @mostlyrightmd/codegen from schemas/stations.json.\n// DO NOT EDIT — regenerate with: pnpm codegen\n// Last manifest SHA recorded in schemas/EXPORT_MANIFEST.json\n\nexport interface StationInfo {\n code: string | null;\n ghcnh_id: string | null;\n icao: string;\n name: string | null;\n tz: string;\n latitude: number | null;\n longitude: number | null;\n country: string | null;\n venues: ReadonlyArray<string>;\n}\n\nexport const STATIONS: ReadonlyArray<StationInfo> = [\n {\n code: \"EDDB\",\n country: \"DE\",\n ghcnh_id: null,\n icao: \"EDDB\",\n latitude: 52.3667,\n longitude: 13.5033,\n name: \"Berlin Brandenburg\",\n tz: \"Europe/Berlin\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EDDF\",\n country: \"DE\",\n ghcnh_id: null,\n icao: \"EDDF\",\n latitude: 50.0379,\n longitude: 8.5622,\n name: \"Frankfurt am Main\",\n tz: \"Europe/Berlin\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EDDM\",\n country: \"DE\",\n ghcnh_id: null,\n icao: \"EDDM\",\n latitude: 48.3538,\n longitude: 11.7861,\n name: \"Munich Franz Josef Strauss\",\n tz: \"Europe/Berlin\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EFHK\",\n country: \"FI\",\n ghcnh_id: null,\n icao: \"EFHK\",\n latitude: 60.3172,\n longitude: 24.9633,\n name: \"Helsinki-Vantaa\",\n tz: \"Europe/Helsinki\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EGKK\",\n country: \"GB\",\n ghcnh_id: null,\n icao: \"EGKK\",\n latitude: 51.1481,\n longitude: -0.1903,\n name: \"London Gatwick\",\n tz: \"Europe/London\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EGLL\",\n country: \"GB\",\n ghcnh_id: null,\n icao: \"EGLL\",\n latitude: 51.4706,\n longitude: -0.4619,\n name: \"London Heathrow\",\n tz: \"Europe/London\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EHAM\",\n country: \"NL\",\n ghcnh_id: null,\n icao: \"EHAM\",\n latitude: 52.3086,\n longitude: 4.7639,\n name: \"Amsterdam Schiphol\",\n tz: \"Europe/Amsterdam\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EKCH\",\n country: \"DK\",\n ghcnh_id: null,\n icao: \"EKCH\",\n latitude: 55.6181,\n longitude: 12.6561,\n name: \"Copenhagen Kastrup\",\n tz: \"Europe/Copenhagen\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"EPWA\",\n country: \"PL\",\n ghcnh_id: null,\n icao: \"EPWA\",\n latitude: 52.1657,\n longitude: 20.9671,\n name: \"Warsaw Chopin\",\n tz: \"Europe/Warsaw\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"ESSA\",\n country: \"SE\",\n ghcnh_id: null,\n icao: \"ESSA\",\n latitude: 59.6519,\n longitude: 17.9186,\n name: \"Stockholm Arlanda\",\n tz: \"Europe/Stockholm\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"ATL\",\n country: \"US\",\n ghcnh_id: \"USW00013874\",\n icao: \"KATL\",\n latitude: 33.6407,\n longitude: -84.4277,\n name: \"Hartsfield-Jackson Atlanta International\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"AUS\",\n country: \"US\",\n ghcnh_id: \"USW00013904\",\n icao: \"KAUS\",\n latitude: 30.1975,\n longitude: -97.6664,\n name: \"Austin-Bergstrom International\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"BNA\",\n country: \"US\",\n ghcnh_id: \"USW00013897\",\n icao: \"KBNA\",\n latitude: 36.1245,\n longitude: -86.6782,\n name: \"Nashville International\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"BOS\",\n country: \"US\",\n ghcnh_id: \"USW00014739\",\n icao: \"KBOS\",\n latitude: 42.3656,\n longitude: -71.0096,\n name: \"Boston Logan International\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"CVG\",\n country: \"US\",\n ghcnh_id: \"USW00093814\",\n icao: \"KCVG\",\n latitude: 39.0488,\n longitude: -84.6678,\n name: \"Cincinnati/Northern Kentucky International\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"DCA\",\n country: \"US\",\n ghcnh_id: \"USW00013743\",\n icao: \"KDCA\",\n latitude: 38.8512,\n longitude: -77.0402,\n name: \"Washington Reagan National\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"DEN\",\n country: \"US\",\n ghcnh_id: \"USW00003017\",\n icao: \"KDEN\",\n latitude: 39.8561,\n longitude: -104.6737,\n name: \"Denver International\",\n tz: \"America/Denver\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"DFW\",\n country: \"US\",\n ghcnh_id: \"USW00003927\",\n icao: \"KDFW\",\n latitude: 32.8998,\n longitude: -97.0403,\n name: \"Dallas-Fort Worth International\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"DTW\",\n country: \"US\",\n ghcnh_id: \"USW00094847\",\n icao: \"KDTW\",\n latitude: 42.2124,\n longitude: -83.3534,\n name: \"Detroit Metropolitan Wayne County\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"HOU\",\n country: \"US\",\n ghcnh_id: \"USW00012918\",\n icao: \"KHOU\",\n latitude: 29.6454,\n longitude: -95.2789,\n name: \"Houston Hobby\",\n tz: \"America/Chicago\",\n venues: [],\n },\n {\n code: \"IAH\",\n country: \"US\",\n ghcnh_id: \"USW00012960\",\n icao: \"KIAH\",\n latitude: 29.9844,\n longitude: -95.3414,\n name: \"Houston George Bush Intercontinental\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"LAS\",\n country: \"US\",\n ghcnh_id: \"USW00023169\",\n icao: \"KLAS\",\n latitude: 36.084,\n longitude: -115.1537,\n name: \"Harry Reid (McCarran) International\",\n tz: \"America/Los_Angeles\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"LAX\",\n country: \"US\",\n ghcnh_id: \"USW00023174\",\n icao: \"KLAX\",\n latitude: 33.9425,\n longitude: -118.4081,\n name: \"Los Angeles International\",\n tz: \"America/Los_Angeles\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"MDW\",\n country: \"US\",\n ghcnh_id: \"USW00014819\",\n icao: \"KMDW\",\n latitude: 41.7868,\n longitude: -87.7522,\n name: \"Chicago Midway International\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"MIA\",\n country: \"US\",\n ghcnh_id: \"USW00012839\",\n icao: \"KMIA\",\n latitude: 25.7959,\n longitude: -80.287,\n name: \"Miami International\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"MSP\",\n country: \"US\",\n ghcnh_id: \"USW00014922\",\n icao: \"KMSP\",\n latitude: 44.8848,\n longitude: -93.2223,\n name: \"Minneapolis-St Paul International\",\n tz: \"America/Chicago\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"MSY\",\n country: \"US\",\n ghcnh_id: \"USW00012916\",\n icao: \"KMSY\",\n latitude: 29.9934,\n longitude: -90.258,\n name: \"New Orleans Louis Armstrong International\",\n tz: \"America/Chicago\",\n venues: [],\n },\n {\n code: \"NYC\",\n country: \"US\",\n ghcnh_id: \"USW00094728\",\n icao: \"KNYC\",\n latitude: 40.7789,\n longitude: -73.9692,\n name: \"Central Park, New York\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"OKC\",\n country: \"US\",\n ghcnh_id: \"USW00013967\",\n icao: \"KOKC\",\n latitude: 35.3931,\n longitude: -97.6007,\n name: \"Oklahoma City Will Rogers World\",\n tz: \"America/Chicago\",\n venues: [],\n },\n {\n code: \"PHL\",\n country: \"US\",\n ghcnh_id: \"USW00013739\",\n icao: \"KPHL\",\n latitude: 39.8721,\n longitude: -75.2411,\n name: \"Philadelphia International\",\n tz: \"America/New_York\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"PHX\",\n country: \"US\",\n ghcnh_id: \"USW00023183\",\n icao: \"KPHX\",\n latitude: 33.4373,\n longitude: -112.0078,\n name: \"Phoenix Sky Harbor International\",\n tz: \"America/Phoenix\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"SAT\",\n country: \"US\",\n ghcnh_id: \"USW00012921\",\n icao: \"KSAT\",\n latitude: 29.5337,\n longitude: -98.4698,\n name: \"San Antonio International\",\n tz: \"America/Chicago\",\n venues: [],\n },\n {\n code: \"SEA\",\n country: \"US\",\n ghcnh_id: \"USW00024233\",\n icao: \"KSEA\",\n latitude: 47.4502,\n longitude: -122.3088,\n name: \"Seattle-Tacoma International\",\n tz: \"America/Los_Angeles\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"SFO\",\n country: \"US\",\n ghcnh_id: \"USW00023234\",\n icao: \"KSFO\",\n latitude: 37.6213,\n longitude: -122.379,\n name: \"San Francisco International\",\n tz: \"America/Los_Angeles\",\n venues: [\n \"kalshi\",\n \"polymarket\",\n ],\n },\n {\n code: \"SLC\",\n country: \"US\",\n ghcnh_id: \"USW00024127\",\n icao: \"KSLC\",\n latitude: 40.7884,\n longitude: -111.9778,\n name: \"Salt Lake City International\",\n tz: \"America/Denver\",\n venues: [\n \"kalshi\",\n ],\n },\n {\n code: \"LEBL\",\n country: \"ES\",\n ghcnh_id: null,\n icao: \"LEBL\",\n latitude: 41.2974,\n longitude: 2.0833,\n name: \"Barcelona El Prat\",\n tz: \"Europe/Madrid\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LEMD\",\n country: \"ES\",\n ghcnh_id: null,\n icao: \"LEMD\",\n latitude: 40.4719,\n longitude: -3.5626,\n name: \"Madrid Barajas\",\n tz: \"Europe/Madrid\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LFPB\",\n country: \"FR\",\n ghcnh_id: null,\n icao: \"LFPB\",\n latitude: 48.9694,\n longitude: 2.4414,\n name: \"Paris Le Bourget\",\n tz: \"Europe/Paris\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LFPG\",\n country: \"FR\",\n ghcnh_id: null,\n icao: \"LFPG\",\n latitude: 49.0097,\n longitude: 2.5479,\n name: \"Paris Charles de Gaulle\",\n tz: \"Europe/Paris\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LFPO\",\n country: \"FR\",\n ghcnh_id: null,\n icao: \"LFPO\",\n latitude: 48.7233,\n longitude: 2.3794,\n name: \"Paris Orly\",\n tz: \"Europe/Paris\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LIMC\",\n country: \"IT\",\n ghcnh_id: null,\n icao: \"LIMC\",\n latitude: 45.6306,\n longitude: 8.7281,\n name: \"Milan Malpensa\",\n tz: \"Europe/Rome\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LIRF\",\n country: \"IT\",\n ghcnh_id: null,\n icao: \"LIRF\",\n latitude: 41.8003,\n longitude: 12.2389,\n name: \"Rome Fiumicino\",\n tz: \"Europe/Rome\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LOWW\",\n country: \"AT\",\n ghcnh_id: null,\n icao: \"LOWW\",\n latitude: 48.1103,\n longitude: 16.5697,\n name: \"Vienna International\",\n tz: \"Europe/Vienna\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"LSZH\",\n country: \"CH\",\n ghcnh_id: null,\n icao: \"LSZH\",\n latitude: 47.4647,\n longitude: 8.5492,\n name: \"Zurich\",\n tz: \"Europe/Zurich\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"NZAA\",\n country: \"NZ\",\n ghcnh_id: null,\n icao: \"NZAA\",\n latitude: -37.0081,\n longitude: 174.7917,\n name: \"Auckland\",\n tz: \"Pacific/Auckland\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"NZWN\",\n country: \"NZ\",\n ghcnh_id: null,\n icao: \"NZWN\",\n latitude: -41.3272,\n longitude: 174.8053,\n name: \"Wellington\",\n tz: \"Pacific/Auckland\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"OERK\",\n country: \"SA\",\n ghcnh_id: null,\n icao: \"OERK\",\n latitude: 24.9576,\n longitude: 46.6988,\n name: \"Riyadh King Khalid International\",\n tz: \"Asia/Riyadh\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"OMDB\",\n country: \"AE\",\n ghcnh_id: null,\n icao: \"OMDB\",\n latitude: 25.2532,\n longitude: 55.3657,\n name: \"Dubai International\",\n tz: \"Asia/Dubai\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"OTHH\",\n country: \"QA\",\n ghcnh_id: null,\n icao: \"OTHH\",\n latitude: 25.2731,\n longitude: 51.608,\n name: \"Doha Hamad International\",\n tz: \"Asia/Qatar\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"RCTP\",\n country: \"TW\",\n ghcnh_id: null,\n icao: \"RCTP\",\n latitude: 25.0777,\n longitude: 121.2328,\n name: \"Taipei Taoyuan\",\n tz: \"Asia/Taipei\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"RJAA\",\n country: \"JP\",\n ghcnh_id: null,\n icao: \"RJAA\",\n latitude: 35.7647,\n longitude: 140.3864,\n name: \"Tokyo Narita\",\n tz: \"Asia/Tokyo\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"RJTT\",\n country: \"JP\",\n ghcnh_id: null,\n icao: \"RJTT\",\n latitude: 35.5522,\n longitude: 139.78,\n name: \"Tokyo Haneda\",\n tz: \"Asia/Tokyo\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"RKSI\",\n country: \"KR\",\n ghcnh_id: null,\n icao: \"RKSI\",\n latitude: 37.4691,\n longitude: 126.4505,\n name: \"Seoul Incheon\",\n tz: \"Asia/Seoul\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"SAEZ\",\n country: \"AR\",\n ghcnh_id: null,\n icao: \"SAEZ\",\n latitude: -34.8222,\n longitude: -58.5358,\n name: \"Buenos Aires Ezeiza\",\n tz: \"America/Argentina/Buenos_Aires\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"SBGR\",\n country: \"BR\",\n ghcnh_id: null,\n icao: \"SBGR\",\n latitude: -23.4356,\n longitude: -46.4731,\n name: \"São Paulo Guarulhos\",\n tz: \"America/Sao_Paulo\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"UUEE\",\n country: \"RU\",\n ghcnh_id: null,\n icao: \"UUEE\",\n latitude: 55.9728,\n longitude: 37.4147,\n name: \"Moscow Sheremetyevo\",\n tz: \"Europe/Moscow\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"VABB\",\n country: \"IN\",\n ghcnh_id: null,\n icao: \"VABB\",\n latitude: 19.0887,\n longitude: 72.8679,\n name: \"Mumbai Chhatrapati Shivaji\",\n tz: \"Asia/Kolkata\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"VHHH\",\n country: \"HK\",\n ghcnh_id: null,\n icao: \"VHHH\",\n latitude: 22.308,\n longitude: 113.9185,\n name: \"Hong Kong International\",\n tz: \"Asia/Hong_Kong\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"VIDP\",\n country: \"IN\",\n ghcnh_id: null,\n icao: \"VIDP\",\n latitude: 28.5562,\n longitude: 77.1,\n name: \"Delhi Indira Gandhi\",\n tz: \"Asia/Kolkata\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"VTBS\",\n country: \"TH\",\n ghcnh_id: null,\n icao: \"VTBS\",\n latitude: 13.69,\n longitude: 100.7501,\n name: \"Bangkok Suvarnabhumi\",\n tz: \"Asia/Bangkok\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"WSSS\",\n country: \"SG\",\n ghcnh_id: null,\n icao: \"WSSS\",\n latitude: 1.3644,\n longitude: 103.9915,\n name: \"Singapore Changi\",\n tz: \"Asia/Singapore\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"YBBN\",\n country: \"AU\",\n ghcnh_id: null,\n icao: \"YBBN\",\n latitude: -27.3842,\n longitude: 153.1175,\n name: \"Brisbane\",\n tz: \"Australia/Brisbane\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"YMML\",\n country: \"AU\",\n ghcnh_id: null,\n icao: \"YMML\",\n latitude: -37.6733,\n longitude: 144.8433,\n name: \"Melbourne Tullamarine\",\n tz: \"Australia/Melbourne\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"YSSY\",\n country: \"AU\",\n ghcnh_id: null,\n icao: \"YSSY\",\n latitude: -33.9461,\n longitude: 151.1772,\n name: \"Sydney Kingsford Smith\",\n tz: \"Australia/Sydney\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"ZBAA\",\n country: \"CN\",\n ghcnh_id: null,\n icao: \"ZBAA\",\n latitude: 40.0801,\n longitude: 116.5846,\n name: \"Beijing Capital\",\n tz: \"Asia/Shanghai\",\n venues: [\n \"polymarket\",\n ],\n },\n {\n code: \"ZSPD\",\n country: \"CN\",\n ghcnh_id: null,\n icao: \"ZSPD\",\n latitude: 31.1443,\n longitude: 121.8083,\n name: \"Shanghai Pudong\",\n tz: \"Asia/Shanghai\",\n venues: [\n \"polymarket\",\n ],\n },\n] as const;\n\nexport const STATION_BY_CODE: ReadonlyMap<string, StationInfo> = new Map<string, StationInfo>([\n [\"ATL\", STATIONS[10]!],\n [\"AUS\", STATIONS[11]!],\n [\"BNA\", STATIONS[12]!],\n [\"BOS\", STATIONS[13]!],\n [\"CVG\", STATIONS[14]!],\n [\"DCA\", STATIONS[15]!],\n [\"DEN\", STATIONS[16]!],\n [\"DFW\", STATIONS[17]!],\n [\"DTW\", STATIONS[18]!],\n [\"EDDB\", STATIONS[0]!],\n [\"EDDF\", STATIONS[1]!],\n [\"EDDM\", STATIONS[2]!],\n [\"EFHK\", STATIONS[3]!],\n [\"EGKK\", STATIONS[4]!],\n [\"EGLL\", STATIONS[5]!],\n [\"EHAM\", STATIONS[6]!],\n [\"EKCH\", STATIONS[7]!],\n [\"EPWA\", STATIONS[8]!],\n [\"ESSA\", STATIONS[9]!],\n [\"HOU\", STATIONS[19]!],\n [\"IAH\", STATIONS[20]!],\n [\"LAS\", STATIONS[21]!],\n [\"LAX\", STATIONS[22]!],\n [\"LEBL\", STATIONS[35]!],\n [\"LEMD\", STATIONS[36]!],\n [\"LFPB\", STATIONS[37]!],\n [\"LFPG\", STATIONS[38]!],\n [\"LFPO\", STATIONS[39]!],\n [\"LIMC\", STATIONS[40]!],\n [\"LIRF\", STATIONS[41]!],\n [\"LOWW\", STATIONS[42]!],\n [\"LSZH\", STATIONS[43]!],\n [\"MDW\", STATIONS[23]!],\n [\"MIA\", STATIONS[24]!],\n [\"MSP\", STATIONS[25]!],\n [\"MSY\", STATIONS[26]!],\n [\"NYC\", STATIONS[27]!],\n [\"NZAA\", STATIONS[44]!],\n [\"NZWN\", STATIONS[45]!],\n [\"OERK\", STATIONS[46]!],\n [\"OKC\", STATIONS[28]!],\n [\"OMDB\", STATIONS[47]!],\n [\"OTHH\", STATIONS[48]!],\n [\"PHL\", STATIONS[29]!],\n [\"PHX\", STATIONS[30]!],\n [\"RCTP\", STATIONS[49]!],\n [\"RJAA\", STATIONS[50]!],\n [\"RJTT\", STATIONS[51]!],\n [\"RKSI\", STATIONS[52]!],\n [\"SAEZ\", STATIONS[53]!],\n [\"SAT\", STATIONS[31]!],\n [\"SBGR\", STATIONS[54]!],\n [\"SEA\", STATIONS[32]!],\n [\"SFO\", STATIONS[33]!],\n [\"SLC\", STATIONS[34]!],\n [\"UUEE\", STATIONS[55]!],\n [\"VABB\", STATIONS[56]!],\n [\"VHHH\", STATIONS[57]!],\n [\"VIDP\", STATIONS[58]!],\n [\"VTBS\", STATIONS[59]!],\n [\"WSSS\", STATIONS[60]!],\n [\"YBBN\", STATIONS[61]!],\n [\"YMML\", STATIONS[62]!],\n [\"YSSY\", STATIONS[63]!],\n [\"ZBAA\", STATIONS[64]!],\n [\"ZSPD\", STATIONS[65]!],\n]);\n\nexport const STATION_BY_ICAO: ReadonlyMap<string, StationInfo> = new Map<string, StationInfo>([\n [\"EDDB\", STATIONS[0]!],\n [\"EDDF\", STATIONS[1]!],\n [\"EDDM\", STATIONS[2]!],\n [\"EFHK\", STATIONS[3]!],\n [\"EGKK\", STATIONS[4]!],\n [\"EGLL\", STATIONS[5]!],\n [\"EHAM\", STATIONS[6]!],\n [\"EKCH\", STATIONS[7]!],\n [\"EPWA\", STATIONS[8]!],\n [\"ESSA\", STATIONS[9]!],\n [\"KATL\", STATIONS[10]!],\n [\"KAUS\", STATIONS[11]!],\n [\"KBNA\", STATIONS[12]!],\n [\"KBOS\", STATIONS[13]!],\n [\"KCVG\", STATIONS[14]!],\n [\"KDCA\", STATIONS[15]!],\n [\"KDEN\", STATIONS[16]!],\n [\"KDFW\", STATIONS[17]!],\n [\"KDTW\", STATIONS[18]!],\n [\"KHOU\", STATIONS[19]!],\n [\"KIAH\", STATIONS[20]!],\n [\"KLAS\", STATIONS[21]!],\n [\"KLAX\", STATIONS[22]!],\n [\"KMDW\", STATIONS[23]!],\n [\"KMIA\", STATIONS[24]!],\n [\"KMSP\", STATIONS[25]!],\n [\"KMSY\", STATIONS[26]!],\n [\"KNYC\", STATIONS[27]!],\n [\"KOKC\", STATIONS[28]!],\n [\"KPHL\", STATIONS[29]!],\n [\"KPHX\", STATIONS[30]!],\n [\"KSAT\", STATIONS[31]!],\n [\"KSEA\", STATIONS[32]!],\n [\"KSFO\", STATIONS[33]!],\n [\"KSLC\", STATIONS[34]!],\n [\"LEBL\", STATIONS[35]!],\n [\"LEMD\", STATIONS[36]!],\n [\"LFPB\", STATIONS[37]!],\n [\"LFPG\", STATIONS[38]!],\n [\"LFPO\", STATIONS[39]!],\n [\"LIMC\", STATIONS[40]!],\n [\"LIRF\", STATIONS[41]!],\n [\"LOWW\", STATIONS[42]!],\n [\"LSZH\", STATIONS[43]!],\n [\"NZAA\", STATIONS[44]!],\n [\"NZWN\", STATIONS[45]!],\n [\"OERK\", STATIONS[46]!],\n [\"OMDB\", STATIONS[47]!],\n [\"OTHH\", STATIONS[48]!],\n [\"RCTP\", STATIONS[49]!],\n [\"RJAA\", STATIONS[50]!],\n [\"RJTT\", STATIONS[51]!],\n [\"RKSI\", STATIONS[52]!],\n [\"SAEZ\", STATIONS[53]!],\n [\"SBGR\", STATIONS[54]!],\n [\"UUEE\", STATIONS[55]!],\n [\"VABB\", STATIONS[56]!],\n [\"VHHH\", STATIONS[57]!],\n [\"VIDP\", STATIONS[58]!],\n [\"VTBS\", STATIONS[59]!],\n [\"WSSS\", STATIONS[60]!],\n [\"YBBN\", STATIONS[61]!],\n [\"YMML\", STATIONS[62]!],\n [\"YSSY\", STATIONS[63]!],\n [\"ZBAA\", STATIONS[64]!],\n [\"ZSPD\", STATIONS[65]!],\n]);\n","// Snapshot math — settlement-window and market-close arithmetic.\n//\n// Ported from `packages/core/src/mostlyright/snapshot.py` and\n// `packages/core/src/mostlyright/_internal/_pairs.py:market_close_utc`.\n//\n// Key concepts:\n// - LOCAL STANDARD TIME (LST): station's standard UTC offset, DST ignored.\n// Kalshi NHIGH/NLOW contracts define the settlement window in LST.\n// - Settlement window: midnight-midnight LST for a given date.\n// During US daylight saving the clock window is 1:00 AM–1:00 AM next day\n// (EDT), but the UTC bounds are the same year-round.\n// - CLI publication delay: NWS issues the overnight final CLI ~04:00–10:00\n// UTC the day after observation. Default: 10 h after midnight LST.\n\n// ---------------------------------------------------------------------------\n// Station → IANA timezone database\n// ---------------------------------------------------------------------------\n//\n// Used to extract the LOCAL STANDARD TIME UTC offset via a January reference\n// moment. Ported from `mostlyright.snapshot._STATION_TZ`.\n\nexport const _STATION_TZ: Readonly<Record<string, string>> = Object.freeze({\n // Eastern (UTC-5 standard / UTC-4 DST)\n NYC: \"America/New_York\",\n JFK: \"America/New_York\",\n LGA: \"America/New_York\",\n EWR: \"America/New_York\",\n ATL: \"America/New_York\",\n BOS: \"America/New_York\",\n PHL: \"America/New_York\",\n DCA: \"America/New_York\",\n IAD: \"America/New_York\",\n BWI: \"America/New_York\",\n MIA: \"America/New_York\",\n MCO: \"America/New_York\",\n TPA: \"America/New_York\",\n CLT: \"America/New_York\",\n RDU: \"America/New_York\",\n CLE: \"America/New_York\",\n PIT: \"America/New_York\",\n BUF: \"America/New_York\",\n DTW: \"America/Detroit\",\n IND: \"America/Indiana/Indianapolis\",\n CVG: \"America/New_York\",\n CMH: \"America/New_York\",\n SYR: \"America/New_York\",\n ALB: \"America/New_York\",\n BTV: \"America/New_York\",\n ORF: \"America/New_York\",\n RIC: \"America/New_York\",\n GSO: \"America/New_York\",\n CHS: \"America/New_York\",\n SAV: \"America/New_York\",\n JAX: \"America/New_York\",\n RSW: \"America/New_York\",\n PBI: \"America/New_York\",\n FLL: \"America/New_York\",\n // Central (UTC-6 standard / UTC-5 DST)\n ORD: \"America/Chicago\",\n MDW: \"America/Chicago\",\n DFW: \"America/Chicago\",\n DAL: \"America/Chicago\",\n IAH: \"America/Chicago\",\n HOU: \"America/Chicago\",\n MSP: \"America/Chicago\",\n STL: \"America/Chicago\",\n MCI: \"America/Chicago\",\n OMA: \"America/Chicago\",\n MKE: \"America/Chicago\",\n MSY: \"America/Chicago\",\n MEM: \"America/Chicago\",\n BNA: \"America/Chicago\",\n OKC: \"America/Chicago\",\n SAT: \"America/Chicago\",\n AUS: \"America/Chicago\",\n DSM: \"America/Chicago\",\n TUL: \"America/Chicago\",\n LIT: \"America/Chicago\",\n BIR: \"America/Chicago\",\n SDF: \"America/Chicago\",\n HSV: \"America/Chicago\",\n BHM: \"America/Chicago\",\n MOB: \"America/Chicago\",\n BTR: \"America/Chicago\",\n SHV: \"America/Chicago\",\n // Mountain (UTC-7 standard / UTC-6 DST)\n DEN: \"America/Denver\",\n SLC: \"America/Denver\",\n ABQ: \"America/Denver\",\n BOI: \"America/Boise\",\n BZN: \"America/Denver\",\n GJT: \"America/Denver\",\n // Arizona: no DST (UTC-7 always)\n PHX: \"America/Phoenix\",\n TUS: \"America/Phoenix\",\n // Pacific (UTC-8 standard / UTC-7 DST)\n LAX: \"America/Los_Angeles\",\n SFO: \"America/Los_Angeles\",\n SEA: \"America/Los_Angeles\",\n PDX: \"America/Los_Angeles\",\n LAS: \"America/Los_Angeles\",\n SAN: \"America/Los_Angeles\",\n OAK: \"America/Los_Angeles\",\n SJC: \"America/Los_Angeles\",\n SMF: \"America/Los_Angeles\",\n RNO: \"America/Los_Angeles\",\n FAT: \"America/Los_Angeles\",\n SNA: \"America/Los_Angeles\",\n ONT: \"America/Los_Angeles\",\n BUR: \"America/Los_Angeles\",\n // Alaska (UTC-9 standard / UTC-8 DST)\n ANC: \"America/Anchorage\",\n FAI: \"America/Anchorage\",\n JNU: \"America/Juneau\",\n // Hawaii (UTC-10, no DST)\n HNL: \"Pacific/Honolulu\",\n OGG: \"Pacific/Honolulu\",\n KOA: \"Pacific/Honolulu\",\n // International (iter-6 H12): minimal set required to un-skip the\n // case-5 RJTT year-wrap cache behavior test. Python's\n // `mostlyright.snapshot._resolve_tz` falls back to the broader STATIONS\n // registry for intl ICAOs; the TS port hasn't ported that fallback\n // yet (tracked as TS-W6 — exhaustive intl-station tz coverage). This\n // entry closes H12 cleanly without pulling the whole STATIONS map in.\n // ICAO key (RJTT) — international stations have no 3-letter NWS code.\n // Tokyo Haneda — UTC+9 LST, no DST.\n RJTT: \"Asia/Tokyo\",\n});\n\n/** Reference UTC moment in January (no DST in Northern Hemisphere US). */\nexport const _JAN_REF = new Date(Date.UTC(2024, 0, 15, 12, 0, 0));\n\n/** NWS CLI typical publication delay: 10 h after midnight LST. */\nexport const _CLI_PUBLICATION_DELAY_HOURS = 10.0;\n\n/** Kalshi market typical close time (LST). */\nexport const _MARKET_CLOSE_HOUR_LST = 16;\nexport const _MARKET_CLOSE_MINUTE_LST = 30;\n\n// ---------------------------------------------------------------------------\n// LST offset extraction\n// ---------------------------------------------------------------------------\n\nconst _OFFSET_CACHE = new Map<string, number>();\n\n/**\n * Return the LOCAL STANDARD TIME UTC offset (in hours) for an IANA tz,\n * sampled from January 15 2024 12:00 UTC so the result is never affected\n * by DST in the Northern Hemisphere.\n *\n * Implementation: format `_JAN_REF` in the target tz via Intl.DateTimeFormat\n * and diff against the UTC formatted view to recover the offset.\n */\nexport function _lstOffsetHours(stationTz: string): number {\n const cached = _OFFSET_CACHE.get(stationTz);\n if (cached !== undefined) return cached;\n\n // We compute: localComponents(stationTz, _JAN_REF) − utcComponents(_JAN_REF).\n // The difference gives the tz offset in (hours). Negative for west of UTC.\n const fmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: stationTz,\n hour12: false,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n });\n const parts = fmt.formatToParts(_JAN_REF);\n const get = (type: string): number => {\n const part = parts.find((p) => p.type === type);\n if (!part) {\n throw new Error(`Intl.DateTimeFormat missing ${type} for tz=${stationTz}`);\n }\n return Number(part.value);\n };\n\n const year = get(\"year\");\n const month = get(\"month\");\n const day = get(\"day\");\n let hour = get(\"hour\");\n const minute = get(\"minute\");\n const second = get(\"second\");\n // Some locales return hour \"24\" instead of \"00\" for midnight; normalize.\n if (hour === 24) hour = 0;\n\n // Compute the timezone's wall-clock for _JAN_REF treated as UTC.\n const localAsUtc = Date.UTC(year, month - 1, day, hour, minute, second);\n const offsetMs = localAsUtc - _JAN_REF.getTime();\n const offsetHours = offsetMs / 3_600_000;\n _OFFSET_CACHE.set(stationTz, offsetHours);\n return offsetHours;\n}\n\n// ---------------------------------------------------------------------------\n// Station code normalization + tz lookup\n// ---------------------------------------------------------------------------\n\nfunction _stationCodeNormalized(station: string): string {\n const s = station.trim().toUpperCase();\n if (s.length === 4 && s.startsWith(\"K\")) {\n return s.substring(1);\n }\n return s;\n}\n\n/**\n * Resolve a station code (NWS 3-letter, ICAO 4-letter) to an IANA tz string.\n * Honors `tzOverride` first, then the built-in `_STATION_TZ` map.\n * Throws if no tz can be resolved.\n */\nexport function _resolveStationTz(station: string, tzOverride?: string): string {\n if (tzOverride) return tzOverride;\n const code = _stationCodeNormalized(station);\n const tz = _STATION_TZ[code];\n if (tz) return tz;\n throw new Error(\n `Unknown station timezone: ${JSON.stringify(code)}. Add it to _STATION_TZ or pass tzOverride=\"America/...\".`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// as_of parsing\n// ---------------------------------------------------------------------------\n\nfunction _parseAsOf(asOf: Date | string): Date {\n if (asOf instanceof Date) {\n if (Number.isNaN(asOf.getTime())) {\n throw new Error(\"Invalid Date passed as asOf\");\n }\n return asOf;\n }\n let s = asOf.trim();\n // Python: bare ISO without tz → assume UTC.\n if (s.endsWith(\"Z\")) {\n // Date.parse handles \"Z\" natively.\n } else if (!/[+-]\\d{2}:?\\d{2}$/.test(s)) {\n // No timezone suffix — treat as UTC.\n s = `${s}Z`;\n }\n const ms = Date.parse(s);\n if (!Number.isFinite(ms)) {\n throw new Error(`Invalid as_of string: ${JSON.stringify(asOf)}`);\n }\n return new Date(ms);\n}\n\n// ---------------------------------------------------------------------------\n// Public surface\n// ---------------------------------------------------------------------------\n\nfunction _pad2(n: number): string {\n return n < 10 ? `0${n}` : `${n}`;\n}\n\nfunction _isoDate(year: number, month: number, day: number): string {\n return `${year}-${_pad2(month)}-${_pad2(day)}`;\n}\n\n/**\n * Return the Kalshi settlement date (YYYY-MM-DD LST) for a UTC moment.\n *\n * Kalshi NHIGH/NLOW contracts cover midnight–midnight LOCAL STANDARD TIME.\n * DST is ignored: the window is always fixed to the standard UTC offset.\n */\nexport function settlementDateFor(\n asOf: Date | string,\n station: string,\n tzOverride?: string,\n): string {\n const utcDt = _parseAsOf(asOf);\n const tz = _resolveStationTz(station, tzOverride);\n const offsetHours = _lstOffsetHours(tz);\n // offsetHours is negative for US stations → lstMs < utcMs.\n const lstMs = utcDt.getTime() + offsetHours * 3_600_000;\n const lst = new Date(lstMs);\n // Use getUTC* because we already shifted the epoch by the LST offset.\n return _isoDate(lst.getUTCFullYear(), lst.getUTCMonth() + 1, lst.getUTCDate());\n}\n\n/**\n * Return UTC start/end of the Kalshi settlement window for a date.\n * The window is midnight-midnight LST, expressed in UTC.\n */\nexport function settlementWindowUtc(\n dateStr: string,\n station: string,\n tzOverride?: string,\n): [Date, Date] {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(dateStr);\n if (!match) {\n throw new Error(`Invalid ISO date for settlement window: ${JSON.stringify(dateStr)}`);\n }\n const [, yStr, mStr, dStr] = match;\n const year = Number(yStr);\n const month = Number(mStr);\n const day = Number(dStr);\n const tz = _resolveStationTz(station, tzOverride);\n const offsetHours = _lstOffsetHours(tz);\n\n // midnight LST = 00:00 LST = (00:00 UTC) − offset (offset is negative)\n // Example: UTC-5 → midnight LST = 05:00 UTC.\n const midnightLstAsUtcMs = Date.UTC(year, month - 1, day, 0, 0, 0);\n const startMs = midnightLstAsUtcMs - offsetHours * 3_600_000;\n const start = new Date(startMs);\n const end = new Date(startMs + 24 * 3_600_000);\n return [start, end];\n}\n\n/**\n * Return the UTC time at which the NWS CLI for a date is expected to be\n * available. Default delay is 10 h after midnight LST on the next day.\n */\nexport function cliAvailableAt(\n dateStr: string,\n station: string,\n delayHours: number = _CLI_PUBLICATION_DELAY_HOURS,\n tzOverride?: string,\n): Date {\n const [, windowEnd] = settlementWindowUtc(dateStr, station, tzOverride);\n return new Date(windowEnd.getTime() + delayHours * 3_600_000);\n}\n\n/**\n * Return the UTC time of the Kalshi market close for a settlement date.\n * Kalshi NHIGH/NLOW markets close at 4:30 PM LST on the day of settlement.\n */\nexport function marketCloseUtc(dateStr: string, station: string, tzOverride?: string): Date {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(dateStr);\n if (!match) {\n throw new Error(`Invalid ISO date for market close: ${JSON.stringify(dateStr)}`);\n }\n const [, yStr, mStr, dStr] = match;\n const year = Number(yStr);\n const month = Number(mStr);\n const day = Number(dStr);\n const tz = _resolveStationTz(station, tzOverride);\n const offsetHours = _lstOffsetHours(tz);\n\n const marketCloseAsUtcMs = Date.UTC(\n year,\n month - 1,\n day,\n _MARKET_CLOSE_HOUR_LST,\n _MARKET_CLOSE_MINUTE_LST,\n 0,\n );\n return new Date(marketCloseAsUtcMs - offsetHours * 3_600_000);\n}\n","// Cache-skip rule predicates — pure functions over inputs.\n//\n// Mirrors `packages/weather/src/mostlyright/weather/cache.py`:\n// - `_is_current_lst_month` / `_is_current_lst_year`\n// - `_is_live_source`\n//\n// Plus one TS-NEW addition required by TS-CACHE-02:\n// - `isWithinVolatileWindow` (30-day volatile-window check for archive\n// endpoints). Python's `cache.py` predates this rule; back-porting to\n// Python is tracked as a CROSS-SDK-SYNC parity ticket.\n//\n// All functions accept an optional `now: Date` test seam — production\n// callers pass `new Date()` once at the call site (plan 06).\n\nimport { STATION_BY_CODE, STATION_BY_ICAO } from \"../../data/generated/stations.js\";\nimport { _lstOffsetHours } from \"../../snapshot.js\";\n\n/** Resolve a station identifier (3-letter code OR 4-letter ICAO) to LST offset hours. */\nfunction _lstOffsetHoursFor(station: string): number {\n const upper = station.trim().toUpperCase();\n const byCode = STATION_BY_CODE.get(upper);\n if (byCode !== undefined) return _lstOffsetHours(byCode.tz);\n const byIcao = STATION_BY_ICAO.get(upper);\n if (byIcao !== undefined) return _lstOffsetHours(byIcao.tz);\n if (upper.length === 4 && upper.startsWith(\"K\")) {\n const stripped = upper.slice(1);\n const retry = STATION_BY_CODE.get(stripped);\n if (retry !== undefined) return _lstOffsetHours(retry.tz);\n }\n throw new RangeError(`unknown station: ${JSON.stringify(station)}`);\n}\n\n/**\n * Compute the station's current LST wall-clock as a UTC Date offset by the\n * LST hour shift. Use `getUTC*` to read fields (we already shifted the epoch).\n */\nfunction _nowLst(station: string, now: Date = new Date()): Date {\n const offsetHours = _lstOffsetHoursFor(station);\n return new Date(now.getTime() + offsetHours * 3_600_000);\n}\n\n/**\n * True iff `(year, month)` is the current LST month for `station`.\n *\n * Mirrors Python `_is_current_lst_month`. The current month is mutable\n * (observations still arriving) — caching it would serve stale data.\n */\nexport function shouldSkipCacheForCurrentLstMonth(\n station: string,\n year: number,\n month: number,\n now?: Date,\n): boolean {\n const lst = _nowLst(station, now);\n return lst.getUTCFullYear() === year && lst.getUTCMonth() + 1 === month;\n}\n\n/**\n * True iff `year` is the current LST year for `station`. Annual analog of\n * the monthly variant — gates the climate cache.\n */\nexport function shouldSkipCacheForCurrentLstYear(\n station: string,\n year: number,\n now?: Date,\n): boolean {\n const lst = _nowLst(station, now);\n return lst.getUTCFullYear() === year;\n}\n\n/**\n * True iff `(year, month)` is a **strictly past** UTC month relative to\n * `now` — i.e. cacheable on the strictest possible temporal axis.\n *\n * iter-12 C14: `shouldSkipCacheForCurrentLstMonth` and `isMonthVolatile`\n * (lives in `meta/src/research.ts`) only catch the *current* LST month\n * and the immediate post-month volatile tail. Both predicates return\n * false for months that lie in the FUTURE relative to `now`, or for the\n * current UTC month when the station's LST is still in the prior UTC\n * month (negative tz offsets near UTC midnight). An empty / partial\n * fetch for such a month would be persisted and later served as\n * \"complete.\" `isWritableMonth` is a stricter additional gate: it\n * requires the (year, month) to be lexicographically less than the\n * UTC current month, so neither future months nor the partial current\n * UTC month are ever cacheable — regardless of any station's LST.\n *\n * Mirrors Python `cache.py:_is_current_lst_month`'s implicit invariant\n * (Python paths use parquet-on-disk which can't be written for future\n * dates because the cache root never spawns those years). TS callers\n * MUST gate cache reads AND writes on this predicate before applying\n * the LST / volatile-window gates.\n */\nexport function isWritableMonth(year: number, month: number, now: Date): boolean {\n const nowYear = now.getUTCFullYear();\n const nowMonth = now.getUTCMonth() + 1; // 1-12\n if (year < nowYear) return true;\n if (year > nowYear) return false;\n return month < nowMonth;\n}\n\n/**\n * True iff `year` is a **strictly past** UTC year relative to `now` —\n * the annual analog of `isWritableMonth`.\n *\n * iter-12 C15: `shouldSkipCacheForCurrentLstYear` only catches the\n * current LST year. It misses (a) future years, which would silently\n * cache empty/incomplete data, and (b) the UTC Jan-1 boundary window\n * where the station's LST is still in the prior calendar year (negative\n * tz offsets) but the UTC year has already rolled over — without this\n * gate the new UTC year, which is mutable, could be written. Stricter\n * additional gate: require `year < now.getUTCFullYear()`. TS callers\n * MUST gate cache reads AND writes on this predicate before applying\n * the LST / volatile-window gates.\n */\nexport function isWritableYear(year: number, now: Date): boolean {\n return year < now.getUTCFullYear();\n}\n\n/**\n * True iff `source` ends with `.live`.\n *\n * Mirrors Python `_is_live_source` byte-equivalently — accepts null /\n * undefined / empty (returns false in all three cases).\n */\nexport function isLiveSource(source: string | null | undefined): boolean {\n return typeof source === \"string\" && source.length > 0 && source.endsWith(\".live\");\n}\n\n/**\n * **TS-NEW** addition per TS-CACHE-02: archive endpoints within `days` days\n * of `archiveAsOf` are treated as volatile (some sources amend their\n * published data for ~30 days post-event). NOT a Python port today — file\n * a CROSS-SDK-SYNC parity ticket if Python adopts it.\n *\n * Returns true iff `eventDate` falls within `[archiveAsOf - days, archiveAsOf]`\n * (inclusive at both endpoints — an event exactly `days` days before\n * `archiveAsOf` is still volatile and MUST be re-fetched).\n *\n * Events AFTER `archiveAsOf` are never volatile by this rule (deltaDays < 0).\n */\nexport function isWithinVolatileWindow(eventDate: string, archiveAsOf: string, days = 30): boolean {\n const e = Date.parse(`${eventDate}T00:00:00Z`);\n const a = Date.parse(`${archiveAsOf}T00:00:00Z`);\n if (!Number.isFinite(e) || !Number.isFinite(a)) {\n throw new RangeError(\n `invalid YYYY-MM-DD: eventDate=${JSON.stringify(eventDate)} archiveAsOf=${JSON.stringify(archiveAsOf)}`,\n );\n }\n const deltaDays = (a - e) / 86_400_000;\n return deltaDays >= 0 && deltaDays <= days;\n}\n","// Cache-key generators — pure functions producing the canonical key strings\n// `cacheKeyForObservations(station, year, month)` and\n// `cacheKeyForClimate(station, year)`. Matches the Python file-path zero-\n// padded month/year scheme (Python: `01.parquet`, TS: `:01`).\n//\n// Station is upper-cased but NOT validated here (validation is the\n// orchestrator's job; this module stays pure).\n//\n// iter-7 H13 / H14: an optional `source` segment was added to\n// `cacheKeyForObservations` so the multi-source observations cache\n// (IEM ASOS + GHCNh) does not collide on the same `(station, year, month)`\n// triplet. Python writes one parquet per month containing the merged\n// observations from all sources; the TS orchestrator caches per-source\n// chunks pre-merge (because the fetchers are independent paths) and\n// disambiguates with the source segment. Omitting `source` preserves the\n// legacy 3-arg key shape — useful for tests that don't care about source\n// (sentinel preloads, fixture replays) and matches the canonical\n// Python-parity contract for callers that have already pre-merged sources.\n\nconst MIN_YEAR = 1900;\nconst MAX_YEAR = 2100;\nconst SOURCE_RE = /^[a-z0-9_-]+$/;\n\n/**\n * Build the canonical observations cache key.\n *\n * Examples:\n * `cacheKeyForObservations(\"KNYC\", 2025, 1)` →\n * `\"mostlyright:v1:observations:KNYC:2025:01\"`.\n * `cacheKeyForObservations(\"KNYC\", 2025, 1, \"iem\")` →\n * `\"mostlyright:v1:observations:KNYC:2025:01:iem\"`.\n *\n * The `source` segment (optional, lowercase alphanumeric / hyphen /\n * underscore) namespaces per-source pre-merge chunks so IEM ASOS and\n * GHCNh writes for the same `(station, year, month)` do not collide.\n * Omit for back-compat (sentinel preloads, fixture replays).\n */\nexport function cacheKeyForObservations(\n station: string,\n year: number,\n month: number,\n source?: string,\n): string {\n if (!Number.isInteger(year) || year < MIN_YEAR || year > MAX_YEAR) {\n throw new RangeError(`year out of range: ${year}`);\n }\n if (!Number.isInteger(month) || month < 1 || month > 12) {\n throw new RangeError(`month out of range: ${month}`);\n }\n const yyyy = String(year).padStart(4, \"0\");\n const mm = String(month).padStart(2, \"0\");\n const base = `mostlyright:v1:observations:${station.toUpperCase()}:${yyyy}:${mm}`;\n if (source === undefined) return base;\n if (typeof source !== \"string\" || !SOURCE_RE.test(source)) {\n throw new RangeError(\n `source must match ${SOURCE_RE.source} (lowercase alnum / hyphen / underscore); got ${JSON.stringify(source)}`,\n );\n }\n return `${base}:${source}`;\n}\n\n/**\n * Build the canonical climate cache key (annual).\n *\n * Example: `cacheKeyForClimate(\"KNYC\", 2025)` →\n * `\"mostlyright:v1:climate:KNYC:2025\"`.\n */\nexport function cacheKeyForClimate(station: string, year: number): string {\n if (!Number.isInteger(year) || year < MIN_YEAR || year > MAX_YEAR) {\n throw new RangeError(`year out of range: ${year}`);\n }\n const yyyy = String(year).padStart(4, \"0\");\n return `mostlyright:v1:climate:${station.toUpperCase()}:${yyyy}`;\n}\n"],"mappings":"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,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,OAAO,SAAS,EAAE,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AACxB,CAAC;AAEM,IAAM,kBAAoD,oBAAI,IAAyB;AAAA,EAC5F,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,CAAC,CAAE;AAAA,EACrB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,QAAQ,SAAS,EAAE,CAAE;AAAA,EACtB,CAAC,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","names":[]}
@@ -23,6 +23,7 @@ __export(temporal_exports, {
23
23
  KnowledgeView: () => KnowledgeView,
24
24
  LeakageDetector: () => LeakageDetector,
25
25
  TimePoint: () => TimePoint,
26
+ assertIssuedAtPopulated: () => assertIssuedAtPopulated,
26
27
  assertNoLeakage: () => assertNoLeakage
27
28
  });
28
29
  module.exports = __toCommonJS(temporal_exports);
@@ -274,9 +275,9 @@ function toJsonSafe(value, seen) {
274
275
  }
275
276
  return { _repr_only: true, value: String(value) };
276
277
  }
277
- var TradewindsError = class extends Error {
278
+ var MostlyRightError = class extends Error {
278
279
  /** Subclass override — the stable string enum surfaced via `errorCode`. */
279
- static defaultErrorCode = "TRADEWINDS_ERROR";
280
+ static defaultErrorCode = "MOSTLYRIGHT_ERROR";
280
281
  errorCode;
281
282
  source;
282
283
  requestId;
@@ -308,7 +309,7 @@ var TradewindsError = class extends Error {
308
309
  return safe;
309
310
  }
310
311
  };
311
- var SchemaValidationError = class extends TradewindsError {
312
+ var SchemaValidationError = class extends MostlyRightError {
312
313
  static defaultErrorCode = "SCHEMA_VALIDATION_FAILED";
313
314
  schemaId;
314
315
  violations;
@@ -331,7 +332,7 @@ var SchemaValidationError = class extends TradewindsError {
331
332
  };
332
333
  }
333
334
  };
334
- var LeakageError = class extends TradewindsError {
335
+ var LeakageError = class extends MostlyRightError {
335
336
  static defaultErrorCode = "LEAKAGE_DETECTED";
336
337
  asOf;
337
338
  violatingCount;
@@ -351,6 +352,26 @@ var LeakageError = class extends TradewindsError {
351
352
  };
352
353
  }
353
354
  };
355
+ var IssuedAtMissingError = class extends SchemaValidationError {
356
+ static defaultErrorCode = "ISSUED_AT_MISSING";
357
+ violatingCountRows;
358
+ constructor(message, options = {}) {
359
+ super(message, {
360
+ ...options,
361
+ schemaId: "schema.forecast.station.v1",
362
+ violations: [{ column: "issued_at", rule: "non_null" }]
363
+ });
364
+ this.violatingCountRows = options.violatingCount ?? 0;
365
+ }
366
+ payload() {
367
+ return {
368
+ ...super.payload(),
369
+ name: "IssuedAtMissingError",
370
+ violating_count: this.violatingCountRows,
371
+ origin_issue: "Tarabcak/mostlyright#70"
372
+ };
373
+ }
374
+ };
354
375
 
355
376
  // src/temporal/knowledge-view.ts
356
377
  var KnowledgeView = class {
@@ -417,6 +438,7 @@ var KnowledgeView = class {
417
438
 
418
439
  // src/temporal/leakage.ts
419
440
  var SAMPLE_CAP = 10;
441
+ var ISSUED_AT_SAMPLE_CAP = 5;
420
442
  var RUNTIME_SCHEMA_ID = "<runtime>";
421
443
  function assertNoLeakage(rows, asOf) {
422
444
  if (!(asOf instanceof TimePoint)) {
@@ -493,12 +515,42 @@ var LeakageDetector = class {
493
515
  check(rows) {
494
516
  assertNoLeakage(rows, this.#asOf);
495
517
  }
518
+ /**
519
+ * Phase 20 OM-04: defensive non-null check for `issuedAt`.
520
+ *
521
+ * Independent of `asOf` — the bound cutoff is irrelevant when the row
522
+ * carries no model-run time at all. Throws {@link IssuedAtMissingError}
523
+ * if any row's `issuedAt` is null/undefined/empty.
524
+ */
525
+ checkIssuedAt(rows) {
526
+ assertIssuedAtPopulated(rows);
527
+ }
496
528
  };
529
+ function assertIssuedAtPopulated(rows) {
530
+ if (rows.length === 0) return;
531
+ const violations = [];
532
+ for (let i = 0; i < rows.length; i++) {
533
+ const r = rows[i];
534
+ const v = r == null ? null : r.issuedAt;
535
+ if (v == null || v === "") {
536
+ violations.push({ row_idx: i });
537
+ }
538
+ }
539
+ if (violations.length === 0) return;
540
+ throw new IssuedAtMissingError(
541
+ `${violations.length} row(s) have null issuedAt; cannot verify leakage-safety`,
542
+ {
543
+ violatingCount: violations.length,
544
+ sampleViolations: violations.slice(0, ISSUED_AT_SAMPLE_CAP)
545
+ }
546
+ );
547
+ }
497
548
  // Annotate the CommonJS export names for ESM import in node:
498
549
  0 && (module.exports = {
499
550
  KnowledgeView,
500
551
  LeakageDetector,
501
552
  TimePoint,
553
+ assertIssuedAtPopulated,
502
554
  assertNoLeakage
503
555
  });
504
556
  //# sourceMappingURL=index.cjs.map