From 77cf7a011bb8e0c69280341cfdb61df66b6fdba3 Mon Sep 17 00:00:00 2001 From: Jack Steam Date: Fri, 13 Nov 2026 11:42:37 -0600 Subject: [PATCH 1/2] docs: consolidate chart and location research --- docs/research/README.md | 16 ++++ docs/research/lahiri-integration.md | 32 ++++++++ .../research/ordinary-chart-initialization.md | 62 +++++++++++++++ docs/research/timezone-city-mapping.md | 77 +++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 docs/research/README.md create mode 100644 docs/research/lahiri-integration.md create mode 100644 docs/research/ordinary-chart-initialization.md create mode 100644 docs/research/timezone-city-mapping.md diff --git a/docs/research/README.md b/docs/research/README.md new file mode 100644 index 0000000..da8a656 --- /dev/null +++ b/docs/research/README.md @@ -0,0 +1,16 @@ +# Research archive + +These documents preserve dated investigations from separate research branches. +They are historical evidence, not current implementation status or new product +approvals. Read each document against its inspection date and pinned source +revisions; verify live issue, PR, engine, and tooling state before acting on it. +Original issue links are retained as historical references. + +| Investigation | Original commit | +| ----------------------------------------------------------------- | ------------------------------------------ | +| [Ordinary chart initialization](ordinary-chart-initialization.md) | `5cad61e32946d020a93a17d86777d176457bda49` | +| [Timezone-to-city mapping](timezone-city-mapping.md) | `632238e1442b6bba1d653f0e283b7a1b23311d46` | +| [Lahiri integration prerequisite](lahiri-integration.md) | `9def663cc1430e38716de16c07afb1f1a9b0a16c` | + +The original research content is preserved with Markdown formatting normalized. Consolidating it here does +not implement the proposed behavior or establish numerical or product acceptance. diff --git a/docs/research/lahiri-integration.md b/docs/research/lahiri-integration.md new file mode 100644 index 0000000..56b6805 --- /dev/null +++ b/docs/research/lahiri-integration.md @@ -0,0 +1,32 @@ +# Lahiri integration prerequisite + +Inspected 2026-11-10 for [Compare three fixed zodiac systems while preserving the chosen house system](https://github.com/AstrologyEngine/web-issues/issues/30). This is a read-only investigation of engine state, not a new implementation or numerical acceptance report. + +## Finding + +Reuse the existing engine effort: [feat: add Lahiri chart reference (benchmark alignment pending)](https://github.com/AstrologyEngine/library/pull/9). It is open and draft, on `feat/lahiri` at `2b86542`, with an explicit consumer-rollout exclusion. Its local worktree is `/Users/jacksteam/Documents/AstrologyEngine/library/.worktrees/lahiri`; it was clean when inspected. Do not duplicate that work, copy its unaccepted binary into the website, or choose another Lahiri model while treating the existing effort as absent. + +The refreshed engine default `e47f53bdc00875b4e03885571f2461617da0971d` exposes Tropical, Fagan–Bradley and True Sky, without Lahiri. Its unified `calculate_chart` pipeline owns reference offset, daily-rate correction, projection, sign assignment and house construction. Use the accepted source revision rather than assuming the candidate branch is ready for consumers. [Current configuration](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/src/conventions.rs), [shared pipeline](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/src/chart.rs). + +## Existing numerical contract and acceptance gap + +The candidate already selects current PAC/Indian Astronomical Ephemeris Lahiri: J2000 mean offset 23°51′25.53″ and the publication's formula introduced in 2021, evaluated in TT, plus the engine's nutation for true-equinoctial tropical coordinates. It adds the reference to Rust and Wasm through the shared projection pipeline. Its stated helper range is 1800–2200 TT, additionally restricted by dataset coverage. These are candidate contracts, not a fresh endorsement of full-chart accuracy. [Candidate implementation and tests](https://github.com/AstrologyEngine/library/blob/2b86542/src/sidereal.rs), [candidate convention notes](https://github.com/AstrologyEngine/library/blob/2b86542/docs/chart-conventions.md#lahiri). + +The official [IMD publication page](https://mausam.imd.gov.in/responsive/indianAstronomicalEphemeris.php) identifies PAC as publisher and links the 2027 publication archive. The candidate cites printed pages 382 and 423 for its mean formula and nutation relationship. This investigation verified the live publisher/index link; it did not independently inspect the archive pages or rerun numerical comparisons. + +The latest PR description is more current than the candidate's initial five-chart notes: reference transforms pass all 125 dates; matched-TT tropical bodies pass 123/125, with remaining Saturn and Ceres discrepancies. Whole Sign/Equal geometry passes 110/125 per zodiac and Placidus 109/121 admitted cases. Polar orientation, time conventions, remaining frame errors and fitting-versus-source behavior remain follow-ups. Passing regular CI does not clear these numerical acceptance gaps. The PR remains draft and explicitly excludes rollout. [Current investigation and acceptance status](https://github.com/AstrologyEngine/library/pull/9). + +## Verification and distribution constraints + +The engine [AGENTS.md](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/AGENTS.md#swiss-ephemeris-prohibition) prohibits Swiss Ephemeris use in runtime, development, tests, comparisons, and derived reference artifacts. An executable Swiss oracle or fixtures generated from it is therefore unavailable under current instructions. Discussion in prose is permitted; that exception does not authorize execution or copied code. Continue the existing approved benchmark investigation and permitted PAC/JPL source checks; do not introduce a new comparison harness using prohibited software. + +The current engine is MPL-2.0, including its first-party adapters. Rebuilt browser distributions must preserve notices and ship the corresponding source snapshot (`ASTROLOGY_ENGINE_SOURCE.tar.gz`) alongside Wasm. The website's MIT license does not remove those covered-file requirements. [Distribution instructions](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/THIRD_PARTY_NOTICES.md). + +## Consumer handoff after engine acceptance + +1. Resume the existing engine PR's benchmark prerequisites and record acceptance before consumer rollout. No new product choice of zodiac is necessary; fixed Lahiri is already approved. +2. Pin the accepted engine commit, build the browser adapter from that exact source, preserve its notices/source snapshot, and record the new Wasm hash. The documented build needs Rust 1.96, Bun 1.3.14, `wasm32-unknown-unknown`, and wasm-bindgen-cli 0.2.122. The first three were locally available; `wasm-bindgen` was absent from PATH. [Build guide](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/examples/configurable-chart/README.md), [build script](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/examples/configurable-chart/build-wasm.ts). +3. Update website settings and chart schemas to admit `lahiri`, the Vedic preset, help text, worker hash and snapshot provenance together. Retain the existing dataset unless evidence requires a separately validated change. The website currently pins engine `b2bd547...` and Wasm `22c1aa9...`; changing a label alone cannot satisfy the ticket. [Worker](../../src/lib/calculation/worker.ts), [snapshot validation](../../src/lib/calculation/snapshot.ts), [settings](../../src/lib/settings.ts). +4. Validate zodiac and requested-house independence across all three systems, actual fallback metadata, native/Wasm behavior, browser interactions, bounded measurement events, and staged revision. Engine numerical acceptance, website checks, CI, staging behavior and explicit product acceptance remain separate gates. + +No source code, engine worktree, benchmark data or product settings were changed by this investigation. diff --git a/docs/research/ordinary-chart-initialization.md b/docs/research/ordinary-chart-initialization.md new file mode 100644 index 0000000..00fd369 --- /dev/null +++ b/docs/research/ordinary-chart-initialization.md @@ -0,0 +1,62 @@ +# Ordinary chart initialization: calculation contract + +Research for [Specify ordinary chart initialization in the calculation library](https://github.com/AstrologyEngine/web/issues/8), under [Port the plugin UI into a standalone astrology explorer](https://github.com/AstrologyEngine/web/issues/5). Checked 2026-11-07. Planning only; no runtime, website or library implementation. + +## Finding and source identity + +**Existing library and shipped browser capabilities suffice. No library calculation change or new astronomical API is required to initialize this ordinary chart.** The website needs a host adapter that captures an instant, obtains the city result, constructs consistent chart metadata, and submits the same worker request used for edited birth details. This conclusion follows from the explicit-input Rust and Wasm APIs below, not from the name “birth chart.” + +Live GitHub identifies the library as [`AstrologyEngine/library`](https://github.com/AstrologyEngine/library), default branch `main`, at `b2bd547728f31a951a1afd78dfaa94225d8c152f`. The plugin already pins this exact revision. The sibling library checkout was stale at `71350f0889c3b5e1585935d2017c97efe0bb5848`; its older MIT manifest and `calculate_configured_chart` API must not be treated as the current contract. Current source has MPL-2.0 licensing and a unified `calculate_chart` API. Sources: [current Cargo manifest](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/Cargo.toml), [current chart API](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/chart.rs), [plugin provenance](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/docs/calculation-provenance.md). + +The plugin source inspected is `8446c7b1388349a28daaabf27f13096b61142271`. Its shipped source archive agrees with the live pinned API for chart input and design search. The shipped source archive is a separate packaging artifact from the original upstream commit tarball expected by `scripts/rebuild-engine.sh`; their hashes are not interchangeable. + +## Explicit runtime contract + +The current Rust API is `calculate_chart(&Ephemeris, ChartInput { epoch, location, house_system, zodiac }) -> Result`. `Location` contains latitude/longitude in degrees; valid ranges are [-90,90] and [-180,180]. Longitude is east positive (the sidereal-angle formula adds it). The public Wasm wrapper accepts caller-supplied dataset bytes and JSON with these fields: + +| Input | Required meaning | +| ----------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `instant` | `{ scale: "utc", value: "YYYY-MM-DDTHH:mm:ssZ" }`, or finite `{ scale: "et", value: seconds }` for engine ET replay | +| `latitude`, `longitude` | Explicit geographic coordinates of the resolved city or edited place | +| `house_system` | `whole-sign`, `equal`, or `placidus` | +| `configuration` | Explicit reference (`tropical`, `fagan-bradley`, `true-sky`), divisions (`equal`, `constellation`), and Ophiuchus choice | + +UTC parsing requires an explicit `Z` or ` UTC` suffix. Never pass local wall-clock text as UTC or pass JavaScript Unix milliseconds as ET seconds. The runtime does not read the clock, detect a timezone, resolve a city, load a dataset, or supply product settings. Sources: [Wasm wrapper](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/examples/configurable-chart/wasm/src/lib.rs), [angles and coordinate convention](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/astro/houses.rs), [runtime boundary](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/AGENTS.md). + +`ChartValues` supplies effective configuration, convention revision, reference offset, speed reference, nineteen body/angle entries with longitude/speed/declination and sign progress, zodiac sectors, separate Whole Sign house sectors where applicable, twelve validated cusps, and requested/actual house systems. Angular values are degrees and speeds degrees/day. Preserve these returned values: do not project longitudes a second time or reconstruct sign and house tables from equal 30-degree assumptions. Placidus may return Porphyry fallback; overlapping cusp sets fail. True Sky retains tropical speeds, and angle speeds of zero mean not calculated. Sources: [chart result and calculation](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/chart.rs), [conventions](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/conventions.rs), [plugin result validator](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/chart.ts). + +## Minimum website adapter specification + +1. Capture the visit-start instant once. Initialization, data-download retries, settings changes and view switches use that captured instant until the user edits the chart. Do not recapture the clock after loading location/data. No clock timer, chart modes, persisted input or automatic refresh is introduced; this follows the [approved behavior resolution](https://github.com/AstrologyEngine/web/issues/6#issuecomment-6710681281). +2. Accept a resolved location result containing city identity/display fields, latitude, longitude, effective IANA timezone and real lookup provenance. An unavailable result must be explicit. Selection, alias treatment, unmapped-zone handling and fallback policy remain in [Choose inferred-city selection and fallback policies](https://github.com/AstrologyEngine/web/issues/16); this research does not select a fallback city or mapping dataset policy. +3. Derive local date, local time and the offset at that exact UTC instant using the effective timezone. Preserve the UTC instant as authority. A known instant maps to one civil time and offset even during a daylight-saving overlap; do not round-trip it through ambiguous civil-time parsing. Edited local birth input still follows the plugin resolver's ambiguity rules. +4. Match the plugin's current whole-second birth schema: normalize the single captured timestamp once to whole seconds, then derive UTC and all civil fields from that same value, with `timePrecision: "second"`. This is a concrete compatibility requirement of using that schema, not a library precision limitation. Retaining fractional seconds instead requires coordinated host schema/editor changes; do not silently calculate a different instant from the one represented by metadata. +5. Build a transient birth-details value compatible with the editor/snapshot contract. The existing schema requires place id/city/region/country/label, coordinates, timezone, offset, UTC, resolverVersion, atlasHash and timezoneDataVersion. Record truthful initializer/lookup identifiers and hashes; never pretend initialization ran through the plugin's server resolver or processed its atlas. Browser Intl does not establish a pinned tzdb version. If the website separates initializer provenance from edited-birth provenance, adapt host schemas together rather than inserting fake values. +6. Apply plugin defaults explicitly: Tropical, equal sign divisions, Ophiuchus false (effective engine value null), Whole Sign houses, `progressInSign` atmakaraka, Astrology enabled and Human Design disabled. Later settings changes use the same ordinary chart. Constellation divisions require True Sky and an explicit Ophiuchus enabled/disabled choice. No settings persistence is added. +7. Submit `{ generation, birth, settings }` to the calculation worker and publish only its validated snapshot for the current generation. Preserve recoverable loading/error states, retry behavior and generation-based rejection of stale results. The browser worker remains the execution host; the library remains pure and stateless. + +Sources for requirements 3–7: [birth/settings schema and defaults](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/server/domain.ts), [birth resolver provenance](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/docs/birth-resolver-provenance.md), [worker](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/worker.ts), [snapshot validation](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/snapshot.ts). These specify adapter responsibilities, not permission to implement them in this planning map. + +## Aspects and provenance ownership + +The library owns positions, sign assignments, angles, cusps, fallback reporting and convention metadata. The plugin's pure `deriveAstrology(selected, tropical, method)` owns aspects, atmakaraka and intercepted signs. Reuse its selected-frame and tropical-basis calculations and preserve its aspect body-pair policy. Its aspects are derived over all returned pairs; the ten-planet eligibility set is for atmakaraka, not an aspect filter. The existing aspect angles/orbs are Conjunction 0/10, Semisextile 30/2, Sextile 60/6, Square 90/8, Trine 120/8, Quincunx 150/3 and Opposition 180/10, with applying/separating determined from tropical speeds. Do not move these policies into Rust merely to support initialization. Source: [derivation](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/chart.ts). + +The host snapshot owns calculation id/generation, complete inputs/requested settings and asset/source identities: engine commit, supplementary policy-source commit, wrapper SHA-256, full-dataset SHA-256/fingerprint, selected-slice SHA-256 and returned convention revision. Location lookup/timezone provenance is separate from astronomical dataset identity. The worker verifies index, Wasm and slice hashes and validates output. Reusing assets preserves their actual pins; rebuilding requires updating verified identities together, not relabelling old bytes. Sources: [worker](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/worker.ts), [snapshot](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/snapshot.ts), [rebuild script](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/scripts/rebuild-engine.sh). + +## Coverage, errors and Human Design + +The shipped index advertises birth coverage from `1849-12-31T23:59:27.816001860Z` through `2149-12-20T23:58:50.816456371Z`. That is asset coverage, not a timeless library guarantee. The worker chooses the slice by UTC year and checks download identity. Annual slices include the previous year and padding, clipped to source coverage. Runtime chart admission also depends on finite-difference speed support (half-day samples on either side); retain generated fitted guard margins. Never clamp an invalid date or substitute coordinates/data silently. Sources: [index](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/static/engine/ephemeris/index.json), [segment preparation](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/examples/configurable-chart/prepare-segments.ts), [runtime guidance](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/AGENTS.md). + +Keep invalid/unavailable location distinct at the initializer boundary. Preserve worker errors `INVALID_INPUT`, `DATA_UNAVAILABLE`, `DATA_INTEGRITY`, `OUT_OF_RANGE`, `CALCULATION_FAILED`, and `DESIGN_MOMENT_UNAVAILABLE`; the Wasm wrapper itself returns error strings and the runtime has invalid-input, out-of-coverage and evaluation failures. This research does not introduce a new typed Rust error API. Loading failures and integrity failures must not yield a plausible partial chart. Sources: [worker errors](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/worker.ts), [runtime errors](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/lib.rs). + +Human Design already works with the same chart inputs. When enabled, the worker calls existing `design_moment_et`: find the backward tropical Sun crossing at birth Sun minus 88 degrees, then calculate the design chart using the returned **ET seconds directly** and the selected configuration/location. Do not convert ET through JavaScript Date or substitute “88 days earlier.” The search requires 89 days of public lookback coverage, so birth-date admission does not guarantee Human Design availability near the dataset's lower edge. Search errors and no crossing remain distinct underlying cases, even though the plugin intentionally presents its existing generic design-unavailable error. Preserve existing derived gates/channels/bodygraph policies and unchanged input semantics for edited natal charts. Sources: [design export](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/examples/configurable-chart/wasm/src/lib.rs), [search](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/search.rs), [lookback constant](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/src/coverage_window.rs), [plugin search adapter](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/design-search.ts), [HD derivation](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/src/lib/calculation/human-design.ts). + +## Verification and handoff + +A direct Bun execution of the **existing shipped Wasm** on 2026-11-07 used a fixed current-era instant (`2026-11-07T18:00:00Z`), explicit coordinates (41.85, -87.65), and plugin default chart settings. It returned nineteen entries, twelve cusps and `astrology-engine-conventions-v1`. Existing `design_moment_et` returned finite ET; calculating that design instant returned nineteen entries and twelve cusps. Coordinates were explicit test inputs, not an inferred-city policy decision. This is local execution evidence, not browser/CSP acceptance, native parity, or independent astronomical validation. + +Required later implementation checks: fixed-clock one-capture initialization; consistent local/UTC/offset fields across midnight and DST overlaps; unknown-zone policy from its own decision; plugin-default/settings parity; invalid coordinates/settings; source and slice endpoints with speed padding; HD lower-edge lookback; index/Wasm/slice integrity and retry; stale-generation rejection; same snapshot for initial versus manually supplied identical inputs. Run the existing pinned full/slice and native/Wasm regression paths when rebuilding assets or changing the wrapper. Preserve metadata/sign tables exactly and compare numerical fields within the existing 1e-12 tolerance. Existing evidence reports 90 browser birth and 90 design full/slice cases with zero difference, but this session did not rerun that suite. Sources: [plugin calculation tests](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/tests/calculation.test.ts), [reported verification boundaries](https://github.com/AstrologyEngine/plugin/blob/8446c7b1388349a28daaabf27f13096b61142271/docs/calculation-provenance.md). + +The library's own [AGENTS.md](https://github.com/AstrologyEngine/library/blob/b2bd547728f31a951a1afd78dfaa94225d8c152f/AGENTS.md) separates pure runtime from native preparation and host I/O and prohibits all Swiss Ephemeris execution, wrappers and derived validation artifacts. Preserve those boundaries and MPL notices/source obligations when redistributing existing artifacts. No Swiss Ephemeris was used here. + +No library implementation issue is required for this finding. If a later verified gap needs library changes, coordinate through `AstrologyEngine/library` GitHub Issues using its current root/scoped instructions and verification workflows; an empty open-issue listing is not a separate tracker specification. The website integration ticket owns packaging, worker origin/CSP, birth-editor/resolver integration and provenance-schema adaptation. The city-policy ticket remains unresolved. Neither is resolved implicitly by this research. diff --git a/docs/research/timezone-city-mapping.md b/docs/research/timezone-city-mapping.md new file mode 100644 index 0000000..ee3603c --- /dev/null +++ b/docs/research/timezone-city-mapping.md @@ -0,0 +1,77 @@ +# Timezone-to-city mapping research + +Research for [Define timezone-to-city location mapping](https://github.com/AstrologyEngine/web/issues/7), part of [Port the plugin UI into a standalone astrology explorer](https://github.com/AstrologyEngine/web/issues/5). Checked 2026-11-07. Planning only; no mapping or application code is implemented. + +## Finding + +A static, versioned lookup generated from GeoNames settlement records and IANA/ECMA identifier rules is feasible. It can deterministically select the largest **recorded population in a chosen snapshot**, rather than assuming the timezone namesake is its largest city. Neither source establishes a globally consistent, current census definition of “largest city.” Universal city coverage and failure behavior need explicit product policy. + +## Sources and identifier handling + +- [GeoNames export documentation](https://download.geonames.org/export/dump/readme.txt) defines downloadable records containing stable numeric ID, place name, feature classification, country, population, decimal WGS84 latitude/longitude, IANA timezone, and modification date. `allCountries.zip` contains the combined records; `cities500.zip` restricts coverage to population above 500 or selected administrative seats. The latter is convenient for a sample, insufficient as a promise of every inhabited timezone. +- [GeoNames source list](https://www.geonames.org/data-sources.html) shows aggregation from many providers. The export has no population observation year or common city-boundary definition. A record modification date is not a census date. Consequently, a maximum is a dataset result, not proof of the largest contemporary municipality, urban area, or metro area. +- [IANA theory](https://data.iana.org/time-zones/tzdb/theory.html) defines timezones by civil-clock history, not geographic proximity or just current UTC offset. Names are chosen for stability; a timezone namesake does not constitute a population ranking. Do not infer city from the final path component or group cities by present offset. +- [ECMA-402 timezone requirements](https://tc39.es/ecma402/#sec-use-of-the-iana-time-zone-database) preserve country-associated identifiers in `zone.tab`, even where ordinary tzdb builds merge their clocks. They also define country-preserving alias resolution and accommodate delayed adoption of renamed identifiers. Accept both old and new names; do not rely on the generator's installed runtime as the authoritative alias dataset. Read the browser default through `Intl.DateTimeFormat().resolvedOptions().timeZone`, with exception/missing-value handling. Host configuration is an approximation, not measured location. +- [IANA backward links](https://data.iana.org/time-zones/tzdb/backward) include `US/Central → America/Chicago`, `Asia/Calcutta → Asia/Kolkata`, and `Europe/Kiev → Europe/Kyiv`. They also merge `Europe/Amsterdam → Europe/Brussels` and `Africa/Accra → Africa/Abidjan`. Blindly following every link would discard useful country identity. +- [zone.tab](https://data.iana.org/time-zones/tzdb/zone.tab) retains a country-associated geographical identifier; [zone1970.tab](https://data.iana.org/time-zones/tzdb/zone1970.tab) groups clocks across countries and provides principal-location coordinates. Neither contains city populations or geographic boundary polygons. Principal coordinates are not a verified largest-city coordinate source. Although IANA deprecates `zone.tab` for ordinary timezone selection, ECMA explicitly uses it for its country-preserving semantics. + +These facts support a geographical lookup identity aligned with ECMA, rather than an equivalence class of all clocks sharing an IANA `Zone`. That alignment is a proposed interpretation of the owner's requirement; it should be confirmed in the follow-up decision. + +## Concrete generation approach — proposal, not owner-approved policy + +1. Pin a tzdb release, its relevant identifier files (including `zone.tab`, `backward`, and `backzone` where country-preserving resolution requires it), and a dated GeoNames extract. Prefer the full extract when generating the final coverage report; do not ship it to browsers or fetch it per visit. +2. Construct a versioned identifier-to-geographical-key table following ECMA country preservation. Keep geographical `zone.tab` entries distinct; connect spelling/legacy aliases to the appropriate key. Check every GeoNames timezone against that same table. Do not just recursively flatten `backward`; country-preserving cases such as `Pacific/Truk` require the additional ECMA rules. Preserve the original browser identifier for diagnosis. +3. Define eligible settlements explicitly. The sample below uses feature class `P` and only `PPL`, `PPLA`, `PPLA2`, `PPLA3`, `PPLA4`, `PPLA5`, `PPLC`, `PPLG`; positive integer population; finite latitude/longitude within normal bounds. This excludes neighborhoods, historical/abandoned places, and non-settlement administrative areas. The [GeoNames feature code definitions](https://download.geonames.org/export/dump/featureCodes_en.txt) distinguish these categories. Broader small-settlement eligibility, including `PPLL`, `PPLF`, `PPLR`, `STLMT`, and the newly documented `PPLCD`, needs a declared policy before final generation. Do not silently exclude an inhabited region because it lacks a large city. +4. Group by geographical key; rank by population descending, then numeric GeoNames ID ascending. Use the chosen record's point coordinates and name; never sum overlapping city, neighborhood, and metro records. Retain GeoNames ID, country, raw timezone, population, and modification date in provenance. +5. Emit a compact lookup plus coverage/audit report. Every expected geographical identifier must have either an audited selection or an explicit unresolved reason. Flag no-candidate regions, unknown timezone strings, invalid coordinates, unexpected cross-country aliasing, unusual winner changes, and suspicious geography. Maintain reviewed exclusions/overrides with source and reason if policy permits them. +6. The browser performs only lookup. A missing or non-geographical identifier returns a typed unresolved result for the product policy to handle. Never substitute the server's timezone. Deliver ordinary chart inputs to the existing calculation adapter; browser detection and data acquisition stay outside the calculation library. + +The ranking, tie rule, selected fields, and coverage checks are engineering proposals. They become a specification only after the outstanding population/coverage policy is settled. + +## Direct data checks + +Downloaded the official [cities500.zip](https://download.geonames.org/export/dump/cities500.zip) on 2026-11-07. Archive member timestamp: `2026-11-07 03:47:24` (timezone unspecified). SHA-256: `bf2516f404ceefd24e099e48c8cd91730c9b1ab85158dd77eb9d943275d6b072`. + +Parsed UTF-8 tab-separated rows using the documented schema, applied the exact sample filter above, and sorted by `(-population, numeric geonameid)` within each **literal GeoNames timezone**. This sample does not implement alias generation. It contained 236,953 records; 194,783 eligible records across 391 literal timezone IDs. + +| Literal timezone | Maximum eligible record | ID | Recorded population | Coordinates | +| ------------------- | ----------------------- | ------- | ------------------: | -------------------- | +| America/Chicago | Chicago | 4887398 | 2,664,452 | 41.85003, -87.65005 | +| America/Los_Angeles | Los Angeles | 5368361 | 3,820,914 | 34.05223, -118.24368 | +| Asia/Kolkata | Mumbai | 1275339 | 12,691,836 | 19.07283, 72.88261 | +| Europe/Amsterdam | Rotterdam | 2747891 | 868,135 | 51.9225, 4.47917 | +| Africa/Accra | Kumasi | 2298890 | 2,544,530 | 6.68848, -1.62443 | + +Mumbai and Kumasi demonstrate why namesake substitution fails. Rotterdam is the maximum **settlement record** in this snapshot (`PPL`); Amsterdam's `PPLC` record has 741,636. No municipality records were compared. This establishes a snapshot ranking only; it does not establish Rotterdam as the largest real-world Dutch city. Mixed population dates/definitions remain a material limitation. + +A join against downloaded `zone.tab` found 27 identifiers with no eligible positive-population record in this small extract, including `Australia/Eucla`, `Australia/Lord_Howe`, `America/Adak`, and Antarctic identifiers. This is not proof those places are uninhabited or absent from the full extract. The full extract was not downloaded or audited. + +The literal `Pacific/Chatham` maximum was `Windsor Park`, ID `13631316`, population 4,000, coordinates `-36.73966, 174.7423`; `Waitangi`, ID `4032804`, population 140, coordinates `-43.95353, -176.55973`, was another candidate. The separation is an apparent data-quality anomaly requiring review before use; this research has not corrected either record. Numeric validation alone cannot establish geographic correctness. + +Downloaded IANA `version` reported `2026f`, matching the [IANA release page](https://www.iana.org/time-zones). Relevant file hashes: + +- `zone.tab`: `e2e8e31c4e10f44576c79345e76060591dbb3eef6ce14e006afc8a373caa9593` +- `zone1970.tab`: `5f23781702bf51408ff1581daa109ab3b9257fb433b1554e579d92172892c0cf` +- `backward`: `b8296b9ef1ece72d813878132c0f17e2c52b26af6004eeb9c37d049b64cd9401` + +The download URLs are mutable. Hashes identify this checked sample; a future implementation must retain/pin its own source snapshots. No global generated mapping or browser compatibility check was performed. + +## Licensing, attribution, and maintenance + +GeoNames declares [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) in its export documentation. The license permits adaptation and redistribution with appropriate credit, a license link, and an indication of changes. Proposed attribution: “City data: GeoNames, CC BY 4.0; filtered and ranked by AstrologyEngine,” linked to the source and license. Retain attribution with distributed derived data and in an accessible website credits surface. Placement is a later integration detail, not resolved here. + +[IANA's license](https://data.iana.org/time-zones/tzdb/LICENSE) places the data files in the public domain unless otherwise specified. Keep their version/license metadata. Any additional alias dataset would require its own license review; it is not assumed here. + +GeoNames offers daily extracts; IANA publishes periodic rule updates. A reproducible build should record URLs, UTC download time, archive/member hashes, tzdb version, generator/policy version, and curated exceptions. Rebuild as a reviewed data change when dependencies update; compare winners, coverage, and aliases before release. No background updating or live third-party lookup is needed. An automatic schedule has not been chosen. + +Existing sibling plugin source inspected: `src/lib/server/birth/atlas-row.ts` already models city/population/timezone/coordinates; `scripts/birth/manifest.ts` records GeoNames licensing and SHA-256 asset hashes. Those are useful conventions, but this research does not establish that the shipped atlas has exhaustive timezone coverage or validated city rankings. + +## Decisions still requiring the owner + +One follow-up grilling ticket can settle the mapping policy, one question at a time: + +1. **Meaning of largest city:** Is the maximum eligible GeoNames settlement population in a pinned snapshot sufficient, with reviewed exceptions, or is a common census/urban-area definition required? The former is compact and deterministic but can produce counterintuitive ranks; the latter needs further primary population sources and a clear shared definition. Confirm ECMA country-preserving geography rather than merging all clock-equivalent countries. +2. **Coverage and data errors:** Are small settlements allowed when no city exists, and may reviewed geographic corrections/exclusions override the raw maximum? The sample filter and suspicious Chatham result make this concrete. Unknown/zero population cannot establish a maximum. +3. **Unresolved browser location:** What should users see for missing/throwing Intl, UTC/GMT-only or fixed-offset identifiers (`Etc/GMT±n`, `+05:30`), newer unsupported zones, no eligible settlement, or rejected data? An explicit default city, opening the birth editor before calculation, or another owner-defined behavior are product alternatives. UTC is valid but does not imply London; numeric offsets do not identify longitude/latitude. Do not silently invent a location. + +These are new product choices, not grounds to reopen the approved one-chart, fresh-visit, transient-input behavior. The separate calculation-initialization ticket retains ownership of input/output shapes, epoch/time semantics, settings, engine provenance, and WASM parity. From bb07c90a4a66e517ac187ceb1329b3e2dfd10dee Mon Sep 17 00:00:00 2001 From: Jack Steam Date: Fri, 13 Nov 2026 14:42:10 -0600 Subject: [PATCH 2/2] docs: remove machine-specific research path --- docs/research/README.md | 2 +- docs/research/lahiri-integration.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/research/README.md b/docs/research/README.md index da8a656..3e1e3f4 100644 --- a/docs/research/README.md +++ b/docs/research/README.md @@ -12,5 +12,5 @@ Original issue links are retained as historical references. | [Timezone-to-city mapping](timezone-city-mapping.md) | `632238e1442b6bba1d653f0e283b7a1b23311d46` | | [Lahiri integration prerequisite](lahiri-integration.md) | `9def663cc1430e38716de16c07afb1f1a9b0a16c` | -The original research content is preserved with Markdown formatting normalized. Consolidating it here does +The original research content is preserved with Markdown formatting normalized and a local machine path removed. Consolidating it here does not implement the proposed behavior or establish numerical or product acceptance. diff --git a/docs/research/lahiri-integration.md b/docs/research/lahiri-integration.md index 56b6805..4ada8d0 100644 --- a/docs/research/lahiri-integration.md +++ b/docs/research/lahiri-integration.md @@ -4,7 +4,7 @@ Inspected 2026-11-10 for [Compare three fixed zodiac systems while preserving th ## Finding -Reuse the existing engine effort: [feat: add Lahiri chart reference (benchmark alignment pending)](https://github.com/AstrologyEngine/library/pull/9). It is open and draft, on `feat/lahiri` at `2b86542`, with an explicit consumer-rollout exclusion. Its local worktree is `/Users/jacksteam/Documents/AstrologyEngine/library/.worktrees/lahiri`; it was clean when inspected. Do not duplicate that work, copy its unaccepted binary into the website, or choose another Lahiri model while treating the existing effort as absent. +Reuse the existing engine effort: [feat: add Lahiri chart reference (benchmark alignment pending)](https://github.com/AstrologyEngine/library/pull/9). It is open and draft, on `feat/lahiri` at `2b86542`, with an explicit consumer-rollout exclusion. The local worktree was clean when inspected. Do not duplicate that work, copy its unaccepted binary into the website, or choose another Lahiri model while treating the existing effort as absent. The refreshed engine default `e47f53bdc00875b4e03885571f2461617da0971d` exposes Tropical, Fagan–Bradley and True Sky, without Lahiri. Its unified `calculate_chart` pipeline owns reference offset, daily-rate correction, projection, sign assignment and house construction. Use the accepted source revision rather than assuming the candidate branch is ready for consumers. [Current configuration](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/src/conventions.rs), [shared pipeline](https://github.com/AstrologyEngine/library/blob/e47f53bdc00875b4e03885571f2461617da0971d/src/chart.rs).